diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/base/nsAccessibilityService.h firefox-trunk-85.0~a1~hg20201117r557492/accessible/base/nsAccessibilityService.h --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/base/nsAccessibilityService.h 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/base/nsAccessibilityService.h 2020-11-17 19:31:23.000000000 +0000 @@ -498,6 +498,8 @@ "text value change", // EVENT_TEXT_VALUE_CHANGE "scrolling", // EVENT_SCROLLING "announcement", // EVENT_ANNOUNCEMENT + "live region added", // EVENT_LIVE_REGION_ADDED + "live region removed", // EVENT_LIVE_REGION_REMOVED }; #endif diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/interfaces/nsIAccessibleEvent.idl firefox-trunk-85.0~a1~hg20201117r557492/accessible/interfaces/nsIAccessibleEvent.idl --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/interfaces/nsIAccessibleEvent.idl 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/interfaces/nsIAccessibleEvent.idl 2020-11-17 19:31:23.000000000 +0000 @@ -429,9 +429,19 @@ const unsigned long EVENT_ANNOUNCEMENT = 0x0059; /** + * A live region has been introduced. Mac only. + */ + const unsigned long EVENT_LIVE_REGION_ADDED = 0x005A; + + /** + * A live region has been removed (aria-live attribute changed). Mac Only. + */ + const unsigned long EVENT_LIVE_REGION_REMOVED = 0x005B; + + /** * Help make sure event map does not get out-of-line. */ - const unsigned long EVENT_LAST_ENTRY = 0x005A; + const unsigned long EVENT_LAST_ENTRY = 0x005C; /** * The type of event, based on the enumerated event values diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/AccessibleWrap.mm firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/AccessibleWrap.mm --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/AccessibleWrap.mm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/AccessibleWrap.mm 2020-11-17 19:31:23.000000000 +0000 @@ -5,7 +5,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "DocAccessible.h" +#include "DocAccessibleWrap.h" #include "nsObjCExceptions.h" #include "nsCocoaUtils.h" @@ -30,7 +30,36 @@ using namespace mozilla::a11y; AccessibleWrap::AccessibleWrap(nsIContent* aContent, DocAccessible* aDoc) - : Accessible(aContent, aDoc), mNativeObject(nil), mNativeInited(false) {} + : Accessible(aContent, aDoc), mNativeObject(nil), mNativeInited(false) { + if (aContent && aContent->IsElement() && aDoc) { + // Check if this accessible is a live region and queue it + // it for dispatching an event after it has been inserted. + DocAccessibleWrap* doc = static_cast(aDoc); + static const dom::Element::AttrValuesArray sLiveRegionValues[] = { + nsGkAtoms::OFF, nsGkAtoms::polite, nsGkAtoms::assertive, nullptr}; + int32_t attrValue = aContent->AsElement()->FindAttrValueIn( + kNameSpaceID_None, nsGkAtoms::aria_live, sLiveRegionValues, + eIgnoreCase); + if (attrValue == 0) { + // aria-live is "off", do nothing. + } else if (attrValue > 0) { + // aria-live attribute is polite or assertive. It's live! + doc->QueueNewLiveRegion(this); + } else if (const nsRoleMapEntry* roleMap = + aria::GetRoleMap(aContent->AsElement())) { + // aria role defines it as a live region. It's live! + if (roleMap->liveAttRule == ePoliteLiveAttr) { + doc->QueueNewLiveRegion(this); + } + } else if (nsStaticAtom* value = GetAccService()->MarkupAttribute( + aContent, nsGkAtoms::live)) { + // HTML element defines it as a live region. It's live! + if (value == nsGkAtoms::polite || value == nsGkAtoms::assertive) { + doc->QueueNewLiveRegion(this); + } + } + } +} AccessibleWrap::~AccessibleWrap() {} @@ -120,11 +149,17 @@ nsresult rv = Accessible::HandleAccEvent(aEvent); NS_ENSURE_SUCCESS(rv, rv); + uint32_t eventType = aEvent->GetEventType(); + + if (eventType == nsIAccessibleEvent::EVENT_SHOW) { + DocAccessibleWrap* doc = static_cast(Document()); + doc->ProcessNewLiveRegions(); + } + if (IPCAccessibilityActive()) { return NS_OK; } - uint32_t eventType = aEvent->GetEventType(); Accessible* eventTarget = nullptr; switch (eventType) { @@ -222,6 +257,9 @@ case nsIAccessibleEvent::EVENT_SELECTION: case nsIAccessibleEvent::EVENT_SELECTION_ADD: case nsIAccessibleEvent::EVENT_SELECTION_REMOVE: + case nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED: + case nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED: + case nsIAccessibleEvent::EVENT_NAME_CHANGE: [nativeAcc handleAccessibleEvent:eventType]; break; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/DocAccessibleWrap.h firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/DocAccessibleWrap.h --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/DocAccessibleWrap.h 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/DocAccessibleWrap.h 2020-11-17 19:31:23.000000000 +0000 @@ -20,9 +20,23 @@ public: DocAccessibleWrap(dom::Document* aDocument, PresShell* aPresShell); + virtual ~DocAccessibleWrap(); + virtual void Shutdown() override; - virtual ~DocAccessibleWrap(); + virtual void AttributeChanged(dom::Element* aElement, int32_t aNameSpaceID, + nsAtom* aAttribute, int32_t aModType, + const nsAttrValue* aOldValue) override; + + void QueueNewLiveRegion(Accessible* aAccessible); + + void ProcessNewLiveRegions(); + + protected: + virtual void DoInitialUpdate() override; + + private: + nsTHashtable mNewLiveRegions; }; } // namespace a11y diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/DocAccessibleWrap.mm firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/DocAccessibleWrap.mm --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/DocAccessibleWrap.mm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/DocAccessibleWrap.mm 2020-11-17 19:31:23.000000000 +0000 @@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DocAccessibleWrap.h" +#include "DocAccessible-inl.h" #import "mozAccessible.h" #import "MOXTextMarkerDelegate.h" @@ -23,3 +24,80 @@ } DocAccessibleWrap::~DocAccessibleWrap() {} + +void DocAccessibleWrap::AttributeChanged(dom::Element* aElement, + int32_t aNameSpaceID, + nsAtom* aAttribute, int32_t aModType, + const nsAttrValue* aOldValue) { + DocAccessible::AttributeChanged(aElement, aNameSpaceID, aAttribute, aModType, + aOldValue); + if (aAttribute == nsGkAtoms::aria_live) { + Accessible* accessible = + mContent != aElement ? GetAccessible(aElement) : this; + if (!accessible) { + return; + } + + static const dom::Element::AttrValuesArray sLiveRegionValues[] = { + nsGkAtoms::OFF, nsGkAtoms::polite, nsGkAtoms::assertive, nullptr}; + int32_t attrValue = + aElement->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::aria_live, + sLiveRegionValues, eIgnoreCase); + if (attrValue > 0) { + if (!aOldValue || aOldValue->IsEmptyString() || + aOldValue->Equals(nsGkAtoms::OFF, eIgnoreCase)) { + // This element just got an active aria-live attribute value + FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED, + accessible); + } + } else { + if (aOldValue && (aOldValue->Equals(nsGkAtoms::polite, eIgnoreCase) || + aOldValue->Equals(nsGkAtoms::assertive, eIgnoreCase))) { + // This element lost an active live region + FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED, + accessible); + } else if (attrValue == 0) { + // aria-live="off", check if its a role-based live region that + // needs to be removed. + if (const nsRoleMapEntry* roleMap = accessible->ARIARoleMap()) { + // aria role defines it as a live region. It's live! + if (roleMap->liveAttRule == ePoliteLiveAttr) { + FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED, + accessible); + } + } else if (nsStaticAtom* value = GetAccService()->MarkupAttribute( + aElement, nsGkAtoms::live)) { + // HTML element defines it as a live region. It's live! + if (value == nsGkAtoms::polite || value == nsGkAtoms::assertive) { + FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED, + accessible); + } + } + } + } + } +} + +void DocAccessibleWrap::QueueNewLiveRegion(Accessible* aAccessible) { + if (!aAccessible) { + return; + } + + mNewLiveRegions.PutEntry(aAccessible->UniqueID()); +} + +void DocAccessibleWrap::ProcessNewLiveRegions() { + for (auto iter = mNewLiveRegions.Iter(); !iter.Done(); iter.Next()) { + if (Accessible* liveRegion = + GetAccessibleByUniqueID(const_cast(iter.Get()->GetKey()))) { + FireDelayedEvent(nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED, liveRegion); + } + } + + mNewLiveRegions.Clear(); +} + +void DocAccessibleWrap::DoInitialUpdate() { + DocAccessible::DoInitialUpdate(); + ProcessNewLiveRegions(); +} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/MOXAccessibleBase.h firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/MOXAccessibleBase.h --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/MOXAccessibleBase.h 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/MOXAccessibleBase.h 2020-11-17 19:31:23.000000000 +0000 @@ -123,6 +123,8 @@ // override - (id)moxTextMarkerDelegate; +- (BOOL)moxIsLiveRegion; + #pragma mark - - (NSString*)description; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/MOXAccessibleBase.mm firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/MOXAccessibleBase.mm --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/MOXAccessibleBase.mm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/MOXAccessibleBase.mm 2020-11-17 19:31:23.000000000 +0000 @@ -511,6 +511,10 @@ return nil; } +- (BOOL)moxIsLiveRegion { + return NO; +} + #pragma mark - // objc-style description (from NSObject); not to be confused with the diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/MOXAccessibleProtocol.h firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/MOXAccessibleProtocol.h --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/MOXAccessibleProtocol.h 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/MOXAccessibleProtocol.h 2020-11-17 19:31:23.000000000 +0000 @@ -57,6 +57,9 @@ // Return text delegate if it exists. - (id _Nullable)moxTextMarkerDelegate; +// Return true if this accessible is a live region +- (BOOL)moxIsLiveRegion; + @optional #pragma mark - AttributeGetters @@ -281,6 +284,15 @@ // AXEditableAncestor - (id _Nullable)moxEditableAncestor; +// AXARIAAtomic +- (NSNumber* _Nullable)moxARIAAtomic; + +// AXARIALive +- (NSString* _Nullable)moxARIALive; + +// AXARIARelevant +- (NSString* _Nullable)moxARIARelevant; + // AXMozDebugDescription - (NSString* _Nullable)moxMozDebugDescription; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/MOXSearchInfo.mm firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/MOXSearchInfo.mm --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/MOXSearchInfo.mm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/MOXSearchInfo.mm 2020-11-17 19:31:23.000000000 +0000 @@ -329,6 +329,13 @@ : RotorMacRoleRule(@"AXTextField"); [matches addObjectsFromArray:[self getMatchesForRule:rule]]; } + + if ([key isEqualToString:@"AXLiveRegionSearchKey"]) { + RotorLiveRegionRule rule = mImmediateDescendantsOnly + ? RotorLiveRegionRule(geckoRootAcc) + : RotorLiveRegionRule(); + [matches addObjectsFromArray:[self getMatchesForRule:rule]]; + } } return matches; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/mozAccessible.h firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/mozAccessible.h --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/mozAccessible.h 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/mozAccessible.h 2020-11-17 19:31:23.000000000 +0000 @@ -59,6 +59,8 @@ uint64_t mCachedState; nsStaticAtom* mARIARole; + + bool mIsLiveRegion; } // inits with the given wrap or proxy accessible @@ -133,6 +135,8 @@ - (id)moxTextMarkerDelegate; +- (BOOL)moxIsLiveRegion; + // Attribute getters // override @@ -184,6 +188,15 @@ - (NSString*)moxARIACurrent; // override +- (NSNumber*)moxARIAAtomic; + +// override +- (NSString*)moxARIALive; + +// override +- (NSString*)moxARIARelevant; + +// override - (id)moxTitleUIElement; // override diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/mozAccessible.mm firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/mozAccessible.mm --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/mozAccessible.mm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/mozAccessible.mm 2020-11-17 19:31:23.000000000 +0000 @@ -41,6 +41,8 @@ - (BOOL)providesLabelNotTitle; - (nsStaticAtom*)ARIARole; + +- (void)maybePostLiveRegionChanged; @end @implementation mozAccessible @@ -207,6 +209,12 @@ return [self stateWithMask:states::FOCUSABLE] == 0; } + if (selector == @selector(moxARIALive) || + selector == @selector(moxARIAAtomic) || + selector == @selector(moxARIARelevant)) { + return ![self moxIsLiveRegion]; + } + return [super moxBlockSelector:selector]; } @@ -260,6 +268,10 @@ getOrCreateForDoc:mGeckoAccessible.AsProxy()->Document()]; } +- (BOOL)moxIsLiveRegion { + return mIsLiveRegion; +} + - (id)moxHitTest:(NSPoint)point { MOZ_ASSERT(!mGeckoAccessible.IsNull()); @@ -709,6 +721,23 @@ return utils::GetAccAttr(self, "current"); } +- (NSNumber*)moxARIAAtomic { + return @(utils::GetAccAttr(self, "atomic") != nil); +} + +- (NSString*)moxARIALive { + return utils::GetAccAttr(self, "live"); +} + +- (NSString*)moxARIARelevant { + if (NSString* relevant = utils::GetAccAttr(self, "container-relevant")) { + return relevant; + } + + // Default aria-relevant value + return @"additions text"; +} + - (id)moxTitleUIElement { MOZ_ASSERT(!mGeckoAccessible.IsNull()); @@ -911,11 +940,20 @@ return NO; } +- (void)maybePostLiveRegionChanged { + for (id element = self; [element conformsToProtocol:@protocol(MOXAccessible)]; + element = [element moxUnignoredParent]) { + if ([element moxIsLiveRegion]) { + [element moxPostNotification:@"AXLiveRegionChanged"]; + return; + } + } +} + - (void)handleAccessibleTextChangeEvent:(NSString*)change inserted:(BOOL)isInserted inContainer:(const AccessibleOrProxy&)container at:(int32_t)start { - // XXX: Eventually live region handling will go here. } - (void)handleAccessibleEvent:(uint32_t)eventType { @@ -963,6 +1001,17 @@ withUserInfo:userInfo]; break; } + case nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED: + mIsLiveRegion = true; + [self moxPostNotification:@"AXLiveRegionCreated"]; + break; + case nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED: + mIsLiveRegion = false; + break; + case nsIAccessibleEvent::EVENT_REORDER: + case nsIAccessibleEvent::EVENT_NAME_CHANGE: + [self maybePostLiveRegionChanged]; + break; } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/Platform.mm firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/Platform.mm --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/Platform.mm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/Platform.mm 2020-11-17 19:31:23.000000000 +0000 @@ -77,14 +77,16 @@ } void ProxyEvent(ProxyAccessible* aProxy, uint32_t aEventType) { - // ignore everything but focus-changed, value-changed, caret, - // selection, and document load complete events for now. + // Ignore event that we don't escape below, they aren't yet supported. if (aEventType != nsIAccessibleEvent::EVENT_FOCUS && aEventType != nsIAccessibleEvent::EVENT_VALUE_CHANGE && aEventType != nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE && aEventType != nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED && aEventType != nsIAccessibleEvent::EVENT_DOCUMENT_LOAD_COMPLETE && - aEventType != nsIAccessibleEvent::EVENT_REORDER) + aEventType != nsIAccessibleEvent::EVENT_REORDER && + aEventType != nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED && + aEventType != nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED && + aEventType != nsIAccessibleEvent::EVENT_NAME_CHANGE) return; mozAccessible* wrapper = GetNativeFromGeckoAccessible(aProxy); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/RotorRules.h firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/RotorRules.h --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/RotorRules.h 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/RotorRules.h 2020-11-17 19:31:23.000000000 +0000 @@ -113,6 +113,15 @@ int32_t mLevel; }; +class RotorLiveRegionRule : public RotorRule { + public: + explicit RotorLiveRegionRule(AccessibleOrProxy& aDirectDescendantsFrom) + : RotorRule(aDirectDescendantsFrom) {} + explicit RotorLiveRegionRule() : RotorRule() {} + + uint16_t Match(const AccessibleOrProxy& aAccOrProxy) override; +}; + /** * This rule matches all accessibles with roles::OUTLINEITEM. If * outlines are nested, it ignores the nested subtree and returns diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/RotorRules.mm firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/RotorRules.mm --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/mac/RotorRules.mm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/mac/RotorRules.mm 2020-11-17 19:31:23.000000000 +0000 @@ -308,6 +308,18 @@ return result; } +uint16_t RotorLiveRegionRule::Match(const AccessibleOrProxy& aAccOrProxy) { + uint16_t result = RotorRule::Match(aAccOrProxy); + + if ((result & nsIAccessibleTraversalRule::FILTER_MATCH)) { + mozAccessible* nativeMatch = GetNativeFromGeckoAccessible(aAccOrProxy); + if (![nativeMatch moxIsLiveRegion]) { + result &= ~nsIAccessibleTraversalRule::FILTER_MATCH; + } + } + return result; +} + // Outline Rule OutlineRule::OutlineRule() : RotorRule(){}; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/browser/mac/browser.ini firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/browser/mac/browser.ini --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/browser/mac/browser.ini 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/browser/mac/browser.ini 2020-11-17 19:31:23.000000000 +0000 @@ -39,3 +39,4 @@ [browser_navigate.js] [browser_outline.js] [browser_hierarchy.js] +[browser_live_regions.js] diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/browser/mac/browser_live_regions.js firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/browser/mac/browser_live_regions.js --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/browser/mac/browser_live_regions.js 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/browser/mac/browser_live_regions.js 2020-11-17 19:31:23.000000000 +0000 @@ -0,0 +1,164 @@ +/* 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/. */ + +"use strict"; + +/** + * Test live region creation and removal. + */ +addAccessibleTask( + ` +
Polite region
+
Assertive region
+ `, + async (browser, accDoc) => { + let politeRegion = getNativeInterface(accDoc, "polite"); + ok( + !politeRegion.attributeNames.includes("AXARIALive"), + "region is not live" + ); + + let liveRegionAdded = waitForMacEvent("AXLiveRegionCreated", "polite"); + await SpecialPowers.spawn(browser, [], () => { + content.document + .getElementById("polite") + .setAttribute("aria-atomic", "true"); + content.document + .getElementById("polite") + .setAttribute("aria-live", "polite"); + }); + await liveRegionAdded; + is( + politeRegion.getAttributeValue("AXARIALive"), + "polite", + "region is now live" + ); + ok(politeRegion.getAttributeValue("AXARIAAtomic"), "region is atomic"); + is( + politeRegion.getAttributeValue("AXARIARelevant"), + "removals", + "region has defined aria-relevant" + ); + + let assertiveRegion = getNativeInterface(accDoc, "assertive"); + is( + assertiveRegion.getAttributeValue("AXARIALive"), + "assertive", + "region is assertive" + ); + ok( + !assertiveRegion.getAttributeValue("AXARIAAtomic"), + "region is not atomic" + ); + is( + assertiveRegion.getAttributeValue("AXARIARelevant"), + "additions text", + "region has default aria-relevant" + ); + + let liveRegionRemoved = waitForEvent( + EVENT_LIVE_REGION_REMOVED, + "assertive" + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.getElementById("assertive").removeAttribute("aria-live"); + }); + await liveRegionRemoved; + ok(!assertiveRegion.getAttributeValue("AXARIALive"), "region is not live"); + + liveRegionAdded = waitForMacEvent("AXLiveRegionCreated", "new-region"); + await SpecialPowers.spawn(browser, [], () => { + let newRegionElm = content.document.createElement("div"); + newRegionElm.id = "new-region"; + newRegionElm.setAttribute("aria-live", "assertive"); + content.document.body.appendChild(newRegionElm); + }); + await liveRegionAdded; + + let newRegion = getNativeInterface(accDoc, "new-region"); + is( + newRegion.getAttributeValue("AXARIALive"), + "assertive", + "region is assertive" + ); + + let loadComplete = Promise.all([ + waitForMacEvent("AXLoadComplete"), + waitForMacEvent("AXLiveRegionCreated", "region-1"), + waitForMacEvent("AXLiveRegionCreated", "region-2"), + waitForMacEvent("AXLiveRegionCreated", "status"), + waitForMacEvent("AXLiveRegionCreated", "output"), + ]); + + await SpecialPowers.spawn(browser, [], () => { + content.location = `data:text/html;charset=utf-8, +
+
+
+
+ `; + }); + let webArea = (await loadComplete)[0]; + + is(webArea.getAttributeValue("AXRole"), "AXWebArea", "web area yeah"); + const searchPred = { + AXSearchKey: "AXLiveRegionSearchKey", + AXResultsLimit: -1, + AXDirection: "AXDirectionNext", + }; + const liveRegions = webArea.getParameterizedAttributeValue( + "AXUIElementsForSearchPredicate", + NSDictionary(searchPred) + ); + Assert.deepEqual( + liveRegions.map(r => r.getAttributeValue("AXDOMIdentifier")), + ["region-1", "region-2", "status", "output"], + "SearchPredicate returned all live regions" + ); + } +); + +/** + * Test live region changes + */ +addAccessibleTask( + ` +
+ The time is 4:55pm + + +
+ `, + async (browser, accDoc) => { + let liveRegionChanged = waitForMacEvent("AXLiveRegionChanged", "live"); + await SpecialPowers.spawn(browser, [], () => { + content.document.getElementById("time").textContent = "4:56pm"; + }); + await liveRegionChanged; + ok(true, "changed textContent"); + + liveRegionChanged = waitForMacEvent("AXLiveRegionChanged", "live"); + await SpecialPowers.spawn(browser, [], () => { + content.document.getElementById("p").style.display = "block"; + }); + await liveRegionChanged; + ok(true, "changed display style to block"); + + liveRegionChanged = waitForMacEvent("AXLiveRegionChanged", "live"); + await SpecialPowers.spawn(browser, [], () => { + content.document.getElementById("p").style.display = "none"; + }); + await liveRegionChanged; + ok(true, "changed display style to none"); + + liveRegionChanged = waitForMacEvent("AXLiveRegionChanged", "live"); + await SpecialPowers.spawn(browser, [], () => { + content.document + .getElementById("button") + .setAttribute("aria-label", "Stop"); + }); + await liveRegionChanged; + ok(true, "changed aria-label"); + } +); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/browser/mac/head.js firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/browser/mac/head.js --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/browser/mac/head.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/browser/mac/head.js 2020-11-17 19:31:23.000000000 +0000 @@ -28,13 +28,25 @@ } function waitForMacEventWithInfo(notificationType, filter) { + let filterFunc = (macIface, data) => { + if (!filter) { + return true; + } + + if (typeof filter == "function") { + return filter(macIface, data); + } + + return macIface.getAttributeValue("AXDOMIdentifier") == filter; + }; + return new Promise(resolve => { let eventObserver = { observe(subject, topic, data) { let macEvent = subject.QueryInterface(Ci.nsIAccessibleMacEvent); if ( data === notificationType && - (!filter || filter(macEvent.macIface, macEvent.data)) + filterFunc(macEvent.macIface, macEvent.data) ) { Services.obs.removeObserver(this, "accessible-mac-event"); resolve(macEvent); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/browser/shared-head.js firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/browser/shared-head.js --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/browser/shared-head.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/browser/shared-head.js 2020-11-17 19:31:23.000000000 +0000 @@ -431,7 +431,11 @@ gIsRemoteIframe = options.remoteIframe; gIsIframe = options.iframe || gIsRemoteIframe; let url; - if (doc.endsWith("html") && !gIsIframe) { + if (options.chrome && doc.endsWith("html")) { + // Load with a chrome:// URL so this loads as a chrome document in the + // parent process. + url = `${CURRENT_DIR}${doc}`; + } else if (doc.endsWith("html") && !gIsIframe) { url = `${CURRENT_CONTENT_DIR}${doc}`; } else { url = snippetToURL(doc, options); @@ -445,10 +449,13 @@ } }); - const onContentDocLoad = waitForEvent( - EVENT_DOCUMENT_LOAD_COMPLETE, - DEFAULT_CONTENT_DOC_BODY_ID - ); + let onContentDocLoad; + if (!options.chrome) { + onContentDocLoad = waitForEvent( + EVENT_DOCUMENT_LOAD_COMPLETE, + DEFAULT_CONTENT_DOC_BODY_ID + ); + } let onIframeDocLoad; if (options.remoteIframe && !options.skipFissionDocLoad) { @@ -476,11 +483,29 @@ await SimpleTest.promiseFocus(browser); await loadContentScripts(browser, "Common.jsm"); - if (Services.appinfo.browserTabsRemoteAutostart) { + if (options.chrome) { + ok(!browser.isRemoteBrowser, "Not remote browser"); + } else if (Services.appinfo.browserTabsRemoteAutostart) { ok(browser.isRemoteBrowser, "Actually remote browser"); } - const { accessible: docAccessible } = await onContentDocLoad; + let docAccessible; + if (options.chrome) { + // Chrome documents don't fire DOCUMENT_LOAD_COMPLETE. Instead, wait + // until we can get the DocAccessible and it doesn't have the busy + // state. + await BrowserTestUtils.waitForCondition(() => { + docAccessible = getAccessible(browser.contentWindow.document); + if (!docAccessible) { + return false; + } + const state = {}; + docAccessible.getState(state, {}); + return !(state.value & STATE_BUSY); + }); + } else { + ({ accessible: docAccessible } = await onContentDocLoad); + } let iframeDocAccessible; if (gIsIframe) { if (!options.skipFissionDocLoad) { @@ -515,6 +540,12 @@ * - {Boolean} topLevel * Flag to run the test with content in the top level content process. * Default is true. + * - {Boolean} chrome + * Flag to run the test with content as a chrome document in the + * parent process. Default is false. This is only valid if url is a + * relative URL to a XUL document, not a markup snippet. topLevel + * should usually be set to false in this case, since XUL documents + * don't work in the content process. * - {Boolean} iframe * Flag to run the test with content wrapped in an iframe. Default is * false. @@ -533,11 +564,28 @@ * a set of attributes to be applied to a iframe content document body */ function addAccessibleTask(doc, task, options = {}) { - const { topLevel = true, iframe = false, remoteIframe = false } = options; + const { + topLevel = true, + chrome = false, + iframe = false, + remoteIframe = false, + } = options; if (topLevel) { add_task( accessibleTask(doc, task, { ...options, + chrome: false, + iframe: false, + remoteIframe: false, + }) + ); + } + + if (chrome) { + add_task( + accessibleTask(doc, task, { + ...options, + topLevel: false, iframe: false, remoteIframe: false, }) @@ -549,6 +597,7 @@ accessibleTask(doc, task, { ...options, topLevel: false, + chrome: false, remoteIframe: false, }) ); @@ -559,6 +608,7 @@ accessibleTask(doc, task, { ...options, topLevel: false, + chrome: false, iframe: false, }) ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/mochitest/name/test_browserui.xhtml firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/mochitest/name/test_browserui.xhtml --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/mochitest/name/test_browserui.xhtml 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/mochitest/name/test_browserui.xhtml 2020-11-17 19:31:23.000000000 +0000 @@ -34,8 +34,8 @@ let docLoaded = waitForEvent(EVENT_DOCUMENT_LOAD_COMPLETE, event => event.accessible.QueryInterface(nsIAccessibleDocument).URL === ABOUT_LICENSE_URL, `Loaded tab: ${ABOUT_LICENSE_URL}`); - await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, - ABOUT_LICENSE_URL); + BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, + "about:license"); await loaded; await docLoaded; await winFocused; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/mochitest/promisified-events.js firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/mochitest/promisified-events.js --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/tests/mochitest/promisified-events.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/tests/mochitest/promisified-events.js 2020-11-17 19:31:23.000000000 +0000 @@ -42,6 +42,8 @@ const EVENT_ALERT = nsIAccessibleEvent.EVENT_ALERT; const EVENT_TEXT_SELECTION_CHANGED = nsIAccessibleEvent.EVENT_TEXT_SELECTION_CHANGED; +const EVENT_LIVE_REGION_ADDED = nsIAccessibleEvent.EVENT_LIVE_REGION_ADDED; +const EVENT_LIVE_REGION_REMOVED = nsIAccessibleEvent.EVENT_LIVE_REGION_REMOVED; const EventsLogger = { enabled: false, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/accessible/windows/msaa/nsEventMap.h firefox-trunk-85.0~a1~hg20201117r557492/accessible/windows/msaa/nsEventMap.h --- firefox-trunk-84.0~a1~hg20201115r557261/accessible/windows/msaa/nsEventMap.h 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/accessible/windows/msaa/nsEventMap.h 2020-11-17 19:31:23.000000000 +0000 @@ -102,5 +102,7 @@ EVENT_OBJECT_VALUECHANGE, // nsIAccessibleEvent::EVENT_TEXT_VALUE_CHANGE kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_SCROLLING kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_ANNOUNCEMENT + kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_LIVE_REGION_ADDED + kEVENT_WIN_UNKNOWN, // nsIAccessibleEvent::EVENT_LIVE_REGION_REMOVED // clang-format on }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/actors/BrowserTabParent.jsm firefox-trunk-85.0~a1~hg20201117r557492/browser/actors/BrowserTabParent.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/browser/actors/BrowserTabParent.jsm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/actors/BrowserTabParent.jsm 2020-11-17 19:31:23.000000000 +0000 @@ -30,15 +30,6 @@ browser.ownerGlobal.gBrowserInit._firstContentWindowPaintDeferred.resolve(); break; } - - case "Browser:LoadURI": { - if (gBrowser.sessionHistoryInParent) { - message.data.historyIndex = - browsingContext.sessionHistory.requestedIndex; - } - gBrowser.ownerGlobal.RedirectLoad(browser, message.data); - break; - } } } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/browser.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/browser.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/browser.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/browser.js 2020-11-17 19:31:23.000000000 +0000 @@ -1537,32 +1537,31 @@ throw new Error("Cannot load with mismatched userContextId"); } - let { - uriObject, - requiredRemoteType, - mustChangeProcess, - newFrameloader, - } = E10SUtils.shouldLoadURIInBrowser( - browser, - uri, - gMultiProcessBrowser, - gFissionBrowser, - loadFlags - ); - if (uriObject && handleUriInChrome(browser, uriObject)) { - // If we've handled the URI in Chrome then just return here. - return; - } - if (newFrameloader) { - // If a new frameloader is needed for process reselection because this used - // to be a preloaded browser, clear the preloaded state now. - browser.removeAttribute("preloadedState"); - } + // Attempt to perform URI fixup to see if we can handle this URI in chrome. + try { + let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_NONE; + if (loadFlags & Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { + fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP; + } + if (loadFlags & Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS) { + fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS; + } + if (PrivateBrowsingUtils.isBrowserPrivate(browser)) { + fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_PRIVATE_CONTEXT; + } - // !requiredRemoteType means we're loading in the parent/this process. - if (!requiredRemoteType) { - browser.isNavigating = true; + let uriObject = Services.uriFixup.getFixupURIInfo(uri, fixupFlags) + .preferredURI; + if (uriObject && handleUriInChrome(browser, uriObject)) { + // If we've handled the URI in Chrome, then just return here. + return; + } + } catch (e) { + // getFixupURIInfo may throw. Gracefully recover and try to load the URI normally. } + + // XXX(nika): Is `browser.isNavigating` necessary anymore? + browser.isNavigating = true; let loadURIOptions = { triggeringPrincipal, csp, @@ -1572,96 +1571,9 @@ hasValidUserGestureActivation, }; try { - if (!mustChangeProcess) { - browser.webNavigation.loadURI(uri, loadURIOptions); - } else { - // Check if the current browser is allowed to unload. - let { permitUnload } = browser.permitUnload(); - if (!permitUnload) { - return; - } - - if (postData) { - postData = serializeInputStream(postData); - } - - let loadParams = { - uri, - triggeringPrincipal: triggeringPrincipal - ? E10SUtils.serializePrincipal(triggeringPrincipal) - : null, - flags: loadFlags, - referrerInfo: E10SUtils.serializeReferrerInfo(referrerInfo), - remoteType: requiredRemoteType, - postData, - newFrameloader, - csp: csp ? gSerializationHelper.serializeToString(csp) : null, - }; - - if (userContextId) { - loadParams.userContextId = userContextId; - } - - if (browser.webNavigation.maybeCancelContentJSExecution) { - let cancelContentJSEpoch = browser.webNavigation.maybeCancelContentJSExecution( - Ci.nsIRemoteTab.NAVIGATE_URL, - { uri: uriObject } - ); - loadParams.cancelContentJSEpoch = cancelContentJSEpoch; - } - LoadInOtherProcess(browser, loadParams); - } - } catch (e) { - // If anything goes wrong when switching remoteness, just switch remoteness - // manually and load the URI. - // We might lose history that way but at least the browser loaded a page. - // This might be necessary if SessionStore wasn't initialized yet i.e. - // when the homepage is a non-remote page. - if (mustChangeProcess) { - Cu.reportError(e); - gBrowser.updateBrowserRemotenessByURL(browser, uri); - - browser.webNavigation.loadURI(uri, loadURIOptions); - } else { - throw e; - } + browser.webNavigation.loadURI(uri, loadURIOptions); } finally { - if (!requiredRemoteType) { - browser.isNavigating = false; - } - } -} - -// Starts a new load in the browser first switching the browser to the correct -// process -function LoadInOtherProcess(browser, loadOptions, historyIndex = -1) { - let tab = gBrowser.getTabForBrowser(browser); - SessionStore.navigateAndRestore(tab, loadOptions, historyIndex); -} - -// Called when a docshell has attempted to load a page in an incorrect process. -// This function is responsible for loading the page in the correct process. -function RedirectLoad(browser, data) { - if (browser.getAttribute("preloadedState") === "consumed") { - browser.removeAttribute("preloadedState"); - data.loadOptions.newFrameloader = true; - } - - // We should only start the redirection if the browser window has finished - // starting up. Otherwise, we should wait until the startup is done. - if (gBrowserInit.delayedStartupFinished) { - LoadInOtherProcess(browser, data.loadOptions, data.historyIndex); - } else { - let delayedStartupFinished = (subject, topic) => { - if (topic == "browser-delayed-startup-finished" && subject == window) { - Services.obs.removeObserver(delayedStartupFinished, topic); - LoadInOtherProcess(browser, data.loadOptions, data.historyIndex); - } - }; - Services.obs.addObserver( - delayedStartupFinished, - "browser-delayed-startup-finished" - ); + browser.isNavigating = false; } } @@ -5193,50 +5105,6 @@ ); }, - // Check whether this URI should load in the current process - shouldLoadURI( - aDocShell, - aURI, - aReferrerInfo, - aHasPostData, - aTriggeringPrincipal, - aCsp - ) { - if (!gMultiProcessBrowser) { - return true; - } - - let browser = aDocShell - .QueryInterface(Ci.nsIDocShellTreeItem) - .sameTypeRootTreeItem.QueryInterface(Ci.nsIDocShell).chromeEventHandler; - - // Ignore loads that aren't in the main tabbrowser - if ( - browser.localName != "browser" || - !browser.getTabBrowser || - browser.getTabBrowser() != gBrowser - ) { - return true; - } - - if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aHasPostData)) { - // XXX: Do we want to complain if we have post data but are still - // redirecting the load? Perhaps a telemetry probe? Theoretically we - // shouldn't do this, as it throws out data. See bug 1348018. - E10SUtils.redirectLoad( - aDocShell, - aURI, - aReferrerInfo, - aTriggeringPrincipal, - null, - aCsp - ); - return false; - } - - return true; - }, - onProgressChange( aWebProgress, aRequest, @@ -6253,9 +6121,9 @@ // If we have an opener, that means that the caller is expecting access // to the nsIDOMWindow of the opened tab right away. For e10s windows, // this means forcing the newly opened browser to be non-remote so that - // we can hand back the nsIDOMWindow. The XULBrowserWindow.shouldLoadURI - // will do the job of shuttling off the newly opened browser to run in - // the right process once it starts loading a URI. + // we can hand back the nsIDOMWindow. DocumentLoadListener will do the + // job of shuttling off the newly opened browser to run in the right + // process once it starts loading a URI. let forceNotRemote = aOpenWindowInfo && !aOpenWindowInfo.isRemote; let userContextId = aOpenWindowInfo ? aOpenWindowInfo.originAttributes.userContextId diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/tab-content.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/tab-content.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/tab-content.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/tab-content.js 2020-11-17 19:31:23.000000000 +0000 @@ -11,11 +11,6 @@ ChromeUtils.defineModuleGetter( this, - "E10SUtils", - "resource://gre/modules/E10SUtils.jsm" -); -ChromeUtils.defineModuleGetter( - this, "BrowserUtils", "resource://gre/modules/BrowserUtils.jsm" ); @@ -42,25 +37,11 @@ aTriggeringPrincipal, aCsp ) { - if (!E10SUtils.shouldLoadURI(aDocShell, aURI, aHasPostData)) { - E10SUtils.redirectLoad( - aDocShell, - aURI, - aReferrerInfo, - aTriggeringPrincipal, - null, - aCsp - ); - return false; - } - return true; }, shouldLoadURIInThisProcess(aURI) { - let remoteSubframes = docShell.QueryInterface(Ci.nsILoadContext) - .useRemoteSubframes; - return E10SUtils.shouldLoadURIInThisProcess(aURI, remoteSubframes); + return true; }, }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/about/browser_aboutNewTab_bookmarksToolbar.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/about/browser_aboutNewTab_bookmarksToolbar.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/about/browser_aboutNewTab_bookmarksToolbar.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/about/browser_aboutNewTab_bookmarksToolbar.js 2020-11-17 19:31:23.000000000 +0000 @@ -31,7 +31,7 @@ ); // 2: Test that the toolbar is hidden when the browser is navigated away from newtab - await BrowserTestUtils.loadURI(newtab.linkedBrowser, "https://example.com"); + BrowserTestUtils.loadURI(newtab.linkedBrowser, "https://example.com"); await BrowserTestUtils.browserLoaded(newtab.linkedBrowser); if (featureEnabled) { await waitForBookmarksToolbarVisibility({ @@ -46,7 +46,7 @@ ); // 3: Re-load about:newtab in the browser for the following tests and confirm toolbar reappears - await BrowserTestUtils.loadURI(newtab.linkedBrowser, "about:newtab"); + BrowserTestUtils.loadURI(newtab.linkedBrowser, "about:newtab"); await BrowserTestUtils.browserLoaded(newtab.linkedBrowser); if (featureEnabled) { await waitForBookmarksToolbarVisibility({ @@ -92,7 +92,7 @@ }); // 7: Similar to #3 above, loading about:newtab in example should show toolbar - await BrowserTestUtils.loadURI(example.linkedBrowser, "about:newtab"); + BrowserTestUtils.loadURI(example.linkedBrowser, "about:newtab"); await BrowserTestUtils.browserLoaded(example.linkedBrowser); if (featureEnabled) { await waitForBookmarksToolbarVisibility({ @@ -126,10 +126,7 @@ await BrowserTestUtils.switchTab(gBrowser, newtab); await waitForBookmarksToolbarVisibility({ visible: false }); ok(!isBookmarksToolbarVisible(), "Toolbar should hide with custom newtab"); - await BrowserTestUtils.loadURI( - example.linkedBrowser, - AboutNewTab.newTabURL - ); + BrowserTestUtils.loadURI(example.linkedBrowser, AboutNewTab.newTabURL); await BrowserTestUtils.browserLoaded(example.linkedBrowser); await BrowserTestUtils.switchTab(gBrowser, example); if (featureEnabled) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/about/browser_aboutNewTab_defaultBrowserNotification.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/about/browser_aboutNewTab_defaultBrowserNotification.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/about/browser_aboutNewTab_defaultBrowserNotification.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/about/browser_aboutNewTab_defaultBrowserNotification.js 2020-11-17 19:31:23.000000000 +0000 @@ -74,10 +74,7 @@ "Notification should be default browser" ); - await BrowserTestUtils.loadURI( - gBrowser.selectedBrowser, - "https://example.com" - ); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "https://example.com"); let notificationRemoved = await TestUtils.waitForCondition( () => @@ -108,7 +105,7 @@ !gBrowser.getNotificationBox(tab.linkedBrowser).currentNotification, "a notification should not be shown on about:robots" ); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:home"); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:home"); let notification = await TestUtils.waitForCondition( () => diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/about/browser_aboutStopReload.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/about/browser_aboutStopReload.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/about/browser_aboutStopReload.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/about/browser_aboutStopReload.js 2020-11-17 19:31:23.000000000 +0000 @@ -57,7 +57,7 @@ stopReloadContainerObserver.observe(stopReloadContainer, { attributeFilter: ["animate"], }); - await BrowserTestUtils.loadURI(tab.linkedBrowser, "about:mozilla"); + BrowserTestUtils.loadURI(tab.linkedBrowser, "about:mozilla"); BrowserTestUtils.removeTab(tab); Assert.ok( @@ -82,7 +82,7 @@ stopReloadContainerObserver.observe(stopReloadContainer, { attributeFilter: ["animate"], }); - await BrowserTestUtils.loadURI(tab.linkedBrowser, "about:mozilla"); + BrowserTestUtils.loadURI(tab.linkedBrowser, "about:mozilla"); BrowserTestUtils.removeTab(tab); Assert.ok( @@ -132,7 +132,7 @@ return !gBrowser.tabAnimationsInProgress; }); let animatePromise = getAnimatePromise(stopReloadContainer); - await BrowserTestUtils.loadURI(tab.linkedBrowser, "https://example.com"); + BrowserTestUtils.loadURI(tab.linkedBrowser, "https://example.com"); await animatePromise; BrowserTestUtils.removeTab(tab); @@ -158,7 +158,7 @@ return !gBrowser.tabAnimationsInProgress; }); let animatePromise = getAnimatePromise(stopReloadContainer); - await BrowserTestUtils.loadURI(tab.linkedBrowser, "https://example.com"); + BrowserTestUtils.loadURI(tab.linkedBrowser, "https://example.com"); await animatePromise; await waitForNoAnimation(stopReloadContainer); BrowserTestUtils.removeTab(tab); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/about/browser_bug435325.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/about/browser_bug435325.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/about/browser_bug435325.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/about/browser_bug435325.js 2020-11-17 19:31:23.000000000 +0000 @@ -21,7 +21,7 @@ await BrowserTestUtils.withNewTab("about:blank", async function(browser) { let netErrorLoaded = BrowserTestUtils.waitForErrorPage(browser); - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await netErrorLoaded; // Re-enable the proxy so example.com is resolved to localhost, rather than diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/contextMenu/browser_contextmenu_loadblobinnewtab.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/contextMenu/browser_contextmenu_loadblobinnewtab.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/contextMenu/browser_contextmenu_loadblobinnewtab.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/contextMenu/browser_contextmenu_loadblobinnewtab.js 2020-11-17 19:31:24.000000000 +0000 @@ -20,7 +20,7 @@ false, RESOURCE_LINK ); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, RESOURCE_LINK); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, RESOURCE_LINK); await loaded; const generatedBlobURL = await ContentTask.spawn( @@ -97,7 +97,7 @@ false, RESOURCE_LINK ); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, RESOURCE_LINK); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, RESOURCE_LINK); await loaded; const generatedBlobURL = await ContentTask.spawn( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/forms/browser_selectpopup.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/forms/browser_selectpopup.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/forms/browser_selectpopup.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/forms/browser_selectpopup.js 2020-11-17 19:31:23.000000000 +0000 @@ -904,7 +904,7 @@ let browserLoadedPromise = BrowserTestUtils.browserLoaded( newWin.gBrowser.selectedBrowser ); - await BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, pageUrl); + BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, pageUrl); await browserLoadedPromise; newWin.gBrowser.selectedBrowser.focus(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/fullscreen/browser.ini firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/fullscreen/browser.ini --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/fullscreen/browser.ini 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/fullscreen/browser.ini 2020-11-17 19:31:24.000000000 +0000 @@ -15,6 +15,6 @@ [browser_fullscreen_window_open.js] skip-if = debug && os == 'mac' # Bug 1568570 [browser_fullscreen_window_focus.js] -skip-if = os == 'mac' || (debug && fission && os == "linux" && os_version == "18.04") # Bug 1568570, 1618386 +skip-if = os == 'mac' # Bug 1568570 [browser_fullscreen_api_fission.js] support-files = fullscreen.html FullscreenFrame.jsm diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/browser_bug495058.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/browser_bug495058.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/browser_bug495058.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/browser_bug495058.js 2020-11-17 19:31:24.000000000 +0000 @@ -8,7 +8,8 @@ add_task(async function() { for (let uri of URIS) { let tab = BrowserTestUtils.addTab(gBrowser); - await BrowserTestUtils.loadURI(tab.linkedBrowser, uri); + BrowserTestUtils.loadURI(tab.linkedBrowser, uri); + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); let win = gBrowser.replaceTabWithWindow(tab); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/browser_bug724239.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/browser_bug724239.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/browser_bug724239.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/browser_bug724239.js 2020-11-17 19:31:23.000000000 +0000 @@ -22,11 +22,11 @@ async function(browser) { // Can't load it directly because that'll use a preloaded tab if present. let stopped = BrowserTestUtils.browserStopped(browser, "about:newtab"); - await BrowserTestUtils.loadURI(browser, "about:newtab"); + BrowserTestUtils.loadURI(browser, "about:newtab"); await stopped; stopped = BrowserTestUtils.browserStopped(browser, "http://example.com/"); - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await stopped; // This makes sure the parent process has the most up-to-date notion diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/browser_page_style_menu.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/browser_page_style_menu.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/browser_page_style_menu.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/browser_page_style_menu.js 2020-11-17 19:31:24.000000000 +0000 @@ -34,7 +34,7 @@ false ); let browser = tab.linkedBrowser; - await BrowserTestUtils.loadURI(browser, WEB_ROOT + "page_style_sample.html"); + BrowserTestUtils.loadURI(browser, WEB_ROOT + "page_style_sample.html"); await promiseStylesheetsLoaded(tab, 17); let menuitems = fillPopupAndGetItems(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/browser_page_style_menu_update.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/browser_page_style_menu_update.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/browser_page_style_menu_update.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/browser_page_style_menu_update.js 2020-11-17 19:31:24.000000000 +0000 @@ -14,7 +14,7 @@ false ); let browser = tab.linkedBrowser; - await BrowserTestUtils.loadURI(browser, PAGE); + BrowserTestUtils.loadURI(browser, PAGE); await promiseStylesheetsLoaded(tab, 17); let menupopup = document.getElementById("pageStyleMenu").menupopup; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/head.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/head.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/general/head.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/general/head.js 2020-11-17 19:31:23.000000000 +0000 @@ -377,7 +377,7 @@ async function loadBadCertPage(url) { let loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); await loaded; await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/performance/browser_preferences_usage.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/performance/browser_preferences_usage.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/performance/browser_preferences_usage.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/performance/browser_preferences_usage.js 2020-11-17 19:31:23.000000000 +0000 @@ -264,7 +264,7 @@ for (let i = 0; i < 50; i++) { let url = urls[i % urls.length]; info(`Navigating to ${url}...`); - await BrowserTestUtils.loadURI(tab.linkedBrowser, url); + BrowserTestUtils.loadURI(tab.linkedBrowser, url); await BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, url); info(`Loaded ${url}.`); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/performance/browser_startup_content.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/performance/browser_startup_content.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/performance/browser_startup_content.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/performance/browser_startup_content.js 2020-11-17 19:31:23.000000000 +0000 @@ -41,7 +41,6 @@ "resource:///actors/LinkHandlerChild.jsm", "resource:///actors/PageStyleChild.jsm", "resource:///actors/SearchTelemetryChild.jsm", - "resource://gre/modules/E10SUtils.jsm", "resource://gre/modules/Readerable.jsm", // Telemetry diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/permissions/browser_autoplay_blocked.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/permissions/browser_autoplay_blocked.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/permissions/browser_autoplay_blocked.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/permissions/browser_autoplay_blocked.js 2020-11-17 19:31:23.000000000 +0000 @@ -208,7 +208,7 @@ Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.BLOCKED); await BrowserTestUtils.withNewTab("about:home", async function(browser) { - await BrowserTestUtils.loadURI(browser, AUTOPLAY_PAGE); + BrowserTestUtils.loadURI(browser, AUTOPLAY_PAGE); await blockedIconShown(); gBrowser.goBack(); @@ -255,7 +255,7 @@ await BrowserTestUtils.withNewTab("about:home", async function(browser) { await blockedIconHidden(); - await BrowserTestUtils.loadURI(browser, AUTOPLAY_PAGE); + BrowserTestUtils.loadURI(browser, AUTOPLAY_PAGE); await blockedIconShown(); Services.prefs.setIntPref(AUTOPLAY_PREF, Ci.nsIAutoplay.ALLOWED); @@ -308,7 +308,7 @@ await BrowserTestUtils.withNewTab("about:home", async function(browser) { await blockedIconHidden(); - await BrowserTestUtils.loadURI(browser, MUTED_AUTOPLAY_PAGE); + BrowserTestUtils.loadURI(browser, MUTED_AUTOPLAY_PAGE); await blockedIconShown(); await openIdentityPopup(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_deprecatedTLSVersions.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_deprecatedTLSVersions.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_deprecatedTLSVersions.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_deprecatedTLSVersions.js 2020-11-17 19:31:23.000000000 +0000 @@ -46,7 +46,7 @@ await BrowserTestUtils.withNewTab("about:blank", async function(browser) { // Try deprecated versions - await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_0); + BrowserTestUtils.loadURI(browser, HTTPS_TLS1_0); await BrowserTestUtils.browserLoaded(browser); isSecurityState(browser, "broken"); is( @@ -56,7 +56,7 @@ ); await checkConnectionState("not-secure"); - await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_1); + BrowserTestUtils.loadURI(browser, HTTPS_TLS1_1); await BrowserTestUtils.browserLoaded(browser); isSecurityState(browser, "broken"); is( @@ -67,14 +67,14 @@ await checkConnectionState("not-secure"); // Transition to secure - await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_2); + BrowserTestUtils.loadURI(browser, HTTPS_TLS1_2); await BrowserTestUtils.browserLoaded(browser); isSecurityState(browser, "secure"); is(getIdentityMode(), "verifiedDomain", "Identity should be verified"); await checkConnectionState("secure"); // Transition back to broken - await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_1); + BrowserTestUtils.loadURI(browser, HTTPS_TLS1_1); await BrowserTestUtils.browserLoaded(browser); isSecurityState(browser, "broken"); is( @@ -85,7 +85,7 @@ await checkConnectionState("not-secure"); // TLS1.3 for completeness - await BrowserTestUtils.loadURI(browser, HTTPS_TLS1_3); + BrowserTestUtils.loadURI(browser, HTTPS_TLS1_3); await BrowserTestUtils.browserLoaded(browser); isSecurityState(browser, "secure"); is(getIdentityMode(), "verifiedDomain", "Identity should be verified"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_getSecurityInfo.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_getSecurityInfo.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_getSecurityInfo.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_getSecurityInfo.js 2020-11-17 19:31:24.000000000 +0000 @@ -14,7 +14,7 @@ add_task(async function test() { await BrowserTestUtils.withNewTab("about:blank", async function(browser) { let loaded = BrowserTestUtils.waitForErrorPage(browser); - await BrowserTestUtils.loadURI(browser, "https://self-signed.example.com"); + BrowserTestUtils.loadURI(browser, "https://self-signed.example.com"); await loaded; let securityInfo = await browser.browsingContext.currentWindowGlobal.getSecurityInfo(); @@ -33,14 +33,14 @@ ); loaded = BrowserTestUtils.browserLoaded(browser); - await BrowserTestUtils.loadURI(browser, "http://example.com"); + BrowserTestUtils.loadURI(browser, "http://example.com"); await loaded; securityInfo = await browser.browsingContext.currentWindowGlobal.getSecurityInfo(); ok(!securityInfo, "Found no security info"); loaded = BrowserTestUtils.browserLoaded(browser); - await BrowserTestUtils.loadURI(browser, "https://example.com"); + BrowserTestUtils.loadURI(browser, "https://example.com"); await loaded; securityInfo = await browser.browsingContext.currentWindowGlobal.getSecurityInfo(); @@ -55,7 +55,7 @@ ); loaded = BrowserTestUtils.browserLoaded(browser); - await BrowserTestUtils.loadURI(browser, IFRAME_PAGE); + BrowserTestUtils.loadURI(browser, IFRAME_PAGE); await loaded; // Get the info of the parent, which is HTTP. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_mixed_content_cert_override.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_mixed_content_cert_override.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_mixed_content_cert_override.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_mixed_content_cert_override.js 2020-11-17 19:31:23.000000000 +0000 @@ -52,7 +52,7 @@ checkIdentityPopup("connection-mixed-active-loaded.svg"); // check that a warning is shown even without mixed content - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( gBrowser.selectedBrowser, "https://self-signed.example.com" ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_mixedContentFromOnunload.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_mixedContentFromOnunload.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_mixedContentFromOnunload.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_mixedContentFromOnunload.js 2020-11-17 19:31:23.000000000 +0000 @@ -38,7 +38,7 @@ // Navigation from an http page to a https page with no mixed content // The http page loads an http image on unload url = HTTPS_TEST_ROOT_1 + "file_mixedContentFromOnunload_test1.html"; - await BrowserTestUtils.loadURI(browser, url); + BrowserTestUtils.loadURI(browser, url); await BrowserTestUtils.browserLoaded(browser); // check security state. Since current url is https and doesn't have any // mixed content resources, we expect it to be secure. @@ -51,10 +51,10 @@ // Navigation from an http page to a https page that has mixed display content // The https page loads an http image on unload url = HTTP_TEST_ROOT_2 + "file_mixedContentFromOnunload.html"; - await BrowserTestUtils.loadURI(browser, url); + BrowserTestUtils.loadURI(browser, url); await BrowserTestUtils.browserLoaded(browser); url = HTTPS_TEST_ROOT_2 + "file_mixedContentFromOnunload_test2.html"; - await BrowserTestUtils.loadURI(browser, url); + BrowserTestUtils.loadURI(browser, url); await BrowserTestUtils.browserLoaded(browser); isSecurityState(browser, "broken"); await assertMixedContentBlockingState(browser, { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_mixed_content_with_navigation.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_mixed_content_with_navigation.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/browser_mixed_content_with_navigation.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/browser_mixed_content_with_navigation.js 2020-11-17 19:31:24.000000000 +0000 @@ -49,7 +49,7 @@ // seem to work with withNewTab. await BrowserTestUtils.withNewTab("about:blank", async browser => { // Navigate to the test URI. - await BrowserTestUtils.loadURI(browser, testcase.uri); + BrowserTestUtils.loadURI(browser, testcase.uri); if (!testcase.expectErrorPage) { await BrowserTestUtils.browserLoaded(browser, false, testcase.uri); } else { @@ -62,7 +62,7 @@ ); // Navigate to a URI that should be secure. - await BrowserTestUtils.loadURI(browser, kSecureURI); + BrowserTestUtils.loadURI(browser, kSecureURI); await BrowserTestUtils.browserLoaded(browser, false, kSecureURI); let secureIdentityMode = window.document.getElementById("identity-box") .className; @@ -91,7 +91,7 @@ is(secureIdentityMode, "verifiedDomain", "identity should start as secure"); // Navigate to the test URI. - await BrowserTestUtils.loadURI(browser, testcase.uri); + BrowserTestUtils.loadURI(browser, testcase.uri); if (!testcase.expectErrorPage) { await BrowserTestUtils.browserLoaded(browser, false, testcase.uri); } else { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/head.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/head.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/siteIdentity/head.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/siteIdentity/head.js 2020-11-17 19:31:23.000000000 +0000 @@ -402,7 +402,7 @@ async function loadBadCertPage(url) { let loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); await loaded; await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/static/browser_all_files_referenced.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/static/browser_all_files_referenced.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/static/browser_all_files_referenced.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/static/browser_all_files_referenced.js 2020-11-17 19:31:23.000000000 +0000 @@ -59,6 +59,9 @@ // referencing the whitelisted file in a way that the test can't detect, or a // bug number to remove or use the file if it is indeed currently unreferenced. var whitelist = [ + // pocket/content/panels/tmpl/loggedoutvariants/variant_a.handlebars + { file: "chrome://pocket/content/panels/img/glyph.svg" }, + // toolkt/components/pdfjs/content/PdfStreamConverter.jsm { file: "chrome://pdf.js/locale/chrome.properties" }, { file: "chrome://pdf.js/locale/viewer.properties" }, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabMediaIndicator/browser_mediaplayback_audibility_change.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabMediaIndicator/browser_mediaplayback_audibility_change.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabMediaIndicator/browser_mediaplayback_audibility_change.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabMediaIndicator/browser_mediaplayback_audibility_change.js 2020-11-17 19:31:24.000000000 +0000 @@ -62,7 +62,7 @@ await waitForTabSoundIndicatorAppears(tab); info(`sound indicator should disappear after navigating tab to blank page`); - await BrowserTestUtils.loadURI(tab.linkedBrowser, "about:blank"); + BrowserTestUtils.loadURI(tab.linkedBrowser, "about:blank"); await waitForTabSoundIndicatorDisappears(tab); info("remove tab"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabMediaIndicator/browser_mediaPlayback.js 2020-11-17 19:31:24.000000000 +0000 @@ -14,8 +14,10 @@ } async function test_on_browser(url, browser) { + info(`run test for ${url}`); + const startPromise = wait_for_event(browser, "DOMAudioPlaybackStarted"); BrowserTestUtils.loadURI(browser, url); - await wait_for_event(browser, "DOMAudioPlaybackStarted"); + await startPromise; await wait_for_event(browser, "DOMAudioPlaybackStopped"); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabs/browser_close_during_beforeunload.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabs/browser_close_during_beforeunload.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabs/browser_close_during_beforeunload.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabs/browser_close_during_beforeunload.js 2020-11-17 19:31:23.000000000 +0000 @@ -14,7 +14,7 @@ let win = await BrowserTestUtils.openNewBrowserWindow(); let browser = win.gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await SpecialPowers.spawn(browser, [], () => { // eslint-disable-next-line mozilla/balanced-listeners diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabs/browser_e10s_chrome_process.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabs/browser_e10s_chrome_process.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabs/browser_e10s_chrome_process.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabs/browser_e10s_chrome_process.js 2020-11-17 19:31:23.000000000 +0000 @@ -36,14 +36,7 @@ false, endURL ); - let expectSyncChange = await transitionTask(browser, endURL); - if (expectSyncChange) { - is( - browser.isRemoteBrowser, - endProcessIsRemote, - "Should have switched to the right process synchronously" - ); - } + await transitionTask(browser, endURL); await docLoadedPromise; is(browser.currentURI.spec, endURL, "Should have made it to the final URL"); @@ -121,21 +114,17 @@ // Loads the new page by calling browser.loadURI directly async function loadURI(browser, uri) { info("Calling browser.loadURI"); - await BrowserTestUtils.loadURI(browser, uri); - return true; + BrowserTestUtils.loadURI(browser, uri); }, // Loads the new page by finding a link with the right href in the document and // clicking it function clickLink(browser, uri) { info("Clicking link"); - SpecialPowers.spawn(browser, [uri], function frame_script(frameUri) { let link = content.document.querySelector("a[href='" + frameUri + "']"); link.click(); }); - - return false; }, ]; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabs/browser_e10s_switchbrowser.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabs/browser_e10s_switchbrowser.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabs/browser_e10s_switchbrowser.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabs/browser_e10s_switchbrowser.js 2020-11-17 19:31:24.000000000 +0000 @@ -356,18 +356,7 @@ info("2"); // Load another page info("Loading about:robots"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:robots"); - is( - gBrowser.selectedBrowser.isRemoteBrowser, - false, - "Remote attribute should be correct" - ); - is( - gBrowser.selectedBrowser.permanentKey, - permanentKey, - "browser.permanentKey is still the same" - ); - + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:robots"); await BrowserTestUtils.browserStopped(gBrowser); is( gBrowser.selectedBrowser.isRemoteBrowser, @@ -383,21 +372,10 @@ info("3"); // Load the remote page again info("Loading http://example.org/" + DUMMY_PATH); - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( gBrowser.selectedBrowser, "http://example.org/" + DUMMY_PATH ); - is( - gBrowser.selectedBrowser.isRemoteBrowser, - expectedRemote, - "Remote attribute should be correct" - ); - is( - gBrowser.selectedBrowser.permanentKey, - permanentKey, - "browser.permanentKey is still the same" - ); - await BrowserTestUtils.browserStopped(gBrowser); is( gBrowser.selectedBrowser.isRemoteBrowser, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabs/browser_navigatePinnedTab.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabs/browser_navigatePinnedTab.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/tabs/browser_navigatePinnedTab.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/tabs/browser_navigatePinnedTab.js 2020-11-17 19:31:23.000000000 +0000 @@ -39,7 +39,7 @@ false, "http://example.com/" ); - await BrowserTestUtils.loadURI(appTab.linkedBrowser, "http://example.com/"); + BrowserTestUtils.loadURI(appTab.linkedBrowser, "http://example.com/"); info("Started loading example.com"); await pageLoadPromise; info("Loaded example.com"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/zoom/head.js firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/zoom/head.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/base/content/test/zoom/head.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/base/content/test/zoom/head.js 2020-11-17 19:31:24.000000000 +0000 @@ -219,7 +219,7 @@ let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle); if (url) { - await BrowserTestUtils.loadURI(tab.linkedBrowser, url); + BrowserTestUtils.loadURI(tab.linkedBrowser, url); } return loaded; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_browserAction_contextMenu.js 2020-11-17 19:31:24.000000000 +0000 @@ -662,7 +662,8 @@ await customizationReady; } else { info("Navigate the about:addons tab to about:blank"); - await BrowserTestUtils.loadURI(browser, "about:blank"); + BrowserTestUtils.loadURI(browser, "about:blank"); + await BrowserTestUtils.browserLoaded(browser); } return menu; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_browserAction_popup_preload.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_browserAction_popup_preload.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_browserAction_popup_preload.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_browserAction_popup_preload.js 2020-11-17 19:31:24.000000000 +0000 @@ -288,10 +288,7 @@ }); let win = await BrowserTestUtils.openNewBrowserWindow(); - await BrowserTestUtils.loadURI( - win.gBrowser.selectedBrowser, - "http://example.com/" - ); + BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, "http://example.com/"); await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser); // Make sure the mouse isn't hovering over the browserAction widget. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_commands_onCommand.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_commands_onCommand.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_commands_onCommand.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_commands_onCommand.js 2020-11-17 19:31:24.000000000 +0000 @@ -185,7 +185,7 @@ // Create a window before the extension is loaded. let win1 = await BrowserTestUtils.openNewBrowserWindow(); - await BrowserTestUtils.loadURI(win1.gBrowser.selectedBrowser, "about:robots"); + BrowserTestUtils.loadURI(win1.gBrowser.selectedBrowser, "about:robots"); await BrowserTestUtils.browserLoaded(win1.gBrowser.selectedBrowser); // We would have previously focused the window's content area after the @@ -269,7 +269,7 @@ // Create another window after the extension is loaded. let win2 = await BrowserTestUtils.openNewBrowserWindow(); - await BrowserTestUtils.loadURI(win2.gBrowser.selectedBrowser, "about:robots"); + BrowserTestUtils.loadURI(win2.gBrowser.selectedBrowser, "about:robots"); await BrowserTestUtils.browserLoaded(win2.gBrowser.selectedBrowser); // See comment above. @@ -309,10 +309,7 @@ let privateWin = await BrowserTestUtils.openNewBrowserWindow({ private: true, }); - await BrowserTestUtils.loadURI( - privateWin.gBrowser.selectedBrowser, - "about:robots" - ); + BrowserTestUtils.loadURI(privateWin.gBrowser.selectedBrowser, "about:robots"); await BrowserTestUtils.browserLoaded(privateWin.gBrowser.selectedBrowser); // See comment above. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_currentWindow.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_currentWindow.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_currentWindow.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_currentWindow.js 2020-11-17 19:31:24.000000000 +0000 @@ -62,10 +62,10 @@ await focusWindow(win2); - await BrowserTestUtils.loadURI(win1.gBrowser.selectedBrowser, "about:robots"); + BrowserTestUtils.loadURI(win1.gBrowser.selectedBrowser, "about:robots"); await BrowserTestUtils.browserLoaded(win1.gBrowser.selectedBrowser); - await BrowserTestUtils.loadURI(win2.gBrowser.selectedBrowser, "about:config"); + BrowserTestUtils.loadURI(win2.gBrowser.selectedBrowser, "about:config"); await BrowserTestUtils.browserLoaded(win2.gBrowser.selectedBrowser); let extension = ExtensionTestUtils.loadExtension({ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow_targetSwitch.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow_targetSwitch.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow_targetSwitch.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_devtools_inspectedWindow_targetSwitch.js 2020-11-17 19:31:24.000000000 +0000 @@ -29,7 +29,7 @@ const originalTabId = await getCurrentTabId(extension); const onSwitched = toolbox.targetList.once("switched-target"); - await BrowserTestUtils.loadURI(tab.linkedBrowser, uri); + BrowserTestUtils.loadURI(tab.linkedBrowser, uri); await onSwitched; const currentTabId = await getCurrentTabId(extension); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_devtools_network_targetSwitch.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_devtools_network_targetSwitch.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_devtools_network_targetSwitch.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_devtools_network_targetSwitch.js 2020-11-17 19:31:24.000000000 +0000 @@ -14,7 +14,7 @@ async function testOnNavigatedEvent(uri, tab, toolbox, extension) { const onNavigated = extension.awaitMessage("network-onNavigated"); const onSwitched = toolbox.targetList.once("switched-target"); - await BrowserTestUtils.loadURI(tab.linkedBrowser, uri); + BrowserTestUtils.loadURI(tab.linkedBrowser, uri); await onSwitched; const result = await onNavigated; is(result, uri, "devtools.network.onNavigated works correctly"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_find.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_find.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_find.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_find.js 2020-11-17 19:31:24.000000000 +0000 @@ -407,7 +407,7 @@ let privateWin = await BrowserTestUtils.openNewBrowserWindow({ private: true, }); - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( privateWin.gBrowser.selectedBrowser, "http://example.com" ); @@ -446,7 +446,7 @@ let privateWin = await BrowserTestUtils.openNewBrowserWindow({ private: true, }); - await BrowserTestUtils.loadURI(privateWin.gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(privateWin.gBrowser.selectedBrowser, url); await BrowserTestUtils.browserLoaded(privateWin.gBrowser.selectedBrowser); let extension = ExtensionTestUtils.loadExtension({ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_menus_refresh.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_menus_refresh.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_menus_refresh.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_menus_refresh.js 2020-11-17 19:31:24.000000000 +0000 @@ -403,7 +403,7 @@ elem = extension.getXULElementByMenuId("item2"); is(elem, null, "menu item 2 should be hidden"); - await BrowserTestUtils.loadURI(tab.linkedBrowser, PAGE + "?2"); + BrowserTestUtils.loadURI(tab.linkedBrowser, PAGE + "?2"); await BrowserTestUtils.browserStopped(tab.linkedBrowser); await extension.callMenuApi("refresh"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_sessions_getRecentlyClosed.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_sessions_getRecentlyClosed.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_sessions_getRecentlyClosed.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_sessions_getRecentlyClosed.js 2020-11-17 19:31:24.000000000 +0000 @@ -9,7 +9,7 @@ add_task(async function test_sessions_get_recently_closed() { async function openAndCloseWindow(url = "http://example.com", tabUrls) { let win = await BrowserTestUtils.openNewBrowserWindow(); - await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url); await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser); if (tabUrls) { for (let url of tabUrls) { @@ -145,7 +145,7 @@ // Test with a window with navigation history. let win = await BrowserTestUtils.openNewBrowserWindow(); for (let url of ["about:robots", "about:mozilla", "http://example.com/"]) { - await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url); await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_sessions_getRecentlyClosed_tabs.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_sessions_getRecentlyClosed_tabs.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_sessions_getRecentlyClosed_tabs.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_sessions_getRecentlyClosed_tabs.js 2020-11-17 19:31:24.000000000 +0000 @@ -53,7 +53,7 @@ let win = await BrowserTestUtils.openNewBrowserWindow(); let tabBrowser = win.gBrowser.selectedBrowser; for (let url of ["about:robots", "about:mozilla", "about:config"]) { - await BrowserTestUtils.loadURI(tabBrowser, url); + BrowserTestUtils.loadURI(tabBrowser, url); await BrowserTestUtils.browserLoaded(tabBrowser, false, url); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_sessions_restore.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_sessions_restore.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_sessions_restore.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_sessions_restore.js 2020-11-17 19:31:24.000000000 +0000 @@ -87,7 +87,7 @@ await extension.awaitMessage("ready"); let win = await BrowserTestUtils.openNewBrowserWindow(); - await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, "about:config"); + BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, "about:config"); await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser); for (let url of ["about:robots", "about:mozilla"]) { await BrowserTestUtils.openNewForegroundTab(win.gBrowser, url); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_tabs_update_url.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_tabs_update_url.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_tabs_update_url.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_tabs_update_url.js 2020-11-17 19:31:24.000000000 +0000 @@ -171,7 +171,7 @@ let win = await BrowserTestUtils.openNewBrowserWindow(); let tabBrowser = win.gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(tabBrowser, URL); + BrowserTestUtils.loadURI(tabBrowser, URL); await BrowserTestUtils.browserLoaded(tabBrowser, false, URL); let tab = win.gBrowser.selectedTab; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_windows.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_windows.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/extensions/test/browser/browser_ext_windows.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/extensions/test/browser/browser_ext_windows.js 2020-11-17 19:31:24.000000000 +0000 @@ -191,7 +191,7 @@ let promiseLoaded = BrowserTestUtils.browserLoaded( realWin.gBrowser.selectedBrowser ); - await BrowserTestUtils.loadURI(realWin.gBrowser.selectedBrowser, NEW_URL); + BrowserTestUtils.loadURI(realWin.gBrowser.selectedBrowser, NEW_URL); await promiseLoaded; await verifyTitle( realWin, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/aboutwelcome/AboutWelcomeChild.jsm 2020-11-17 19:31:24.000000000 +0000 @@ -307,6 +307,8 @@ // about:welcome loads outside of the "FirstStartup" scenario this will likely not be ready experimentData = ExperimentAPI.getExperiment({ featureId: "aboutwelcome", + // Telemetry handled in AboutNewTabService.jsm + sendExposurePing: false, }); } catch (e) { Cu.reportError(e); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/lib/ASRouter.jsm firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/lib/ASRouter.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/lib/ASRouter.jsm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/lib/ASRouter.jsm 2020-11-17 19:31:24.000000000 +0000 @@ -354,7 +354,10 @@ for (const featureId of provider.messageGroups) { let experimentData; try { - experimentData = ExperimentAPI.getExperiment({ featureId }); + experimentData = ExperimentAPI.getExperiment({ + featureId, + sendExposurePing: false, + }); // Not enrolled in any experiment for this feature, we can skip if (!experimentData) { continue; @@ -367,8 +370,16 @@ // If the feature is not enabled there is no message to send back. // Other branches might be enabled so we check those as well in case we // need to send a reach ping. - if (ExperimentAPI.isFeatureEnabled(featureId, false)) { - experiments.push(ExperimentAPI.getFeatureValue(featureId)); + let featureData = experimentData.branch.feature; + if (featureData.enabled) { + experiments.push({ + forExposureEvent: { + sent: experimentData.exposurePingSent, + experimentSlug: experimentData.slug, + branchSlug: experimentData.branch.slug, + }, + ...featureData.value, + }); } if (!REACH_EVENT_GROUPS.includes(featureId)) { @@ -1812,6 +1823,18 @@ nonReachMessages.push(message); } } + + // Exposure events only apply to messages that come from the + // messaging-experiments provider + if (nonReachMessages.length && nonReachMessages[0].forExposureEvent) { + ExperimentAPI.recordExposureEvent( + // Any message processed by ASRouter will report the exposure event + // as `cfr` + "cfr", + nonReachMessages[0].forExposureEvent + ); + } + return this.sendMessage( nonReachMessages[0] || null, trigger, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/lib/TelemetryFeed.jsm firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/lib/TelemetryFeed.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/lib/TelemetryFeed.jsm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/lib/TelemetryFeed.jsm 2020-11-17 19:31:24.000000000 +0000 @@ -319,18 +319,19 @@ /** * Check if it is in the CFR experiment cohort by querying against the * experiment manager of Messaging System + * + * @return {bool} */ get isInCFRCohort() { try { - const experimentData = ExperimentAPI.getExperiment({ + const experimentData = ExperimentAPI.getExperimentMetaData({ featureId: "cfr", }); if (experimentData && experimentData.slug) { return true; } - } catch (e) { - return false; - } + } catch (e) {} + return false; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_aboutwelcome_observer.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_aboutwelcome_observer.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_aboutwelcome_observer.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_aboutwelcome_observer.js 2020-11-17 19:31:24.000000000 +0000 @@ -62,10 +62,7 @@ aboutWelcomeActor.AboutWelcomeObserver, "AboutWelcomeObserver is not null" ); - await BrowserTestUtils.loadURI( - gBrowser.selectedBrowser, - "http://example.com/#foo" - ); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "http://example.com/#foo"); await BrowserTestUtils.waitForLocationChange( gBrowser, "http://example.com/#foo" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_asrouter_cfr.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_asrouter_cfr.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_asrouter_cfr.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_asrouter_cfr.js 2020-11-17 19:31:24.000000000 +0000 @@ -220,7 +220,7 @@ add_task(async function test_cfr_notification_show() { // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); const response = await trigger_cfr_panel(browser, "example.com"); @@ -274,7 +274,7 @@ add_task(async function test_cfr_notification_show() { // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); let response = await trigger_cfr_panel(browser, "example.com", { @@ -340,7 +340,7 @@ add_task(async function test_cfr_notification_minimize() { // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); let response = await trigger_cfr_panel(browser, "example.com"); @@ -387,7 +387,7 @@ add_task(async function test_cfr_notification_minimize_2() { // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); let response = await trigger_cfr_panel(browser, "example.com"); @@ -449,7 +449,7 @@ add_task(async function test_cfr_addon_install() { // addRecommendation checks that scheme starts with http and host matches const browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); const response = await trigger_cfr_panel(browser, "example.com", { @@ -508,7 +508,7 @@ add_task(async function test_cfr_pin_tab_notification_show() { // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); const response = await trigger_cfr_panel(browser, "example.com", { @@ -564,7 +564,7 @@ async function test_cfr_social_tracking_protection_notification_show() { // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); const showPanel = BrowserTestUtils.waitForEvent( @@ -617,7 +617,7 @@ // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); const showPanel = BrowserTestUtils.waitForEvent( @@ -680,7 +680,7 @@ // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); const showPanel = BrowserTestUtils.waitForEvent( @@ -730,7 +730,7 @@ add_task(async function test_cfr_features_and_addon_show() { // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); // Trigger Feature CFR @@ -821,7 +821,7 @@ add_task(async function test_cfr_addon_and_features_show() { // addRecommendation checks that scheme starts with http and host matches let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); // Trigger Feature CFR @@ -919,17 +919,17 @@ "example.com", ]); - await BrowserTestUtils.loadURI(browser, "about:blank"); + BrowserTestUtils.loadURI(browser, "about:blank"); await BrowserTestUtils.browserLoaded(browser, false, "about:blank"); - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); Assert.equal(count, 1, "Count navigation to example.com"); // Anchor scroll triggers a location change event with the same document // https://searchfox.org/mozilla-central/rev/8848b9741fc4ee4e9bc3ae83ea0fc048da39979f/uriloader/base/nsIWebProgressListener.idl#400-403 - await BrowserTestUtils.loadURI(browser, "http://example.com/#foo"); + BrowserTestUtils.loadURI(browser, "http://example.com/#foo"); await BrowserTestUtils.waitForLocationChange( gBrowser, "http://example.com/#foo" @@ -937,7 +937,7 @@ Assert.equal(count, 1, "It should ignore same page navigation"); - await BrowserTestUtils.loadURI(browser, TEST_URL); + BrowserTestUtils.loadURI(browser, TEST_URL); await BrowserTestUtils.browserLoaded(browser, false, TEST_URL); Assert.equal(count, 2, "We moved to a new document"); @@ -954,7 +954,7 @@ await frequentVisitsTrigger.init(triggerHandler, [], ["*://*.example.com/"]); const browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); await BrowserTestUtils.waitForCondition( @@ -962,7 +962,7 @@ "Registered pattern matched the current location" ); - await BrowserTestUtils.loadURI(browser, "about:config"); + BrowserTestUtils.loadURI(browser, "about:config"); await BrowserTestUtils.browserLoaded(browser, false, "about:config"); await BrowserTestUtils.waitForCondition( @@ -970,7 +970,7 @@ "Navigated to a new page but not a match" ); - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); await BrowserTestUtils.waitForCondition( @@ -978,7 +978,7 @@ "Navigated to a location that matches the pattern but within 15 mins" ); - await BrowserTestUtils.loadURI(browser, "http://www.example.com/"); + BrowserTestUtils.loadURI(browser, "http://www.example.com/"); await BrowserTestUtils.browserLoaded( browser, false, @@ -1019,7 +1019,7 @@ add_task(async function test_cfr_notification_keyboard() { // addRecommendation checks that scheme starts with http and host matches const browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, "http://example.com/"); + BrowserTestUtils.loadURI(browser, "http://example.com/"); await BrowserTestUtils.browserLoaded(browser, false, "http://example.com/"); const response = await trigger_cfr_panel(browser, "example.com"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_asrouter_experimentsAPILoader.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_asrouter_experimentsAPILoader.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_asrouter_experimentsAPILoader.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_asrouter_experimentsAPILoader.js 2020-11-17 19:31:24.000000000 +0000 @@ -173,7 +173,10 @@ // Wait to load the messages from the messaging-experiments provider await ASRouter.loadMessagesFromAllProviders(); - Assert.ok(ASRouter.state.messages.find(m => m.id === "xman_test_message")); + Assert.ok( + ASRouter.state.messages.find(m => m.id === "xman_test_message"), + "Experiment message found in ASRouter state" + ); await client.db.clear(); await SpecialPowers.popPrefEnv(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_asrouter_group_frequency.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_asrouter_group_frequency.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_asrouter_group_frequency.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_asrouter_group_frequency.js 2020-11-17 19:31:24.000000000 +0000 @@ -119,7 +119,7 @@ Assert.ok(groupState.enabled, "Group is enabled"); let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); - await BrowserTestUtils.loadURI(tab1.linkedBrowser, TEST_URL); + BrowserTestUtils.loadURI(tab1.linkedBrowser, TEST_URL); let chiclet = document.getElementById("contextual-feature-recommendation"); Assert.ok(chiclet, "CFR chiclet element found (tab1)"); @@ -138,7 +138,7 @@ BrowserTestUtils.removeTab(tab1); let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); - await BrowserTestUtils.loadURI(tab2.linkedBrowser, TEST_URL); + BrowserTestUtils.loadURI(tab2.linkedBrowser, TEST_URL); Assert.ok(chiclet, "CFR chiclet element found (tab2)"); await BrowserTestUtils.waitForCondition( @@ -161,7 +161,7 @@ BrowserTestUtils.removeTab(tab2); let tab3 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); - await BrowserTestUtils.loadURI(tab3.linkedBrowser, TEST_URL); + BrowserTestUtils.loadURI(tab3.linkedBrowser, TEST_URL); await BrowserTestUtils.waitForCondition( () => chiclet.hidden, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_asrouter_group_userprefs.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_asrouter_group_userprefs.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/browser_asrouter_group_userprefs.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/browser_asrouter_group_userprefs.js 2020-11-17 19:31:24.000000000 +0000 @@ -113,7 +113,7 @@ Assert.ok(ASRouter.isUnblockedMessage(msg), "Message is unblocked"); let tab1 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); - await BrowserTestUtils.loadURI(tab1.linkedBrowser, TEST_URL); + BrowserTestUtils.loadURI(tab1.linkedBrowser, TEST_URL); let chiclet = document.getElementById("contextual-feature-recommendation"); Assert.ok(chiclet, "CFR chiclet element found"); @@ -135,7 +135,7 @@ ); let tab2 = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL); - await BrowserTestUtils.loadURI(tab2.linkedBrowser, TEST_URL); + BrowserTestUtils.loadURI(tab2.linkedBrowser, TEST_URL); await BrowserTestUtils.waitForCondition( () => chiclet.hidden, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/head.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/head.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/browser/head.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/browser/head.js 2020-11-17 19:31:24.000000000 +0000 @@ -98,7 +98,7 @@ // eslint-disable-next-line no-unused-vars async function waitForUrlLoad(url) { let browser = gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, url); + BrowserTestUtils.loadURI(browser, url); await BrowserTestUtils.browserLoaded(browser, false, url); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/unit/asrouter/ASRouter.test.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/unit/asrouter/ASRouter.test.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/unit/asrouter/ASRouter.test.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/unit/asrouter/ASRouter.test.js 2020-11-17 19:31:24.000000000 +0000 @@ -286,6 +286,7 @@ }, }, }), + recordExposureEvent: sandbox.stub(), getAllBranches: sandbox.stub().resolves([ { branch: { @@ -299,8 +300,6 @@ }, ]), ready: sandbox.stub().resolves(), - getFeatureValue: sandbox.stub().returns(null), - isFeatureEnabled: sandbox.stub().returns(false), }, SpecialMessageActions: { handleAction: sandbox.stub(), @@ -2099,6 +2098,38 @@ }); assert.notCalled(Services.telemetry.recordEvent); }); + it("should record the Exposure event if found any", async () => { + let messages = [ + { + id: "foo1", + forExposureEvent: { + sent: false, + experimentSlug: "foo", + branchSlug: "bar", + }, + experimentSlug: "exp01", + branchSlug: "branch01", + template: "simple_template", + trigger: { id: "foo" }, + content: { title: "Foo1", body: "Foo123-1" }, + }, + ]; + sandbox.stub(Router, "handleMessageRequest").resolves(messages); + sandbox.spy(Services.telemetry, "recordEvent"); + + await Router.sendTriggerMessage({ + tabId: 0, + browser: {}, + id: "foo", + }); + + assert.calledOnce(global.ExperimentAPI.recordExposureEvent); + assert.calledWithExactly( + global.ExperimentAPI.recordExposureEvent, + "cfr", + messages[0].forExposureEvent + ); + }); }); describe("_getBundledMessages", () => { @@ -2814,6 +2845,7 @@ assert.calledOnce(global.ExperimentAPI.getExperiment); assert.calledWithExactly(global.ExperimentAPI.getExperiment, { featureId: "asrouter", + sendExposurePing: false, }); }); it("should handle the case of no experiments in the ExperimentAPI", async () => { @@ -2858,24 +2890,9 @@ }; global.ExperimentAPI.getExperiment.returns(enrollment); - global.ExperimentAPI.isFeatureEnabled.returns( - enrollment.branch.feature.enabled - ); - global.ExperimentAPI.getFeatureValue.returns( - enrollment.branch.feature.value - ); const result = await MessageLoaderUtils.loadMessagesForProvider(args); - assert.calledWithExactly( - global.ExperimentAPI.isFeatureEnabled, - "asrouter", - false - ); - assert.calledWithExactly( - global.ExperimentAPI.getFeatureValue, - "asrouter" - ); assert.lengthOf(result.messages, 1); }); it("should skip disabled features and not load the messages", async () => { @@ -2895,22 +2912,9 @@ }; global.ExperimentAPI.getExperiment.returns(enrollment); - global.ExperimentAPI.isFeatureEnabled.returns( - enrollment.branch.feature.enabled - ); - global.ExperimentAPI.getFeatureValue.returns( - enrollment.branch.feature.value - ); const result = await MessageLoaderUtils.loadMessagesForProvider(args); - assert.calledOnce(global.ExperimentAPI.isFeatureEnabled); - assert.notCalled(global.ExperimentAPI.getFeatureValue); - assert.calledWithExactly( - global.ExperimentAPI.isFeatureEnabled, - "asrouter", - false - ); assert.lengthOf(result.messages, 0); }); it("should fetch messages from the ExperimentAPI", async () => { @@ -2944,12 +2948,6 @@ }; global.ExperimentAPI.getExperiment.returns(enrollment); - global.ExperimentAPI.isFeatureEnabled.returns( - enrollment.branch.feature.enabled - ); - global.ExperimentAPI.getFeatureValue.returns( - enrollment.branch.feature.value - ); global.ExperimentAPI.getAllBranches.resolves([ enrollment.branch, { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/unit/lib/TelemetryFeed.test.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/unit/lib/TelemetryFeed.test.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/newtab/test/unit/lib/TelemetryFeed.test.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/newtab/test/unit/lib/TelemetryFeed.test.js 2020-11-17 19:31:24.000000000 +0000 @@ -37,7 +37,7 @@ let fakeHomePageUrl; let fakeHomePage; let fakeExtensionSettingsStore; - let ExperimentAPI = { getExperiment: () => {} }; + let ExperimentAPI = { getExperimentMetaData: () => {} }; class PingCentre { sendPing() {} uninit() {} @@ -815,7 +815,7 @@ return "release"; }, }); - sandbox.stub(ExperimentAPI, "getExperiment").returns({ + sandbox.stub(ExperimentAPI, "getExperimentMetaData").returns({ slug: "SOME-CFR-EXP", }); const data = { @@ -888,7 +888,7 @@ return "release"; }, }); - sandbox.stub(ExperimentAPI, "getExperiment").returns({ + sandbox.stub(ExperimentAPI, "getExperimentMetaData").returns({ slug: "SOME-CFR-EXP", }); const data = { @@ -1885,19 +1885,19 @@ it("should return false if there is no CFR experiment registered", () => { assert.ok(!instance.isInCFRCohort); }); - it("should return false if getExperiment throws", () => { - sandbox.stub(ExperimentAPI, "getExperiment").throws(); + it("should return false if getExperimentMetaData throws", () => { + sandbox.stub(ExperimentAPI, "getExperimentMetaData").throws(); assert.ok(!instance.isInCFRCohort); }); it("should return true if there is a CFR experiment registered", () => { - sandbox.stub(ExperimentAPI, "getExperiment").returns({ + sandbox.stub(ExperimentAPI, "getExperimentMetaData").returns({ slug: "SOME-CFR-EXP", }); assert.ok(instance.isInCFRCohort); assert.propertyVal( - ExperimentAPI.getExperiment.firstCall.args[0], + ExperimentAPI.getExperimentMetaData.firstCall.args[0], "featureId", "cfr" ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/css/signup.css firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/css/signup.css --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/css/signup.css 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/css/signup.css 2020-11-17 19:31:24.000000000 +0000 @@ -445,10 +445,14 @@ } .los_variant_bottom { - text-align: center; + text-align: start; padding: 26px 22px; } +.los_variant_a .los_variant_bottom { + text-align: center; +} + .los_variant_bottom .los_variant_button { font-style: normal; font-weight: 500; @@ -458,11 +462,24 @@ color: #FFFFFF; border-radius: 4px; background: #0060DF; - display: block; + display: inline-block; padding: 8px 16px; margin-bottom: 16px } +.los_variant_a .los_variant_bottom .los_variant_button { + display: block; +} + +.los_variant_bottom .los_variant_button:hover { + color: #fff; +} + +.los_variant_c .los_variant_bottom { + border-top: 1px solid #D7D7DB; + margin-top: 20px; +} + .los_variant_bottom .los_variant_sub { font-style: normal; font-weight: normal; @@ -475,16 +492,43 @@ color: #0060DF; } +.los_variant_top a { + font-size: 15px; +} + .los_variant_a .los_variant_top { - background-color: #e8f7f6; + background: #e8f7f6 url(../img/variant_a.png) bottom right no-repeat; + background-size: contain; + padding-block: 6px 24px; + padding-inline: 24px 102px; + height: 260px; +} + +.los_variant_a .los_variant_top p { + margin-bottom: 0; } .los_variant_b .los_variant_top { - background-color: #DCEAFF; + background: #DCEAFF url(../img/variant_b.png) bottom right no-repeat; + background-size: 80%; + padding: 24px 24px 160px; +} + +.los_variant_top:dir(rtl) { + background-position-x: left; +} + +.los_variant_b .los_variant_top a { + font-size: 15px; + line-height: 18px; + text-decoration-line: underline; + color: #0C0C0D; } .los_variant_c .los_variant_top { - background-color: #ffffff; + background: #fff url(../img/variant_c.png) bottom right no-repeat; + background-size: contain; + padding: 24px 24px 160px; } .los_variant h1 { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/img/glyph.svg firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/img/glyph.svg --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/img/glyph.svg 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/img/glyph.svg 2020-11-17 19:31:24.000000000 +0000 @@ -0,0 +1,4 @@ + + + + Binary files /tmp/tmp8S9FEj/XE5iYQkxtp/firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/img/variant_a.png and /tmp/tmp8S9FEj/M4WexYix8J/firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/img/variant_a.png differ Binary files /tmp/tmp8S9FEj/XE5iYQkxtp/firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/img/variant_b.png and /tmp/tmp8S9FEj/M4WexYix8J/firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/img/variant_b.png differ Binary files /tmp/tmp8S9FEj/XE5iYQkxtp/firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/img/variant_c.png and /tmp/tmp8S9FEj/M4WexYix8J/firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/img/variant_c.png differ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/js/tmpl.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/js/tmpl.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/js/tmpl.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/js/tmpl.js 2020-11-17 19:31:24.000000000 +0000 @@ -37,13 +37,13 @@ return "
\n \n
\n"; },"useData":true}); templates['variant_a'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - return "
\n
\n

Click this [v] button to save articles, videos, and links to Pocket.

\n

Enjoy everything you save, on any device.

\n Learn more ›\n
\n\n
\n Get Pocket for free\n

Already a Pocket user? Log in.

\n
\n
\n"; + return "
\n
\n

Click the \"Pocket button to save articles, videos, and links to Pocket.

\n

Enjoy everything you save, on any device.

\n Learn more ›\n
\n\n
\n Get Pocket for free\n

Already a Pocket user? Log in.

\n
\n
\n"; },"useData":true}); templates['variant_b'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - return "
\n
\n

Here's your save button for the internet.

\n Learn more ›\n
\n\n
\n Get Pocket for free\n

Already a Pocket user? Log in.

\n
\n
\n"; + return "
\n
\n

Here's your save button for the internet.

\n Learn more ›\n
\n\n
\n Get Pocket for free\n

Already a Pocket user? Log in.

\n
\n
\n"; },"useData":true}); templates['variant_c'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - return "
\n
\n

Get Pocket to save anything to your personal corner of the internet.

\n Learn more ›\n
\n\n
\n Sign up for free\n

Already a Pocket user? Log in.

\n
\n
\n\n\n"; + return "
\n
\n

Get Pocket to save anything to your personal corner of the internet.

\n Learn more ›\n
\n\n
\n Sign up for free\n

Already a Pocket user? Log in.

\n
\n
\n"; },"useData":true}); templates['saved_premiumextras'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { return "
\r\n
"; @@ -94,7 +94,7 @@ return "

" + alias3(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"learnmore","hash":{},"data":data}) : helper))) @@ -104,7 +104,7 @@ return "

" + alias3(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"learnmore","hash":{},"data":data}) : helper))) @@ -122,7 +122,7 @@ + alias3(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signuptosave","hash":{},"data":data}) : helper))) + "\n

" + alias3(((helper = (helper = helpers.signupfirefox || (depth0 != null ? depth0.signupfirefox : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signupfirefox","hash":{},"data":data}) : helper))) @@ -130,7 +130,7 @@ + alias3(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) + " " + alias3(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"loginnow","hash":{},"data":data}) : helper))) @@ -146,13 +146,13 @@ + alias3(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signuptosave","hash":{},"data":data}) : helper))) + "\n

" + alias3(((helper = (helper = helpers.signupfirefox || (depth0 != null ? depth0.signupfirefox : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signupfirefox","hash":{},"data":data}) : helper))) + "

\n

" + alias3(((helper = (helper = helpers.signupemail || (depth0 != null ? depth0.signupemail : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signupemail","hash":{},"data":data}) : helper))) @@ -160,7 +160,7 @@ + alias3(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) + " " + alias3(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"loginnow","hash":{},"data":data}) : helper))) @@ -170,13 +170,13 @@ return "

" + + "/firefox_tryitnow?utm_campaign=logged_out_save_test&utm_source=control&s=ffi&tv=panel_tryit&t=tryitnow\" target=\"_blank\" class=\"btn signup-btn-tryitnow\">" + alias3(((helper = (helper = helpers.tryitnow || (depth0 != null ? depth0.tryitnow : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"tryitnow","hash":{},"data":data}) : helper))) + "

\n

" + alias3(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) + " " + alias3(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"loginnow","hash":{},"data":data}) : helper))) @@ -203,7 +203,7 @@ return "

" + alias3(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"learnmore","hash":{},"data":data}) : helper))) @@ -213,7 +213,7 @@ return "

" + alias3(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"learnmore","hash":{},"data":data}) : helper))) @@ -231,7 +231,7 @@ + alias3(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signuptosave","hash":{},"data":data}) : helper))) + "\n

" + alias3(((helper = (helper = helpers.signupfirefox || (depth0 != null ? depth0.signupfirefox : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signupfirefox","hash":{},"data":data}) : helper))) @@ -239,7 +239,7 @@ + alias3(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) + " " + alias3(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"loginnow","hash":{},"data":data}) : helper))) @@ -255,13 +255,13 @@ + alias3(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signuptosave","hash":{},"data":data}) : helper))) + "\n

" + alias3(((helper = (helper = helpers.signupfirefox || (depth0 != null ? depth0.signupfirefox : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signupfirefox","hash":{},"data":data}) : helper))) + "

\n

" + alias3(((helper = (helper = helpers.signupemail || (depth0 != null ? depth0.signupemail : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"signupemail","hash":{},"data":data}) : helper))) @@ -269,7 +269,7 @@ + alias3(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) + " " + alias3(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"loginnow","hash":{},"data":data}) : helper))) @@ -279,13 +279,13 @@ return "

" + + "/firefox_tryitnow?utm_campaign=logged_out_save_test&utm_source=control&s=ffi&tv=panel_tryit&t=tryitnow\" target=\"_blank\" class=\"btn signup-btn-tryitnow\">" + alias3(((helper = (helper = helpers.tryitnow || (depth0 != null ? depth0.tryitnow : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"tryitnow","hash":{},"data":data}) : helper))) + "

\n

" + alias3(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"alreadyhaveacct","hash":{},"data":data}) : helper))) + " " + alias3(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"loginnow","hash":{},"data":data}) : helper))) @@ -303,7 +303,7 @@ + ((stack1 = helpers['if'].call(depth0,(depth0 != null ? depth0.showlearnmore : depth0),{"name":"if","hash":{},"fn":this.program(1, data, 0),"inverse":this.program(6, data, 0),"data":data})) != null ? stack1 : "") + " \n

\n \n\n
\n" + ((stack1 = helpers['if'].call(depth0,(depth0 != null ? depth0.fxasignedin : depth0),{"name":"if","hash":{},"fn":this.program(8, data, 0),"inverse":this.program(10, data, 0),"data":data})) != null ? stack1 : "") - + "\n
\n"; + + "\n\n\n"; },"useData":true}); templates['item_recs'] = template({"1":function(depth0,helpers,partials,data) { return "

Similar Stories

\n"; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_a.handlebars firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_a.handlebars --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_a.handlebars 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_a.handlebars 2020-11-17 19:31:24.000000000 +0000 @@ -1,12 +1,12 @@
diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_b.handlebars firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_b.handlebars --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_b.handlebars 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_b.handlebars 2020-11-17 19:31:24.000000000 +0000 @@ -1,11 +1,11 @@

Here's your save button for the internet.

- Learn more › + Learn more ›
- Get Pocket for free -

Already a Pocket user? Log in.

+ +

Already a Pocket user?

diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_c.handlebars firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_c.handlebars --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_c.handlebars 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/loggedoutvariants/variant_c.handlebars 2020-11-17 19:31:24.000000000 +0000 @@ -1,13 +1,11 @@

Get Pocket to save anything to your personal corner of the internet.

- Learn more › + Learn more ›
- Sign up for free -

Already a Pocket user? Log in.

+ +

Already a Pocket user?

- - diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/signup_shell.handlebars firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/signup_shell.handlebars --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/signup_shell.handlebars 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/signup_shell.handlebars 2020-11-17 19:31:24.000000000 +0000 @@ -3,9 +3,9 @@

{{tagline}}

{{#if showlearnmore}} {{#if controlvariant}} -

{{learnmore}}

+

{{learnmore}}

{{else}} -

{{learnmore}}

+

{{learnmore}}

{{/if}} {{else}}

{{learnmore}}

@@ -15,17 +15,17 @@
{{#if fxasignedin}}

{{signuptosave}}

-

-

{{alreadyhaveacct}} .

+

+

{{alreadyhaveacct}} .

{{else}} {{#if controlvariant}}

{{signuptosave}}

-

-

-

{{alreadyhaveacct}} .

+

+

+

{{alreadyhaveacct}} .

{{else}} -

-

{{alreadyhaveacct}} .

+

+

{{alreadyhaveacct}} .

{{{tos}}}

{{/if}} {{/if}} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars 2020-11-17 19:31:24.000000000 +0000 @@ -11,9 +11,9 @@

{{taglinestory_two}}

{{#if showlearnmore}} {{#if controlvariant}} -

{{learnmore}}

+

{{learnmore}}

{{else}} -

{{learnmore}}

+

{{learnmore}}

{{/if}} {{else}}

{{learnmore}}

@@ -25,19 +25,20 @@
{{#if fxasignedin}}

{{signuptosave}}

-

-

{{alreadyhaveacct}} .

+

+

{{alreadyhaveacct}} .

{{else}} {{#if controlvariant}}

{{signuptosave}}

-

-

-

{{alreadyhaveacct}} .

+

+

+

{{alreadyhaveacct}} .

{{else}} -

-

{{alreadyhaveacct}} .

+

+

{{alreadyhaveacct}} .

{{{tos}}}

{{/if}} {{/if}}
+ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/addEngine.xhtml firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/addEngine.xhtml --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/addEngine.xhtml 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/addEngine.xhtml 2020-11-17 19:31:24.000000000 +0000 @@ -11,7 +11,7 @@ xmlns:html="http://www.w3.org/1999/xhtml" data-l10n-id="add-engine-window" data-l10n-attrs="title, style" - persist="screenX screenY width height" screenX="24" screenY="24"> + persist="width height"> + data-l10n-attrs="title, style"> diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/blocklists.xhtml firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/blocklists.xhtml --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/blocklists.xhtml 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/blocklists.xhtml 2020-11-17 19:31:24.000000000 +0000 @@ -15,7 +15,7 @@ xmlns:html="http://www.w3.org/1999/xhtml" onload="gBlocklistManager.onLoad();" onunload="gBlocklistManager.uninit();" - persist="screenX screenY width height"> + persist="width height"> + persist="width height"> + persist="lastSelected"> diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/connection.xhtml firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/connection.xhtml --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/connection.xhtml 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/connection.xhtml 2020-11-17 19:31:24.000000000 +0000 @@ -12,7 +12,7 @@ xmlns:html="http://www.w3.org/1999/xhtml" data-l10n-id="connection-window" data-l10n-attrs="title, style" - persist="lastSelected screenX screenY" + persist="lastSelected" onload="gConnectionsDialog.checkForSystemProxy();"> + persist="width height"> + persist="lastSelected"> diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/languages.xhtml firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/languages.xhtml --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/languages.xhtml 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/languages.xhtml 2020-11-17 19:31:24.000000000 +0000 @@ -12,7 +12,7 @@ xmlns:html="http://www.w3.org/1999/xhtml" data-l10n-id="webpage-languages-window" data-l10n-attrs="title, style" - persist="lastSelected screenX screenY" + persist="lastSelected" onload="gLanguagesDialog.onLoad();"> diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/selectBookmark.xhtml firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/selectBookmark.xhtml --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/selectBookmark.xhtml 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/selectBookmark.xhtml 2020-11-17 19:31:24.000000000 +0000 @@ -13,7 +13,7 @@ xmlns:html="http://www.w3.org/1999/xhtml" data-l10n-id="select-bookmark-window" data-l10n-attrs="title, style" - persist="screenX screenY width height" screenX="24" screenY="24" + persist="width height" onload="SelectBookmarkDialog.init();"> diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/siteDataSettings.xhtml firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/siteDataSettings.xhtml --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/preferences/dialogs/siteDataSettings.xhtml 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/preferences/dialogs/siteDataSettings.xhtml 2020-11-17 19:31:24.000000000 +0000 @@ -17,7 +17,7 @@ style="width: 45em;" onload="gSiteDataSettings.init();" onkeypress="gSiteDataSettings.onKeyPress(event);" - persist="screenX screenY width height"> + persist="width height"> + persist="width height"> + persist="width height"> el.hidden), "all of the warnings to reload tabs are initially hidden" @@ -889,7 +895,8 @@ "all of the warnings to reload tabs are still hidden" ); Services.prefs.setStringPref(CAT_PREF, "standard"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:newtab"); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:newtab"); + await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); }); // Checks that the reload tabs message reloads all tabs except the active tab. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_blobUrl.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_blobUrl.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_blobUrl.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_blobUrl.js 2020-11-17 19:31:24.000000000 +0000 @@ -13,7 +13,7 @@ false, BASE_URI ); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, BASE_URI); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, BASE_URI); await loaded; let blobURL; @@ -42,7 +42,7 @@ false, BASE_URI ); - await BrowserTestUtils.loadURI(privateTab, BASE_URI); + BrowserTestUtils.loadURI(privateTab, BASE_URI); await privateTabLoaded; await SpecialPowers.spawn(privateTab, [blobURL], function(url) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_newtab_from_popup.js 2020-11-17 19:31:24.000000000 +0000 @@ -37,7 +37,7 @@ // First, open a private browsing window, and load our // testing page. let privBrowser = privWin.gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(privBrowser, WINDOW_BODY); + BrowserTestUtils.loadURI(privBrowser, WINDOW_BODY); await BrowserTestUtils.browserLoaded(privBrowser); // Next, click on the link in the testing page, and ensure diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_windowtitle.js 2020-11-17 19:31:24.000000000 +0000 @@ -35,7 +35,7 @@ async function testTabTitle(aWindow, url, insidePB, expected_title) { let tab = await BrowserTestUtils.openNewForegroundTab(aWindow.gBrowser); - await BrowserTestUtils.loadURI(tab.linkedBrowser, url); + BrowserTestUtils.loadURI(tab.linkedBrowser, url); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); await BrowserTestUtils.waitForCondition(() => { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_zoomrestore.js 2020-11-17 19:31:24.000000000 +0000 @@ -19,21 +19,19 @@ }); } - function promiseTestReady(aIsZoomedWindow, aWindow) { + async function promiseTestReady(aIsZoomedWindow, aWindow) { // Need to wait on two things, the ordering of which is not guaranteed: // (1) the page load, and (2) FullZoom's update to the new page's zoom // level. FullZoom broadcasts "browser-fullZoom:location-change" when its // update is done. (See bug 856366 for details.) let browser = aWindow.gBrowser.selectedBrowser; - return BrowserTestUtils.loadURI(browser, "about:blank") - .then(() => { - return Promise.all([ - BrowserTestUtils.browserLoaded(browser), - promiseLocationChange(), - ]); - }) - .then(() => doTest(aIsZoomedWindow, aWindow)); + BrowserTestUtils.loadURI(browser, "about:blank"); + await Promise.all([ + BrowserTestUtils.browserLoaded(browser), + promiseLocationChange(), + ]); + doTest(aIsZoomedWindow, aWindow); } function doTest(aIsZoomedWindow, aWindow) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/search/test/browser/browser_searchTelemetry.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/search/test/browser/browser_searchTelemetry.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/search/test/browser/browser_searchTelemetry.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/search/test/browser/browser_searchTelemetry.js 2020-11-17 19:31:24.000000000 +0000 @@ -216,7 +216,7 @@ let win = await BrowserTestUtils.openNewBrowserWindow(); let url = getSERPUrl(getPageUrl(false, true)); - await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url); await BrowserTestUtils.browserLoaded( win.gBrowser.selectedBrowser, false, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/ContentRestore.jsm firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/ContentRestore.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/ContentRestore.jsm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/ContentRestore.jsm 2020-11-17 19:31:24.000000000 +0000 @@ -18,11 +18,6 @@ "Utils", "resource://gre/modules/sessionstore/Utils.jsm" ); -ChromeUtils.defineModuleGetter( - this, - "E10SUtils", - "resource://gre/modules/E10SUtils.jsm" -); /** * This module implements the content side of session restoration. The chrome * side is handled by SessionStore.jsm. The functions in this module are called @@ -254,56 +249,12 @@ if (loadArguments) { // If the load was started in another process, and the in-flight channel // was redirected into this process, resume that load within our process. - if (loadArguments.redirectLoadSwitchId) { - webNavigation.resumeRedirectedLoad( - loadArguments.redirectLoadSwitchId, - loadArguments.redirectHistoryIndex - ); - return true; - } - - // A load has been redirected to a new process so get history into the - // same state it was before the load started then trigger the load. - // Referrer information is now stored as a referrerInfo property. We - // should also cope with the old format of passing `referrer` and - // `referrerPolicy` separately. - let referrerInfo = loadArguments.referrerInfo; - if (referrerInfo) { - referrerInfo = E10SUtils.deserializeReferrerInfo(referrerInfo); - } else { - let referrer = loadArguments.referrer - ? Services.io.newURI(loadArguments.referrer) - : null; - let referrerPolicy = - "referrerPolicy" in loadArguments - ? loadArguments.referrerPolicy - : Ci.nsIReferrerInfo.EMPTY; - let ReferrerInfo = Components.Constructor( - "@mozilla.org/referrer-info;1", - "nsIReferrerInfo", - "init" - ); - referrerInfo = new ReferrerInfo(referrerPolicy, true, referrer); - } - let postData = loadArguments.postData - ? E10SUtils.makeInputStream(loadArguments.postData) - : null; - let triggeringPrincipal = E10SUtils.deserializePrincipal( - loadArguments.triggeringPrincipal, - () => Services.scriptSecurityManager.createNullPrincipal({}) + // + // NOTE: In this case `isRemotenessUpdate` must be true. + webNavigation.resumeRedirectedLoad( + loadArguments.redirectLoadSwitchId, + loadArguments.redirectHistoryIndex ); - let csp = loadArguments.csp - ? E10SUtils.deserializeCSP(loadArguments.csp) - : null; - - let loadURIOptions = { - triggeringPrincipal, - loadFlags: loadArguments.flags, - referrerInfo, - postData, - csp, - }; - webNavigation.loadURI(loadArguments.uri, loadURIOptions); } else if (tabData.userTypedValue && tabData.userTypedClear) { // If the user typed a URL into the URL bar and hit enter right before // we crashed, we want to start loading that page again. A non-zero diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/SessionStore.jsm firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/SessionStore.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/SessionStore.jsm 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/SessionStore.jsm 2020-11-17 19:31:24.000000000 +0000 @@ -13,7 +13,6 @@ const TAB_LAZY_STATES = new WeakMap(); const TAB_STATE_NEEDS_RESTORE = 1; const TAB_STATE_RESTORING = 2; -const TAB_STATE_WILL_RESTORE = 3; const TAB_STATE_FOR_BROWSER = new WeakMap(); const WINDOW_RESTORE_IDS = new WeakMap(); const WINDOW_RESTORE_ZINDICES = new WeakMap(); @@ -430,14 +429,6 @@ return SessionStoreInternal.reviveAllCrashedTabs(); }, - navigateAndRestore(tab, loadArguments, historyIndex) { - return SessionStoreInternal.navigateAndRestore( - tab, - loadArguments, - historyIndex - ); - }, - updateSessionStoreFromTablistener(aBrowser, aBrowsingContext, aData) { return SessionStoreInternal.updateSessionStoreFromTablistener( aBrowser, @@ -604,11 +595,6 @@ // reason about. _saveableClosedWindowData: new WeakSet(), - // A map (xul:browser -> object) that maps a browser that is switching - // remoteness via navigateAndRestore, to the loadArguments that were - // most recently passed when calling navigateAndRestore. - _remotenessChangingBrowsers: new WeakMap(), - // whether a setBrowserState call is in progress _browserSetState: false, @@ -1055,14 +1041,6 @@ OnHistoryReplaceEntry() { this.notifySHistoryChanges(-1); - - let win = this.browser.ownerGlobal; - let tab = win ? win.gBrowser.getTabForBrowser(this.browser) : null; - if (tab) { - let event = tab.ownerDocument.createEvent("CustomEvent"); - event.initCustomEvent("SSHistoryReplaceEntry", true, false); - tab.dispatchEvent(event); - } }, }; @@ -3866,148 +3844,6 @@ }, /** - * Navigate the given |tab| by first collecting its current state and then - * either changing only the index of the currently shown history entry, - * or restoring the exact same state again and passing the new URL to load - * in |loadArguments|. Use this method to seamlessly switch between pages - * loaded in the parent and pages loaded in the child process. - * - * This method might be called multiple times before it has finished - * flushing the browser tab. If that occurs, the loadArguments from - * the most recent call to navigateAndRestore will be used once the - * flush has finished. - * - * This method returns a promise which will be resolved when the browser - * element's process has been swapped. The load is not guaranteed to have - * been completed at this point. - */ - navigateAndRestore(tab, loadArguments, historyIndex) { - let window = tab.ownerGlobal; - - if (!window.__SSi) { - Cu.reportError("Tab's window must be tracked."); - return Promise.reject(); - } - - let browser = tab.linkedBrowser; - - // If we were alerady waiting for a flush from a previous call to - // navigateAndRestore on this tab, update the loadArguments stored, and - // asynchronously wait on the flush's promise. - if (this._remotenessChangingBrowsers.has(browser.permanentKey)) { - let opts = this._remotenessChangingBrowsers.get(browser.permanentKey); - // XXX(nika): In the existing logic, we always use the initial - // historyIndex value, and don't update it if multiple navigateAndRestore - // calls are made. Should we update it here? - opts.loadArguments = loadArguments; - return opts.promise; - } - - // Begin the asynchronous NavigateAndRestore process, and store the current - // load arguments and promise in our _remotenessChangingBrowsers weakmap. - let promise = this._asyncNavigateAndRestore(tab); - this._remotenessChangingBrowsers.set(browser.permanentKey, { - loadArguments, - historyIndex, - promise, - }); - - // Set up the browser UI to look like we're doing something while waiting - // for a TabStateFlush from our frame scripts. - let uriObj; - try { - uriObj = Services.io.newURI(loadArguments.uri); - } catch (e) {} - - // Start the throbber to pretend we're doing something while actually - // waiting for data from the frame script. This throbber is disabled - // if the URI is a local about: URI. - if (!uriObj || (uriObj && !uriObj.schemeIs("about"))) { - tab.setAttribute("busy", "true"); - } - - // Hack to ensure that the about:home, about:newtab, and about:welcome - // favicon is loaded instantaneously, to avoid flickering and improve - // perceived performance. - window.gBrowser.setDefaultIcon(tab, uriObj); - - TAB_STATE_FOR_BROWSER.set(tab.linkedBrowser, TAB_STATE_WILL_RESTORE); - - // Notify of changes to closed objects. - this._notifyOfClosedObjectsChange(); - - return promise; - }, - - /** - * Internal logic called by navigateAndRestore to flush tab state, and - * trigger a remoteness changing load with the most recent load arguments. - * - * This method's promise will resolve when the process for the given - * xul:browser element has successfully been swapped. - * - * @param tab to navigate and restore. - */ - async _asyncNavigateAndRestore(tab) { - let permanentKey = tab.linkedBrowser.permanentKey; - let browser = tab.linkedBrowser; - - // NOTE: This is currently the only async operation used, but this is likely - // to change in the future. - await this.prepareToChangeRemoteness(browser); - - // Now that we have flushed state, our loadArguments, etc. may have been - // overwritten by multiple calls to navigateAndRestore. Load the most - // recently stored one. - let { loadArguments, historyIndex } = this._remotenessChangingBrowsers.get( - permanentKey - ); - this._remotenessChangingBrowsers.delete(permanentKey); - - // The tab might have been closed/gone in the meantime. - if (tab.closing || !tab.linkedBrowser) { - return; - } - - // The tab or its window might be gone. - let window = tab.ownerGlobal; - if (!window || !window.__SSi || window.closed) { - return; - } - - let tabState = TabState.clone(tab, TAB_CUSTOM_VALUES.get(tab)); - let options = { - restoreImmediately: true, - // We want to make sure that this information is passed to restoreTab - // whether or not a historyIndex is passed in. Thus, we extract it from - // the loadArguments. - newFrameloader: loadArguments.newFrameloader, - remoteType: loadArguments.remoteType, - // Make sure that SessionStore knows that this restoration is due - // to a navigation, as opposed to us restoring a closed window or tab. - restoreContentReason: RESTORE_TAB_CONTENT_REASON.NAVIGATE_AND_RESTORE, - }; - - if (historyIndex >= 0) { - tabState.index = historyIndex + 1; - tabState.index = Math.max( - 1, - Math.min(tabState.index, tabState.entries.length) - ); - } else { - options.loadArguments = loadArguments; - } - - // Need to reset restoring tabs. - if (TAB_STATE_FOR_BROWSER.has(tab.linkedBrowser)) { - this._resetLocalTabRestoringState(tab); - } - - // Restore the state into the tab. - this.restoreTab(tab, tabState, options); - }, - - /** * Retrieves the latest session history information for a tab. The cached data * is returned immediately, but a callback may be provided that supplies * up-to-date data when or if it is available. The callback is passed a single @@ -4943,9 +4779,6 @@ let activeIndex = tabData.index - 1; let activePageData = tabData.entries[activeIndex] || null; let uri = activePageData ? activePageData.url || null : null; - if (loadArguments) { - uri = loadArguments.uri; - } this.markTabAsRestoring(aTab); @@ -4953,22 +4786,10 @@ // necessary. let isRemotenessUpdate = aOptions.isRemotenessUpdate; if (!isRemotenessUpdate) { - let newFrameloader = aOptions.newFrameloader; - if (aOptions.remoteType !== undefined) { - // We already have a selected remote type so we update to that. - isRemotenessUpdate = tabbrowser.updateBrowserRemoteness(browser, { - remoteType: aOptions.remoteType, - newFrameloader, - }); - } else { - isRemotenessUpdate = tabbrowser.updateBrowserRemotenessByURL( - browser, - uri, - { - newFrameloader, - } - ); - } + isRemotenessUpdate = tabbrowser.updateBrowserRemotenessByURL( + browser, + uri + ); if (isRemotenessUpdate) { // We updated the remoteness, so we need to send the history down again. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser_async_remove_tab.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser_async_remove_tab.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser_async_remove_tab.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser_async_remove_tab.js 2020-11-17 19:31:24.000000000 +0000 @@ -32,56 +32,6 @@ return ss.undoCloseTab(window, index); } -function promiseNewLocationAndHistoryEntryReplaced(tab, snippet) { - let browser = tab.linkedBrowser; - - if (SpecialPowers.Services.appinfo.sessionHistoryInParent) { - SpecialPowers.spawn(browser, [snippet], async function(codeSnippet) { - // Need to define 'webNavigation' for 'codeSnippet' - // eslint-disable-next-line no-unused-vars - let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation); - // Evaluate the snippet that changes the location. - // eslint-disable-next-line no-eval - eval(codeSnippet); - }); - return promiseOnHistoryReplaceEntry(tab); - } - - return SpecialPowers.spawn(browser, [snippet], async function(codeSnippet) { - let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation); - let shistory = webNavigation.sessionHistory.legacySHistory; - - // Evaluate the snippet that changes the location. - // eslint-disable-next-line no-eval - eval(codeSnippet); - - return new Promise(resolve => { - let listener = { - OnHistoryReplaceEntry() { - shistory.removeSHistoryListener(this); - resolve(); - }, - - QueryInterface: ChromeUtils.generateQI([ - "nsISHistoryListener", - "nsISupportsWeakReference", - ]), - }; - - shistory.addSHistoryListener(listener); - - /* Keep the weak shistory listener alive. */ - docShell.chromeEventHandler.addEventListener("unload", function() { - try { - shistory.removeSHistoryListener(listener); - } catch (e) { - /* Will most likely fail. */ - } - }); - }); - }); -} - add_task(async function dont_save_empty_tabs() { let { tab, r } = await createTabWithRandomValue("about:blank"); @@ -132,10 +82,14 @@ ok(browser.isRemoteBrowser, "browser is remote"); // Replace about:blank with a new remote page. - let snippet = - 'webNavigation.loadURI("https://example.com/",\ - {triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal()})'; - await promiseNewLocationAndHistoryEntryReplaced(tab, snippet); + let entryReplaced = promiseOnHistoryReplaceEntry(browser); + await SpecialPowers.spawn(browser, [], async () => { + let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation); + webNavigation.loadURI("https://example.com/", { + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); + }); + await entryReplaced; // Remotness shouldn't have changed. ok(browser.isRemoteBrowser, "browser is still remote"); @@ -157,14 +111,10 @@ ok(browser.isRemoteBrowser, "browser is remote"); // Replace about:blank with a non-remote entry. - await BrowserTestUtils.loadURI(browser, "about:robots"); + BrowserTestUtils.loadURI(browser, "about:robots"); + await BrowserTestUtils.browserLoaded(browser); ok(!browser.isRemoteBrowser, "browser is not remote anymore"); - // Switching remoteness caused a SessionRestore to begin, moving over history - // and initiating the load in the target process. Wait for the full restore - // and load to complete before trying to close the tab. - await promiseTabRestored(tab); - // Remove the tab before the update arrives. let promise = promiseRemoveTabAndSessionState(tab); @@ -178,10 +128,15 @@ add_task(async function dont_save_empty_tabs_final() { let { tab, r } = await createTabWithRandomValue("https://example.com/"); + let browser = tab.linkedBrowser; + ok(browser.isRemoteBrowser, "browser is remote"); // Replace the current page with an about:blank entry. - let snippet = 'content.location.replace("about:blank")'; - await promiseNewLocationAndHistoryEntryReplaced(tab, snippet); + let entryReplaced = promiseOnHistoryReplaceEntry(browser); + await SpecialPowers.spawn(browser, [], async () => { + content.location.replace("about:blank"); + }); + await entryReplaced; // Remove the tab before the update arrives. let promise = promiseRemoveTabAndSessionState(tab); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser_async_window_flushing.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser_async_window_flushing.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser_async_window_flushing.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser_async_window_flushing.js 2020-11-17 19:31:24.000000000 +0000 @@ -38,12 +38,8 @@ content.location = newPage; }); - if (SpecialPowers.Services.appinfo.sessionHistoryInParent) { - let tab = newWin.gBrowser.selectedTab; - await promiseOnHistoryReplaceEntry(tab); - } else { - await promiseOnHistoryReplaceEntryInChild(browser); - } + await promiseOnHistoryReplaceEntry(browser); + // Clear out the userTypedValue so that the new window looks like // it's really not worth restoring. browser.userTypedValue = null; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser.ini firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser.ini --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser.ini 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser.ini 2020-11-17 19:31:24.000000000 +0000 @@ -80,7 +80,7 @@ skip-if = debug # bug 1167933 [browser_async_remove_tab.js] run-if = e10s -skip-if = fission || debug # bug 1211084 +skip-if = debug # bug 1211084 [browser_attributes.js] [browser_backup_recovery.js] skip-if = (verify && debug && (os == 'linux')) diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser_restore_reversed_z_order.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser_restore_reversed_z_order.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser_restore_reversed_z_order.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser_restore_reversed_z_order.js 2020-11-17 19:31:24.000000000 +0000 @@ -20,7 +20,7 @@ let browserLoaded = BrowserTestUtils.browserLoaded( window.gBrowser.selectedBrowser ); - await BrowserTestUtils.loadURI(window.gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(window.gBrowser.selectedBrowser, url); await browserLoaded; // Capture the title. gTestURLsMap.set(url, window.gBrowser.selectedTab.label); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser_sessionHistory.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser_sessionHistory.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/browser_sessionHistory.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/browser_sessionHistory.js 2020-11-17 19:31:24.000000000 +0000 @@ -17,8 +17,8 @@ const PAGE = "http://example.com/"; // Load a new URI. - let historyReplacePromise = promiseOnHistoryReplaceEntryInChild(browser); - await BrowserTestUtils.loadURI(browser, PAGE); + let historyReplacePromise = promiseOnHistoryReplaceEntry(browser); + BrowserTestUtils.loadURI(browser, PAGE); // Remove the tab before it has finished loading. await historyReplacePromise; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/head.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/head.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/sessionstore/test/head.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/sessionstore/test/head.js 2020-11-17 19:31:24.000000000 +0000 @@ -524,10 +524,6 @@ return new Promise(resolve => whenDelayedStartupFinished(aWindow, resolve)); } -function promiseOnHistoryReplaceEntry(tab) { - return BrowserTestUtils.waitForEvent(tab, "SSHistoryReplaceEntry"); -} - function promiseTabRestored(tab) { return BrowserTestUtils.waitForEvent(tab, "SSTabRestored"); } @@ -659,7 +655,7 @@ ); } -function promiseOnHistoryReplaceEntryInChild(browser) { +function promiseOnHistoryReplaceEntry(browser) { if (SpecialPowers.Services.appinfo.sessionHistoryInParent) { return new Promise(resolve => { let sessionHistory = browser.browsingContext?.sessionHistory; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/touchbar/tests/browser/browser_touchbar_tests.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/touchbar/tests/browser/browser_touchbar_tests.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/touchbar/tests/browser/browser_touchbar_tests.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/touchbar/tests/browser/browser_touchbar_tests.js 2020-11-17 19:31:24.000000000 +0000 @@ -97,7 +97,7 @@ "chrome://browser/skin/search-glass.svg", "OpenLocation should be displaying the search glass icon." ); - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( gBrowser.selectedBrowser, TEST_PATH + "video_test.html" ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser/browser_autoOpen.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser/browser_autoOpen.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser/browser_autoOpen.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser/browser_autoOpen.js 2020-11-17 19:31:24.000000000 +0000 @@ -81,7 +81,7 @@ // After example.com closes, about:newtab/home is selected again. await checkOpensOnFocus(); // Load example.com in the same tab. - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( gBrowser.selectedBrowser, "http://example.com/" ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser/browser_inputHistory_emptystring.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser/browser_inputHistory_emptystring.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser/browser_inputHistory_emptystring.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser/browser_inputHistory_emptystring.js 2020-11-17 19:31:24.000000000 +0000 @@ -88,7 +88,7 @@ // A page other than TEST_URL must be loaded, or the first Top Site // result will be a switch-to-tab result and page won't be reloaded when // the result is selected. - await BrowserTestUtils.loadURI(selectedBrowser, "http://example.org/"); + BrowserTestUtils.loadURI(selectedBrowser, "http://example.org/"); await BrowserTestUtils.browserLoaded(selectedBrowser); gURLBar.blur(); EventUtils.synthesizeMouseAtCenter(gURLBar.textbox, {}); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser/browser_remoteness_switch.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser/browser_remoteness_switch.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser/browser_remoteness_switch.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser/browser_remoteness_switch.js 2020-11-17 19:31:24.000000000 +0000 @@ -35,7 +35,7 @@ ) { return loadedURL == "about:config"; }); - await BrowserTestUtils.loadURI(browser, "about:config"); + BrowserTestUtils.loadURI(browser, "about:config"); await didLoad; gBrowser.goBack(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser/browser_retainedResultsOnFocus.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser/browser_retainedResultsOnFocus.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser/browser_retainedResultsOnFocus.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser/browser_retainedResultsOnFocus.js 2020-11-17 19:31:24.000000000 +0000 @@ -268,7 +268,7 @@ registerCleanupFunction(PlacesUtils.history.clear); let win = await BrowserTestUtils.openNewBrowserWindow(); - await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, "about:robots"); + BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, "about:robots"); let tab1 = win.gBrowser.selectedTab; info("Open a new tab and the empty search"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser-tips/browser_interventions.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser-tips/browser_interventions.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser-tips/browser_interventions.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser-tips/browser_interventions.js 2020-11-17 19:31:24.000000000 +0000 @@ -195,7 +195,7 @@ Assert.ok(BrowserTestUtils.is_visible(helpButton)); EventUtils.synthesizeMouseAtCenter(helpButton, {}); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, helpUrl); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, helpUrl); await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser-tips/browser_searchTips_interaction.js firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser-tips/browser_searchTips_interaction.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/components/urlbar/tests/browser-tips/browser_searchTips_interaction.js 2020-11-15 14:37:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/components/urlbar/tests/browser-tips/browser_searchTips_interaction.js 2020-11-17 19:31:24.000000000 +0000 @@ -157,7 +157,7 @@ await setDefaultEngine("Google"); await BrowserTestUtils.withNewTab("about:blank", async () => { await withDNSRedirect("www.google.com", "/", async url => { - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT, false); @@ -327,7 +327,7 @@ await setDefaultEngine("Google"); await BrowserTestUtils.withNewTab("about:blank", async () => { await withDNSRedirect("www.google.com", "/", async url => { - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT, false); @@ -383,7 +383,7 @@ await setDefaultEngine("Google"); await BrowserTestUtils.withNewTab("about:blank", async () => { await withDNSRedirect("www.google.com", "/", async url => { - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT, false); @@ -490,7 +490,7 @@ // Give it a big persistence so it doesn't go away on page load. note.persistence = 100; await withDNSRedirect("www.google.com", "/", async url => { - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.NONE); box.removeNotification(note, true); @@ -516,7 +516,7 @@ await setDefaultEngine("Google"); await BrowserTestUtils.withNewTab("about:blank", async () => { await withDNSRedirect("www.google.com", "/", async url => { - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url); await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT, false); // We're just looking for any target outside the Urlbar. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/config/mozconfigs/macosx64/plain-opt firefox-trunk-85.0~a1~hg20201117r557492/browser/config/mozconfigs/macosx64/plain-opt --- firefox-trunk-84.0~a1~hg20201115r557261/browser/config/mozconfigs/macosx64/plain-opt 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/config/mozconfigs/macosx64/plain-opt 2020-11-17 19:31:24.000000000 +0000 @@ -0,0 +1,8 @@ +CARGO="${MOZ_FETCHES_DIR}/rustc/bin/cargo" +RUSTC="${MOZ_FETCHES_DIR}/rustc/bin/rustc" +RUSTDOC="${MOZ_FETCHES_DIR}/rustc/bin/rustdoc" +RUSTFMT="${MOZ_FETCHES_DIR}/rustc/bin/rustfmt" +CBINDGEN="${MOZ_FETCHES_DIR}/cbindgen/cbindgen" + +export NODEJS="${MOZ_FETCHES_DIR}/node/bin/node" +NASM="${MOZ_FETCHES_DIR}/nasm/nasm" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/config/version_display.txt firefox-trunk-85.0~a1~hg20201117r557492/browser/config/version_display.txt --- firefox-trunk-84.0~a1~hg20201115r557261/browser/config/version_display.txt 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/config/version_display.txt 2020-11-17 19:31:24.000000000 +0000 @@ -1 +1 @@ -84.0a1 +85.0a1 diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/config/version.txt firefox-trunk-85.0~a1~hg20201117r557492/browser/config/version.txt --- firefox-trunk-84.0~a1~hg20201115r557261/browser/config/version.txt 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/config/version.txt 2020-11-17 19:31:24.000000000 +0000 @@ -1 +1 @@ -84.0a1 +85.0a1 diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/extensions/formautofill/test/browser/browser_autocomplete_marked_back_forward.js firefox-trunk-85.0~a1~hg20201117r557492/browser/extensions/formautofill/test/browser/browser_autocomplete_marked_back_forward.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/extensions/formautofill/test/browser/browser_autocomplete_marked_back_forward.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/extensions/formautofill/test/browser/browser_autocomplete_marked_back_forward.js 2020-11-17 19:31:24.000000000 +0000 @@ -38,7 +38,7 @@ // Now navigate forward and make sure autofill autocomplete results are still attached let loadPromise = BrowserTestUtils.browserLoaded(browser); - await BrowserTestUtils.loadURI(browser, `${URL}?load=2`); + BrowserTestUtils.loadURI(browser, `${URL}?load=2`); info("expecting browser loaded"); await loadPromise; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/browser_Telemetry_numberOfSiteOriginsPerDocument.js firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/browser_Telemetry_numberOfSiteOriginsPerDocument.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/browser_Telemetry_numberOfSiteOriginsPerDocument.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/browser_Telemetry_numberOfSiteOriginsPerDocument.js 2020-11-17 19:31:24.000000000 +0000 @@ -77,11 +77,11 @@ ]; // Navigate to an interstitial page. - await BrowserTestUtils.loadURI(tab.linkedBrowser, "about:blank"); + BrowserTestUtils.loadURI(tab.linkedBrowser, "about:blank"); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); // Navigate to another test page. - await BrowserTestUtils.loadURI(tab.linkedBrowser, testPage); + BrowserTestUtils.loadURI(tab.linkedBrowser, testPage); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); wgpDestroyedPromises.push( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/browser_UsageTelemetry_domains.js firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/browser_UsageTelemetry_domains.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/browser_UsageTelemetry_domains.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/browser_UsageTelemetry_domains.js 2020-11-17 19:31:24.000000000 +0000 @@ -83,7 +83,7 @@ checkCounts({ totalURIs: 0, domainCount: 0, totalUnfilteredURIs: 0 }); // Open a different page and check the counts. - await BrowserTestUtils.loadURI(firstTab.linkedBrowser, "http://example.com/"); + BrowserTestUtils.loadURI(firstTab.linkedBrowser, "http://example.com/"); await BrowserTestUtils.browserLoaded(firstTab.linkedBrowser); checkCounts({ totalURIs: 1, domainCount: 1, totalUnfilteredURIs: 1 }); @@ -98,7 +98,7 @@ // Open a new window and set the tab to a new address. let newWin = await BrowserTestUtils.openNewBrowserWindow(); - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( newWin.gBrowser.selectedBrowser, "http://example.com/" ); @@ -123,7 +123,7 @@ // Check that we're counting page fragments. let loadingStopped = browserLocationChanged(newWin.gBrowser.selectedBrowser); - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( newWin.gBrowser.selectedBrowser, "http://example.com/#2" ); @@ -131,7 +131,7 @@ checkCounts({ totalURIs: 3, domainCount: 1, totalUnfilteredURIs: 3 }); // Check that a different URI from the example.com domain doesn't increment the unique count. - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( newWin.gBrowser.selectedBrowser, "http://test1.example.com/" ); @@ -139,7 +139,7 @@ checkCounts({ totalURIs: 4, domainCount: 1, totalUnfilteredURIs: 4 }); // Make sure that the unique domains counter is incrementing for a different domain. - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( newWin.gBrowser.selectedBrowser, "https://example.org/" ); @@ -169,7 +169,7 @@ // Check that uncommon protocols get counted in the unfiltered URI probe. const TEST_PAGE = "data:text/html,Click meThe paragraph."; - await BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, TEST_PAGE); + BrowserTestUtils.loadURI(newWin.gBrowser.selectedBrowser, TEST_PAGE); await BrowserTestUtils.browserLoaded(newWin.gBrowser.selectedBrowser); checkCounts({ totalURIs: 5, domainCount: 2, totalUnfilteredURIs: 6 }); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/browser_UsageTelemetry.js firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/browser_UsageTelemetry.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/browser_UsageTelemetry.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/browser_UsageTelemetry.js 2020-11-17 19:31:24.000000000 +0000 @@ -306,7 +306,7 @@ ); openedTabs.push(tab); BrowserUsageTelemetry._lastRecordTabCount = 0; - await BrowserTestUtils.loadURI(tab.linkedBrowser, "http://example.com/"); + BrowserTestUtils.loadURI(tab.linkedBrowser, "http://example.com/"); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); checkTabCountHistogram( tabCountHist.snapshot(), @@ -382,7 +382,7 @@ Date.now() - MINIMUM_TAB_COUNT_INTERVAL_MS / 2; { let oldLastRecordTabCount = BrowserUsageTelemetry._lastRecordTabCount; - await BrowserTestUtils.loadURI(tab.linkedBrowser, "http://example.com/"); + BrowserTestUtils.loadURI(tab.linkedBrowser, "http://example.com/"); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); checkTabCountHistogram( tabCountHist.snapshot(), @@ -400,7 +400,7 @@ Date.now() - (MINIMUM_TAB_COUNT_INTERVAL_MS + 1000); { let oldLastRecordTabCount = BrowserUsageTelemetry._lastRecordTabCount; - await BrowserTestUtils.loadURI(tab.linkedBrowser, "http://example.com/"); + BrowserTestUtils.loadURI(tab.linkedBrowser, "http://example.com/"); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); checkTabCountHistogram( tabCountHist.snapshot(), diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/browser_UsageTelemetry_private_and_restore.js firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/browser_UsageTelemetry_private_and_restore.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/browser_UsageTelemetry_private_and_restore.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/browser_UsageTelemetry_private_and_restore.js 2020-11-17 19:31:24.000000000 +0000 @@ -32,7 +32,7 @@ let privateWin = await BrowserTestUtils.openNewBrowserWindow({ private: true, }); - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( privateWin.gBrowser.selectedBrowser, "http://example.com/" ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/formValidation/browser_form_validation.js firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/formValidation/browser_form_validation.js --- firefox-trunk-84.0~a1~hg20201115r557261/browser/modules/test/browser/formValidation/browser_form_validation.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/modules/test/browser/formValidation/browser_form_validation.js 2020-11-17 19:31:24.000000000 +0000 @@ -416,7 +416,7 @@ gInvalidFormPopup, "popuphidden" ); - await BrowserTestUtils.loadURI(browser, "data:text/html,
hello!
"); + BrowserTestUtils.loadURI(browser, "data:text/html,
hello!
"); await BrowserTestUtils.browserLoaded(browser); await popupHiddenPromise; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm firefox-trunk-85.0~a1~hg20201117r557492/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm 2020-11-17 19:31:24.000000000 +0000 @@ -152,7 +152,7 @@ .removeAttribute("remotecontrol"); let selectedBrowser = browserWindow.gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(selectedBrowser, HOME_PAGE); + BrowserTestUtils.loadURI(selectedBrowser, HOME_PAGE); await BrowserTestUtils.browserLoaded(selectedBrowser); for (let i = 0; i < this.combos.length; i++) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/build/build-clang/clang-11-linux64.json firefox-trunk-85.0~a1~hg20201117r557492/build/build-clang/clang-11-linux64.json --- firefox-trunk-84.0~a1~hg20201115r557261/build/build-clang/clang-11-linux64.json 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/build/build-clang/clang-11-linux64.json 2020-11-17 19:31:24.000000000 +0000 @@ -18,6 +18,7 @@ "android-mangling-error.patch", "unpoison-thread-stacks_clang_10.patch", "downgrade-mangling-error.patch", + "llvmorg-12-init-10926-gb79e990f401-LTO-new-pass-manager.patch", "loosen-msvc-detection.patch" ] } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/build/build-clang/clang-11-win64.json firefox-trunk-85.0~a1~hg20201117r557492/build/build-clang/clang-11-win64.json --- firefox-trunk-84.0~a1~hg20201115r557261/build/build-clang/clang-11-win64.json 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/build/build-clang/clang-11-win64.json 2020-11-17 19:31:24.000000000 +0000 @@ -12,6 +12,7 @@ "unpoison-thread-stacks_clang_10.patch", "downgrade-mangling-error.patch", "bug47258-extract-symbols-mbcs.patch", + "llvmorg-12-init-10926-gb79e990f401-LTO-new-pass-manager.patch", "loosen-msvc-detection.patch" ] } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/build/build-clang/llvmorg-12-init-10926-gb79e990f401-LTO-new-pass-manager.patch firefox-trunk-85.0~a1~hg20201117r557492/build/build-clang/llvmorg-12-init-10926-gb79e990f401-LTO-new-pass-manager.patch --- firefox-trunk-84.0~a1~hg20201115r557261/build/build-clang/llvmorg-12-init-10926-gb79e990f401-LTO-new-pass-manager.patch 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/build/build-clang/llvmorg-12-init-10926-gb79e990f401-LTO-new-pass-manager.patch 2020-11-17 19:31:24.000000000 +0000 @@ -0,0 +1,66 @@ +diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h +index 7c439176f3a4..ae969c6bdd8b 100644 +--- a/lld/COFF/Config.h ++++ b/lld/COFF/Config.h +@@ -155,6 +155,11 @@ struct Configuration { + // Used for /opt:lldltocachepolicy=policy + llvm::CachePruningPolicy ltoCachePolicy; + ++ // Used for /opt:[no]ltonewpassmanager ++ bool ltoNewPassManager = false; ++ // Used for /opt:[no]ltodebugpassmanager ++ bool ltoDebugPassManager = false; ++ + // Used for /merge:from=to (e.g. /merge:.rdata=.text) + std::map merge; + +diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp +index 9ceccef86779..db2ae241dddf 100644 +--- a/lld/COFF/Driver.cpp ++++ b/lld/COFF/Driver.cpp +@@ -1418,6 +1418,8 @@ void LinkerDriver::link(ArrayRef argsArr) { + unsigned icfLevel = + args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on + unsigned tailMerge = 1; ++ bool ltoNewPM = false; ++ bool ltoDebugPM = false; + for (auto *arg : args.filtered(OPT_opt)) { + std::string str = StringRef(arg->getValue()).lower(); + SmallVector vec; +@@ -1435,6 +1437,14 @@ void LinkerDriver::link(ArrayRef argsArr) { + tailMerge = 2; + } else if (s == "nolldtailmerge") { + tailMerge = 0; ++ } else if (s == "ltonewpassmanager") { ++ ltoNewPM = true; ++ } else if (s == "noltonewpassmanager") { ++ ltoNewPM = false; ++ } else if (s == "ltodebugpassmanager") { ++ ltoDebugPM = true; ++ } else if (s == "noltodebugpassmanager") { ++ ltoDebugPM = false; + } else if (s.startswith("lldlto=")) { + StringRef optLevel = s.substr(7); + if (optLevel.getAsInteger(10, config->ltoo) || config->ltoo > 3) +@@ -1464,6 +1474,8 @@ void LinkerDriver::link(ArrayRef argsArr) { + config->doGC = doGC; + config->doICF = icfLevel > 0; + config->tailMerge = (tailMerge == 1 && config->doICF) || tailMerge == 2; ++ config->ltoNewPassManager = ltoNewPM; ++ config->ltoDebugPassManager = ltoDebugPM; + + // Handle /lldsavetemps + if (args.hasArg(OPT_lldsavetemps)) +diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp +index bb44819e60f8..e55fb544b050 100644 +--- a/lld/COFF/LTO.cpp ++++ b/lld/COFF/LTO.cpp +@@ -82,6 +82,8 @@ static lto::Config createConfig() { + c.MAttrs = getMAttrs(); + c.CGOptLevel = args::getCGOptLevel(config->ltoo); + c.AlwaysEmitRegularLTOObj = !config->ltoObjPath.empty(); ++ c.UseNewPM = config->ltoNewPassManager; ++ c.DebugPassManager = config->ltoDebugPassManager; + + if (config->saveTemps) + checkError(c.addSaveTemps(std::string(config->outputFile) + ".", diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/build/moz.configure/lto-pgo.configure firefox-trunk-85.0~a1~hg20201117r557492/build/moz.configure/lto-pgo.configure --- firefox-trunk-84.0~a1~hg20201115r557261/build/moz.configure/lto-pgo.configure 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/build/moz.configure/lto-pgo.configure 2020-11-17 19:31:24.000000000 +0000 @@ -278,11 +278,16 @@ # binary size growth while still getting good performance. # (For hot functions, PGO will put a multiplier on this limit.) if target.os == "WINNT": + ldflags.append("-opt:ltonewpassmanager") ldflags.append("-mllvm:-import-instr-limit=10") + ldflags.append("-mllvm:-import-hot-multiplier=30") elif target.os == "OSX": + # ld64 doesn't seem to have an option for the new pass manager ldflags.append("-Wl,-mllvm,-import-instr-limit=10") elif c_compiler.type == "clang": + ldflags.append("-Wl,-plugin-opt=new-pass-manager") ldflags.append("-Wl,-plugin-opt=-import-instr-limit=10") + ldflags.append("-Wl,-plugin-opt=-import-hot-multiplier=30") return namespace( enabled=enabled, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/build/non-unified-compat firefox-trunk-85.0~a1~hg20201117r557492/build/non-unified-compat --- firefox-trunk-84.0~a1~hg20201115r557261/build/non-unified-compat 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/build/non-unified-compat 2020-11-17 19:31:24.000000000 +0000 @@ -63,4 +63,13 @@ dom/url/ dom/vr/ dom/webauthn/ -dom/webbrowserpersist/ \ No newline at end of file +dom/webbrowserpersist/ +dom/webgpu/ +dom/webidl/ +dom/webshare/ +dom/websocket/ +dom/workers/ +dom/worklet/ +dom/xhr/ +dom/xml/ +dom/xslt/ \ No newline at end of file diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/BUILDID firefox-trunk-85.0~a1~hg20201117r557492/BUILDID --- firefox-trunk-84.0~a1~hg20201115r557261/BUILDID 2020-11-15 14:44:29.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/BUILDID 2020-11-17 19:37:15.000000000 +0000 @@ -1 +1 @@ -20201115153453 \ No newline at end of file +20201117202825 \ No newline at end of file diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/config/makefiles/rust.mk firefox-trunk-85.0~a1~hg20201117r557492/config/makefiles/rust.mk --- firefox-trunk-84.0~a1~hg20201115r557261/config/makefiles/rust.mk 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/config/makefiles/rust.mk 2020-11-17 19:31:24.000000000 +0000 @@ -53,8 +53,11 @@ cargo_build_flags += -j1 endif -# This should also be paired with -Zbuild-std, but that doesn't work yet. +# We also need to rebuild the rust stdlib so that it's instrumented. Because +# build-std is still pretty experimental, we need to explicitly request +# the panic_abort crate for `panic = "abort"` support. ifdef MOZ_TSAN +cargo_build_flags += -Zbuild-std=std,panic_abort RUSTFLAGS += -Zsanitizer=thread endif diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/config/milestone.txt firefox-trunk-85.0~a1~hg20201117r557492/config/milestone.txt --- firefox-trunk-84.0~a1~hg20201115r557261/config/milestone.txt 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/config/milestone.txt 2020-11-17 19:31:24.000000000 +0000 @@ -10,4 +10,4 @@ # hardcoded milestones in the tree from these two files. #-------------------------------------------------------- -84.0a1 +85.0a1 diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/debian/changelog firefox-trunk-85.0~a1~hg20201117r557492/debian/changelog --- firefox-trunk-84.0~a1~hg20201115r557261/debian/changelog 2020-11-15 18:50:55.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/debian/changelog 2020-11-17 19:43:21.000000000 +0000 @@ -1,5 +1,13 @@ -firefox-trunk (84.0~a1~hg20201115r557261-0ubuntu0.20.10.1~umd2) groovy; urgency=emergency +firefox-trunk (85.0~a1~hg20201117r557492-0ubuntu0.20.10.1~umd1) groovy; urgency=emergency + * + * New upstream snapshot + + -- Rico Tzschichholz Tue, 17 Nov 2020 20:43:21 +0100 + +firefox-trunk (84.0~a1~hg20201115r557261-0ubuntu1) hirsute; urgency=medium + + [ Rico Tzschichholz ] * Update patches - debian/patches/armhf-reduce-linker-memory-use.patch - debian/patches/dont-checkout-locales.patch @@ -7,9 +15,15 @@ - debian/patches/support-coinstallable-trunk-build.patch - debian/patches/ubuntu-ua-string-changes.patch - debian/patches/use-system-icupkg.patch - * New upstream snapshot + * Irgnore checksums of cleaned files + - debian/patches/rust-drop-checksums.patch + + [ Olivier Tilloy ] + * Fix FTBFS on armhf + - update and re-enable fix-armhf-webrtc-build.patch + - add armhf-do-not-build-qcms-with-neon.patch - -- Rico Tzschichholz Sun, 15 Nov 2020 19:50:55 +0100 + -- Rico Tzschichholz Sun, 15 Nov 2020 19:52:29 +0100 firefox-trunk (83.0~a1~hg20201019r553351-0ubuntu1) groovy; urgency=medium diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/debian/patches/armhf-do-not-build-qcms-with-neon.patch firefox-trunk-85.0~a1~hg20201117r557492/debian/patches/armhf-do-not-build-qcms-with-neon.patch --- firefox-trunk-84.0~a1~hg20201115r557261/debian/patches/armhf-do-not-build-qcms-with-neon.patch 2020-11-13 12:40:55.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/debian/patches/armhf-do-not-build-qcms-with-neon.patch 2020-11-17 07:30:09.000000000 +0000 @@ -23,12 +23,13 @@ use crate::transform_neon::{ qcms_transform_data_bgra_out_lut_neon, qcms_transform_data_rgb_out_lut_neon, qcms_transform_data_rgba_out_lut_neon, -@@ -1424,9 +1424,9 @@ pub unsafe extern "C" fn qcms_transform_ +@@ -1424,10 +1424,10 @@ pub unsafe extern "C" fn qcms_transform_ (*transform).transform_fn = Some(qcms_transform_data_bgra_out_lut_sse2) } } -- } else if cfg!(any(target_arch = "arm", target_arch = "aarch64")) && qcms_supports_neon -+ } else if cfg!(any(target_arch = "aarch64")) && qcms_supports_neon +- } else if cfg!(any(target_arch = "arm", target_arch = "aarch64")) ++ } else if cfg!(any(target_arch = "aarch64")) + && qcms_supports_neon.load(Ordering::Relaxed) { - #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] + #[cfg(any(target_arch = "aarch64"))] @@ -39,6 +40,6 @@ } #[no_mangle] pub unsafe extern "C" fn qcms_enable_neon() { -- qcms_supports_neon = true; -+ qcms_supports_neon = cfg!(any(target_arch = "aarch64")); +- qcms_supports_neon.store(true, Ordering::Relaxed); ++ qcms_supports_neon.store(cfg!(any(target_arch = "aarch64")), Ordering::Relaxed); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/framework/test/browser_toolbox_remoteness_change.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/framework/test/browser_toolbox_remoteness_change.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/framework/test/browser_toolbox_remoteness_change.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/framework/test/browser_toolbox_remoteness_change.js 2020-11-17 19:31:25.000000000 +0000 @@ -49,7 +49,7 @@ // So, fallback to BrowserTestUtils helpers in this test when // the target-switching preference is turned off. const onBrowserLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - await BrowserTestUtils.loadURI(tab.linkedBrowser, URL_2); + BrowserTestUtils.loadURI(tab.linkedBrowser, URL_2); await onBrowserLoaded; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/fronts/object.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/fronts/object.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/fronts/object.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/fronts/object.js 2020-11-17 19:31:25.000000000 +0000 @@ -240,6 +240,43 @@ } /** + * Request the state of a promise. + */ + async getPromiseState() { + if (this._grip.class !== "Promise") { + console.error("getPromiseState is only valid for promise grips."); + return null; + } + + let response, promiseState; + try { + response = await super.promiseState(); + promiseState = response.promiseState; + } catch (error) { + // Before Firefox 85 (bug 1552648), the promiseState request didn't exist. + // The promise state was directly included in the grip. + if (error.message.includes("unrecognizedPacketType")) { + promiseState = this._grip.promiseState; + response = { promiseState }; + } else { + throw error; + } + } + + const { value, reason } = promiseState; + + if (value) { + promiseState.value = getAdHocFrontOrPrimitiveGrip(value, this); + } + + if (reason) { + promiseState.reason = getAdHocFrontOrPrimitiveGrip(reason, this); + } + + return response; + } + + /** * Request the target and handler internal slots of a proxy. */ async getProxySlots() { @@ -356,24 +393,6 @@ * @param {String|Number|Object} packet: The packet returned by the server */ function createChildFronts(objectFront, packet) { - // Handle Promise fullfilled and rejected values - if (packet.class == "Promise" && packet.promiseState) { - if (packet.promiseState.state == "fulfilled" && packet.promiseState.value) { - packet.promiseState.value = getAdHocFrontOrPrimitiveGrip( - packet.promiseState.value, - objectFront - ); - } else if ( - packet.promiseState.state == "rejected" && - packet.promiseState.reason - ) { - packet.promiseState.reason = getAdHocFrontOrPrimitiveGrip( - packet.promiseState.reason, - objectFront - ); - } - } - if (packet.preview) { const { message, entries } = packet.preview; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/animation/test/browser_animation_fission_switch-target.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/animation/test/browser_animation_fission_switch-target.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/animation/test/browser_animation_fission_switch-target.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/animation/test/browser_animation_fission_switch-target.js 2020-11-17 19:31:25.000000000 +0000 @@ -83,7 +83,7 @@ const previousAnimationsFront = animationInspector.animationsFront; const onReloaded = inspector.once("reloaded"); const onUpdated = inspector.once("inspector-updated"); - await BrowserTestUtils.loadURI(browser, uri); + BrowserTestUtils.loadURI(browser, uri); await waitUntil( () => previousAnimationsFront !== animationInspector.animationsFront ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_panel-select.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_panel-select.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_panel-select.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_panel-select.js 2020-11-17 19:31:25.000000000 +0000 @@ -104,10 +104,7 @@ await _selectSidebarPanel(inspector, "changesview"); info("Navigate to another page"); - await BrowserTestUtils.loadURI( - tab.linkedBrowser, - _toDataURL(TEST_ANOTHER_URI) - ); + BrowserTestUtils.loadURI(tab.linkedBrowser, _toDataURL(TEST_ANOTHER_URI)); info("Select the compatibility panel again"); const onSelectedNodePaneUpdated = waitForUpdateSelectedNodeAction( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_top-level-target-change.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_top-level-target-change.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_top-level-target-change.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/compatibility/test/browser/browser_compatibility_event_top-level-target-change.js 2020-11-17 19:31:25.000000000 +0000 @@ -71,6 +71,6 @@ const onSelectedNodeUpdated = waitForUpdateSelectedNodeAction(store); const onTopLevelTargetUpdated = waitForUpdateTopLevelTargetAction(store); const onLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - await BrowserTestUtils.loadURI(tab.linkedBrowser, uri); + BrowserTestUtils.loadURI(tab.linkedBrowser, uri); await Promise.all([onLoaded, onSelectedNodeUpdated, onTopLevelTargetUpdated]); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/index.xhtml firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/index.xhtml --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/index.xhtml 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/index.xhtml 2020-11-17 19:31:25.000000000 +0000 @@ -25,6 +25,9 @@ + + + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/test/browser_inspector_remove-iframe-during-load.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/test/browser_inspector_remove-iframe-during-load.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/inspector/test/browser_inspector_remove-iframe-during-load.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/inspector/test/browser_inspector_remove-iframe-during-load.js 2020-11-17 19:31:25.000000000 +0000 @@ -17,7 +17,7 @@ // See next comments. const browser = tab.linkedBrowser; const onBrowserLoaded = BrowserTestUtils.browserLoaded(browser); - await BrowserTestUtils.loadURI(browser, TEST_URL); + BrowserTestUtils.loadURI(browser, TEST_URL); await onBrowserLoaded; // We do not want to wait for the inspector to be fully ready before testing diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/locales/en-US/aboutdebugging.ftl firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/locales/en-US/aboutdebugging.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/locales/en-US/aboutdebugging.ftl 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/locales/en-US/aboutdebugging.ftl 2020-11-17 19:31:25.000000000 +0000 @@ -59,10 +59,6 @@ # Text displayed as connection error in sidebar item when the connection has timed out. about-debugging-sidebar-item-connect-button-connection-timeout = Connection timed out -# Temporary text displayed in sidebar items representing remote runtimes after -# successfully connecting to them. Temporary UI, do not localize. -about-debugging-sidebar-item-connected-label = Connected - # Text displayed in sidebar items for remote devices where a compatible browser (eg # Firefox) has not been detected yet. Typically, Android phones connected via USB with # USB debugging enabled, but where Firefox is not started. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/memory/test/browser/browser_memory_fission_switch_target.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/memory/test/browser/browser_memory_fission_switch_target.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/memory/test/browser/browser_memory_fission_switch_target.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/memory/test/browser/browser_memory_fission_switch_target.js 2020-11-17 19:31:25.000000000 +0000 @@ -19,7 +19,7 @@ const { gToolbox: toolbox, gStore: store } = panel.panelWin; info("Open a page running on the content process"); - await BrowserTestUtils.loadURI(tab.linkedBrowser, CONTENT_PROCESS_URI); + BrowserTestUtils.loadURI(tab.linkedBrowser, CONTENT_PROCESS_URI); await BrowserTestUtils.browserLoaded(tab.linkedBrowser); await takeAndWaitSnapshot( panel.panelWin, @@ -80,7 +80,7 @@ async function navigateTo(uri, toolbox, tab) { const onSwitched = toolbox.targetList.once("switched-target"); const onLoaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser); - await BrowserTestUtils.loadURI(tab.linkedBrowser, uri); + BrowserTestUtils.loadURI(tab.linkedBrowser, uri); await onLoaded; await onSwitched; ok(true, "switched-target event is fired"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/performance/test/browser_perf-fission-switch-target.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/performance/test/browser_perf-fission-switch-target.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/performance/test/browser_perf-fission-switch-target.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/performance/test/browser_perf-fission-switch-target.js 2020-11-17 19:31:25.000000000 +0000 @@ -41,11 +41,11 @@ await PerformanceView.once(EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED); info("Navigate to a page running on main process"); - await BrowserTestUtils.loadURI(tab.linkedBrowser, MAIN_PROCESS_URL); + BrowserTestUtils.loadURI(tab.linkedBrowser, MAIN_PROCESS_URL); await PerformanceView.once(EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED); info("Return to a page running on content process again"); - await BrowserTestUtils.loadURI(tab.linkedBrowser, CONTENT_PROCESS_URL); + BrowserTestUtils.loadURI(tab.linkedBrowser, CONTENT_PROCESS_URL); await PerformanceView.once(EVENTS.UI_RECORDING_PROFILER_STATUS_RENDERED); info("Stop recording"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/responsive/test/browser/head.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/responsive/test/browser/head.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/responsive/test/browser/head.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/responsive/test/browser/head.js 2020-11-17 19:31:25.000000000 +0000 @@ -589,7 +589,7 @@ async function load(browser, url) { const loaded = BrowserTestUtils.browserLoaded(browser, false, null, false); - await BrowserTestUtils.loadURI(browser, url); + BrowserTestUtils.loadURI(browser, url); await loaded; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/object-inspector/utils/client.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/object-inspector/utils/client.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/object-inspector/utils/client.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/object-inspector/utils/client.js 2020-11-17 19:31:25.000000000 +0000 @@ -79,6 +79,10 @@ } } +async function getPromiseState(objectFront) { + return objectFront.getPromiseState(); +} + async function getProxySlots(objectFront) { return objectFront.getProxySlots(); } @@ -100,5 +104,6 @@ enumSymbols, getPrototype, getFullText, + getPromiseState, getProxySlots, }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/object-inspector/utils/load-properties.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/object-inspector/utils/load-properties.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/object-inspector/utils/load-properties.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/object-inspector/utils/load-properties.js 2020-11-17 19:31:25.000000000 +0000 @@ -9,6 +9,7 @@ getPrototype, enumSymbols, getFullText, + getPromiseState, getProxySlots, } = require("devtools/client/shared/components/object-inspector/utils/client"); @@ -24,6 +25,7 @@ nodeIsEntries, nodeIsMapEntry, nodeIsPrimitive, + nodeIsPromise, nodeIsProxy, nodeNeedsNumericalBuckets, nodeIsLongString, @@ -77,6 +79,10 @@ promises.push(getFullText(longStringFront, item)); } + if (shouldLoadItemPromiseState(item, loadedProperties)) { + promises.push(getPromiseState(getObjectFront())); + } + if (shouldLoadItemProxySlots(item, loadedProperties)) { promises.push(getProxySlots(getObjectFront())); } @@ -104,6 +110,10 @@ data.fullText = response.fullText; } + if (response.promiseState) { + data.promiseState = response.promiseState; + } + if (response.proxyTarget && response.proxyHandler) { data.proxyTarget = response.proxyTarget; data.proxyHandler = response.proxyHandler; @@ -198,6 +208,10 @@ return !loadedProperties.has(item.path) && nodeIsLongString(item); } +function shouldLoadItemPromiseState(item, loadedProperties = new Map()) { + return !loadedProperties.has(item.path) && nodeIsPromise(item); +} + function shouldLoadItemProxySlots(item, loadedProperties = new Map()) { return !loadedProperties.has(item.path) && nodeIsProxy(item); } @@ -211,5 +225,6 @@ shouldLoadItemPrototype, shouldLoadItemSymbols, shouldLoadItemFullText, + shouldLoadItemPromiseState, shouldLoadItemProxySlots, }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/object-inspector/utils/node.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/object-inspector/utils/node.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/object-inspector/utils/node.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/object-inspector/utils/node.js 2020-11-17 19:31:25.000000000 +0000 @@ -281,11 +281,8 @@ ); } -function makeNodesForPromiseProperties(item) { - const { - promiseState: { reason, value, state }, - } = getValue(item); - +function makeNodesForPromiseProperties(loadedProps, item) { + const { reason, value, state } = loadedProps.promiseState; const properties = []; if (state) { @@ -577,10 +574,6 @@ }, this); } - if (nodeIsPromise(parent)) { - nodes.push(...makeNodesForPromiseProperties(parent)); - } - if (nodeHasEntries(parent)) { nodes.push(makeNodesForEntries(parent)); } @@ -805,6 +798,10 @@ return addToCache(makeNodesForMapEntry(item)); } + if (nodeIsPromise(item) && hasLoadedProps) { + return addToCache(makeNodesForPromiseProperties(loadedProps, item)); + } + if (nodeIsProxy(item) && hasLoadedProps) { return addToCache(makeNodesForProxyProperties(loadedProps, item)); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/test/node/components/object-inspector/utils/promises.test.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/test/node/components/object-inspector/utils/promises.test.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/test/node/components/object-inspector/utils/promises.test.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/test/node/components/object-inspector/utils/promises.test.js 2020-11-17 19:31:25.000000000 +0000 @@ -31,24 +31,24 @@ }); it("makeNodesForPromiseProperties", () => { - const promise = { + const item = { path: "root", contents: { value: { actor: "server2.conn2.child1/obj36", - promiseState: { - state: "rejected", - reason: { - type: "3", - }, - }, class: "Promise", type: "object", }, }, }; + const promiseState = { + state: "rejected", + reason: { + type: "3", + }, + }; - const properties = makeNodesForPromiseProperties(promise); + const properties = makeNodesForPromiseProperties({promiseState}, item); expect(properties).toMatchSnapshot(); }); }); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/test/node/components/object-inspector/utils/__snapshots__/promises.test.js.snap firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/test/node/components/object-inspector/utils/__snapshots__/promises.test.js.snap --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/components/test/node/components/object-inspector/utils/__snapshots__/promises.test.js.snap 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/components/test/node/components/object-inspector/utils/__snapshots__/promises.test.js.snap 2020-11-17 19:31:25.000000000 +0000 @@ -13,12 +13,6 @@ "value": Object { "actor": "server2.conn2.child1/obj36", "class": "Promise", - "promiseState": Object { - "reason": Object { - "type": "3", - }, - "state": "rejected", - }, "type": "object", }, }, @@ -42,12 +36,6 @@ "value": Object { "actor": "server2.conn2.child1/obj36", "class": "Promise", - "promiseState": Object { - "reason": Object { - "type": "3", - }, - "state": "rejected", - }, "type": "object", }, }, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/test/shared-head.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/test/shared-head.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/shared/test/shared-head.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/shared/test/shared-head.js 2020-11-17 19:31:25.000000000 +0000 @@ -482,7 +482,7 @@ null, isErrorPage ); - await BrowserTestUtils.loadURI(browser, uri); + BrowserTestUtils.loadURI(browser, uri); info(`Waiting for page to be loaded…`); await onBrowserLoaded; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_nested_promise.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_nested_promise.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_nested_promise.js 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/webconsole/test/browser/browser_webconsole_object_inspector_nested_promise.js 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,85 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Check evaluating and expanding promises in the console. +const TEST_URI = + "data:text/html;charset=utf8," + + "

Object Inspector on deeply nested promises

"; + +add_task(async function testExpandNestedPromise() { + const hud = await openNewTabAndConsole(TEST_URI); + + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() { + let nestedPromise = Promise.resolve({}); + for (let i = 0; i < 5; ++i) { + Object.setPrototypeOf(nestedPromise, null); + nestedPromise = Promise.resolve(nestedPromise); + } + content.wrappedJSObject.console.log("oi-test", nestedPromise); + }); + + const node = await waitFor(() => findMessage(hud, "oi-test")); + const oi = node.querySelector(".tree"); + const [promiseNode] = getObjectInspectorNodes(oi); + + expandObjectInspectorNode(promiseNode); + await waitFor(() => getObjectInspectorNodes(oi).length > 1); + checkChildren(promiseNode, [``, ``]); + + const valueNode = findObjectInspectorNode(oi, ""); + expandObjectInspectorNode(valueNode); + await waitFor(() => getObjectInspectorChildrenNodes(valueNode).length > 0); + checkChildren(valueNode, [``, ``]); +}); + +add_task(async function testExpandCyclicPromise() { + const hud = await openNewTabAndConsole(TEST_URI); + + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() { + let resolve; + const cyclicPromise = new Promise(r => { + resolve = r; + }); + Object.setPrototypeOf(cyclicPromise, null); + const otherPromise = Promise.reject(cyclicPromise); + otherPromise.catch(() => {}); + Object.setPrototypeOf(otherPromise, null); + resolve(otherPromise); + content.wrappedJSObject.console.log("oi-test", cyclicPromise); + }); + + const node = await waitFor(() => findMessage(hud, "oi-test")); + const oi = node.querySelector(".tree"); + const [promiseNode] = getObjectInspectorNodes(oi); + + expandObjectInspectorNode(promiseNode); + await waitFor(() => getObjectInspectorNodes(oi).length > 1); + checkChildren(promiseNode, [``, ``]); + + const valueNode = findObjectInspectorNode(oi, ""); + expandObjectInspectorNode(valueNode); + await waitFor(() => getObjectInspectorChildrenNodes(valueNode).length > 0); + checkChildren(valueNode, [``, ``]); + + const reasonNode = findObjectInspectorNode(oi, ""); + expandObjectInspectorNode(reasonNode); + await waitFor(() => getObjectInspectorChildrenNodes(reasonNode).length > 0); + checkChildren(reasonNode, [``, ``]); +}); + +function checkChildren(node, expectedChildren) { + const children = getObjectInspectorChildrenNodes(node); + is( + children.length, + expectedChildren.length, + "There is the expected number of children" + ); + children.forEach((child, index) => { + ok( + child.textContent.includes(expectedChildren[index]), + `Expected "${expectedChildren[index]}" child` + ); + }); +} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/webconsole/test/browser/browser_webconsole_warn_about_replaced_api.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/webconsole/test/browser/browser_webconsole_warn_about_replaced_api.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/webconsole/test/browser/browser_webconsole_warn_about_replaced_api.js 2020-11-15 14:37:53.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/webconsole/test/browser/browser_webconsole_warn_about_replaced_api.js 2020-11-17 19:31:25.000000000 +0000 @@ -21,7 +21,7 @@ const onBrowserLoaded = BrowserTestUtils.browserLoaded( gBrowser.selectedBrowser ); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TEST_URI_REPLACED); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, TEST_URI_REPLACED); await onBrowserLoaded; const toolbox = await openToolboxForTab(gBrowser.selectedTab, "webconsole"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/webconsole/test/browser/_webconsole.ini firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/webconsole/test/browser/_webconsole.ini --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/client/webconsole/test/browser/_webconsole.ini 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/client/webconsole/test/browser/_webconsole.ini 2020-11-17 19:31:25.000000000 +0000 @@ -307,6 +307,7 @@ [browser_webconsole_object_inspector_getters_shadowed.js] [browser_webconsole_object_inspector_key_sorting.js] [browser_webconsole_object_inspector_local_session_storage.js] +[browser_webconsole_object_inspector_nested_promise.js] [browser_webconsole_object_inspector_nested_proxy.js] [browser_webconsole_object_inspector_selected_text.js] [browser_webconsole_object_inspector_scroll.js] diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/actors/network-monitor/utils/error-codes.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/actors/network-monitor/utils/error-codes.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/actors/network-monitor/utils/error-codes.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/actors/network-monitor/utils/error-codes.js 2020-11-17 19:31:25.000000000 +0000 @@ -471,7 +471,6 @@ NS_ERROR_STORAGE_CONSTRAINT: 0x80630003, NS_ERROR_DOM_FILE_NOT_FOUND_ERR: 0x80650000, NS_ERROR_DOM_FILE_NOT_READABLE_ERR: 0x80650001, - NS_ERROR_DOM_FILE_ABORT_ERR: 0x80650002, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR: 0x80660001, NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR: 0x80660003, NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR: 0x80660004, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/actors/object.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/actors/object.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/actors/object.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/actors/object.js 2020-11-17 19:31:25.000000000 +0000 @@ -165,8 +165,9 @@ this.hooks.incrementGripDepth(); - if (g.class == "Promise") { - g.promiseState = this._createPromiseState(); + // TODO (bug 1676476): remove this and instead add a previewer for promises. + if (g.class == "Promise" && this.hooks.getGripDepth() < 3) { + g.promiseState = this.promiseState().promiseState; } if (g.class == "Function") { @@ -250,7 +251,7 @@ /** * Returns an object exposing the internal Promise state. */ - _createPromiseState: function() { + promiseState: function() { const { state, value, reason } = getPromiseState(this.obj); const promiseState = { state }; @@ -267,7 +268,7 @@ promiseState.timeToSettle = this.obj.promiseTimeToResolution; } - return promiseState; + return { promiseState }; }, /** diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/tests/browser/browser_navigateEvents.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/tests/browser/browser_navigateEvents.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/tests/browser/browser_navigateEvents.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/tests/browser/browser_navigateEvents.js 2020-11-17 19:31:25.000000000 +0000 @@ -177,7 +177,7 @@ const onBrowserLoaded = BrowserTestUtils.browserLoaded( gBrowser.selectedBrowser ); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, URL2); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, URL2); await onBrowserLoaded; // Wait for all events to be received diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/tests/xpcshell/test_objectgrips-nested-promise.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/tests/xpcshell/test_objectgrips-nested-promise.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/tests/xpcshell/test_objectgrips-nested-promise.js 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/tests/xpcshell/test_objectgrips-nested-promise.js 2020-11-17 19:31:26.000000000 +0000 @@ -0,0 +1,57 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +/* eslint-disable no-shadow, max-nested-callbacks */ + +"use strict"; + +Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true); +registerCleanupFunction(() => { + Services.prefs.clearUserPref("security.allow_eval_with_system_principal"); +}); + +add_task( + threadFrontTest(async ({ threadFront, debuggee }) => { + const packet = await executeOnNextTickAndWaitForPause( + () => evalCode(debuggee), + threadFront + ); + + const [grip1, grip2] = packet.frame.arguments; + strictEqual(grip1.class, "Promise", "promise1 has a promise grip."); + strictEqual(grip2.class, "Promise", "promise2 has a promise grip."); + + const objClient1 = threadFront.pauseGrip(grip1); + const objClient2 = threadFront.pauseGrip(grip2); + const { promiseState: state1 } = await objClient1.getPromiseState(); + const { promiseState: state2 } = await objClient2.getPromiseState(); + + strictEqual(state1.state, "fulfilled", "promise1 was fulfilled."); + strictEqual(state1.value, objClient2, "promise1 fulfilled with promise2."); + ok(!state1.hasOwnProperty("reason"), "promise1 has no rejection reason."); + + strictEqual(state2.state, "rejected", "promise2 was rejected."); + strictEqual(state2.reason, objClient1, "promise2 rejected with promise1."); + ok(!state2.hasOwnProperty("value"), "promise2 has no resolution value."); + + await threadFront.resume(); + }) +); + +function evalCode(debuggee) { + debuggee.eval( + function stopMe(arg) { + debugger; + }.toString() + ); + + debuggee.eval(` + var resolve; + var promise1 = new Promise(r => {resolve = r}); + Object.setPrototypeOf(promise1, null); + var promise2 = Promise.reject(promise1); + promise2.catch(() => {}); + Object.setPrototypeOf(promise2, null); + resolve(promise2); + stopMe(promise1, promise2); + `); +} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/tests/xpcshell/xpcshell.ini firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/tests/xpcshell/xpcshell.ini --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/server/tests/xpcshell/xpcshell.ini 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/server/tests/xpcshell/xpcshell.ini 2020-11-17 19:31:25.000000000 +0000 @@ -160,6 +160,7 @@ [test_objectgrips-fn-apply-01.js] [test_objectgrips-fn-apply-02.js] [test_objectgrips-fn-apply-03.js] +[test_objectgrips-nested-promise.js] [test_objectgrips-nested-proxy.js] [test_promise_state-01.js] [test_promise_state-02.js] diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/shared/resources/tests/browser_target_list_service_workers_navigation.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/shared/resources/tests/browser_target_list_service_workers_navigation.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/shared/resources/tests/browser_target_list_service_workers_navigation.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/shared/resources/tests/browser_target_list_service_workers_navigation.js 2020-11-17 19:31:25.000000000 +0000 @@ -65,7 +65,7 @@ }); info("Go to .org page, wait for onAvailable to be called"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, ORG_PAGE_URL); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, ORG_PAGE_URL); await checkHooks(hooks, { available: 2, destroyed: 0, @@ -91,7 +91,7 @@ }); info("Go back to page 1"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, COM_PAGE_URL); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, COM_PAGE_URL); await checkHooks(hooks, { available: 2, destroyed: 1, @@ -150,7 +150,7 @@ }); info("Go to .org page, wait for onAvailable to be called"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, ORG_PAGE_URL); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, ORG_PAGE_URL); await checkHooks(hooks, { available: 2, destroyed: 1, @@ -170,7 +170,7 @@ await checkHooks(hooks, { available: 3, destroyed: 3, targets: [] }); info("Go back to page 1, wait for onDestroyed and onAvailable to be called"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, COM_PAGE_URL); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, COM_PAGE_URL); await checkHooks(hooks, { available: 4, destroyed: 3, @@ -241,7 +241,7 @@ await waitForRegistrationReady(tab, COM_PAGE_URL); info("Navigate to another page"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, ORG_PAGE_URL); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, ORG_PAGE_URL); // Avoid TV failures, where target list still starts thinking that the // current domain is .com . @@ -267,7 +267,7 @@ await checkHooks(hooks, { available: 1, destroyed: 1, targets: [] }); info("Go back .com page, wait for onAvailable to be called"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, COM_PAGE_URL); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, COM_PAGE_URL); await checkHooks(hooks, { available: 2, destroyed: 1, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/shared/resources/tests/browser_target_list_tab_workers.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/shared/resources/tests/browser_target_list_tab_workers.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/shared/resources/tests/browser_target_list_tab_workers.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/shared/resources/tests/browser_target_list_tab_workers.js 2020-11-17 19:31:25.000000000 +0000 @@ -284,7 +284,7 @@ ); info("Check that navigating away does destroy all targets"); - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( tab.linkedBrowser, "data:text/html,Away" ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/shared/specs/object.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/shared/specs/object.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/shared/specs/object.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/shared/specs/object.js 2020-11-17 19:31:25.000000000 +0000 @@ -92,6 +92,14 @@ functionDisplayName: "string", }); +types.addDictType("object.promiseState", { + state: "string", + value: "nullable:object.descriptor", + reason: "nullable:object.descriptor", + creationTimestamp: "number", + timeToSettle: "nullable:number", +}); + types.addDictType("object.proxySlots", { proxyTarget: "object.descriptor", proxyHandler: "object.descriptor", @@ -188,6 +196,10 @@ rejectionStack: RetVal("array:object.originalSourceLocation"), }, }, + promiseState: { + request: {}, + response: RetVal("object.promiseState"), + }, proxySlots: { request: {}, response: RetVal("object.proxySlots"), diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/devtools/shared/test-helpers/.eslintrc.js firefox-trunk-85.0~a1~hg20201117r557492/devtools/shared/test-helpers/.eslintrc.js --- firefox-trunk-84.0~a1~hg20201115r557261/devtools/shared/test-helpers/.eslintrc.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/devtools/shared/test-helpers/.eslintrc.js 2020-11-17 19:31:25.000000000 +0000 @@ -1,3 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + "use strict"; module.exports = { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docs/setup/configuring_build_options.rst firefox-trunk-85.0~a1~hg20201117r557492/docs/setup/configuring_build_options.rst --- firefox-trunk-84.0~a1~hg20201115r557261/docs/setup/configuring_build_options.rst 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docs/setup/configuring_build_options.rst 2020-11-17 19:31:25.000000000 +0000 @@ -244,11 +244,17 @@ ``ac_add_options --disable-optimize`` Disables compiler optimization. This makes it much easier to step through code in a debugger. +``ac_add_options --enable-release`` + Enables more conservative, release engineering-oriented options. This may + slow down builds. This also turns on full optimizations for Rust. Note this + is the default when building release/beta/esr. ``ac_add_options --enable-debug-js-modules`` Enable only JavaScript assertions. This is useful when working locally on JavaScript-powered components like the DevTools. This will help catch any errors introduced into the JS code, with less of a performance impact compared to the ``--enable-debug`` option. +``export RUSTC_OPT_LEVEL=2`` + Enable full optimizations for Rust code. You can make an optimized build with debugging symbols. See :ref:`Building with Debug Symbols `. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/base/nsIURIFixup.idl firefox-trunk-85.0~a1~hg20201117r557492/docshell/base/nsIURIFixup.idl --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/base/nsIURIFixup.idl 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/base/nsIURIFixup.idl 2020-11-17 19:31:25.000000000 +0000 @@ -123,7 +123,7 @@ /** * Convert load flags from nsIWebNavigation to URI fixup flags for use in - * createFixupURI or getFixupURIInfo. + * getFixupURIInfo. * * @param aURIText Candidate URI; used for determining whether to * allow keyword lookups. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/base/URIFixup.jsm firefox-trunk-85.0~a1~hg20201117r557492/docshell/base/URIFixup.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/base/URIFixup.jsm 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/base/URIFixup.jsm 2020-11-17 19:31:25.000000000 +0000 @@ -133,7 +133,7 @@ XPCOMUtils.defineLazyGetter( this, "possibleProtocolRegex", - () => /^([a-z][a-z0-9.+\t-]*):/i + () => /^([a-z][a-z0-9.+\t-]*)(:|;)?(\/\/)?/i ); // Regex used to match IPs. Note that these are not made to validate IPs, but @@ -272,7 +272,14 @@ let info = new URIFixupInfo(uriString); - let scheme = extractScheme(uriString); + const { + scheme, + fixedSchemeUriString, + fixupChangedProtocol, + } = extractScheme(uriString, fixupFlags); + uriString = fixedSchemeUriString; + info.fixupChangedProtocol = fixupChangedProtocol; + if (scheme == "view-source") { let { preferredURI, postData } = fixupViewSource(uriString, fixupFlags); info.preferredURI = info.fixedURI = preferredURI; @@ -291,34 +298,7 @@ } } - // Fix up common scheme typos. - // TODO: Use levenshtein distance here? - let isCommonProtocol = COMMON_PROTOCOLS.includes(scheme); - if ( - fixupSchemeTypos && - fixupFlags & FIXUP_FLAG_FIX_SCHEME_TYPOS && - scheme && - !isCommonProtocol - ) { - info.fixupChangedProtocol = [ - ["ttp", "http"], - ["htp", "http"], - ["ttps", "https"], - ["tps", "https"], - ["ps", "https"], - ["htps", "https"], - ["ile", "file"], - ["le", "file"], - ].some(([typo, fixed]) => { - if (uriString.startsWith(typo + ":")) { - scheme = fixed; - uriString = scheme + uriString.substring(typo.length); - isCommonProtocol = true; - return true; - } - return false; - }); - } + const isCommonProtocol = COMMON_PROTOCOLS.includes(scheme); let canHandleProtocol = scheme && @@ -936,12 +916,73 @@ /** * Mimics the logic in Services.io.extractScheme, but avoids crossing XPConnect. + * This also tries to fixup the scheme if it was clearly mistyped. * @param {string} uriString the string to examine - * @returns {string} a scheme or empty string if one could not be identified + * @param {integer} fixupFlags The original fixup flags + * @returns {object} + * scheme: a typo fixed scheme or empty string if one could not be identified + * fixedSchemeUriString: uri string with a typo fixed scheme + * fixupChangedProtocol: true if the scheme is fixed up */ -function extractScheme(uriString) { - let matches = uriString.match(possibleProtocolRegex); - return matches ? matches[1].replace("\t", "").toLowerCase() : ""; +function extractScheme(uriString, fixupFlags = FIXUP_FLAG_NONE) { + const matches = uriString.match(possibleProtocolRegex); + const hasColon = matches?.[2] === ":"; + const hasSlash2 = matches?.[3] === "//"; + + const isFixupSchemeTypos = + fixupSchemeTypos && fixupFlags & FIXUP_FLAG_FIX_SCHEME_TYPOS; + + if ( + !matches || + (!hasColon && !hasSlash2) || + (!hasColon && !isFixupSchemeTypos) + ) { + return { + scheme: "", + fixedSchemeUriString: uriString, + fixupChangedProtocol: false, + }; + } + + let scheme = matches[1].replace("\t", "").toLowerCase(); + let fixedSchemeUriString = uriString; + + if (isFixupSchemeTypos && hasSlash2) { + // Fix up typos for string that user would have intented as protocol. + const afterProtocol = uriString.substring(matches[0].length); + fixedSchemeUriString = `${scheme}://${afterProtocol}`; + } + + let fixupChangedProtocol = false; + + if (isFixupSchemeTypos) { + // Fix up common scheme typos. + // TODO: Use levenshtein distance here? + fixupChangedProtocol = [ + ["ttp", "http"], + ["htp", "http"], + ["ttps", "https"], + ["tps", "https"], + ["ps", "https"], + ["htps", "https"], + ["ile", "file"], + ["le", "file"], + ].some(([typo, fixed]) => { + if (scheme === typo) { + scheme = fixed; + fixedSchemeUriString = + scheme + fixedSchemeUriString.substring(typo.length); + return true; + } + return false; + }); + } + + return { + scheme, + fixedSchemeUriString, + fixupChangedProtocol, + }; } /** @@ -965,7 +1006,7 @@ let innerURIString = uriString.substring(12).trim(); // Prevent recursion. - let innerScheme = extractScheme(innerURIString); + const { scheme: innerScheme } = extractScheme(innerURIString); if (innerScheme == "view-source") { throw new Components.Exception( "Prevent view-source recursion", diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/shistory/SessionHistoryEntry.cpp firefox-trunk-85.0~a1~hg20201117r557492/docshell/shistory/SessionHistoryEntry.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/shistory/SessionHistoryEntry.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/shistory/SessionHistoryEntry.cpp 2020-11-17 19:31:25.000000000 +0000 @@ -24,7 +24,6 @@ : mURI(aLoadState->URI()), mOriginalURI(aLoadState->OriginalURI()), mResultPrincipalURI(aLoadState->ResultPrincipalURI()), - mReferrerInfo(aLoadState->GetReferrerInfo()), mPostData(aLoadState->PostDataStream()), mLoadType(aLoadState->LoadType()), mSrcdocData(aLoadState->SrcdocData()), @@ -37,6 +36,10 @@ aLoadState->PartitionedPrincipalToInherit(), aLoadState->Csp(), /* FIXME Is this correct? */ aLoadState->TypeHint())) { + if (nsCOMPtr httpChannel = do_QueryInterface(aChannel)) { + mReferrerInfo = httpChannel->GetReferrerInfo(); + } + MaybeUpdateTitleFromURI(); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/browser/browser_bug349769.js firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/browser/browser_bug349769.js --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/browser/browser_bug349769.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/browser/browser_bug349769.js 2020-11-17 19:31:26.000000000 +0000 @@ -26,7 +26,7 @@ for (var uri of uris) { await BrowserTestUtils.withNewTab({ gBrowser }, async function(newBrowser) { let loadedPromise = BrowserTestUtils.browserLoaded(newBrowser); - await BrowserTestUtils.loadURI(newBrowser, uri); + BrowserTestUtils.loadURI(newBrowser, uri); var prin = newBrowser.contentPrincipal; isnot( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/browser_bug343515.js firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/browser_bug343515.js --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/browser_bug343515.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/browser_bug343515.js 2020-11-17 19:31:25.000000000 +0000 @@ -69,10 +69,7 @@ }); // Navigate tab 2 to a different page - await BrowserTestUtils.loadURI( - ctx.tab2Browser, - testPath + "bug343515_pg3.html" - ); + BrowserTestUtils.loadURI(ctx.tab2Browser, testPath + "bug343515_pg3.html"); await BrowserTestUtils.browserLoaded(ctx.tab2Browser); @@ -169,10 +166,7 @@ await BrowserTestUtils.switchTab(gBrowser, ctx.tab1); // Navigate to page 3 - await BrowserTestUtils.loadURI( - ctx.tab1Browser, - testPath + "bug343515_pg3.html" - ); + BrowserTestUtils.loadURI(ctx.tab1Browser, testPath + "bug343515_pg3.html"); await BrowserTestUtils.browserLoaded(ctx.tab1Browser); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/browser_test_bfcache_eviction.js firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/browser_test_bfcache_eviction.js --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/browser_test_bfcache_eviction.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/browser_test_bfcache_eviction.js 2020-11-17 19:31:25.000000000 +0000 @@ -84,7 +84,7 @@ for (var i = 0; i < 4; i++) { testPage = `data:text/html,${i}`; let pagePromise = BrowserTestUtils.browserLoaded(browser); - await BrowserTestUtils.loadURI(browser, testPage); + BrowserTestUtils.loadURI(browser, testPage); await pagePromise; } // 7. Wait for 'content viewer evicted' event to go off diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug1300461.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug1300461.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug1300461.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug1300461.html 2020-11-17 19:31:25.000000000 +0000 @@ -46,8 +46,7 @@ opener.is(shistory.index, 0, "check history index"); opener.ok(webNav.canGoForward, "check canGoForward"); opener.info("file_bug1300461.html tests finished"); - opener.nextTest(); - window.close(); + opener.finishTest(); }, ]; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug1326251.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug1326251.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug1326251.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug1326251.html 2020-11-17 19:31:25.000000000 +0000 @@ -141,8 +141,7 @@ innerStaticFrame = staticFrame.contentDocument.getElementById("staticFrame"); opener.is(innerStaticFrame.contentDocument.location.href, BASE_URL + "frame1.html", "innerStaticFrame location"); opener.ok(!staticFrame.contentDocument.getElementById("dynamicFrame"), "innerDynamicFrame should not exist"); - opener.nextTest(); - window.close(); + opener.finishTest(); }, ]; @@ -177,13 +176,6 @@ function test() { if (opener) { - // Disable the subtest for now since it relies on the bfcache. - if (opener.SpecialPowers.Services.appinfo.sessionHistoryInParent) { - opener.nextTest(); - window.close(); - return; - } - // Ensure the tests are not executed in onload hander. setTimeout(testSteps[opener.testCount++], 0); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug1379762-1.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug1379762-1.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug1379762-1.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug1379762-1.html 2020-11-17 19:31:25.000000000 +0000 @@ -20,8 +20,7 @@ // Do this async so our load event gets a chance to fire if it plans to // do it. setTimeout(function() { - opener.nextTest(); - window.close(); + opener.finishTest(); }); } }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug1609475.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug1609475.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug1609475.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug1609475.html 2020-11-17 19:31:26.000000000 +0000 @@ -14,8 +14,7 @@ var doc2URI = document.getElementById("i2").contentDocument.documentURI; opener.ok(doc2URI.includes("frame1.html"), "Should have loaded the initial page to the second iframe. Got " + doc2URI); - opener.nextTest(); - window.close(); + opener.finishTest(); }, 1000); } else if (loadCount > 2) { opener.ok(false, "Too many load events"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug508537_1.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug508537_1.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug508537_1.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug508537_1.html 2020-11-17 19:31:25.000000000 +0000 @@ -10,8 +10,7 @@ if (opener && ++opener.testCount == 1) { window.location = "goback.html"; } else { - opener.nextTest(); - window.close(); + opener.finishTest(); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug534178.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug534178.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_bug534178.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_bug534178.html 2020-11-17 19:31:25.000000000 +0000 @@ -13,8 +13,7 @@ } document.body.textContent = isOK ? "PASSED" : "FAILED"; opener.ok(isOK, "Duplicate session history entries should have been removed!"); - opener.nextTest(); - window.close(); + opener.finishTest(); } function ifrload() { setTimeout(testDone, 0); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_document_write_1.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_document_write_1.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_document_write_1.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_document_write_1.html 2020-11-17 19:31:25.000000000 +0000 @@ -8,8 +8,7 @@ document.close(); opener.is(history.length, length, "document.open/close should not change history"); - opener.nextTest(); - window.close(); + opener.finishTest(); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_fragment_handling_during_load.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_fragment_handling_during_load.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_fragment_handling_during_load.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_fragment_handling_during_load.html 2020-11-17 19:31:25.000000000 +0000 @@ -9,8 +9,7 @@ return; } opener.ok(true, "Have loaded a new document."); - opener.nextTest(); - window.close(); + opener.finishTest(); } function test() { // Test that executing back() before load has started doesn't interrupt diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_nested_frames.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_nested_frames.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_nested_frames.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_nested_frames.html 2020-11-17 19:31:25.000000000 +0000 @@ -15,8 +15,7 @@ d.write("test"); d.close(); opener.is(window.history.length, 1, "Unexpected history length"); - opener.nextTest(); - window.close(); + opener.finishTest(); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_scrollRestoration.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_scrollRestoration.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_scrollRestoration.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_scrollRestoration.html 2020-11-17 19:31:25.000000000 +0000 @@ -4,13 +4,6 @@ var oldHistoryObject = null; function test(event) { - // Disable the subtest for now since it relies on the bfcache. - if (opener.SpecialPowers.Services.appinfo.sessionHistoryInParent) { - opener.nextTest(); - window.close(); - return; - } - if (!opener.scrollRestorationTest) { opener.scrollRestorationTest = 0; } @@ -139,8 +132,7 @@ } catch (ex) { opener.isnot(ex, null, "Did get an exception"); } - opener.nextTest(); - window.close(); + opener.finishTest(); break; } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_shiftReload_and_pushState.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_shiftReload_and_pushState.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_shiftReload_and_pushState.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_shiftReload_and_pushState.html 2020-11-17 19:31:25.000000000 +0000 @@ -13,8 +13,7 @@ window.location.reload(true); } else { opener.ok(true, "Did run history.push"); - opener.nextTest(); - window.close(); + opener.finishTest(); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_static_and_dynamic_1.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_static_and_dynamic_1.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/file_static_and_dynamic_1.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/file_static_and_dynamic_1.html 2020-11-17 19:31:25.000000000 +0000 @@ -17,8 +17,7 @@ var staticFrame = document.getElementById("staticframe"); opener.ok(String(staticFrame.contentWindow.location).includes(staticFrame.src), "Wrong document loaded!"); - opener.nextTest(); - window.close(); + opener.finishTest(); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/mochitest.ini firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/mochitest.ini --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/mochitest.ini 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/mochitest.ini 2020-11-17 19:31:25.000000000 +0000 @@ -60,6 +60,7 @@ file_bug1375833-frame2.html test_bug145971.html file_bug1609475.html + file_bug1379762-1.html [test_aboutblank_change_process.html] [test_bug13871.html] @@ -90,8 +91,24 @@ [test_performance_navigation.html] skip-if = fission # bug 1666602 [test_sessionhistory.html] -skip-if = toolkit == 'android' || fission # RANDOM on android -support-files = file_bug1379762-1.html +skip-if = verify && (os == 'mac') && debug && webrender # Hit MOZ_CRASH(Shutdown too long, probably frozen, causing a crash.) bug 1677545 +[test_dynamic_frame_forward_back.html] +[test_sessionhistory_document_write.html] +[test_session_history_entry_cleanup.html] +[test_fragment_handling_during_load.html] +[test_nested_frames.html] +[test_shiftReload_and_pushState.html] +[test_scrollRestoration.html] +skip-if = fission # It relies on the bfcache +[test_bug1609475.html] +[test_bug1300461.html] +skip-if = fission +[test_bug1326251.html] +skip-if = toolkit == 'android' || fission # It relies on the bfcache +[test_bug1379762.html] +skip-if = fission # It relies on the bfcache +[test_static_and_dynamic.html] +skip-if = true # This was disabled for a few years now anyway, bug 1677544 [test_sibling-matching-parent.html] [test_sibling-off-domain.html] [test_triggeringprincipal_frame_nav.html] diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_bug1300461.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_bug1300461.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_bug1300461.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_bug1300461.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,75 @@ + + + + + Test for Bug 1300461 + + + + +Mozilla Bug 1300461 +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_bug1326251.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_bug1326251.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_bug1326251.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_bug1326251.html 2020-11-17 19:31:26.000000000 +0000 @@ -0,0 +1,74 @@ + + + + + Test for Bug 1326251 + + + + +Mozilla Bug 1326251 +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_bug1379762.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_bug1379762.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_bug1379762.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_bug1379762.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,36 @@ + + + + + Test for Bug 1379762 + + + + +Mozilla Bug 1379762 +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_bug1609475.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_bug1609475.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_bug1609475.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_bug1609475.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,35 @@ + + + + + Test for Bug 1609475 + + + + +Mozilla Bug 1609475 +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_dynamic_frame_forward_back.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_dynamic_frame_forward_back.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_dynamic_frame_forward_back.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_dynamic_frame_forward_back.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,35 @@ + + + + + Test for Bug 508537 + + + + +Mozilla Bug 508537 +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_fragment_handling_during_load.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_fragment_handling_during_load.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_fragment_handling_during_load.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_fragment_handling_during_load.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,35 @@ + + + + + Test for fragment navigation during load + + + + +Mozilla Bug 978408 +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_nested_frames.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_nested_frames.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_nested_frames.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_nested_frames.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,35 @@ + + + + + Test for Bug 1090918 + + + + +Mozilla Bug 1090918 +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_scrollRestoration.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_scrollRestoration.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_scrollRestoration.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_scrollRestoration.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,44 @@ + + + + + Test for Bug 1155730 + + + + +Mozilla Bug 1155730 +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_sessionhistory_document_write.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_sessionhistory_document_write.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_sessionhistory_document_write.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_sessionhistory_document_write.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,34 @@ + + + + + Test for Session history + document.write + + + + +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_session_history_entry_cleanup.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_session_history_entry_cleanup.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_session_history_entry_cleanup.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_session_history_entry_cleanup.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,35 @@ + + + + + Test for Bug 534178 + + + + +Mozilla Bug 534178 +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_sessionhistory.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_sessionhistory.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_sessionhistory.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_sessionhistory.html 2020-11-17 19:31:25.000000000 +0000 @@ -4,92 +4,26 @@ https://bugzilla.mozilla.org/show_bug.cgi?id= --> - Test for Bug + Test for Bug 462076 -Mozilla Bug +Mozilla Bug 462076

   
+  
+
+
+Mozilla Bug 1003100
+

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_static_and_dynamic.html firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_static_and_dynamic.html --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/navigation/test_static_and_dynamic.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/navigation/test_static_and_dynamic.html 2020-11-17 19:31:25.000000000 +0000 @@ -0,0 +1,36 @@ + + + + + Test for static and dynamic frames and forward-back + + + + +Mozilla Bug +

+ +
+  
+
+ + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/unit/test_URIFixup_info.js firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/unit/test_URIFixup_info.js --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/unit/test_URIFixup_info.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/unit/test_URIFixup_info.js 2020-11-17 19:31:25.000000000 +0000 @@ -635,6 +635,30 @@ fixedURI: "http://pserver:8080/", protocolChange: true, }, + { + input: "http;mozilla", + fixedURI: "http://http;mozilla/", + alternateURI: "http://www.http;mozilla.com/", + keywordLookup: true, + protocolChange: true, + affectedByDNSForSingleWordHosts: true, + }, + { + input: "http//mozilla.org", + fixedURI: "http://mozilla.org/", + shouldRunTest: flags => + flags & Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS, + }, + { + input: "http//mozilla.org", + fixedURI: "http://http//mozilla.org", + alternateURI: "http://www.http.com//mozilla.org", + keywordLookup: true, + protocolChange: true, + affectedByDNSForSingleWordHosts: true, + shouldRunTest: flags => + !(flags & Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS), + }, ]; if (AppConstants.platform == "win") { @@ -752,6 +776,7 @@ protocolChange: expectProtocolChange, inWhitelist: inWhitelist, affectedByDNSForSingleWordHosts: affectedByDNSForSingleWordHosts, + shouldRunTest, } of relevantTests) { // Explicitly force these into a boolean expectKeywordLookup = !!expectKeywordLookup; @@ -774,6 +799,10 @@ ")" ); + if (shouldRunTest && !shouldRunTest(flags)) { + continue; + } + let URIInfo; try { URIInfo = Services.uriFixup.getFixupURIInfo(testInput, flags); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/unit/test_URIFixup.js firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/unit/test_URIFixup.js --- firefox-trunk-84.0~a1~hg20201115r557261/docshell/test/unit/test_URIFixup.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/docshell/test/unit/test_URIFixup.js 2020-11-17 19:31:25.000000000 +0000 @@ -42,6 +42,24 @@ fixed: "file:///this/is/a/test.html", }, { + // Replace ';' with ':'. + wrong: "http;//www.example.com/", + fixed: "http://www.example.com/", + noPrefValue: "http://http;//www.example.com/", + }, + { + // Missing ':'. + wrong: "https//www.example.com/", + fixed: "https://www.example.com/", + noPrefValue: "http://https//www.example.com/", + }, + { + // Missing ':' for file scheme. + wrong: "file///this/is/a/test.html", + fixed: "file:///this/is/a/test.html", + noPrefValue: "http://file///this/is/a/test.html", + }, + { // Valid should not be changed. wrong: "https://example.com/this/is/a/test.html", fixed: "https://example.com/this/is/a/test.html", @@ -86,7 +104,7 @@ item.wrong, Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS ); - Assert.equal(preferredURI.spec, item.wrong); + Assert.equal(preferredURI.spec, item.noPrefValue || item.wrong); } }); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/Navigator.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/base/Navigator.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/Navigator.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/Navigator.cpp 2020-11-17 19:31:25.000000000 +0000 @@ -1275,40 +1275,45 @@ CallerType aCallerType, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); - if (!mWindow || !mWindow->GetOuterWindow() || - mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) { - aRv.Throw(NS_ERROR_NOT_AVAILABLE); + if (!mWindow || !mWindow->IsFullyActive()) { + aRv.ThrowInvalidStateError("The document is not fully active."); return; } - + RefPtr sp; + if (!MediaManager::IsOn(aConstraints.mVideo) && + !MediaManager::IsOn(aConstraints.mAudio)) { + sp = MediaManager::StreamPromise::CreateAndReject( + MakeRefPtr(MediaMgrError::Name::TypeError, + "audio and/or video is required"), + __func__); + } else { + sp = MediaManager::Get()->GetUserMedia(mWindow, aConstraints, aCallerType); + } RefPtr onsuccess(&aOnSuccess); RefPtr onerror(&aOnError); nsWeakPtr weakWindow = nsWeakPtr(do_GetWeakReference(mWindow)); - - MediaManager::Get() - ->GetUserMedia(mWindow, aConstraints, aCallerType) - ->Then( - GetMainThreadSerialEventTarget(), __func__, - [weakWindow, onsuccess = std::move(onsuccess)]( - const RefPtr& aStream) MOZ_CAN_RUN_SCRIPT { - nsCOMPtr window = do_QueryReferent(weakWindow); - if (!window || !window->GetOuterWindow() || - window->GetOuterWindow()->GetCurrentInnerWindow() != window) { - return; // Leave Promise pending after navigation by design. - } - MediaManager::CallOnSuccess(*onsuccess, *aStream); - }, - [weakWindow, onerror = std::move(onerror)]( - const RefPtr& aError) MOZ_CAN_RUN_SCRIPT { - nsCOMPtr window = do_QueryReferent(weakWindow); - if (!window || !window->GetOuterWindow() || - window->GetOuterWindow()->GetCurrentInnerWindow() != window) { - return; // Leave Promise pending after navigation by design. - } - auto error = MakeRefPtr(window, *aError); - MediaManager::CallOnError(*onerror, *error); - }); + sp->Then( + GetMainThreadSerialEventTarget(), __func__, + [weakWindow, onsuccess = std::move(onsuccess)]( + const RefPtr& aStream) MOZ_CAN_RUN_SCRIPT { + nsCOMPtr window = do_QueryReferent(weakWindow); + if (!window || !window->GetOuterWindow() || + window->GetOuterWindow()->GetCurrentInnerWindow() != window) { + return; // Leave Promise pending after navigation by design. + } + MediaManager::CallOnSuccess(*onsuccess, *aStream); + }, + [weakWindow, onerror = std::move(onerror)]( + const RefPtr& aError) MOZ_CAN_RUN_SCRIPT { + nsCOMPtr window = do_QueryReferent(weakWindow); + if (!window || !window->GetOuterWindow() || + window->GetOuterWindow()->GetCurrentInnerWindow() != window) { + return; // Leave Promise pending after navigation by design. + } + auto error = MakeRefPtr(window, *aError); + MediaManager::CallOnError(*onerror, *error); + }); } void Navigator::MozGetUserMediaDevices( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsContentPermissionHelper.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsContentPermissionHelper.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsContentPermissionHelper.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsContentPermissionHelper.cpp 2020-11-17 19:31:26.000000000 +0000 @@ -653,9 +653,7 @@ return NS_OK; } -void nsContentPermissionRequestProxy::OnParentDestroyed() { - mParent = nullptr; -} +void nsContentPermissionRequestProxy::OnParentDestroyed() { mParent = nullptr; } NS_IMPL_ISUPPORTS(nsContentPermissionRequestProxy, nsIContentPermissionRequest) @@ -796,8 +794,10 @@ RemotePermissionRequest::RemotePermissionRequest( nsIContentPermissionRequest* aRequest, nsPIDOMWindowInner* aWindow) - : mRequest(aRequest), mWindow(aWindow), mIPCOpen(false), mDestroyed(false) { -} + : mRequest(aRequest), + mWindow(aWindow), + mIPCOpen(false), + mDestroyed(false) {} RemotePermissionRequest::~RemotePermissionRequest() { MOZ_ASSERT( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsDOMNavigationTiming.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsDOMNavigationTiming.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsDOMNavigationTiming.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsDOMNavigationTiming.cpp 2020-11-17 19:31:26.000000000 +0000 @@ -562,7 +562,7 @@ if (const ContentChild* cc = ContentChild::GetSingleton(); cc && !(IsWebRemoteType(cc->GetRemoteType()) || - IsPriviligedMozillaRemoteType(cc->GetRemoteType()))) { + IsPrivilegedMozillaRemoteType(cc->GetRemoteType()))) { return; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsFocusManager.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsFocusManager.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsFocusManager.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsFocusManager.cpp 2020-11-17 19:31:26.000000000 +0000 @@ -167,6 +167,7 @@ StaticRefPtr nsFocusManager::sInstance; bool nsFocusManager::sMouseFocusesFormControl = false; bool nsFocusManager::sTestMode = false; +uint64_t nsFocusManager::sFocusActionCounter = 0; static const char* kObservedPrefs[] = { "accessibility.browsewithcaret", "accessibility.tabfocus_applies_to_xul", @@ -174,7 +175,8 @@ nullptr}; nsFocusManager::nsFocusManager() - : mActiveBrowsingContextInContentSetFromOtherProcess(false), + : mActionIdForActiveBrowsingContextInContent(0), + mActiveBrowsingContextInContentSetFromOtherProcess(false), mEventHandlingNeedsFlush(false) {} nsFocusManager::~nsFocusManager() { @@ -241,6 +243,7 @@ if (!nsCRT::strcmp(aTopic, "xpcom-shutdown")) { mActiveWindow = nullptr; mActiveBrowsingContextInContent = nullptr; + mActionIdForActiveBrowsingContextInContent = 0; mActiveBrowsingContextInChrome = nullptr; mFocusedWindow = nullptr; mFocusedBrowsingContextInContent = nullptr; @@ -395,7 +398,8 @@ void nsFocusManager::FocusWindow(nsPIDOMWindowOuter* aWindow, CallerType aCallerType) { if (sInstance) { - sInstance->SetFocusedWindowWithCallerType(aWindow, aCallerType); + sInstance->SetFocusedWindowWithCallerType( + aWindow, aCallerType, sInstance->GenerateFocusActionId()); } } @@ -406,7 +410,8 @@ } nsresult nsFocusManager::SetFocusedWindowWithCallerType( - mozIDOMWindowProxy* aWindowToFocus, CallerType aCallerType) { + mozIDOMWindowProxy* aWindowToFocus, CallerType aCallerType, + uint64_t aActionId) { LOGFOCUS(("<>")); nsCOMPtr windowToFocus = @@ -417,7 +422,7 @@ if (frameElement) { // pass false for aFocusChanged so that the caret does not get updated // and scrolling does not occur. - SetFocusInner(frameElement, 0, false, true); + SetFocusInner(frameElement, 0, false, true, aActionId); } else { // this is a top-level window. If the window has a child frame focused, // clear the focus. Otherwise, focus should already be in this frame, or @@ -432,7 +437,7 @@ nsCOMPtr rootWindow = windowToFocus->GetPrivateRoot(); if (rootWindow) { - RaiseWindow(rootWindow, aCallerType); + RaiseWindow(rootWindow, aCallerType, aActionId); } LOGFOCUS(("<>")); @@ -442,7 +447,8 @@ NS_IMETHODIMP nsFocusManager::SetFocusedWindow( mozIDOMWindowProxy* aWindowToFocus) { - return SetFocusedWindowWithCallerType(aWindowToFocus, CallerType::System); + return SetFocusedWindowWithCallerType(aWindowToFocus, CallerType::System, + GenerateFocusActionId()); } NS_IMETHODIMP @@ -477,7 +483,7 @@ NS_ENSURE_ARG(aElement); - SetFocusInner(aElement, aFlags, true, true); + SetFocusInner(aElement, aFlags, true, true, GenerateFocusActionId()); LOGFOCUS(("<>")); @@ -547,7 +553,7 @@ // would be a problem because the caret would move to the beginning of the // focused link making it impossible to navigate the caret over a link. SetFocusInner(MOZ_KnownLive(newFocus->AsElement()), aFlags, - aType != MOVEFOCUS_CARET, true); + aType != MOVEFOCUS_CARET, true, GenerateFocusActionId()); *aElement = do_AddRef(newFocus->AsElement()).take(); } else if (aType == MOVEFOCUS_ROOT || aType == MOVEFOCUS_CARET) { // no content was found, so clear the focus for these two types. @@ -572,11 +578,12 @@ if (IsSameOrAncestor(window, GetFocusedBrowsingContext())) { BrowsingContext* bc = window->GetBrowsingContext(); bool isAncestor = (GetFocusedBrowsingContext() != bc); - if (Blur(bc, nullptr, isAncestor, true)) { + uint64_t actionId = GenerateFocusActionId(); + if (Blur(bc, nullptr, isAncestor, true, actionId)) { // if we are clearing the focus on an ancestor of the focused window, // the ancestor will become the new focused window, so focus it if (isAncestor) { - Focus(window, nullptr, 0, true, false, false, true, false); + Focus(window, nullptr, 0, true, false, false, true, false, actionId); } } } else { @@ -647,7 +654,8 @@ return NS_OK; } -void nsFocusManager::WindowRaised(mozIDOMWindowProxy* aWindow) { +void nsFocusManager::WindowRaised(mozIDOMWindowProxy* aWindow, + uint64_t aActionId) { if (!aWindow) { return; } @@ -687,7 +695,7 @@ // lower the existing window, if any. This shouldn't happen usually. if (mActiveWindow) { - WindowLowered(mActiveWindow); + WindowLowered(mActiveWindow, aActionId); } } else if (bc->IsTop()) { BrowsingContext* active = GetActiveBrowsingContext(); @@ -699,7 +707,7 @@ if (active && active != bc) { if (active->IsInProcess()) { - WindowLowered(active->GetDOMWindow()); + WindowLowered(active->GetDOMWindow(), aActionId); } // No else, because trying to lower other-process windows // from here can result in the BrowsingContext no longer @@ -719,7 +727,7 @@ if (XRE_IsParentProcess()) { mActiveWindow = window; } else if (bc->IsTop()) { - SetActiveBrowsingContextInContent(bc); + SetActiveBrowsingContextInContent(bc, aActionId); } // ensure that the window is enabled and visible @@ -767,10 +775,11 @@ nsCOMPtr appWin(do_GetInterface(baseWindow)); Focus(currentWindow, currentFocus, 0, currentWindow->GetBrowsingContext() != GetFocusedBrowsingContext(), - false, appWin != nullptr, true, focusInOtherContentProcess); + false, appWin != nullptr, true, focusInOtherContentProcess, aActionId); } -void nsFocusManager::WindowLowered(mozIDOMWindowProxy* aWindow) { +void nsFocusManager::WindowLowered(mozIDOMWindowProxy* aWindow, + uint64_t aActionId) { if (!aWindow) { return; } @@ -837,12 +846,12 @@ } else { BrowsingContext* bc = window->GetBrowsingContext(); if (bc == bc->Top()) { - SetActiveBrowsingContextInContent(nullptr); + SetActiveBrowsingContextInContent(nullptr, aActionId); } } if (mFocusedWindow) { - Blur(nullptr, nullptr, true, true); + Blur(nullptr, nullptr, true, true, aActionId); } mWindowBeingLowered = nullptr; @@ -982,7 +991,7 @@ if (currentWindow) { Focus(currentWindow, currentFocus, 0, true, false, false, true, - focusInOtherContentProcess); + focusInOtherContentProcess, GenerateFocusActionId()); } } else { // Sometimes, an element in a window can be focused before the window is @@ -992,7 +1001,8 @@ } } -void nsFocusManager::WindowHidden(mozIDOMWindowProxy* aWindow) { +void nsFocusManager::WindowHidden(mozIDOMWindowProxy* aWindow, + uint64_t aActionId) { // if there is no window or it is not the same or an ancestor of the // currently focused window, just return, as the current focus will not // be affected. @@ -1087,7 +1097,7 @@ if (XRE_IsParentProcess()) { if (mActiveWindow == mFocusedWindow || mActiveWindow == window) { - WindowLowered(mActiveWindow); + WindowLowered(mActiveWindow, aActionId); } else { ClearFocus(mActiveWindow); } @@ -1099,7 +1109,7 @@ if ((mFocusedWindow && mFocusedWindow->GetBrowsingContext() == active) || (window->GetBrowsingContext() == active)) { - WindowLowered(activeWindow); + WindowLowered(activeWindow, aActionId); } else { ClearFocus(activeWindow); } @@ -1163,7 +1173,7 @@ nsresult nsFocusManager::FocusPlugin(Element* aPlugin) { NS_ENSURE_ARG(aPlugin); - SetFocusInner(aPlugin, 0, true, false); + SetFocusInner(aPlugin, 0, true, false, GenerateFocusActionId()); return NS_OK; } @@ -1393,7 +1403,8 @@ } void nsFocusManager::SetFocusInner(Element* aNewContent, int32_t aFlags, - bool aFocusChanged, bool aAdjustWidget) { + bool aFocusChanged, bool aAdjustWidget, + uint64_t aActionId) { // if the element is not focusable, just return and leave the focus as is RefPtr elementToFocus = FlushAndCheckIfFocusable(aNewContent, aFlags); @@ -1691,14 +1702,15 @@ if (!Blur( currentIsSameOrAncestor ? focusedBrowsingContext.get() : nullptr, commonAncestor ? commonAncestor.get() : nullptr, - !isElementInFocusedWindow, aAdjustWidget, elementToFocus)) { + !isElementInFocusedWindow, aAdjustWidget, aActionId, + elementToFocus)) { return; } } Focus(newWindow, elementToFocus, aFlags, !isElementInFocusedWindow, aFocusChanged, false, aAdjustWidget, focusInOtherContentProcess, - blurredInfo); + aActionId, blurredInfo); } else { // otherwise, for inactive windows and when the caller cannot steal the // focus, update the node in the window, and raise the window if desired. @@ -1731,7 +1743,8 @@ if (XRE_IsParentProcess() || newRootBrowsingContext->IsInProcess()) { RaiseWindow(newRootBrowsingContext->GetDOMWindow(), aFlags & FLAG_NONSYSTEMCALLER ? CallerType::NonSystem - : CallerType::System); + : CallerType::System, + aActionId); } else { mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton(); @@ -1739,7 +1752,8 @@ contentChild->SendRaiseWindow(newRootBrowsingContext, aFlags & FLAG_NONSYSTEMCALLER ? CallerType::NonSystem - : CallerType::System); + : CallerType::System, + aActionId); } } } @@ -2055,10 +2069,11 @@ bool nsFocusManager::Blur(BrowsingContext* aBrowsingContextToClear, BrowsingContext* aAncestorBrowsingContextToFocus, bool aIsLeavingDocument, bool aAdjustWidget, - Element* aElementToFocus) { + uint64_t aActionId, Element* aElementToFocus) { if (XRE_IsParentProcess()) { return BlurImpl(aBrowsingContextToClear, aAncestorBrowsingContextToFocus, - aIsLeavingDocument, aAdjustWidget, aElementToFocus); + aIsLeavingDocument, aAdjustWidget, aElementToFocus, + aActionId); } mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton(); @@ -2101,7 +2116,8 @@ true); } return BlurImpl(aBrowsingContextToClear, aAncestorBrowsingContextToFocus, - aIsLeavingDocument, aAdjustWidget, aElementToFocus); + aIsLeavingDocument, aAdjustWidget, aElementToFocus, + aActionId); } if (aBrowsingContextToClear && aBrowsingContextToClear->IsInProcess()) { nsPIDOMWindowOuter* windowToClear = aBrowsingContextToClear->GetDOMWindow(); @@ -2124,7 +2140,7 @@ contentChild->SendBlurToParent( focusedBrowsingContext, aBrowsingContextToClear, aAncestorBrowsingContextToFocus, aIsLeavingDocument, aAdjustWidget, - windowToClearHandled, ancestorWindowToFocusHandled); + windowToClearHandled, ancestorWindowToFocusHandled, aActionId); return true; } @@ -2132,18 +2148,18 @@ mozilla::dom::BrowsingContext* aFocusedBrowsingContext, mozilla::dom::BrowsingContext* aBrowsingContextToClear, mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus, - bool aIsLeavingDocument, bool aAdjustWidget) { + bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId) { if (aFocusedBrowsingContext != GetFocusedBrowsingContext()) { return; } BlurImpl(aBrowsingContextToClear, aAncestorBrowsingContextToFocus, - aIsLeavingDocument, aAdjustWidget, nullptr); + aIsLeavingDocument, aAdjustWidget, nullptr, aActionId); } bool nsFocusManager::BlurImpl(BrowsingContext* aBrowsingContextToClear, BrowsingContext* aAncestorBrowsingContextToFocus, bool aIsLeavingDocument, bool aAdjustWidget, - Element* aElementToFocus) { + Element* aElementToFocus, uint64_t aActionId) { LOGFOCUS(("<>")); // hold a reference to the focused content, which may be null @@ -2268,7 +2284,7 @@ aContext->Canonical()->GetCurrentWindowGlobal()) { if (RefPtr browserParent = windowGlobalParent->GetBrowserParent()) { - browserParent->Deactivate(windowBeingLowered); + browserParent->Deactivate(windowBeingLowered, aActionId); LOGFOCUS(("%s remote browser deactivated %p, %d", aContext == topLevelBrowsingContext ? "Top-level" : "OOP iframe", @@ -2280,7 +2296,7 @@ // Same as above but for out-of-process iframes if (BrowserBridgeChild* bbc = BrowserBridgeChild::GetFrom(element)) { - bbc->Deactivate(windowBeingLowered); + bbc->Deactivate(windowBeingLowered, aActionId); LOGFOCUS(("Out-of-process iframe deactivated %p, %d", bbc, windowBeingLowered)); } @@ -2363,15 +2379,16 @@ return result; } -void nsFocusManager::ActivateRemoteFrameIfNeeded(Element& aElement) { +void nsFocusManager::ActivateRemoteFrameIfNeeded(Element& aElement, + uint64_t aActionId) { if (BrowserParent* remote = BrowserParent::GetFrom(&aElement)) { - remote->Activate(); + remote->Activate(aActionId); LOGFOCUS(("Remote browser activated %p", remote)); } // Same as above but for out-of-process iframes if (BrowserBridgeChild* bbc = BrowserBridgeChild::GetFrom(&aElement)) { - bbc->Activate(); + bbc->Activate(aActionId); LOGFOCUS(("Out-of-process iframe activated %p", bbc)); } } @@ -2379,7 +2396,7 @@ void nsFocusManager::Focus( nsPIDOMWindowOuter* aWindow, Element* aElement, uint32_t aFlags, bool aIsNewDocument, bool aFocusChanged, bool aWindowRaised, - bool aAdjustWidget, bool aFocusInOtherContentProcess, + bool aAdjustWidget, bool aFocusInOtherContentProcess, uint64_t aActionId, const Maybe& aBlurredElementInfo) { LOGFOCUS(("<>")); @@ -2539,7 +2556,7 @@ // if the object being focused is a remote browser, activate remote // content - ActivateRemoteFrameIfNeeded(*aElement); + ActivateRemoteFrameIfNeeded(*aElement, aActionId); } IMEStateManager::OnChangeFocus(presContext, aElement, @@ -2805,7 +2822,7 @@ } void nsFocusManager::RaiseWindow(nsPIDOMWindowOuter* aWindow, - CallerType aCallerType) { + CallerType aCallerType, uint64_t aActionId) { // don't raise windows that are already raised or are in the process of // being lowered @@ -2838,8 +2855,9 @@ nsCOMPtr window(aWindow); RefPtr self(this); NS_DispatchToCurrentThread(NS_NewRunnableFunction( - "nsFocusManager::RaiseWindow", - [self, window]() -> void { self->WindowRaised(window); })); + "nsFocusManager::RaiseWindow", [self, window, aActionId]() -> void { + self->WindowRaised(window, aActionId); + })); return; } @@ -3539,7 +3557,8 @@ if (tookFocus) { nsCOMPtr window = docShell->GetWindow(); if (window->GetFocusedElement() == mFocusedElement) { - Blur(GetFocusedBrowsingContext(), nullptr, true, true); + Blur(GetFocusedBrowsingContext(), nullptr, true, true, + GenerateFocusActionId()); } else { window->SetFocusedElement(nullptr); } @@ -4758,6 +4777,10 @@ // an iframe in that process became an out-of-process // iframe while the IPC broadcast that we're receiving // was in-flight. Let's just ignore this. + LOGFOCUS( + ("Ignored an attempt to set an in-process BrowsingContext [%p] as " + "focused from another process.", + aContext)); return; } mFocusedBrowsingContextInContent = aContext; @@ -4783,15 +4806,16 @@ } void nsFocusManager::SetActiveBrowsingContextInContent( - mozilla::dom::BrowsingContext* aContext) { + mozilla::dom::BrowsingContext* aContext, uint64_t aActionId) { MOZ_ASSERT(!XRE_IsParentProcess()); MOZ_ASSERT(!aContext || aContext->IsInProcess()); mozilla::dom::ContentChild* contentChild = mozilla::dom::ContentChild::GetSingleton(); MOZ_ASSERT(contentChild); + if (aContext != mActiveBrowsingContextInContent) { if (aContext) { - contentChild->SendSetActiveBrowsingContext(aContext); + contentChild->SendSetActiveBrowsingContext(aContext, aActionId); } else if (mActiveBrowsingContextInContent) { // We want to sync this over only if this isn't happening // due to the active BrowsingContext switching processes, @@ -4807,7 +4831,7 @@ RefPtr browserChild = globalChild->GetBrowserChild(); if (browserChild && !browserChild->IsDestroyed()) { contentChild->SendUnsetActiveBrowsingContext( - mActiveBrowsingContextInContent); + mActiveBrowsingContextInContent, aActionId); } } } @@ -4816,6 +4840,7 @@ } mActiveBrowsingContextInContentSetFromOtherProcess = false; mActiveBrowsingContextInContent = aContext; + mActionIdForActiveBrowsingContextInContent = aActionId; MaybeUnlockPointer(aContext); } @@ -4830,10 +4855,15 @@ // an iframe in that process became an out-of-process // iframe while the IPC broadcast that we're receiving // was in-flight. Let's just ignore this. + LOGFOCUS( + ("Ignored an attempt to set an in-process BrowsingContext [%p] as " + "active from another process.", + aContext)); return; } mActiveBrowsingContextInContentSetFromOtherProcess = true; mActiveBrowsingContextInContent = aContext; + mActionIdForActiveBrowsingContextInContent = 0; MaybeUnlockPointer(aContext); } @@ -4843,19 +4873,83 @@ MOZ_ASSERT(aContext); if (mActiveBrowsingContextInContent == aContext) { mActiveBrowsingContextInContent = nullptr; + mActionIdForActiveBrowsingContextInContent = 0; MaybeUnlockPointer(nullptr); + } else { + LOGFOCUS( + ("Ignored an attempt to unset the active BrowsingContext [%p] from " + "another process.", + aContext)); } } -void nsFocusManager::SetActiveBrowsingContextInChrome( - mozilla::dom::BrowsingContext* aContext) { - mActiveBrowsingContextInChrome = aContext; +void nsFocusManager::ReviseActiveBrowsingContext( + mozilla::dom::BrowsingContext* aContext, uint64_t aActionId) { + MOZ_ASSERT(XRE_IsContentProcess()); + if (mActionIdForActiveBrowsingContextInContent == aActionId) { + mActiveBrowsingContextInContent = aContext; + } else { + LOGFOCUS( + ("Ignored a stale attempt to revise the active BrowsingContext [%p].", + aContext)); + } +} + +bool nsFocusManager::SetActiveBrowsingContextInChrome( + mozilla::dom::BrowsingContext* aContext, uint64_t aActionId) { + MOZ_ASSERT(aActionId); + if (ProcessPendingActiveBrowsingContextActionId(aActionId, aContext)) { + mActiveBrowsingContextInChrome = aContext; + return true; + } + return false; } BrowsingContext* nsFocusManager::GetActiveBrowsingContextInChrome() { return mActiveBrowsingContextInChrome; } +void nsFocusManager::InsertNewFocusActionId(uint64_t aActionId) { + MOZ_ASSERT(XRE_IsParentProcess()); + MOZ_ASSERT(!mPendingActiveBrowsingContextActions.Contains(aActionId)); + mPendingActiveBrowsingContextActions.AppendElement(aActionId); +} + +bool nsFocusManager::ProcessPendingActiveBrowsingContextActionId( + uint64_t aActionId, bool aSettingToNonNull) { + MOZ_ASSERT(XRE_IsParentProcess()); + auto index = mPendingActiveBrowsingContextActions.IndexOf(aActionId); + if (index == nsTArray::NoIndex) { + return false; + } + // When aSettingToNonNull is true, we need to remove one more + // element to remove the action id itself in addition to + // removing the older ones. + if (aSettingToNonNull) { + index++; + } + mPendingActiveBrowsingContextActions.RemoveElementsAt(0, index); + return true; +} + +// static +uint64_t nsFocusManager::GenerateFocusActionId() { + uint64_t id = + nsContentUtils::GenerateProcessSpecificId(++sFocusActionCounter); + if (XRE_IsParentProcess()) { + nsFocusManager* fm = GetFocusManager(); + if (fm) { + fm->InsertNewFocusActionId(id); + } + } else { + mozilla::dom::ContentChild* contentChild = + mozilla::dom::ContentChild::GetSingleton(); + MOZ_ASSERT(contentChild); + contentChild->SendInsertNewFocusActionId(id); + } + return id; +} + static bool IsInPointerLockContext(nsPIDOMWindowOuter* aWin) { return nsContentUtils::IsInPointerLockContext( aWin ? aWin->GetBrowsingContext() : nullptr); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsFocusManager.h firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsFocusManager.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsFocusManager.h 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsFocusManager.h 2020-11-17 19:31:26.000000000 +0000 @@ -212,29 +212,30 @@ * Setter for focusedWindow with CallerType */ nsresult SetFocusedWindowWithCallerType(mozIDOMWindowProxy* aWindowToFocus, - mozilla::dom::CallerType aCallerType); + mozilla::dom::CallerType aCallerType, + uint64_t aActionId); /** * Given an element, which must be the focused element, activate the remote * frame it embeds, if any. */ - void ActivateRemoteFrameIfNeeded(mozilla::dom::Element&); + void ActivateRemoteFrameIfNeeded(mozilla::dom::Element&, uint64_t aActionId); /** * Raises the top-level window aWindow at the widget level. */ void RaiseWindow(nsPIDOMWindowOuter* aWindow, - mozilla::dom::CallerType aCallerType); + mozilla::dom::CallerType aCallerType, uint64_t aActionId); /** * Called when a window has been raised. */ - void WindowRaised(mozIDOMWindowProxy* aWindow); + void WindowRaised(mozIDOMWindowProxy* aWindow, uint64_t aActionId); /** * Called when a window has been lowered. */ - void WindowLowered(mozIDOMWindowProxy* aWindow); + void WindowLowered(mozIDOMWindowProxy* aWindow, uint64_t aActionId); /** * Called when a new document in a window is shown. @@ -248,7 +249,7 @@ * Called when a document in a window has been hidden or otherwise can no * longer accept focus. */ - void WindowHidden(mozIDOMWindowProxy* aWindow); + void WindowHidden(mozIDOMWindowProxy* aWindow, uint64_t aActionId); /** * Fire any events that have been delayed due to synchronized actions. @@ -335,7 +336,8 @@ */ MOZ_CAN_RUN_SCRIPT_BOUNDARY void SetFocusInner(mozilla::dom::Element* aNewContent, int32_t aFlags, - bool aFocusChanged, bool aAdjustWidget); + bool aFocusChanged, bool aAdjustWidget, + uint64_t aActionId); /** * Returns true if aPossibleAncestor is the same as aWindow or an @@ -422,19 +424,19 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY bool Blur(mozilla::dom::BrowsingContext* aBrowsingContextToClear, mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus, - bool aIsLeavingDocument, bool aAdjustWidget, + bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId, mozilla::dom::Element* aElementToFocus = nullptr); MOZ_CAN_RUN_SCRIPT_BOUNDARY void BlurFromOtherProcess( mozilla::dom::BrowsingContext* aFocusedBrowsingContext, mozilla::dom::BrowsingContext* aBrowsingContextToClear, mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus, - bool aIsLeavingDocument, bool aAdjustWidget); + bool aIsLeavingDocument, bool aAdjustWidget, uint64_t aActionId); MOZ_CAN_RUN_SCRIPT_BOUNDARY bool BlurImpl(mozilla::dom::BrowsingContext* aBrowsingContextToClear, mozilla::dom::BrowsingContext* aAncestorBrowsingContextToFocus, bool aIsLeavingDocument, bool aAdjustWidget, - mozilla::dom::Element* aElementToFocus); + mozilla::dom::Element* aElementToFocus, uint64_t aActionId); /** * Focus an element in the active window and child frame. @@ -466,7 +468,7 @@ void Focus(nsPIDOMWindowOuter* aWindow, mozilla::dom::Element* aContent, uint32_t aFlags, bool aIsNewDocument, bool aFocusChanged, bool aWindowRaised, bool aAdjustWidget, - bool aFocusInOtherContentProcess, + bool aFocusInOtherContentProcess, uint64_t aActionId, const mozilla::Maybe& = mozilla::Nothing()); /** @@ -781,6 +783,11 @@ void SetFocusedBrowsingContextInChrome( mozilla::dom::BrowsingContext* aContext); + void InsertNewFocusActionId(uint64_t aActionId); + + bool ProcessPendingActiveBrowsingContextActionId(uint64_t aActionId, + bool aSettingToNonNull); + public: // Chrome-only // Gets the chrome process notion of what BrowsingContext is focused @@ -797,7 +804,7 @@ // Sets the BrowsingContext corresponding to top-level Web content // in the frontmost tab if focus is in Web content. void SetActiveBrowsingContextInContent( - mozilla::dom::BrowsingContext* aContext); + mozilla::dom::BrowsingContext* aContext, uint64_t aActionId); // Content-only // Receives notification of another process setting the top-level Web @@ -812,12 +819,24 @@ void UnsetActiveBrowsingContextFromOtherProcess( mozilla::dom::BrowsingContext* aContext); + // Content-only + // Receives a notification from parent that this content process's + // attempt to set the active browsing context was late and the + // prevailing browsing context is instead the first argument of + // this method call. This should be ignored if the second argument + // doesn't match the latest action id associated with setting the + // active browsing context in this process, because in that case, + // this revision is late. + void ReviseActiveBrowsingContext(mozilla::dom::BrowsingContext* aContext, + uint64_t aActionId); + // Chrome-only // Sets the chrome process notion of what content believes to be // the top-level BrowsingContext in the frontmost tab when focus // is in Web content. - void SetActiveBrowsingContextInChrome( - mozilla::dom::BrowsingContext* aContext); + // Returns true if set and false if ignored. + bool SetActiveBrowsingContextInChrome(mozilla::dom::BrowsingContext* aContext, + uint64_t aActionId); public: // Chrome-only @@ -826,19 +845,37 @@ // is in Web content. mozilla::dom::BrowsingContext* GetActiveBrowsingContextInChrome(); + static uint64_t GenerateFocusActionId(); + private: // In the chrome process, the currently active and front-most top-most // window. Not supposed to be used in a meaningful way in content - // processes. + // processes. For legacy reasons, this exists as a separate field + // instead of being derived from mFocusedWindow when needed, because + // the defined relation that mActiveWindow is supposed to be the same + // as or ancestor of mFocusedWindow is temporarily broken when a + // window is being raised or lowered. nsCOMPtr mActiveWindow; // In a content process, the BrowsingContext corresponding to top-level // Web content in the active tab or nullptr if focus is not in a // BrowsingContextGroup that this process participates in. Synced - // across processes in a BrowsingContextGroup. + // across processes in a BrowsingContextGroup. This field exists + // separately from mFocusedBrowsingContextInContent instead of being being + // derived from it, because for legacy reasons the relation + // mFocusedBrowsingContextInContent->Top() == mActiveBrowsingContextInContent + // is temporarily broken when a window is being raised or lowered. // Not supposed to be used in a meaningful way in the chrome process. RefPtr mActiveBrowsingContextInContent; + // If this content process set mActiveBrowsingContextInContent, this + // field holds the corresponding actionId so that + // mActiveBrowsingContextInContent can be revised of the parent rejects + // the update. This field is used for accepting revisions only if nothing + // else has updated mActiveBrowsingContextInContent before the revision + // arrives. + uint64_t mActionIdForActiveBrowsingContextInContent; + // Whether or not mActiveBrowsingContextInContent was set from another process // or from this process. bool mActiveBrowsingContextInContentSetFromOtherProcess; @@ -887,12 +924,74 @@ // and fire them later. nsTArray mDelayedBlurFocusEvents; + // Array of focus action ids for which we haven't seen an active browsing + // context set yet. As set is allowed to overwrite an unset. Therefore, + // an unset removes earlier ids but not the matching id. A set removes + // earlier ids and the matching id. + // + // Conceptually, active browsing context shouldn't have to exist as a + // field, because it should be possible to always derive it from the + // focused browsing context. Unfortunately, for legacy reasons, this + // is not the case while a window is being raised or lowered. + // + // Conceptually, it should be possible for the parent to manage the + // active browsing context. Unfortunately, for legacy reasons, the + // code for setting the active browsing context needs to reside in + // the content process to retain the existing and test-passing code + // flow. + // + // This, obviously, raises the issue of content processes racing to + // set the active browsing context. In particular, there is a pattern + // that the parent initiates actions that cause multiple content + // processes to mutate the active browsing context at almost the + // same time. When two native browser windows change order, the + // lowering isn't distinguished from the case of lowering the + // entire app. For this reason, the owner of the previous active + // browsing context tries to unset it and at almost the same time + // the another content process sets a new active browsing context. + // If the IPC messages for these unset and set actions were to + // arrive in the wrong order, this could get in the wrong state. + // + // To address this issue, the parent manages an authortative order + // of attempts to (un)set the active browsing context using the + // array mPendingActiveBrowsingContextActions. + // + // A process reserves a slot in the order by calling + // GenerateFocusActionId(). Per one call to GenerateFocusActionId(), + // there may be at most one action to set the active browsing context + // to a new value. There may be logically prior attempts to unset it + // (i.e. set it to nullptr). That is, if there are both attempts to + // unset and set the active browsing context with the same action id, + // the attempt to set to a non-null value wins. + // + // The completion of an action from reserting the slot in the order + // and actually performing the setting of the active browsing context + // may span multiple processes and IPC messages. + // + // The at-most-once property is not asserted, because the process + // claiming the position in the order and the process setting the + // active browsing context with that actionId may be different, and + // the act of using an actionId to set the active browsing context + // is used to delete stale items from the array to avoid excessive + // growth of the array. + // + // This arrangement raises the obvious question: Shouldn't + // out-of-order attempts to set the focused browsing context + // also have an array of actionIds ensuring a coherent global + // ordering? Probably yes, but a concrete need has not been + // demonstrated, yet. + nsTArray mPendingActiveBrowsingContextActions; + // If set to true, layout of the document of the event target should be // flushed before handling focus depending events. bool mEventHandlingNeedsFlush; static bool sTestMode; + // Process-specific counter for maintaining the prosess-specific + // uniqueness of actionIds. + static uint64_t sFocusActionCounter; + // the single focus manager static mozilla::StaticRefPtr sInstance; }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsFrameLoader.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsFrameLoader.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsFrameLoader.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsFrameLoader.cpp 2020-11-17 19:31:25.000000000 +0000 @@ -53,6 +53,7 @@ #include "nsIURI.h" #include "nsIXULRuntime.h" #include "nsNetUtil.h" +#include "nsFocusManager.h" #include "nsGkAtoms.h" #include "nsNameSpaceManager.h" @@ -2713,7 +2714,7 @@ return; } - browserParent->Activate(); + browserParent->Activate(nsFocusManager::GenerateFocusActionId()); } void nsFrameLoader::DeactivateRemoteFrame(ErrorResult& aRv) { @@ -2723,7 +2724,7 @@ return; } - browserParent->Deactivate(false); + browserParent->Deactivate(false, nsFocusManager::GenerateFocusActionId()); } void nsFrameLoader::SendCrossProcessMouseEvent(const nsAString& aType, float aX, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsFrameLoaderOwner.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsFrameLoaderOwner.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsFrameLoaderOwner.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsFrameLoaderOwner.cpp 2020-11-17 19:31:26.000000000 +0000 @@ -169,7 +169,8 @@ // we need to update that state for the new BrowserParent too. if (nsFocusManager* fm = nsFocusManager::GetFocusManager()) { if (fm->GetFocusedElement() == owner) { - fm->ActivateRemoteFrameIfNeeded(*owner); + fm->ActivateRemoteFrameIfNeeded(*owner, + nsFocusManager::GenerateFocusActionId()); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsGlobalWindowInner.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsGlobalWindowInner.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsGlobalWindowInner.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsGlobalWindowInner.cpp 2020-11-17 19:31:25.000000000 +0000 @@ -117,6 +117,7 @@ #include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE #include "PostMessageEvent.h" #include "mozilla/dom/DocGroup.h" +#include "mozilla/StaticPrefs_browser.h" #include "mozilla/StaticPrefs_dom.h" #include "PaintWorkletImpl.h" @@ -4259,7 +4260,8 @@ uint32_t nsGlobalWindowInner::GetFocusMethod() { return mFocusMethod; } bool nsGlobalWindowInner::ShouldShowFocusRing() { - if (mFocusByKeyOccurred) { + if (mFocusByKeyOccurred && + StaticPrefs::browser_display_always_show_rings_after_key_focus()) { return true; } @@ -4310,7 +4312,7 @@ nsFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm) { - fm->WindowHidden(GetOuterWindow()); + fm->WindowHidden(GetOuterWindow(), nsFocusManager::GenerateFocusActionId()); } mNeedsFocus = true; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsGlobalWindowOuter.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsGlobalWindowOuter.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/nsGlobalWindowOuter.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/nsGlobalWindowOuter.cpp 2020-11-17 19:31:25.000000000 +0000 @@ -5134,10 +5134,11 @@ parent = bc->Canonical()->GetParentCrossChromeBoundary(); } } + uint64_t actionId = nsFocusManager::GenerateFocusActionId(); if (parent) { if (!parent->IsInProcess()) { if (isActive) { - fm->WindowRaised(this); + fm->WindowRaised(this, actionId); } ContentChild* contentChild = ContentChild::GetSingleton(); MOZ_ASSERT(contentChild); @@ -5159,7 +5160,7 @@ // if there is no parent, this must be a toplevel window, so raise the // window if canFocus is true. If this is a child process, the raise // window request will get forwarded to the parent by the puppet widget. - fm->RaiseWindow(this, aCallerType); + fm->RaiseWindow(this, aCallerType, actionId); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/base/test/browser_bug593387.js firefox-trunk-85.0~a1~hg20201117r557492/dom/base/test/browser_bug593387.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/base/test/browser_bug593387.js 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/base/test/browser_bug593387.js 2020-11-17 19:31:26.000000000 +0000 @@ -50,7 +50,7 @@ // --------------------------------------------------- // Test 2: Try the same with a content top-level context) - await BrowserTestUtils.loadURI(newBrowser, "http://example.com/"); + BrowserTestUtils.loadURI(newBrowser, "http://example.com/"); await BrowserTestUtils.browserLoaded(newBrowser); let observerData = await SpecialPowers.spawn( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/bindings/Exceptions.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/bindings/Exceptions.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/bindings/Exceptions.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/bindings/Exceptions.cpp 2020-11-17 19:31:25.000000000 +0000 @@ -157,6 +157,7 @@ switch (NS_ERROR_GET_MODULE(aRv)) { case NS_ERROR_MODULE_DOM: case NS_ERROR_MODULE_SVG: + case NS_ERROR_MODULE_DOM_FILE: case NS_ERROR_MODULE_DOM_XPATH: case NS_ERROR_MODULE_DOM_INDEXEDDB: case NS_ERROR_MODULE_DOM_FILEHANDLE: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/canvas/ClientWebGLContext.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/canvas/ClientWebGLContext.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/canvas/ClientWebGLContext.cpp 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/canvas/ClientWebGLContext.cpp 2020-11-17 19:31:26.000000000 +0000 @@ -3887,9 +3887,12 @@ const auto bytesPerRowStride = RoundUpToMultipleOf(bytesPerRowUnaligned, unpacking.mUnpackAlignment); - const auto bytesPerImageStride = bytesPerRowStride * unpacking.mUnpackImageHeight; - // SKIP_IMAGES is ignored for 2D targets, but at worst this just makes our shrinking less accurate. - const auto images = CheckedInt(unpacking.mUnpackSkipImages) + size.z; + const auto bytesPerImageStride = + bytesPerRowStride * unpacking.mUnpackImageHeight; + // SKIP_IMAGES is ignored for 2D targets, but at worst this just makes our + // shrinking less accurate. + const auto images = + CheckedInt(unpacking.mUnpackSkipImages) + size.z; const auto bytesUpperBound = bytesPerImageStride * images; if (bytesUpperBound.isValid()) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/canvas/test/test_canvas_focusring.html firefox-trunk-85.0~a1~hg20201117r557492/dom/canvas/test/test_canvas_focusring.html --- firefox-trunk-84.0~a1~hg20201115r557261/dom/canvas/test/test_canvas_focusring.html 2020-11-15 14:37:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/canvas/test/test_canvas_focusring.html 2020-11-17 19:31:26.000000000 +0000 @@ -5,11 +5,7 @@

Canvas test: drawFocusIfNeeded

@@ -59,6 +55,12 @@ + + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/media/test/test_background_video_resume_looping_video_without_audio.html firefox-trunk-85.0~a1~hg20201117r557492/dom/media/test/test_background_video_resume_looping_video_without_audio.html --- firefox-trunk-84.0~a1~hg20201115r557261/dom/media/test/test_background_video_resume_looping_video_without_audio.html 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/media/test/test_background_video_resume_looping_video_without_audio.html 2020-11-17 19:31:27.000000000 +0000 @@ -16,8 +16,12 @@ */ async function startTest() { const video = await createVisibleVideo(); - await startVideo(video); - await suspendVideoDecoding(video); + // Start and immediately suspend the video to avoid races where the video + // decode is complete by the time it should be suspended. + await Promise.all([ + suspendVideoDecoding(video), + startVideo(video), + ]); await resumeVideoDecoding(video); await waitUntilVideoLoopAgain(video); endTestAndClearVideo(video); @@ -59,12 +63,14 @@ info(`suspend video decoding`); video.setVisible(false); await nextVideoSuspends(video); + info(`suspended video decoding`); } async function resumeVideoDecoding(video) { info(`resume video decoding.`); video.setVisible(true); await nextVideoResumes(video); + info(`resumed video decoding`); } async function waitUntilVideoLoopAgain(video) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/media/tests/crashtests/802982.html firefox-trunk-85.0~a1~hg20201117r557492/dom/media/tests/crashtests/802982.html --- firefox-trunk-84.0~a1~hg20201115r557261/dom/media/tests/crashtests/802982.html 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/media/tests/crashtests/802982.html 2020-11-17 19:31:27.000000000 +0000 @@ -15,7 +15,7 @@ function boom() { for (var j = 0; j < 100; ++j) { - navigator.mozGetUserMedia({}, function(){}, function(){}); + navigator.mozGetUserMedia({video:true}, function(){}, function(){}); } finish(); // we're not waiting for success/error callbacks here } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/media/VideoUtils.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/media/VideoUtils.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/media/VideoUtils.cpp 2020-11-15 14:37:55.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/media/VideoUtils.cpp 2020-11-17 19:31:27.000000000 +0000 @@ -188,11 +188,9 @@ if (resampling) { rate = 48000; - } else if (aInfo.mRate == 44100 || aInfo.mRate == 48000) { + } else if (aInfo.mRate >= 44100) { // The original rate is of good quality and we want to minimize unecessary - // resampling. The common scenario being that the sampling rate is one or - // the other. This minimizes audio quality regressions but depends on - // content providers not changing rates mid-stream. + // resampling, so we let cubeb decide how to resample (if needed). rate = aInfo.mRate; } else { // We will resample all data to match cubeb's preferred sampling rate. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webaudio/AudioBufferSourceNode.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webaudio/AudioBufferSourceNode.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webaudio/AudioBufferSourceNode.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webaudio/AudioBufferSourceNode.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -349,7 +349,7 @@ uint32_t numFrames = std::min( WEBAUDIO_BLOCK_SIZE - *aOffsetWithinBlock, aMaxPos - *aCurrentPosition); if (numFrames == WEBAUDIO_BLOCK_SIZE || !aChannels) { - aOutput->SetNull(numFrames); + aOutput->SetNull(WEBAUDIO_BLOCK_SIZE); } else { if (*aOffsetWithinBlock == 0) { aOutput->AllocateChannels(aChannels); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webrtc/jsapi/RemoteTrackSource.h firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webrtc/jsapi/RemoteTrackSource.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webrtc/jsapi/RemoteTrackSource.h 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webrtc/jsapi/RemoteTrackSource.h 2020-11-17 19:31:27.000000000 +0000 @@ -25,7 +25,7 @@ dom::CallerType aCallerType) override { return ApplyConstraintsPromise::CreateAndReject( MakeRefPtr( - dom::MediaStreamError::Name::OverconstrainedError, u""_ns), + dom::MediaStreamError::Name::OverconstrainedError, ""), __func__); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webspeech/recognition/OnlineSpeechRecognitionService.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webspeech/recognition/OnlineSpeechRecognitionService.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webspeech/recognition/OnlineSpeechRecognitionService.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webspeech/recognition/OnlineSpeechRecognitionService.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -96,14 +96,14 @@ bool parsingSuccessful; nsAutoCString result; nsAutoCString hypoValue; - nsAutoString errorMsg; + nsAutoCString errorMsg; SpeechRecognitionErrorCode errorCode; SR_LOG("STT Result: %s", mBuf.get()); if (NS_FAILED(aStatusCode)) { success = false; - errorMsg.Assign(u"Error connecting to the service."_ns); + errorMsg.AssignLiteral("Error connecting to the service."); errorCode = SpeechRecognitionErrorCode::Network; } else { success = true; @@ -113,7 +113,7 @@ if (!parsingSuccessful) { // there's an internal server error success = false; - errorMsg.Assign(u"Internal server error"_ns); + errorMsg.AssignLiteral("Internal server error"); errorCode = SpeechRecognitionErrorCode::Network; } else { result.Assign(root.get("status", "error").asString().c_str()); @@ -124,13 +124,12 @@ confidence = root["data"][0].get("confidence", "0").asFloat(); } else { success = false; - errorMsg.Assign(u"Error reading result data."_ns); + errorMsg.AssignLiteral("Error reading result data."); errorCode = SpeechRecognitionErrorCode::Network; } } else { success = false; - NS_ConvertUTF8toUTF16 error(root.get("message", "").asString().c_str()); - errorMsg.Assign(error); + errorMsg.Assign(root.get("message", "").asString().c_str()); errorCode = SpeechRecognitionErrorCode::No_speech; } } @@ -237,7 +236,7 @@ } mRecognition->DispatchError( SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, - SpeechRecognitionErrorCode::Audio_capture, u"Encoder error"_ns); + SpeechRecognitionErrorCode::Audio_capture, "Encoder error"); })); } @@ -309,7 +308,7 @@ if (NS_WARN_IF(NS_FAILED(rv))) { mRecognition->DispatchError( SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, - SpeechRecognitionErrorCode::Network, u"Unknown URI"_ns); + SpeechRecognitionErrorCode::Network, "Unknown URI"); return; } @@ -324,7 +323,7 @@ if (NS_WARN_IF(!window)) { mRecognition->DispatchError( SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, - SpeechRecognitionErrorCode::Aborted, u"No window"_ns); + SpeechRecognitionErrorCode::Aborted, "No window"); return; } @@ -332,7 +331,7 @@ if (NS_WARN_IF(!doc)) { mRecognition->DispatchError( SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, - SpeechRecognitionErrorCode::Aborted, u"No document"_ns); + SpeechRecognitionErrorCode::Aborted, "No document"); } rv = NS_NewChannel(getter_AddRefs(chan), uri, doc->NodePrincipal(), secFlags, contentPolicy, nullptr, nullptr, nullptr, nullptr, @@ -340,7 +339,7 @@ if (NS_WARN_IF(NS_FAILED(rv))) { mRecognition->DispatchError( SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, - SpeechRecognitionErrorCode::Network, u"Failed to open channel"_ns); + SpeechRecognitionErrorCode::Network, "Failed to open channel"); return; } @@ -385,7 +384,7 @@ if (!audio.SetCapacity(length, fallible)) { mRecognition->DispatchError( SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, - SpeechRecognitionErrorCode::Audio_capture, u"Allocation error"_ns); + SpeechRecognitionErrorCode::Audio_capture, "Allocation error"); return; } @@ -399,7 +398,7 @@ if (NS_WARN_IF(NS_FAILED(rv))) { mRecognition->DispatchError( SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, - SpeechRecognitionErrorCode::Network, u"Failed to open stream"_ns); + SpeechRecognitionErrorCode::Network, "Failed to open stream"); return; } if (bodyStream) { @@ -413,7 +412,7 @@ if (NS_WARN_IF(NS_FAILED(rv))) { mRecognition->DispatchError( SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, - SpeechRecognitionErrorCode::Network, u"Internal server error"_ns); + SpeechRecognitionErrorCode::Network, "Internal server error"); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webspeech/recognition/SpeechRecognition.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webspeech/recognition/SpeechRecognition.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webspeech/recognition/SpeechRecognition.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webspeech/recognition/SpeechRecognition.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -698,7 +698,7 @@ StateBetween(STATE_IDLE, STATE_WAITING_FOR_SPEECH)) { DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR, SpeechRecognitionErrorCode::No_speech, - u"No speech detected (timeout)"_ns); + "No speech detected (timeout)"); } else if (!strcmp(aTopic, SPEECH_RECOGNITION_TEST_END_TOPIC)) { nsCOMPtr obs = services::GetObserverService(); obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC); @@ -719,7 +719,7 @@ DispatchError( SpeechRecognition::EVENT_AUDIO_ERROR, SpeechRecognitionErrorCode::Audio_capture, // TODO different codes? - u"AUDIO_ERROR test event"_ns); + "AUDIO_ERROR test event"); } else { NS_ASSERTION(StaticPrefs::media_webspeech_test_fake_recognition_service(), "Got request for fake recognition service event, but " @@ -811,10 +811,15 @@ } } else { mTrackIsOwned = true; + nsPIDOMWindowInner* win = GetOwner(); + if (!win || !win->IsFullyActive()) { + aRv.ThrowInvalidStateError("The document is not fully active."); + return; + } AutoNoJSAPI nojsapi; RefPtr self(this); MediaManager::Get() - ->GetUserMedia(GetOwner(), constraints, aCallerType) + ->GetUserMedia(win, constraints, aCallerType) ->Then( GetCurrentSerialEventTarget(), __func__, [this, self, @@ -963,7 +968,7 @@ void SpeechRecognition::DispatchError(EventType aErrorType, SpeechRecognitionErrorCode aErrorCode, - const nsAString& aMessage) { + const nsACString& aMessage) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aErrorType == EVENT_RECOGNITIONSERVICE_ERROR || aErrorType == EVENT_AUDIO_ERROR, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webspeech/recognition/SpeechRecognition.h firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webspeech/recognition/SpeechRecognition.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webspeech/recognition/SpeechRecognition.h 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webspeech/recognition/SpeechRecognition.h 2020-11-17 19:31:27.000000000 +0000 @@ -134,10 +134,17 @@ }; void NotifyTrackAdded(const RefPtr& aTrack) override; - + // aMessage should be valid UTF-8, but invalid UTF-8 byte sequences are + // replaced with the REPLACEMENT CHARACTER on conversion to UTF-16. + void DispatchError(EventType aErrorType, + SpeechRecognitionErrorCode aErrorCode, + const nsACString& aMessage); + template void DispatchError(EventType aErrorType, SpeechRecognitionErrorCode aErrorCode, - const nsAString& aMessage); + const char (&aMessage)[N]) { + DispatchError(aErrorType, aErrorCode, nsLiteralCString(aMessage)); + } uint32_t FillSamplesBuffer(const int16_t* aSamples, uint32_t aSampleCount); uint32_t SplitSamplesBuffer(const int16_t* aSamplesBuffer, uint32_t aSampleCount, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/media/webspeech/recognition/test/FakeSpeechRecognitionService.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -84,7 +84,7 @@ mRecognition->DispatchError( SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR, SpeechRecognitionErrorCode::Network, // TODO different codes? - u"RECOGNITIONSERVICE_ERROR test event"_ns); + "RECOGNITIONSERVICE_ERROR test event"); } else if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_FINAL_RESULT")) { RefPtr event = new SpeechEvent( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/general/browser.ini firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/general/browser.ini --- firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/general/browser.ini 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/general/browser.ini 2020-11-17 19:31:28.000000000 +0000 @@ -23,7 +23,6 @@ file_assert_systemprincipal_documents.html file_assert_systemprincipal_documents_iframe.html [browser_test_referrer_loadInOtherProcess.js] -skip-if = fission [browser_test_framing_error_pages.js] support-files = file_framing_error_pages_csp.html diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/general/browser_test_FTP_console_warning.js firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/general/browser_test_FTP_console_warning.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/general/browser_test_FTP_console_warning.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/general/browser_test_FTP_console_warning.js 2020-11-17 19:31:28.000000000 +0000 @@ -37,7 +37,7 @@ Services.console.registerListener(on_new_message); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, kTestURI); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, kTestURI); await BrowserTestUtils.waitForCondition(() => seen_files.length === 0); is(seen_files.length, 0, "All FTP subresources should be blocked"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js 2020-11-17 19:31:28.000000000 +0000 @@ -131,11 +131,6 @@ // Tests referrerInfo when navigating from a page in the remote process to main // process and vice versa. -// The changing process code flow is (cpp) docshell.shouldLoadURI -// -> (JS) browser.shouldLoadURI -> E10sUtils.redirectLoad -// -> ContentRestore.restoreTabContent. -// Finally, docshell will do the load in correct process with the input -// referrerInfo and store an entry to SessionHistory add_task(async function test_navigation() { // Navigate from non remote to remote gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/https-only/browser_console_logging.js firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/https-only/browser_console_logging.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/https-only/browser_console_logging.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/https-only/browser_console_logging.js 2020-11-17 19:31:28.000000000 +0000 @@ -87,7 +87,7 @@ }); Services.console.registerListener(on_new_message); // 1. Upgrade page to https:// - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, kTestURISuccess); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, kTestURISuccess); // 2. Make an exempt http:// request let xhr = new XMLHttpRequest(); xhr.open("GET", kTestURIExempt, true); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/mixedcontentblocker/browser_mixed_content_auto_upgrade_display_console.js firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/mixedcontentblocker/browser_mixed_content_auto_upgrade_display_console.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/security/test/mixedcontentblocker/browser_mixed_content_auto_upgrade_display_console.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/security/test/mixedcontentblocker/browser_mixed_content_auto_upgrade_display_console.js 2020-11-17 19:31:28.000000000 +0000 @@ -22,7 +22,7 @@ }); Services.console.registerListener(on_auto_upgrade_message); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, kTestURI); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, kTestURI); await BrowserTestUtils.waitForCondition(() => seenAutoUpgradeMessage); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser_antitracking.js firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser_antitracking.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser_antitracking.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser_antitracking.js 2020-11-17 19:31:28.000000000 +0000 @@ -72,7 +72,7 @@ let browserLoadedPromise = BrowserTestUtils.browserLoaded( topTab.linkedBrowser ); - await BrowserTestUtils.loadURI(topTab.linkedBrowser, TOP_EMPTY_PAGE); + BrowserTestUtils.loadURI(topTab.linkedBrowser, TOP_EMPTY_PAGE); await browserLoadedPromise; // Create Iframe in the top-level page and verify its state. @@ -92,7 +92,7 @@ // ## Cleanup info("Loading the SW unregister page: " + SW_REGISTER_PAGE); browserLoadedPromise = BrowserTestUtils.browserLoaded(topTab.linkedBrowser); - await BrowserTestUtils.loadURI(topTab.linkedBrowser, SW_REGISTER_PAGE); + BrowserTestUtils.loadURI(topTab.linkedBrowser, SW_REGISTER_PAGE); await browserLoadedPromise; await SpecialPowers.spawn(topTab.linkedBrowser, [], async function() { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser_antitracking_subiframes.js firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser_antitracking_subiframes.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser_antitracking_subiframes.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser_antitracking_subiframes.js 2020-11-17 19:31:28.000000000 +0000 @@ -57,7 +57,7 @@ let browserLoadedPromise = BrowserTestUtils.browserLoaded( topTab.linkedBrowser ); - await BrowserTestUtils.loadURI(topTab.linkedBrowser, TOP_EMPTY_PAGE); + BrowserTestUtils.loadURI(topTab.linkedBrowser, TOP_EMPTY_PAGE); await browserLoadedPromise; // Create Iframe in the top-level page and verify its state. @@ -93,7 +93,7 @@ info("Loading the SW unregister page: " + SW_REGISTER_PAGE); browserLoadedPromise = BrowserTestUtils.browserLoaded(topTab.linkedBrowser); - await BrowserTestUtils.loadURI(topTab.linkedBrowser, SW_REGISTER_PAGE); + BrowserTestUtils.loadURI(topTab.linkedBrowser, SW_REGISTER_PAGE); await browserLoadedPromise; await SpecialPowers.spawn(topTab.linkedBrowser, [], async function() { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser_force_refresh.js firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser_force_refresh.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser_force_refresh.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser_force_refresh.js 2020-11-17 19:31:28.000000000 +0000 @@ -79,7 +79,7 @@ var tab = BrowserTestUtils.addTab(gBrowser); var tabBrowser = gBrowser.getBrowserForTab(tab); gBrowser.selectedTab = tab; - await BrowserTestUtils.loadURI(gBrowser, url); + BrowserTestUtils.loadURI(gBrowser, url); } ); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser.ini firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser.ini --- firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser.ini 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser.ini 2020-11-17 19:31:28.000000000 +0000 @@ -26,6 +26,7 @@ [browser_devtools_serviceworker_interception.js] skip-if = serviceworker_e10s [browser_force_refresh.js] +skip-if = verify # Bug 1603340 [browser_download.js] [browser_download_canceled.js] skip-if = verify diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser_remote_type_process_swap.js firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser_remote_type_process_swap.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/serviceworkers/test/browser_remote_type_process_swap.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/serviceworkers/test/browser_remote_type_process_swap.js 2020-11-17 19:31:28.000000000 +0000 @@ -36,7 +36,7 @@ async function loadURI(aXULBrowser, aURI) { const browserLoadedPromise = BrowserTestUtils.browserLoaded(aXULBrowser); - await BrowserTestUtils.loadURI(aXULBrowser, aURI); + BrowserTestUtils.loadURI(aXULBrowser, aURI); return browserLoadedPromise; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/system/tests/ioutils/test_ioutils_read_write.html firefox-trunk-85.0~a1~hg20201117r557492/dom/system/tests/ioutils/test_ioutils_read_write.html --- firefox-trunk-84.0~a1~hg20201115r557261/dom/system/tests/ioutils/test_ioutils_read_write.html 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/system/tests/ioutils/test_ioutils_read_write.html 2020-11-17 19:31:28.000000000 +0000 @@ -356,7 +356,17 @@ await Assert.rejects( IOUtils.read(tmpFileName, { decompress: true }), - /Could not decompress file because it has an invalid LZ4 header \(wrong magic number: .*\)/, + (actual) => { + is(actual.constructor, DOMException, + "rejection reason constructor for decompress with bad header"); + is(actual.name, "NotReadableError", + "rejection error name for decompress with bad header"); + ok(/Could not decompress file because it has an invalid LZ4 header \(wrong magic number: .*\)/ + .test(actual.message), + "rejection error message for decompress with bad header. Got " + + actual.message); + return true; + }, "IOUtils::read fails to decompress LZ4 data with a bad header" ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/browser/browser_beforeunload_between_chrome_content.js firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/browser/browser_beforeunload_between_chrome_content.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/browser/browser_beforeunload_between_chrome_content.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/browser/browser_beforeunload_between_chrome_content.js 2020-11-17 19:31:28.000000000 +0000 @@ -67,7 +67,7 @@ await injectBeforeUnload(browser); // Navigate to a chrome page. let dialogShown1 = awaitAndCloseBeforeUnloadDialog(false); - await BrowserTestUtils.loadURI(browser, "about:support"); + BrowserTestUtils.loadURI(browser, "about:support"); await Promise.all([dialogShown1, BrowserTestUtils.browserLoaded(browser)]); is(beforeUnloadCount, 1, "Should have received one beforeunload event."); @@ -122,7 +122,7 @@ // Navigate to a content page. let dialogShown1 = awaitAndCloseBeforeUnloadDialog(false); - await BrowserTestUtils.loadURI(browser, TEST_URL); + BrowserTestUtils.loadURI(browser, TEST_URL); await Promise.all([dialogShown1, BrowserTestUtils.browserLoaded(browser)]); is(beforeUnloadCount, 1, "Should have received one beforeunload event."); ok(browser.isRemoteBrowser, "Browser should be remote."); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/browser/browser_focus_steal_from_chrome.js firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/browser/browser_focus_steal_from_chrome.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/browser/browser_focus_steal_from_chrome.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/browser/browser_focus_steal_from_chrome.js 2020-11-17 19:31:28.000000000 +0000 @@ -77,9 +77,9 @@ fg.focus(); // Load the URIs. - await BrowserTestUtils.loadURI(bg, test.uri); + BrowserTestUtils.loadURI(bg, test.uri); await BrowserTestUtils.browserLoaded(bg); - await BrowserTestUtils.loadURI(fg, test.uri); + BrowserTestUtils.loadURI(fg, test.uri); await BrowserTestUtils.browserLoaded(fg); ok(true, "Test1: Both of the tabs are loaded"); @@ -146,15 +146,15 @@ let originalFocus = Services.focus.focusedElement; // Load about:blank just to make sure that everything works nicely - await BrowserTestUtils.loadURI(bg, "about:blank"); + BrowserTestUtils.loadURI(bg, "about:blank"); await BrowserTestUtils.browserLoaded(bg); - await BrowserTestUtils.loadURI(fg, "about:blank"); + BrowserTestUtils.loadURI(fg, "about:blank"); await BrowserTestUtils.browserLoaded(fg); // Load the URIs. - await BrowserTestUtils.loadURI(bg, test.uri); + BrowserTestUtils.loadURI(bg, test.uri); await BrowserTestUtils.browserLoaded(bg); - await BrowserTestUtils.loadURI(fg, test.uri); + BrowserTestUtils.loadURI(fg, test.uri); await BrowserTestUtils.browserLoaded(fg); ok(true, "Test2: Both of the tabs are loaded"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/browser/browser_test_new_window_from_content.js firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/browser/browser_test_new_window_from_content.js --- firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/browser/browser_test_new_window_from_content.js 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/browser/browser_test_new_window_from_content.js 2020-11-17 19:31:28.000000000 +0000 @@ -116,7 +116,7 @@ await BrowserTestUtils.browserLoaded(aBrowser); is(aBrowser.currentURI.spec, expectedSpec, "Should be at dummy.html"); // Now put the browser back where it came from - await BrowserTestUtils.loadURI(aBrowser, kContentDoc); + BrowserTestUtils.loadURI(aBrowser, kContentDoc); await BrowserTestUtils.browserLoaded(aBrowser); })(); case kNewWin: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/mochitest/beacon/test_beaconWithSafelistedContentType.html firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/mochitest/beacon/test_beaconWithSafelistedContentType.html --- firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/mochitest/beacon/test_beaconWithSafelistedContentType.html 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/mochitest/beacon/test_beaconWithSafelistedContentType.html 2020-11-17 19:31:28.000000000 +0000 @@ -60,7 +60,7 @@ testOnPrivateWindow(); }, "cookie-changed"); let testURL = baseURL + "file_beaconSafelist.html"; - await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, testURL); + BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, testURL); await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser, false, testURL); await SpecialPowers.spawn(win.gBrowser.selectedBrowser, [], async () => { await new Promise((resolve, reject) => { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/mochitest/general/test_focusrings.xhtml firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/mochitest/general/test_focusrings.xhtml --- firefox-trunk-84.0~a1~hg20201115r557261/dom/tests/mochitest/general/test_focusrings.xhtml 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/tests/mochitest/general/test_focusrings.xhtml 2020-11-17 19:31:28.000000000 +0000 @@ -155,8 +155,10 @@ mouseRingSize = textControl ? "1px" : "2px"; } - if (elem.localName == "a") + if (elem.localName == "a") { mouseRingSize = ringSize = "0px"; + expectedMatchWithMouse = expectedMatchWithMouse && !isMac; + } synthesizeMouse(elem, 8, 8, { }, childwin); is(childdoc.activeElement, shouldFocus ? elem : childdoc.body, "mouse click on " + list[e]); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Adapter.h firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Adapter.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Adapter.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Adapter.h 2020-11-17 19:31:28.000000000 +0000 @@ -12,6 +12,7 @@ #include "ObjectModel.h" namespace mozilla { +class ErrorResult; namespace dom { class Promise; struct GPUDeviceDescriptor; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/BindGroup.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/BindGroup.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/BindGroup.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/BindGroup.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,7 @@ #include "mozilla/dom/WebGPUBinding.h" #include "BindGroup.h" +#include "ipc/WebGPUChild.h" #include "Device.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/BindGroupLayout.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/BindGroupLayout.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/BindGroupLayout.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/BindGroupLayout.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,7 @@ #include "mozilla/dom/WebGPUBinding.h" #include "BindGroupLayout.h" +#include "ipc/WebGPUChild.h" #include "Device.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Buffer.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Buffer.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Buffer.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Buffer.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -6,8 +6,10 @@ #include "mozilla/dom/WebGPUBinding.h" #include "Buffer.h" +#include "mozilla/dom/Promise.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/ipc/Shmem.h" +#include "ipc/WebGPUChild.h" #include "js/RootingAPI.h" #include "nsContentUtils.h" #include "nsWrapperCache.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/CanvasContext.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/CanvasContext.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/CanvasContext.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/CanvasContext.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -12,6 +12,7 @@ #include "mozilla/layers/CompositorManagerChild.h" #include "mozilla/layers/RenderRootStateManager.h" #include "mozilla/layers/WebRenderBridgeChild.h" +#include "ipc/WebGPUChild.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/CommandBuffer.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/CommandBuffer.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/CommandBuffer.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/CommandBuffer.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,7 @@ #include "mozilla/dom/WebGPUBinding.h" #include "CommandBuffer.h" +#include "ipc/WebGPUChild.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "Device.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/CommandEncoder.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/CommandEncoder.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/CommandEncoder.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/CommandEncoder.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -11,6 +11,9 @@ #include "ComputePassEncoder.h" #include "Device.h" #include "RenderPassEncoder.h" +#include "mozilla/dom/HTMLCanvasElement.h" +#include "mozilla/webgpu/ffi/wgpu.h" +#include "ipc/WebGPUChild.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/CommandEncoder.h firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/CommandEncoder.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/CommandEncoder.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/CommandEncoder.h 2020-11-17 19:31:28.000000000 +0000 @@ -13,6 +13,9 @@ namespace mozilla { namespace dom { +struct GPUComputePassDescriptor; +struct GPUTextureDataLayout; +class HTMLCanvasElement; template class Sequence; class GPUComputePipelineOrGPURenderPipeline; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ComputePassEncoder.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ComputePassEncoder.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ComputePassEncoder.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ComputePassEncoder.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -7,6 +7,7 @@ #include "ComputePassEncoder.h" #include "BindGroup.h" #include "ComputePipeline.h" +#include "CommandEncoder.h" #include "mozilla/webgpu/ffi/wgpu.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ComputePipeline.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ComputePipeline.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ComputePipeline.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ComputePipeline.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -6,6 +6,8 @@ #include "ComputePipeline.h" #include "Device.h" +#include "ipc/WebGPUChild.h" +#include "mozilla/dom/WebGPUBinding.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ComputePipeline.h firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ComputePipeline.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ComputePipeline.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ComputePipeline.h 2020-11-17 19:31:28.000000000 +0000 @@ -8,6 +8,8 @@ #include "nsWrapperCache.h" #include "ObjectModel.h" +#include "mozilla/webgpu/WebGPUTypes.h" +#include "nsTArray.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Device.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Device.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Device.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Device.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -9,6 +9,8 @@ #include "mozilla/ipc/Shmem.h" #include "mozilla/dom/WebGPUBinding.h" #include "Device.h" +#include "CommandEncoder.h" +#include "BindGroup.h" #include "Adapter.h" #include "Buffer.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/DeviceLostInfo.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/DeviceLostInfo.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/DeviceLostInfo.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/DeviceLostInfo.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -4,6 +4,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DeviceLostInfo.h" +#include "mozilla/dom/WebGPUBinding.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Instance.h firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Instance.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Instance.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Instance.h 2020-11-17 19:31:28.000000000 +0000 @@ -12,6 +12,7 @@ #include "ObjectModel.h" namespace mozilla { +class ErrorResult; namespace dom { class Promise; struct GPURequestAdapterOptions; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ipc/WebGPUChild.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ipc/WebGPUChild.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ipc/WebGPUChild.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ipc/WebGPUChild.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -6,6 +6,7 @@ #include "WebGPUChild.h" #include "mozilla/dom/WebGPUBinding.h" #include "mozilla/webgpu/ffi/wgpu.h" +#include "Sampler.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/mochitest/mochitest.ini firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/mochitest/mochitest.ini --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/mochitest/mochitest.ini 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/mochitest/mochitest.ini 2020-11-17 19:31:28.000000000 +0000 @@ -1,7 +1,8 @@ [DEFAULT] subsuite = webgpu -prefs = dom.webgpu.enabled=true -run_if = nightly_build +run-if = nightly_build && webrender +prefs = + dom.webgpu.enabled=true [test_enabled.html] [test_device_creation.html] diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ObjectModel.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ObjectModel.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ObjectModel.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ObjectModel.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -9,6 +9,7 @@ #include "Device.h" #include "CommandEncoder.h" #include "Instance.h" +#include "Texture.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/OutOfMemoryError.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/OutOfMemoryError.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/OutOfMemoryError.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/OutOfMemoryError.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,7 @@ #include "OutOfMemoryError.h" #include "Device.h" +#include "mozilla/dom/WebGPUBinding.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/PipelineLayout.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/PipelineLayout.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/PipelineLayout.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/PipelineLayout.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,7 @@ #include "mozilla/dom/WebGPUBinding.h" #include "PipelineLayout.h" +#include "ipc/WebGPUChild.h" #include "Device.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/RenderPassEncoder.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/RenderPassEncoder.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/RenderPassEncoder.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/RenderPassEncoder.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -8,6 +8,7 @@ #include "BindGroup.h" #include "CommandEncoder.h" #include "RenderPipeline.h" +#include "mozilla/webgpu/ffi/wgpu.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/RenderPipeline.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/RenderPipeline.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/RenderPipeline.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/RenderPipeline.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -6,6 +6,8 @@ #include "RenderPipeline.h" #include "Device.h" +#include "ipc/WebGPUChild.h" +#include "mozilla/dom/WebGPUBinding.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/RenderPipeline.h firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/RenderPipeline.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/RenderPipeline.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/RenderPipeline.h 2020-11-17 19:31:28.000000000 +0000 @@ -8,10 +8,13 @@ #include "nsWrapperCache.h" #include "ObjectModel.h" +#include "mozilla/webgpu/WebGPUTypes.h" +#include "nsTArray.h" namespace mozilla { namespace webgpu { +class BindGroupLayout; class Device; class RenderPipeline final : public ObjectBase, public ChildOf { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Sampler.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Sampler.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Sampler.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Sampler.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,7 @@ #include "mozilla/dom/WebGPUBinding.h" #include "Sampler.h" +#include "ipc/WebGPUChild.h" #include "Device.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ShaderModule.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ShaderModule.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ShaderModule.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ShaderModule.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,7 @@ #include "mozilla/dom/WebGPUBinding.h" #include "ShaderModule.h" +#include "ipc/WebGPUChild.h" #include "Device.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/SwapChain.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/SwapChain.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/SwapChain.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/SwapChain.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,8 @@ #include "SwapChain.h" #include "Texture.h" +#include "mozilla/dom/WebGPUBinding.h" +#include "ipc/WebGPUChild.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Texture.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Texture.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Texture.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Texture.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,8 +5,10 @@ #include "Texture.h" +#include "ipc/WebGPUChild.h" #include "mozilla/webgpu/ffi/wgpu.h" #include "mozilla/dom/HTMLCanvasElement.h" +#include "mozilla/dom/WebGPUBinding.h" #include "TextureView.h" namespace mozilla { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Texture.h firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Texture.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/Texture.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/Texture.h 2020-11-17 19:31:28.000000000 +0000 @@ -8,6 +8,8 @@ #include "nsWrapperCache.h" #include "ObjectModel.h" +#include "mozilla/webgpu/WebGPUTypes.h" +#include "mozilla/WeakPtr.h" namespace mozilla { namespace dom { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/TextureView.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/TextureView.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/TextureView.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/TextureView.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -6,6 +6,9 @@ #include "TextureView.h" #include "Device.h" +#include "mozilla/dom/HTMLCanvasElement.h" +#include "mozilla/dom/WebGPUBinding.h" +#include "ipc/WebGPUChild.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/TextureView.h firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/TextureView.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/TextureView.h 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/TextureView.h 2020-11-17 19:31:28.000000000 +0000 @@ -8,6 +8,7 @@ #include "nsWrapperCache.h" #include "ObjectModel.h" +#include "mozilla/webgpu/WebGPUTypes.h" namespace mozilla { namespace dom { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ValidationError.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ValidationError.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/webgpu/ValidationError.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/webgpu/ValidationError.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,7 @@ #include "ValidationError.h" #include "Device.h" +#include "mozilla/dom/WebGPUBinding.h" namespace mozilla { namespace webgpu { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/Principal.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/Principal.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/Principal.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/Principal.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -9,6 +9,7 @@ #include "jsapi.h" #include "mozilla/Assertions.h" #include "mozilla/dom/StructuredCloneTags.h" +#include "mozilla/dom/workerinternals/JSSettings.h" namespace mozilla { namespace dom { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerController.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerController.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerController.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerController.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -16,6 +16,7 @@ #include "mozilla/RemoteLazyInputStreamUtils.h" #include "mozilla/RemoteLazyInputStreamStorage.h" #include "mozilla/ScopeExit.h" +#include "mozilla/dom/FetchEventOpParent.h" #include "mozilla/dom/FetchEventOpProxyParent.h" #include "mozilla/dom/MessagePortParent.h" #include "mozilla/dom/RemoteWorkerTypes.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerControllerParent.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerControllerParent.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerControllerParent.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerControllerParent.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -16,6 +16,7 @@ #include "mozilla/Assertions.h" #include "mozilla/Unused.h" #include "mozilla/dom/FetchEventOpParent.h" +#include "mozilla/dom/RemoteWorkerParent.h" #include "mozilla/dom/ServiceWorkerOpPromise.h" #include "mozilla/ipc/BackgroundParent.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerManager.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerManager.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerManager.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerManager.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -11,6 +11,7 @@ #include "mozilla/SchedulerGroup.h" #include "mozilla/ScopeExit.h" #include "mozilla/dom/ContentChild.h" // ContentChild::GetSingleton +#include "mozilla/dom/RemoteWorkerController.h" #include "mozilla/dom/RemoteWorkerParent.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/BackgroundUtils.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerParent.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerParent.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerParent.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerParent.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -9,6 +9,7 @@ #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/PFetchEventOpProxyParent.h" #include "mozilla/ipc/BackgroundParent.h" +#include "mozilla/SchedulerGroup.h" #include "mozilla/Unused.h" #include "nsProxyRelease.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerService.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerService.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerService.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerService.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -11,6 +11,7 @@ #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/PBackgroundChild.h" #include "mozilla/ipc/PBackgroundParent.h" +#include "mozilla/SchedulerGroup.h" #include "mozilla/Services.h" #include "mozilla/StaticMutex.h" #include "mozilla/StaticPtr.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerServiceParent.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerServiceParent.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/remoteworkers/RemoteWorkerServiceParent.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/remoteworkers/RemoteWorkerServiceParent.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -6,6 +6,7 @@ #include "RemoteWorkerServiceParent.h" #include "RemoteWorkerManager.h" +#include "mozilla/ipc/BackgroundParent.h" namespace mozilla { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/ScriptLoader.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/ScriptLoader.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/ScriptLoader.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/ScriptLoader.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -72,6 +72,7 @@ #include "mozilla/dom/Response.h" #include "mozilla/dom/ScriptLoader.h" #include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/SerializedStackHolder.h" #include "mozilla/dom/SRILogHelper.h" #include "mozilla/dom/ServiceWorkerBinding.h" #include "mozilla/dom/ServiceWorkerManager.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/sharedworkers/SharedWorkerChild.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/sharedworkers/SharedWorkerChild.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/sharedworkers/SharedWorkerChild.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/sharedworkers/SharedWorkerChild.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -8,6 +8,7 @@ #include "mozilla/dom/ErrorEvent.h" #include "mozilla/dom/ErrorEventBinding.h" #include "mozilla/dom/Exceptions.h" +#include "mozilla/dom/SharedWorker.h" #include "mozilla/dom/WorkerError.h" namespace mozilla { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/sharedworkers/SharedWorkerManager.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/sharedworkers/SharedWorkerManager.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/sharedworkers/SharedWorkerManager.cpp 2020-11-15 14:37:56.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/sharedworkers/SharedWorkerManager.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -7,6 +7,7 @@ #include "SharedWorkerManager.h" #include "SharedWorkerParent.h" #include "SharedWorkerService.h" +#include "mozilla/dom/MessagePort.h" #include "mozilla/dom/PSharedWorker.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ipc/URIUtils.h" @@ -61,7 +62,7 @@ bool SharedWorkerManager::MaybeCreateRemoteWorker( const RemoteWorkerData& aData, uint64_t aWindowID, UniqueMessagePortId& aPortIdentifier, base::ProcessId aProcessId) { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); if (!mRemoteWorkerController) { mRemoteWorkerController = @@ -108,7 +109,7 @@ } void SharedWorkerManager::AddActor(SharedWorkerParent* aParent) { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); MOZ_ASSERT(aParent); MOZ_ASSERT(!mActors.Contains(aParent)); @@ -121,7 +122,7 @@ } void SharedWorkerManager::RemoveActor(SharedWorkerParent* aParent) { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); MOZ_ASSERT(aParent); MOZ_ASSERT(mActors.Contains(aParent)); @@ -141,7 +142,7 @@ } void SharedWorkerManager::Terminate() { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); MOZ_ASSERT(mActors.IsEmpty()); MOZ_ASSERT(mHolders.IsEmpty()); @@ -150,7 +151,7 @@ } void SharedWorkerManager::UpdateSuspend() { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); MOZ_ASSERT(mRemoteWorkerController); uint32_t suspended = 0; @@ -178,7 +179,7 @@ } void SharedWorkerManager::UpdateFrozen() { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); MOZ_ASSERT(mRemoteWorkerController); uint32_t frozen = 0; @@ -208,7 +209,7 @@ bool SharedWorkerManager::IsSecureContext() const { return mIsSecureContext; } void SharedWorkerManager::CreationFailed() { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); for (SharedWorkerParent* actor : mActors) { Unused << actor->SendError(NS_ERROR_FAILURE); @@ -216,12 +217,12 @@ } void SharedWorkerManager::CreationSucceeded() { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); // Nothing to do here. } void SharedWorkerManager::ErrorReceived(const ErrorValue& aValue) { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); for (SharedWorkerParent* actor : mActors) { Unused << actor->SendError(aValue); @@ -229,7 +230,7 @@ } void SharedWorkerManager::Terminated() { - AssertIsOnBackgroundThread(); + ::mozilla::ipc::AssertIsOnBackgroundThread(); for (SharedWorkerParent* actor : mActors) { Unused << actor->SendTerminate(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/sharedworkers/SharedWorkerService.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/sharedworkers/SharedWorkerService.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/sharedworkers/SharedWorkerService.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/sharedworkers/SharedWorkerService.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,7 +5,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "SharedWorkerService.h" +#include "mozilla/dom/MessagePort.h" #include "mozilla/dom/RemoteWorkerTypes.h" +#include "mozilla/dom/SharedWorkerManager.h" #include "mozilla/ipc/BackgroundParent.h" #include "mozilla/ClearOnShutdown.h" #include "mozilla/SchedulerGroup.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/sharedworkers/SharedWorkerService.h firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/sharedworkers/SharedWorkerService.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/sharedworkers/SharedWorkerService.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/sharedworkers/SharedWorkerService.h 2020-11-17 19:31:28.000000000 +0000 @@ -11,6 +11,8 @@ #include "nsISupportsImpl.h" #include "nsTArray.h" +class nsIEventTarget; + namespace mozilla { namespace ipc { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/WorkerCSPEventListener.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/WorkerCSPEventListener.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/WorkerCSPEventListener.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/WorkerCSPEventListener.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -9,6 +9,7 @@ #include "WorkerRef.h" #include "mozilla/dom/SecurityPolicyViolationEvent.h" #include "mozilla/dom/SecurityPolicyViolationEventBinding.h" +#include "mozilla/dom/WorkerRunnable.h" using namespace mozilla::dom; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/WorkerCSPEventListener.h firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/WorkerCSPEventListener.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/WorkerCSPEventListener.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/WorkerCSPEventListener.h 2020-11-17 19:31:28.000000000 +0000 @@ -7,6 +7,7 @@ #ifndef mozilla_dom_WorkerCSPEventListener_h #define mozilla_dom_WorkerCSPEventListener_h +#include "mozilla/dom/WorkerRef.h" #include "mozilla/Mutex.h" #include "nsIContentSecurityPolicy.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/WorkerEventTarget.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/WorkerEventTarget.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/WorkerEventTarget.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/WorkerEventTarget.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -5,6 +5,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WorkerEventTarget.h" +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" namespace mozilla { namespace dom { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/WorkerScope.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/WorkerScope.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/workers/WorkerScope.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/workers/WorkerScope.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -12,6 +12,7 @@ #include "Principal.h" #include "jsapi.h" #include "jsfriendapi.h" +#include "js/CompilationAndEvaluation.h" #include "mozilla/CycleCollectedJSContext.h" #include "mozilla/MozPromise.h" #include "mozilla/StorageAccess.h" @@ -25,16 +26,19 @@ #include "mozilla/dom/Fetch.h" #include "mozilla/dom/IDBFactory.h" #include "mozilla/dom/ImageBitmap.h" +#include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/Performance.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseWorkerProxy.h" #include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/SerializedStackHolder.h" #include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h" #include "mozilla/dom/ServiceWorkerManager.h" #include "mozilla/dom/ServiceWorkerRegistration.h" #include "mozilla/dom/ServiceWorkerUtils.h" #include "mozilla/dom/SharedWorkerGlobalScopeBinding.h" #include "mozilla/dom/SimpleGlobalObject.h" +#include "mozilla/dom/TimeoutHandler.h" #include "mozilla/dom/WorkerCommon.h" #include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h" #include "mozilla/dom/WorkerGlobalScopeBinding.h" @@ -46,6 +50,8 @@ #include "nsDebug.h" #include "nsISerialEventTarget.h" #include "nsJSUtils.h" +#include "nsQueryObject.h" +#include "ScriptLoader.h" #include "xpcpublic.h" #ifdef ANDROID diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/worklet/WorkletGlobalScope.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/worklet/WorkletGlobalScope.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/worklet/WorkletGlobalScope.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/worklet/WorkletGlobalScope.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -7,6 +7,7 @@ #include "WorkletGlobalScope.h" #include "mozilla/dom/WorkletGlobalScopeBinding.h" #include "mozilla/dom/WorkletImpl.h" +#include "mozilla/dom/WorkletThread.h" #include "mozilla/dom/Console.h" #include "nsJSUtils.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/worklet/WorkletImpl.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/worklet/WorkletImpl.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/worklet/WorkletImpl.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/worklet/WorkletImpl.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -14,6 +14,7 @@ #include "mozilla/dom/RegisterWorkletBindings.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/WorkletBinding.h" +#include "mozilla/dom/WorkletGlobalScope.h" #include "nsGlobalWindowInner.h" namespace mozilla { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/worklet/WorkletPrincipals.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/worklet/WorkletPrincipals.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/worklet/WorkletPrincipals.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/worklet/WorkletPrincipals.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -6,6 +6,7 @@ #include "WorkletPrincipals.h" +#include "mozilla/dom/WorkletImpl.h" #include "nsJSPrincipals.h" namespace mozilla { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/worklet/WorkletThread.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/worklet/WorkletThread.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/worklet/WorkletThread.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/worklet/WorkletThread.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -9,8 +9,11 @@ #include "nsContentUtils.h" #include "nsCycleCollector.h" #include "mozilla/dom/AtomList.h" +#include "mozilla/dom/WorkletGlobalScope.h" +#include "mozilla/dom/WorkletPrincipals.h" #include "mozilla/ipc/BackgroundChild.h" #include "mozilla/Attributes.h" +#include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/EventQueue.h" #include "mozilla/ThreadEventQueue.h" #include "js/Exception.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/xhr/XMLHttpRequestMainThread.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/xhr/XMLHttpRequestMainThread.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/xhr/XMLHttpRequestMainThread.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/xhr/XMLHttpRequestMainThread.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -64,6 +64,7 @@ #include "nsVariant.h" #include "nsIScriptError.h" #include "nsICachingChannel.h" +#include "nsICookieJarSettings.h" #include "nsContentUtils.h" #include "nsCycleCollectionParticipant.h" #include "nsError.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/xhr/XMLHttpRequestString.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/xhr/XMLHttpRequestString.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/xhr/XMLHttpRequestString.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/xhr/XMLHttpRequestString.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -164,6 +164,8 @@ XMLHttpRequestString& aString) : mBuffer(aString.mBuffer), mLock(aString.mBuffer->mMutex) {} +XMLHttpRequestStringWriterHelper::~XMLHttpRequestStringWriterHelper() = default; + uint32_t XMLHttpRequestStringWriterHelper::Length() const { return mBuffer->UnsafeLength(); } @@ -181,6 +183,9 @@ XMLHttpRequestStringSnapshot& aSnapshot) : mBuffer(aSnapshot.mBuffer), mLock(aSnapshot.mBuffer->mMutex) {} +XMLHttpRequestStringSnapshotReaderHelper:: + ~XMLHttpRequestStringSnapshotReaderHelper() = default; + const char16_t* XMLHttpRequestStringSnapshotReaderHelper::Buffer() const { return mBuffer->UnsafeData().BeginReading(); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/xhr/XMLHttpRequestString.h firefox-trunk-85.0~a1~hg20201117r557492/dom/xhr/XMLHttpRequestString.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/xhr/XMLHttpRequestString.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/xhr/XMLHttpRequestString.h 2020-11-17 19:31:28.000000000 +0000 @@ -13,6 +13,8 @@ namespace mozilla { namespace dom { +class ArrayBufferBuilder; +class BlobImpl; class DOMString; class XMLHttpRequestStringBuffer; class XMLHttpRequestStringSnapshot; @@ -61,6 +63,7 @@ class MOZ_STACK_CLASS XMLHttpRequestStringWriterHelper final { public: explicit XMLHttpRequestStringWriterHelper(XMLHttpRequestString& aString); + ~XMLHttpRequestStringWriterHelper(); /** * The existing length of the string. Do not call during BulkWrite(). @@ -126,6 +129,7 @@ public: explicit XMLHttpRequestStringSnapshotReaderHelper( XMLHttpRequestStringSnapshot& aSnapshot); + ~XMLHttpRequestStringSnapshotReaderHelper(); const char16_t* Buffer() const; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/xhr/XMLHttpRequestWorker.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/xhr/XMLHttpRequestWorker.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/xhr/XMLHttpRequestWorker.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/xhr/XMLHttpRequestWorker.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -12,6 +12,7 @@ #include "jsfriendapi.h" #include "js/ArrayBuffer.h" // JS::Is{,Detached}ArrayBufferObject #include "js/GCPolicyAPI.h" +#include "js/JSON.h" #include "js/RootingAPI.h" // JS::{Handle,Heap},PersistentRooted #include "js/TracingAPI.h" #include "js/Value.h" // JS::{Undefined,}Value @@ -21,6 +22,7 @@ #include "mozilla/dom/File.h" #include "mozilla/dom/FormData.h" #include "mozilla/dom/ProgressEvent.h" +#include "mozilla/dom/SerializedStackHolder.h" #include "mozilla/dom/StreamBlobImpl.h" #include "mozilla/dom/StructuredCloneHolder.h" #include "mozilla/dom/UnionConversions.h" @@ -36,6 +38,7 @@ #include "nsJSUtils.h" #include "nsThreadUtils.h" +#include "XMLHttpRequestMainThread.h" #include "XMLHttpRequestUpload.h" #include "mozilla/UniquePtr.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/xml/nsXMLContentSink.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/xml/nsXMLContentSink.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/xml/nsXMLContentSink.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/xml/nsXMLContentSink.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -18,6 +18,7 @@ #include "nsGkAtoms.h" #include "nsContentUtils.h" #include "nsDocElementCreatedNotificationRunner.h" +#include "nsIDocShell.h" #include "nsIScriptContext.h" #include "nsNameSpaceManager.h" #include "nsIScriptSecurityManager.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/xml/nsXMLContentSink.h firefox-trunk-85.0~a1~hg20201117r557492/dom/xml/nsXMLContentSink.h --- firefox-trunk-84.0~a1~hg20201115r557261/dom/xml/nsXMLContentSink.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/xml/nsXMLContentSink.h 2020-11-17 19:31:29.000000000 +0000 @@ -103,7 +103,8 @@ // stylesheets are all done loading. virtual void MaybeStartLayout(bool aIgnorePendingSheets); - virtual nsresult AddAttributes(const char16_t** aNode, Element* aElement); + virtual nsresult AddAttributes(const char16_t** aNode, + mozilla::dom::Element* aElement); nsresult AddText(const char16_t* aString, int32_t aLength); virtual bool OnOpenContainer(const char16_t** aAtts, uint32_t aAttsCount, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/dom/xml/nsXMLFragmentContentSink.cpp firefox-trunk-85.0~a1~hg20201117r557492/dom/xml/nsXMLFragmentContentSink.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/dom/xml/nsXMLFragmentContentSink.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/dom/xml/nsXMLFragmentContentSink.cpp 2020-11-17 19:31:28.000000000 +0000 @@ -17,6 +17,7 @@ #include "mozilla/dom/NodeInfo.h" #include "nsContentCreatorFunctions.h" #include "nsError.h" +#include "nsIDocShell.h" #include "nsIScriptError.h" #include "nsTHashtable.h" #include "nsHashKeys.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContextEGL.h firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContextEGL.h --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContextEGL.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContextEGL.h 2020-11-17 19:31:29.000000000 +0000 @@ -90,6 +90,8 @@ virtual void SetDamage(const nsIntRegion& aDamageRegion) override; + GLint GetBufferAge() const override; + virtual void GetWSIInfo(nsCString* const out) const override; // hold a reference to the given surface @@ -100,7 +102,6 @@ bool HasExtBufferAge() const; bool HasKhrPartialUpdate() const; - EGLint GetBufferAge() const; bool BindTex2DOffscreen(GLContext* aOffscreen); void UnbindTex2DOffscreen(GLContext* aOffscreen); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContextGLX.h firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContextGLX.h --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContextGLX.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContextGLX.h 2020-11-17 19:31:29.000000000 +0000 @@ -53,6 +53,8 @@ bool SwapBuffers() override; + GLint GetBufferAge() const override; + void GetWSIInfo(nsCString* const out) const override; // Overrides the current GLXDrawable backing the context and makes the diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContext.h firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContext.h --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContext.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContext.h 2020-11-17 19:31:29.000000000 +0000 @@ -3382,6 +3382,12 @@ virtual void SetDamage(const nsIntRegion& aDamageRegion) {} /** + * Get the buffer age. If it returns 0, that indicates the buffer state is + * unknown and the entire frame should be redrawn. + */ + virtual GLint GetBufferAge() const { return 0; } + + /** * Defines a two-dimensional texture image for context target surface */ virtual bool BindTexImage() { return false; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContextProviderEGL.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContextProviderEGL.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContextProviderEGL.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContextProviderEGL.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -606,7 +606,7 @@ return mEgl->IsExtensionSupported(EGLExtension::KHR_partial_update); } -EGLint GLContextEGL::GetBufferAge() const { +GLint GLContextEGL::GetBufferAge() const { EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE ? mSurfaceOverride : mSurface; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContextProviderGLX.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContextProviderGLX.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLContextProviderGLX.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLContextProviderGLX.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -171,6 +171,9 @@ const SymLoadStruct symbols_swapcontrol[] = {SYMBOL(SwapIntervalEXT), END_OF_SYMBOLS}; + const SymLoadStruct symbols_querydrawable[] = {SYMBOL(QueryDrawable), + END_OF_SYMBOLS}; + const auto fnLoadSymbols = [&](const SymLoadStruct* symbols) { if (pfnLoader.LoadSymbols(symbols)) return true; @@ -217,6 +220,11 @@ "swaps."); } + if (HasExtension(extensionsStr, "GLX_EXT_buffer_age") && + fnLoadSymbols(symbols_querydrawable)) { + mHasBufferAge = true; + } + mIsATI = serverVendor && DoesStringMatch(serverVendor, "ATI"); mIsNVIDIA = serverVendor && DoesStringMatch(serverVendor, "NVIDIA Corporation"); @@ -619,6 +627,21 @@ return true; } +GLint GLContextGLX::GetBufferAge() const { + if (!sGLXLibrary.SupportsBufferAge()) { + return 0; + } + + GLuint result = 0; + mGLX->fQueryDrawable(mDisplay, mDrawable, LOCAL_GLX_BACK_BUFFER_AGE_EXT, + &result); + if (result > INT32_MAX) { + // If the result can't fit, just assume the buffer cannot be reused. + return 0; + } + return result; +} + void GLContextGLX::GetWSIInfo(nsCString* const out) const { Display* display = DefaultXDisplay(); int screen = DefaultScreen(display); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLLibraryEGL.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLLibraryEGL.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLLibraryEGL.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLLibraryEGL.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -146,12 +146,12 @@ static std::shared_ptr GetAndInitWARPDisplay(GLLibraryEGL& egl, void* displayType) { - const EGLAttrib attrib_list[] = {LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, - LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, - // Requires: - LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE, - LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, - LOCAL_EGL_NONE}; + const EGLAttrib attrib_list[] = { + LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, + LOCAL_EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE, + // Requires: + LOCAL_EGL_PLATFORM_ANGLE_TYPE_ANGLE, + LOCAL_EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, LOCAL_EGL_NONE}; const EGLDisplay display = egl.fGetPlatformDisplay( LOCAL_EGL_PLATFORM_ANGLE_ANGLE, displayType, attrib_list); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLXLibrary.h firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLXLibrary.h --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/gl/GLXLibrary.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/gl/GLXLibrary.h 2020-11-17 19:31:29.000000000 +0000 @@ -154,6 +154,10 @@ int interval) const VOID_WRAP(fSwapIntervalEXT(dpy, drawable, interval)) + int fQueryDrawable(Display* dpy, GLXDrawable drawable, int attribute, + unsigned int* value) const + WRAP(fQueryDrawable(dpy, drawable, attribute, value)) + #undef WRAP #undef VOID_WRAP #undef BEFORE_CALL @@ -176,6 +180,10 @@ bool SupportsTextureFromPixmap(gfxASurface* aSurface); bool SupportsVideoSync(); bool SupportsSwapControl() const { return bool(mSymbols.fSwapIntervalEXT); } + bool SupportsBufferAge() const { + MOZ_ASSERT(mInitialized); + return mHasBufferAge; + } bool IsATI() { return mIsATI; } bool IsMesa() { return mClientIsMesa; } @@ -214,6 +222,7 @@ int(GLAPIENTRY* fGetVideoSyncSGI)(unsigned int*); int(GLAPIENTRY* fWaitVideoSyncSGI)(int, int, unsigned int*); void(GLAPIENTRY* fSwapIntervalEXT)(Display*, GLXDrawable, int); + int(GLAPIENTRY* fQueryDrawable)(Display*, GLXDrawable, int, unsigned int*); } mSymbols = {}; #ifdef DEBUG @@ -229,6 +238,7 @@ bool mHasVideoMemoryPurge = false; bool mHasCreateContextAttribs = false; bool mHasVideoSync = false; + bool mHasBufferAge = false; bool mIsATI = false; bool mIsNVIDIA = false; bool mClientIsMesa = false; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/apz/src/AsyncPanZoomController.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/apz/src/AsyncPanZoomController.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/apz/src/AsyncPanZoomController.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/apz/src/AsyncPanZoomController.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -1390,6 +1390,7 @@ GetCurrentTouchBlock() ->GetOverscrollHandoffChain() ->SnapBackOverscrolledApzc(this); + mFlingAccelerator.Reset(); // SnapBackOverscrolledApzc() will put any APZC it causes to snap back // into the OVERSCROLL_ANIMATION state. If that's not us, since we're // done TOUCHING enter the NOTHING state. @@ -1788,6 +1789,7 @@ GetCurrentInputBlock() ->GetOverscrollHandoffChain() ->SnapBackOverscrolledApzc(this); + mFlingAccelerator.Reset(); return nsEventStatus_eConsumeNoDefault; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/apz/test/gtest/TestFlingAcceleration.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/apz/test/gtest/TestFlingAcceleration.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/apz/test/gtest/TestFlingAcceleration.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/apz/test/gtest/TestFlingAcceleration.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -226,3 +226,30 @@ {0, -8, 0, -30, -60, -87, -104, -111}); CHECK_VELOCITY(Down, 13.0, 23.0); } + +TEST_F(APZCFlingAccelerationTester, ShouldNotAccelerateAfterCanceledWithTap) { + // First, build up a lot of speed. + ExecutePanGesture100Hz(ScreenIntPoint{569, 710}, + {11, 2, 107, 18, 148, 57, 133, 159, 21}); + ExecuteWait(TimeDuration::FromMilliseconds(154)); + ExecutePanGesture100Hz(ScreenIntPoint{581, 650}, + {12, 68, 0, 162, 78, 140, 167}); + ExecuteWait(TimeDuration::FromMilliseconds(123)); + ExecutePanGesture100Hz(ScreenIntPoint{568, 723}, {11, 0, 79, 91, 131, 171}); + ExecuteWait(TimeDuration::FromMilliseconds(123)); + ExecutePanGesture100Hz(ScreenIntPoint{598, 678}, + {8, 55, 22, 87, 117, 220, 54}); + ExecuteWait(TimeDuration::FromMilliseconds(134)); + ExecutePanGesture100Hz(ScreenIntPoint{585, 854}, {45, 137, 107, 102, 79}); + ExecuteWait(TimeDuration::FromMilliseconds(246)); + + // Then, interrupt with a tap. + ExecutePanGesture100Hz(ScreenIntPoint{566, 812}, {0, 0, 0, 0}); + ExecuteWait(TimeDuration::FromMilliseconds(869)); + + // Then do a regular fling. + ExecutePanGesture100Hz(ScreenIntPoint{599, 819}, + {0, 0, 8, 35, 8, 38, 29, 37}); + + CHECK_VELOCITY(Up, 2.8, 4.2); +} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/apz/test/mochitest/helper_bug1674935.html firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/apz/test/mochitest/helper_bug1674935.html --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/apz/test/mochitest/helper_bug1674935.html 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/apz/test/mochitest/helper_bug1674935.html 2020-11-17 19:31:29.000000000 +0000 @@ -56,13 +56,15 @@ }); } - async function test(testDriver) { + async function test() { is(window.scrollX, 0, "shouldn't have scrolled (1)"); is(window.scrollY, 0, "shouldn't have scrolled (2)"); + let waitForScroll = waitForScrollEvent(window); + window.synthesizeKey("KEY_ArrowDown"); - await waitForScrollEvent(window); + await waitForScroll; is(window.scrollX, 0, "shouldn't have scrolled (3)"); isnot(window.scrollY, 0, "should have scrolled (4)"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/BufferTexture.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/BufferTexture.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/BufferTexture.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/BufferTexture.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -191,9 +191,6 @@ yOffset, cbOffset, crOffset, aStereoMode, aColorDepth, aYUVColorSpace, aColorRange, hasIntermediateBuffer); - // extra SIMD padding needed for SWGL - bufSize += 16; - return CreateInternal( aAllocator ? aAllocator->GetTextureForwarder() : nullptr, descriptor, gfx::BackendType::NONE, bufSize, aTextureFlags); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/ipc/CompositorBridgeParent.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/ipc/CompositorBridgeParent.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/ipc/CompositorBridgeParent.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/ipc/CompositorBridgeParent.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -704,13 +704,6 @@ this, &CompositorBridgeParent::ScheduleComposition)); } -void CompositorBridgeParent::InvalidateOnCompositorThread() { - MOZ_ASSERT(CompositorThread()); - CompositorThread()->Dispatch( - NewRunnableMethod("layers::CompositorBridgeParent::Invalidate", this, - &CompositorBridgeParent::Invalidate)); -} - void CompositorBridgeParent::PauseComposition() { MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread(), "PauseComposition() can only be called on the compositor thread"); @@ -797,53 +790,6 @@ ResumeComposition(); } -/* - * This will execute a pause synchronously, waiting to make sure that the - * compositor really is paused. - */ -void CompositorBridgeParent::SchedulePauseOnCompositorThread() { - MonitorAutoLock lock(mPauseCompositionMonitor); - - MOZ_ASSERT(CompositorThread()); - CompositorThread()->Dispatch( - NewRunnableMethod("layers::CompositorBridgeParent::PauseComposition", - this, &CompositorBridgeParent::PauseComposition)); - - // Wait until the pause has actually been processed by the compositor thread - lock.Wait(); -} - -bool CompositorBridgeParent::ScheduleResumeOnCompositorThread() { - MonitorAutoLock lock(mResumeCompositionMonitor); - - MOZ_ASSERT(CompositorThread()); - CompositorThread()->Dispatch( - NewRunnableMethod("layers::CompositorBridgeParent::ResumeComposition", - this, &CompositorBridgeParent::ResumeComposition)); - - // Wait until the resume has actually been processed by the compositor thread - lock.Wait(); - - return !mPaused; -} - -bool CompositorBridgeParent::ScheduleResumeOnCompositorThread(int x, int y, - int width, - int height) { - MonitorAutoLock lock(mResumeCompositionMonitor); - - MOZ_ASSERT(CompositorThread()); - CompositorThread()->Dispatch(NewRunnableMethod( - "layers::CompositorBridgeParent::ResumeCompositionAndResize", this, - &CompositorBridgeParent::ResumeCompositionAndResize, x, y, width, - height)); - - // Wait until the resume has actually been processed by the compositor thread - lock.Wait(); - - return !mPaused; -} - void CompositorBridgeParent::UpdatePaintTime(LayerTransactionParent* aLayerTree, const TimeDuration& aPaintTime) { // We get a lot of paint timings for things with empty transactions. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/ipc/CompositorBridgeParent.h firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/ipc/CompositorBridgeParent.h --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/ipc/CompositorBridgeParent.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/ipc/CompositorBridgeParent.h 2020-11-17 19:31:29.000000000 +0000 @@ -479,14 +479,6 @@ // Can be called from any thread void ScheduleRenderOnCompositorThread() override; - void SchedulePauseOnCompositorThread(); - void InvalidateOnCompositorThread(); - /** - * Returns true if a surface was obtained and the resume succeeded; false - * otherwise. - */ - bool ScheduleResumeOnCompositorThread(); - bool ScheduleResumeOnCompositorThread(int x, int y, int width, int height); void ScheduleComposition(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/SourceSurfaceSharedData.h firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/SourceSurfaceSharedData.h --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/SourceSurfaceSharedData.h 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/SourceSurfaceSharedData.h 2020-11-17 19:31:28.000000000 +0000 @@ -86,8 +86,7 @@ private: size_t GetDataLength() const { - // extra SIMD padding needed for SWGL - return static_cast(mStride) * mSize.height + 16; + return static_cast(mStride) * mSize.height; } size_t GetAlignedDataLength() const { @@ -298,8 +297,7 @@ uint8_t* GetDataInternal() const; size_t GetDataLength() const { - // extra SIMD padding needed for SWGL - return static_cast(mStride) * mSize.height + 16; + return static_cast(mStride) * mSize.height; } size_t GetAlignedDataLength() const { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/SurfacePoolCA.mm firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/SurfacePoolCA.mm --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/layers/SurfacePoolCA.mm 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/layers/SurfacePoolCA.mm 2020-11-17 19:31:29.000000000 +0000 @@ -156,14 +156,6 @@ return surface; } - // Add enough padding so that SWGL can safely read up to one SIMD vector worth - // of bytes at the last pixel, which it does for performance reasons. - // - // This in turn also requires specifying a properly aligned bytes per row - // value so odd-sized surfaces like a tooltip still work. - size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow, aSize.width * 4); - size_t allocSize = IOSurfaceAlignProperty(kIOSurfaceAllocSize, bytesPerRow * aSize.height + 16); - AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING("IOSurface creation", GRAPHICS_TileAllocation, nsPrintfCString("%dx%d", aSize.width, aSize.height)); CFTypeRefPtr surface = @@ -172,8 +164,6 @@ (__bridge NSString*)kIOSurfaceHeight : @(aSize.height), (__bridge NSString*)kIOSurfacePixelFormat : @(kCVPixelFormatType_32BGRA), (__bridge NSString*)kIOSurfaceBytesPerElement : @(4), - (__bridge NSString*)kIOSurfaceBytesPerRow : @(bytesPerRow), - (__bridge NSString*)kIOSurfaceAllocSize : @(allocSize), })); if (surface) { // Create a new entry in mInUseEntries. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/qcms/src/transform.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/qcms/src/transform.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/qcms/src/transform.rs 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/qcms/src/transform.rs 2020-11-17 19:31:29.000000000 +0000 @@ -37,7 +37,7 @@ }, }; use crate::{ - iccread::{curveType, qcms_CIE_xyY, qcms_CIE_xyYTRIPLE, qcms_profile}, + iccread::{curveType, qcms_CIE_xyY, qcms_CIE_xyYTRIPLE, qcms_profile, RGB_SIGNATURE}, qcms_intent, s15Fixed16Number, transform_util::clamp_float, }; @@ -54,7 +54,7 @@ }; use ::libc::{self, free, malloc}; -use std::sync::Arc; +use std::sync::{atomic::AtomicBool, Arc}; use std::{ptr::null_mut, sync::atomic::Ordering}; pub const PRECACHE_OUTPUT_SIZE: usize = 8192; @@ -1107,33 +1107,14 @@ Arc::new(precache_output::default()) } -unsafe extern "C" fn transform_alloc() -> *mut qcms_transform { - Box::into_raw(Box::new(Default::default())) -} -unsafe extern "C" fn transform_free(mut t: *mut qcms_transform) { - drop(Box::from_raw(t)) -} #[no_mangle] pub unsafe extern "C" fn qcms_transform_release(mut t: *mut qcms_transform) { - /* ensure we only free the gamma tables once even if there are - * multiple references to the same data */ - (*t).output_table_r = None; - (*t).output_table_g = None; - (*t).output_table_b = None; - - (*t).input_gamma_table_r = None; - (*t).input_gamma_table_g = None; - (*t).input_gamma_table_b = None; - - (*t).input_gamma_table_gray = None; - (*t).output_gamma_lut_r = None; - (*t).output_gamma_lut_g = None; - (*t).output_gamma_lut_b = None; + let t = Box::from_raw(t); /* r_clut points to beginning of buffer allocated in qcms_transform_precacheLUT_float */ if !(*t).r_clut.is_null() { free((*t).r_clut as *mut libc::c_void); } - transform_free(t); + drop(t) } fn sse_version_available() -> i32 { @@ -1174,12 +1155,9 @@ + 1.000 * bradford_matrix.m[1][2] + 0.82521 * bradford_matrix.m[2][2]) / (X * bradford_matrix.m[0][2] + Y * bradford_matrix.m[1][2] + Z * bradford_matrix.m[2][2]); - let mut white_adaption: matrix = { - let mut init = matrix { - m: [[p, 0., 0.], [0., y, 0.], [0., 0., b]], - invalid: false, - }; - init + let mut white_adaption = matrix { + m: [[p, 0., 0.], [0., y, 0.], [0., 0., b]], + invalid: false, }; return matrix_multiply( bradford_matrix_inv, @@ -1189,7 +1167,7 @@ #[no_mangle] pub extern "C" fn qcms_profile_precache_output_transform(mut profile: &mut qcms_profile) { /* we only support precaching on rgb profiles */ - if (*profile).color_space != 0x52474220 { + if (*profile).color_space != RGB_SIGNATURE { return; } if qcms_supports_iccv4.load(Ordering::Relaxed) { @@ -1238,7 +1216,7 @@ /* Replace the current transformation with a LUT transformation using a given number of sample points */ #[no_mangle] pub unsafe extern "C" fn qcms_transform_precacheLUT_float( - mut transform: *mut qcms_transform, + mut transform: Box, mut in_0: &qcms_profile, mut out: &qcms_profile, mut samples: i32, @@ -1306,10 +1284,10 @@ if lut.is_null() { return 0 as *mut qcms_transform; } - return transform; + return Box::into_raw(transform); } #[no_mangle] -pub unsafe extern "C" fn qcms_transform_create( +pub extern "C" fn qcms_transform_create( mut in_0: &qcms_profile, mut in_type: qcms_data_type, mut out: &qcms_profile, @@ -1335,10 +1313,7 @@ debug_assert!(false, "input/output type"); return 0 as *mut qcms_transform; } - let mut transform: *mut qcms_transform = transform_alloc(); - if transform.is_null() { - return 0 as *mut qcms_transform; - } + let mut transform: Box = Box::new(Default::default()); let mut precache: bool = false; if !(*out).output_table_r.is_none() && !(*out).output_table_g.is_none() @@ -1362,10 +1337,9 @@ // TODO For transforming small data sets of about 200x200 or less // precaching should be avoided. let mut result: *mut qcms_transform = - qcms_transform_precacheLUT_float(transform, in_0, out, 33, in_type); + unsafe { qcms_transform_precacheLUT_float(transform, in_0, out, 33, in_type) }; if result.is_null() { debug_assert!(false, "precacheLUT failed"); - qcms_transform_release(transform); return 0 as *mut qcms_transform; } return result; @@ -1376,7 +1350,6 @@ (*transform).output_table_b = Some(Arc::clone((*out).output_table_b.as_ref().unwrap())); } else { if (*out).redTRC.is_none() || (*out).greenTRC.is_none() || (*out).blueTRC.is_none() { - qcms_transform_release(transform); return 0 as *mut qcms_transform; } (*transform).output_gamma_lut_r = Some(build_output_lut((*out).redTRC.as_deref().unwrap())); @@ -1389,13 +1362,14 @@ || (*transform).output_gamma_lut_g.is_none() || (*transform).output_gamma_lut_b.is_none() { - qcms_transform_release(transform); return 0 as *mut qcms_transform; } } - if (*in_0).color_space == 0x52474220 { + if (*in_0).color_space == RGB_SIGNATURE { if precache { - if cfg!(any(target_arch = "x86", target_arch = "x86_64")) && qcms_supports_avx { + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) + && qcms_supports_avx.load(Ordering::Relaxed) + { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { if in_type == QCMS_DATA_RGB_8 { @@ -1421,7 +1395,8 @@ (*transform).transform_fn = Some(qcms_transform_data_bgra_out_lut_sse2) } } - } else if cfg!(any(target_arch = "arm", target_arch = "aarch64")) && qcms_supports_neon + } else if cfg!(any(target_arch = "arm", target_arch = "aarch64")) + && qcms_supports_neon.load(Ordering::Relaxed) { #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] { @@ -1455,7 +1430,6 @@ || (*transform).input_gamma_table_g.is_none() || (*transform).input_gamma_table_b.is_none() { - qcms_transform_release(transform); return 0 as *mut qcms_transform; } /* build combined colorant matrix */ @@ -1464,7 +1438,6 @@ let mut out_matrix: matrix = build_colorant_matrix(out); out_matrix = matrix_invert(out_matrix); if out_matrix.invalid { - qcms_transform_release(transform); return 0 as *mut qcms_transform; } let mut result_0: matrix = matrix_multiply(out_matrix, in_matrix); @@ -1474,7 +1447,6 @@ let mut j: libc::c_uint = 0; while j < 3 { if result_0.m[i as usize][j as usize] != result_0.m[i as usize][j as usize] { - qcms_transform_release(transform); return 0 as *mut qcms_transform; } j = j + 1 @@ -1495,7 +1467,6 @@ } else if (*in_0).color_space == 0x47524159 { (*transform).input_gamma_table_gray = build_input_gamma_table((*in_0).grayTRC.as_deref()); if (*transform).input_gamma_table_gray.is_none() { - qcms_transform_release(transform); return 0 as *mut qcms_transform; } if precache { @@ -1531,11 +1502,10 @@ } } else { debug_assert!(false, "unexpected colorspace"); - qcms_transform_release(transform); return 0 as *mut qcms_transform; } debug_assert!((*transform).transform_fn.is_some()); - return transform; + return Box::into_raw(transform); } #[no_mangle] pub unsafe extern "C" fn qcms_transform_data( @@ -1558,15 +1528,14 @@ pub unsafe extern "C" fn qcms_enable_iccv4() { qcms_supports_iccv4.store(true, Ordering::Relaxed); } -#[no_mangle] -pub static mut qcms_supports_avx: bool = false; -#[no_mangle] -pub static mut qcms_supports_neon: bool = false; +pub static qcms_supports_avx: AtomicBool = AtomicBool::new(false); +pub static qcms_supports_neon: AtomicBool = AtomicBool::new(false); + #[no_mangle] pub unsafe extern "C" fn qcms_enable_avx() { - qcms_supports_avx = true; + qcms_supports_avx.store(true, Ordering::Relaxed); } #[no_mangle] pub unsafe extern "C" fn qcms_enable_neon() { - qcms_supports_neon = true; + qcms_supports_neon.store(true, Ordering::Relaxed); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/src/gfxTelemetry.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/src/gfxTelemetry.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/src/gfxTelemetry.cpp 2020-11-15 14:37:57.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/src/gfxTelemetry.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -26,6 +26,8 @@ return "unavailable-not-built"; case FeatureStatus::UnavailableNoAngle: return "unavailable-no-angle"; + case FeatureStatus::UnavailableNoWebRender: + return "unavailable-no-webrender"; case FeatureStatus::CrashedInHandler: return "crashed"; case FeatureStatus::Blocked: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/src/gfxTelemetry.h firefox-trunk-85.0~a1~hg20201117r557492/gfx/src/gfxTelemetry.h --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/src/gfxTelemetry.h 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/src/gfxTelemetry.h 2020-11-17 19:31:29.000000000 +0000 @@ -26,6 +26,7 @@ UnavailableNoHwCompositing, UnavailableNotBuilt, UnavailableNoAngle, + UnavailableNoWebRender, // This feature crashed immediately when we tried to initialize it, but we // were able to recover via SEH (or something similar). diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/thebes/gfxPlatform.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/thebes/gfxPlatform.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/thebes/gfxPlatform.cpp 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/thebes/gfxPlatform.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -2882,6 +2882,11 @@ "WebGPU can only be enabled in nightly", "WEBGPU_DISABLE_NON_NIGHTLY"_ns); #endif + if (!UseWebRender()) { + feature.ForceDisable(FeatureStatus::UnavailableNoWebRender, + "WebGPU can't present without WebRender", + "FEATURE_FAILURE_WEBGPU_NEED_WEBRENDER"_ns); + } } void gfxPlatform::InitOMTPConfig() { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/webrender_bindings/RenderCompositorD3D11SWGL.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/webrender_bindings/RenderCompositorD3D11SWGL.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/webrender_bindings/RenderCompositorD3D11SWGL.cpp 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/webrender_bindings/RenderCompositorD3D11SWGL.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -225,8 +225,9 @@ mCompositor->GetDevice()->GetImmediateContext(getter_AddRefs(context)); D3D11_MAPPED_SUBRESOURCE mappedSubresource; - DebugOnly hr = context->Map(mCurrentTile.mStagingTexture, 0, - D3D11_MAP_WRITE, 0, &mappedSubresource); + DebugOnly hr = + context->Map(mCurrentTile.mStagingTexture, 0, D3D11_MAP_READ_WRITE, 0, + &mappedSubresource); MOZ_ASSERT(SUCCEEDED(hr)); // aData is expected to contain a pointer to the first pixel within the valid @@ -304,12 +305,7 @@ RefPtr source = new DataTextureSourceD3D11( mCompositor->GetDevice(), gfx::SurfaceFormat::B8G8R8A8, texture); - // We need to pad our tile textures by 16 bytes since SWGL can read up - // to 3 pixels past the end. We don't control the allocation size, so - // add an extra row instead. - desc.Height += 1; - - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ; desc.Usage = D3D11_USAGE_STAGING; desc.BindFlags = 0; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/webrender_bindings/RenderCompositorEGL.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/webrender_bindings/RenderCompositorEGL.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/webrender_bindings/RenderCompositorEGL.cpp 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/webrender_bindings/RenderCompositorEGL.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -10,6 +10,7 @@ #include "GLContextEGL.h" #include "GLContextProvider.h" #include "GLLibraryEGL.h" +#include "mozilla/StaticPrefs_gfx.h" #include "mozilla/gfx/gfxVars.h" #include "mozilla/layers/BuildConstants.h" #include "mozilla/webrender/RenderThread.h" @@ -244,7 +245,11 @@ } size_t RenderCompositorEGL::GetBufferAge() const { - return gl::GLContextEGL::Cast(gl())->GetBufferAge(); + if (!StaticPrefs:: + gfx_webrender_allow_partial_present_buffer_age_AtStartup()) { + return 0; + } + return gl()->GetBufferAge(); } void RenderCompositorEGL::SetBufferDamageRegion(const wr::DeviceIntRect* aRects, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/webrender_bindings/RenderCompositorOGL.cpp firefox-trunk-85.0~a1~hg20201117r557492/gfx/webrender_bindings/RenderCompositorOGL.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/webrender_bindings/RenderCompositorOGL.cpp 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/webrender_bindings/RenderCompositorOGL.cpp 2020-11-17 19:31:29.000000000 +0000 @@ -104,13 +104,13 @@ } uint32_t RenderCompositorOGL::GetMaxPartialPresentRects() { - return mIsEGL ? gfx::gfxVars::WebRenderMaxPartialPresentRects() : 0; + return gfx::gfxVars::WebRenderMaxPartialPresentRects(); } bool RenderCompositorOGL::RequestFullRender() { return false; } bool RenderCompositorOGL::UsePartialPresent() { - return mIsEGL && gfx::gfxVars::WebRenderMaxPartialPresentRects() > 0; + return gfx::gfxVars::WebRenderMaxPartialPresentRects() > 0; } bool RenderCompositorOGL::ShouldDrawPreviousPartialPresentRegions() { @@ -118,10 +118,11 @@ } size_t RenderCompositorOGL::GetBufferAge() const { - if (mIsEGL) { - return gl::GLContextEGL::Cast(gl())->GetBufferAge(); + if (!StaticPrefs:: + gfx_webrender_allow_partial_present_buffer_age_AtStartup()) { + return 0; } - return 0; + return gl()->GetBufferAge(); } } // namespace wr diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/webrender_bindings/src/swgl_bindings.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/webrender_bindings/src/swgl_bindings.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/webrender_bindings/src/swgl_bindings.rs 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/webrender_bindings/src/swgl_bindings.rs 2020-11-17 19:31:29.000000000 +0000 @@ -643,7 +643,7 @@ if lock.is_none() { lock = Some(thread.lock()); } - thread.send_job(lock.as_mut().unwrap(), child, false); + thread.send_job(lock.as_mut().unwrap(), child); } } } @@ -657,10 +657,11 @@ jobs: Mutex, /// Count of unprocessed jobs still in the queue job_count: AtomicIsize, - /// Condition signaled when there are jobs available to process. + /// Condition signaled when either there are jobs available to process or + /// there are no more jobs left to process. Otherwise stated, this signals + /// when the job queue transitions from an empty to non-empty state or from + /// a non-empty to empty state. jobs_available: Condvar, - /// Condition signaled when there are no more jobs left to process. - jobs_completed: Condvar, } /// The SwCompositeThread struct is shared between the SwComposite thread @@ -681,7 +682,6 @@ jobs: Mutex::new(SwCompositeJobQueue::new()), job_count: AtomicIsize::new(0), jobs_available: Condvar::new(), - jobs_completed: Condvar::new(), }); let result = info.clone(); let thread_name = "SwComposite"; @@ -759,7 +759,7 @@ }; self.job_count.fetch_add(num_bands as isize, Ordering::SeqCst); if graph_node.set_job(job, num_bands) { - self.send_job(job_queue, graph_node, true); + self.send_job(job_queue, graph_node); } } @@ -776,10 +776,10 @@ } /// Send a job to the composite thread by adding it to the job queue. - /// Optionally signal that this job has been added in case the queue - /// was empty and the SwComposite thread is waiting for jobs. - fn send_job(&self, queue: &mut SwCompositeJobQueue, job: SwCompositeGraphNodeRef, signal: bool) { - if signal && queue.is_empty() { + /// Signal that this job has been added in case the queue was empty and the + /// SwComposite thread is waiting for jobs. + fn send_job(&self, queue: &mut SwCompositeJobQueue, job: SwCompositeGraphNodeRef) { + if queue.is_empty() { self.jobs_available.notify_all(); } queue.push_back(job); @@ -792,20 +792,25 @@ // won't be held while the job is processed later outside of this // function so that other threads can pull from the queue meanwhile. let mut jobs = self.lock(); - if wait { - while jobs.is_empty() { - match self.job_count.load(Ordering::SeqCst) { - // If waiting inside the SwCompositeThread and we completed all - // available jobs, signal completion. - 0 => self.jobs_completed.notify_all(), - // A negative job count signals to exit immediately. - job_count if job_count < 0 => return None, - _ => {} - } - // The SwCompositeThread needs to wait for jobs to become - // available to avoid busy waiting on the queue. - jobs = self.jobs_available.wait(jobs).unwrap(); - } + while jobs.is_empty() { + match self.job_count.load(Ordering::SeqCst) { + // If we completed all available jobs, signal completion. If + // waiting inside the SwCompositeThread, then block waiting for + // more jobs to become available in a new frame. Otherwise, + // return immediately. + 0 => { + self.jobs_available.notify_all(); + if !wait { + return None; + } + } + // A negative job count signals to exit immediately. + job_count if job_count < 0 => return None, + _ => {} + } + // The SwCompositeThread needs to wait for jobs to become + // available to avoid busy waiting on the queue. + jobs = self.jobs_available.wait(jobs).unwrap(); } // Look for a job at the front of the queue. If there is one, take the // next unprocessed band from the job. If this was the last band in the @@ -846,12 +851,9 @@ // If processing synchronously, just wait for the composite thread // to complete processing any in-flight jobs, then bail. let mut jobs = self.lock(); - // Wake up the composite thread in case it is blocked waiting on a 0 - // job count resulting from job stealing while it was blocked. - self.jobs_available.notify_all(); // If the job count is non-zero here, then there are in-flight jobs. while self.job_count.load(Ordering::SeqCst) > 0 { - jobs = self.jobs_completed.wait(jobs).unwrap(); + jobs = self.jobs_available.wait(jobs).unwrap(); } } @@ -1307,7 +1309,7 @@ native_gl.bind_buffer(gl::PIXEL_UNPACK_BUFFER, tile.pbo_id); native_gl.buffer_data_untyped( gl::PIXEL_UNPACK_BUFFER, - surface.tile_size.area() as isize * 4 + 16, + surface.tile_size.area() as isize * 4, ptr::null(), gl::DYNAMIC_DRAW, ); @@ -1385,7 +1387,7 @@ buf = native_gl.map_buffer_range( gl::PIXEL_UNPACK_BUFFER, 0, - valid_rect.size.area() as isize * 4 + 16, + valid_rect.size.area() as isize * 4, gl::MAP_WRITE_BIT | gl::MAP_INVALIDATE_BUFFER_BIT, ); // | gl::MAP_UNSYNCHRONIZED_BIT); if buf != ptr::null_mut() { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/swgl/src/composite.h firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/swgl/src/composite.h --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/swgl/src/composite.h 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/swgl/src/composite.h 2020-11-17 19:31:29.000000000 +0000 @@ -2,29 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -// Load a partial span > 0 and < 4 pixels. -template -static ALWAYS_INLINE V partial_load_span(P* src, int span) { - return bit_cast( - (span >= 2 ? combine(unaligned_load>(src), - V2

{span > 2 ? unaligned_load

(src + 2) : 0, 0}) - : V4

{unaligned_load

(src), 0, 0, 0})); -} - -// Store a partial span > 0 and < 4 pixels. -template -static ALWAYS_INLINE void partial_store_span(P* dst, V src, int span) { - auto pixels = bit_cast>(src); - if (span >= 2) { - unaligned_store(dst, lowHalf(pixels)); - if (span > 2) { - unaligned_store(dst + 2, pixels.z); - } - } else { - unaligned_store(dst, pixels.x); - } -} - template static inline void scale_row(P* dst, int dstWidth, const P* src, int srcWidth, int span) { @@ -316,7 +293,7 @@ } prepare_texture(srctex); prepare_texture(dsttex, &dstReq); - if (!srcReq.same_size(dstReq) && filter == GL_LINEAR && + if (!srcReq.same_size(dstReq) && srctex.width >= 2 && filter == GL_LINEAR && (srctex.internal_format == GL_RGBA8 || srctex.internal_format == GL_R8 || srctex.internal_format == GL_RG8)) { linear_blit(srctex, srcReq, srcfb->layer, dsttex, dstReq, dstfb->layer, @@ -393,7 +370,7 @@ dest += 4; } if (src < end) { - WideRGBA8 srcpx = unpack(unaligned_load(src)); + WideRGBA8 srcpx = unpack(partial_load_span(src, end - src)); WideRGBA8 dstpx = unpack(partial_load_span(dest, end - src)); auto r = pack(srcpx + dstpx - muldiv255(dstpx, alphas(srcpx))); partial_store_span(dest, r, end - src); @@ -631,10 +608,10 @@ assert(sampler->format == TextureFormat::R8); // Calculate X fraction and clamp X offset into range. - I32 fracx = ix & (I32)0x7F; + I32 fracx = ix; ix >>= 7; - fracx &= (ix >= 0 && ix < int32_t(sampler->width) - 1); - ix = clampCoord(ix, sampler->width); + fracx = ((fracx & (ix >= 0)) | (ix > int32_t(sampler->width) - 2)) & 0x7F; + ix = clampCoord(ix, sampler->width - 1); // Load the sample taps and combine rows. auto abcd = linearRowTapsR8(sampler, ix, offsety, stridey, fracy); @@ -666,10 +643,10 @@ assert(sampler->stride == sampler2->stride); // Calculate X fraction and clamp X offset into range. - I32 fracx = ix & (I32)0x7F; + I32 fracx = ix; ix >>= 7; - fracx &= (ix >= 0 && ix < int32_t(sampler->width) - 1); - ix = clampCoord(ix, sampler->width); + fracx = ((fracx & (ix >= 0)) | (ix > int32_t(sampler->width) - 2)) & 0x7F; + ix = clampCoord(ix, sampler->width - 1); // Load the sample taps for the first sampler and combine rows. auto abcd = linearRowTapsR8(sampler, ix, offsety, stridey, fracy); @@ -712,7 +689,26 @@ int32_t yDU = int32_t((4 << STEP_BITS) * srcDU); int32_t cDU = int32_t((4 << STEP_BITS) * chromaDU); - if (sampler[0].format == TextureFormat::R16) { + if (sampler[0].width < 2 || sampler[1].width < 2) { + // If the source row has less than 2 pixels, it's not safe to use a linear + // filter because it may overread the row. Just convert the single pixel + // with nearest filtering and fill the row with it. + I16 yuv = + CONVERT(round_pixel((Float){ + texelFetch(&sampler[0], ivec2(srcUV), 0).x.x, + texelFetch(&sampler[1], ivec2(chromaUV), 0).x.x, + texelFetch(&sampler[2], ivec2(chromaUV), 0).x.x, 1.0f}), + I16); + auto rgb = YUVConverter::convert(zip(I16(yuv.x), I16(yuv.x)), + zip(I16(yuv.y), I16(yuv.z))); + for (; span >= 4; span -= 4) { + unaligned_store(dest, rgb); + dest += 4; + } + if (span > 0) { + partial_store_span(dest, rgb, span); + } + } else if (sampler[0].format == TextureFormat::R16) { // Sample each YUV plane, rescale it to fit in low 8 bits of word, and then // transform them by the appropriate color space. assert(colorDepth > 8); @@ -824,11 +820,14 @@ float(utex.height) / ytex.height); vec2_scalar chromaUV = srcUV * chromaScale; vec2_scalar chromaDUV = srcDUV * chromaScale; - // Scale UVs by lerp precision - srcUV = linearQuantize(srcUV, 128); - srcDUV *= 128.0f; - chromaUV = linearQuantize(chromaUV, 128); - chromaDUV *= 128.0f; + // Scale UVs by lerp precision. If the row has only 1 pixel, then don't + // quantize so that we can use nearest filtering instead to avoid overreads. + if (ytex.width >= 2 && utex.width >= 2) { + srcUV = linearQuantize(srcUV, 128); + srcDUV *= 128.0f; + chromaUV = linearQuantize(chromaUV, 128); + chromaDUV *= 128.0f; + } // Calculate dest pointer from clamped offsets int destStride = dsttex.stride(); char* dest = dsttex.sample_ptr(dstReq, dstBounds, 0, invertY); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/swgl/src/gl.cc firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/swgl/src/gl.cc --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/swgl/src/gl.cc 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/swgl/src/gl.cc 2020-11-17 19:31:29.000000000 +0000 @@ -592,7 +592,17 @@ if (!buf || size > buf_size) { // Allocate with a SIMD register-sized tail of padding at the end so we // can safely read or write past the end of the texture with SIMD ops. - char* new_buf = (char*)realloc(buf, size + sizeof(Float)); + // Currently only the flat Z-buffer texture needs this padding due to + // full-register loads and stores in check_depth and discard_depth. In + // case some code in the future accidentally uses a linear filter on a + // texture with less than 2 pixels per row, we also add this padding + // just to be safe. All other texture types and use-cases should be + // safe to omit padding. + size_t padding = + internal_format == GL_DEPTH_COMPONENT16 || max(width, min_width) < 2 + ? sizeof(Float) + : 0; + char* new_buf = (char*)realloc(buf, size + padding); assert(new_buf); if (new_buf) { // Successfully reallocated the buffer, so go ahead and set it. @@ -2808,34 +2818,73 @@ } } -template -static inline void discard_output(uint32_t* buf, PackedRGBA8 mask) { - PackedRGBA8 dst = unaligned_load(buf); - WideRGBA8 r = pack_pixels_RGBA8(); - if (blend_key) r = blend_pixels_RGBA8(dst, r); - if (DISCARD) - mask |= bit_cast(fragment_shader->swgl_IsPixelDiscarded); - unaligned_store(buf, (mask & dst) | (~mask & pack(r))); +// Load a partial span > 0 and < 4 pixels. +template +static ALWAYS_INLINE V partial_load_span(const P* src, int span) { + return bit_cast( + (span >= 2 + ? combine(unaligned_load>(src), + V2

{span > 2 ? unaligned_load

(src + 2) : P(0), 0}) + : V4

{unaligned_load

(src), 0, 0, 0})); +} + +// Store a partial span > 0 and < 4 pixels. +template +static ALWAYS_INLINE void partial_store_span(P* dst, V src, int span) { + auto pixels = bit_cast>(src); + if (span >= 2) { + unaligned_store(dst, lowHalf(pixels)); + if (span > 2) { + unaligned_store(dst + 2, pixels.z); + } + } else { + unaligned_store(dst, pixels.x); + } } -template -static inline void discard_output(uint32_t* buf) { - discard_output(buf, 0); +// Dispatcher that chooses when to load a full or partial span +template +static ALWAYS_INLINE V load_span(const P* src) { + if (SPAN >= 4) { + return unaligned_load(src); + } else { + return partial_load_span(src, SPAN); + } } -template <> -inline void discard_output(uint32_t* buf) { - WideRGBA8 r = pack_pixels_RGBA8(); - if (blend_key) r = blend_pixels_RGBA8(unaligned_load(buf), r); - unaligned_store(buf, pack(r)); +// Dispatcher that chooses when to store a full or partial span +template +static ALWAYS_INLINE void store_span(P* dst, V src) { + if (SPAN >= 4) { + unaligned_store(dst, src); + } else { + partial_store_span(dst, src, SPAN); + } } -static inline PackedRGBA8 span_mask_RGBA8(int span) { - return bit_cast(I32(span) < I32{1, 2, 3, 4}); +template +static ALWAYS_INLINE void discard_output(uint32_t* buf, PackedRGBA8 mask) { + WideRGBA8 r = pack_pixels_RGBA8(); + PackedRGBA8 dst = load_span(buf); + if (blend_key) r = blend_pixels_RGBA8(dst, r); + if (DISCARD) + mask |= bit_cast(fragment_shader->swgl_IsPixelDiscarded); + store_span(buf, (mask & dst) | (~mask & pack(r))); } -static inline PackedRGBA8 span_mask(uint32_t*, int span) { - return span_mask_RGBA8(span); +template +static ALWAYS_INLINE void discard_output(uint32_t* buf) { + WideRGBA8 r = pack_pixels_RGBA8(); + if (DISCARD) { + PackedRGBA8 dst = load_span(buf); + if (blend_key) r = blend_pixels_RGBA8(dst, r); + PackedRGBA8 mask = + bit_cast(fragment_shader->swgl_IsPixelDiscarded); + store_span(buf, (mask & dst) | (~mask & pack(r))); + } else { + if (blend_key) r = blend_pixels_RGBA8(load_span(buf), r); + store_span(buf, pack(r)); + } } static inline WideR8 packR8(I32 a) { @@ -2870,54 +2919,72 @@ } } -template +template static inline void discard_output(uint8_t* buf, WideR8 mask) { - WideR8 dst = unpack(unaligned_load(buf)); WideR8 r = pack_pixels_R8(); + WideR8 dst = unpack(load_span(buf)); if (blend_key) r = blend_pixels_R8(dst, r); if (DISCARD) mask |= packR8(fragment_shader->swgl_IsPixelDiscarded); - unaligned_store(buf, pack((mask & dst) | (~mask & r))); + store_span(buf, pack((mask & dst) | (~mask & r))); } -template +template static inline void discard_output(uint8_t* buf) { - discard_output(buf, 0); -} - -template <> -inline void discard_output(uint8_t* buf) { WideR8 r = pack_pixels_R8(); - if (blend_key) r = blend_pixels_R8(unpack(unaligned_load(buf)), r); - unaligned_store(buf, pack(r)); -} - -static inline WideR8 span_mask_R8(int span) { - return bit_cast(WideR8(span) < WideR8{1, 2, 3, 4}); -} - -static inline WideR8 span_mask(uint8_t*, int span) { - return span_mask_R8(span); + if (DISCARD) { + WideR8 dst = unpack(load_span(buf)); + if (blend_key) r = blend_pixels_R8(dst, r); + WideR8 mask = packR8(fragment_shader->swgl_IsPixelDiscarded); + store_span(buf, pack((mask & dst) | (~mask & r))); + } else { + if (blend_key) + r = blend_pixels_R8(unpack(load_span(buf)), r); + store_span(buf, pack(r)); + } } -UNUSED static inline PackedRG8 span_mask_RG8(int span) { - return bit_cast(I16(span) < I16{1, 2, 3, 4}); +template +static inline void commit_output(P* buf, M mask) { + fragment_shader->run(); + discard_output(buf, mask); } template -static inline void commit_output(P* buf, M mask) { +static inline void commit_output(P* buf, M mask, int span) { fragment_shader->run(); - discard_output(buf, mask); + switch (span) { + case 1: + discard_output(buf, mask); + break; + case 2: + discard_output(buf, mask); + break; + default: + discard_output(buf, mask); + break; + } } template static inline void commit_output(P* buf) { fragment_shader->run(); - discard_output(buf); + discard_output(buf); } template static inline void commit_output(P* buf, int span) { - commit_output(buf, span_mask(buf, span)); + fragment_shader->run(); + switch (span) { + case 1: + discard_output(buf); + break; + case 2: + discard_output(buf); + break; + default: + discard_output(buf); + break; + } } template @@ -2937,7 +3004,7 @@ static inline void commit_output(P* buf, Z z, DepthRun* zbuf, int span) { ZMask zmask; if (check_depth(z, zbuf, zmask, span)) { - commit_output(buf, convert_zmask(zmask, buf)); + commit_output(buf, convert_zmask(zmask, buf), span); if (DISCARD) { discard_depth(z, zbuf, zmask); } @@ -3037,7 +3104,7 @@ // it were a full chunk. Mask off only the part of the chunk we want to // use. if (span > 0) { - commit_output(buf, span_mask(buf, span)); + commit_output(buf, span); buf += span; } // Skip past any runs that fail the depth test. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/frame_builder.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/frame_builder.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/frame_builder.rs 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/frame_builder.rs 2020-11-17 19:31:29.000000000 +0000 @@ -468,7 +468,6 @@ resource_cache.block_until_all_resources_added( gpu_cache, - render_tasks, profile, ); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/glyph_rasterizer/mod.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/glyph_rasterizer/mod.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/glyph_rasterizer/mod.rs 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/glyph_rasterizer/mod.rs 2020-11-17 19:31:29.000000000 +0000 @@ -218,8 +218,6 @@ glyph_cache: &mut GlyphCache, texture_cache: &mut TextureCache, gpu_cache: &mut GpuCache, - _: &mut RenderTaskCache, - _: &mut RenderTaskGraph, profile: &mut TransactionProfile, ) { profile.start_time(profiler::GLYPH_RESOLVE_TIME); @@ -1207,8 +1205,6 @@ &mut glyph_cache, &mut TextureCache::new_for_testing(4096, FORMAT), &mut gpu_cache, - &mut render_task_cache, - &mut render_task_tree, &mut TransactionProfile::new(), ); } @@ -1292,8 +1288,6 @@ &mut glyph_cache, &mut TextureCache::new_for_testing(4096, FORMAT), &mut gpu_cache, - &mut render_task_cache, - &mut render_task_tree, &mut TransactionProfile::new(), ); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/picture.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/picture.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/picture.rs 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/picture.rs 2020-11-17 19:31:29.000000000 +0000 @@ -122,7 +122,7 @@ use crate::render_backend::{DataStores, FrameId}; use crate::render_task_graph::RenderTaskId; use crate::render_target::RenderTargetKind; -use crate::render_task::{RenderTask, RenderTaskLocation, BlurTaskCache, ClearMode}; +use crate::render_task::{RenderTask, RenderTaskLocation, BlurTaskCache}; use crate::resource_cache::{ResourceCache, ImageGeneration}; use crate::space::{SpaceMapper, SpaceSnapper}; use crate::scene::SceneProperties; @@ -4959,7 +4959,6 @@ picture_task_id, frame_state.render_tasks, RenderTargetKind::Color, - ClearMode::Transparent, None, original_size.to_i32(), ); @@ -5041,7 +5040,6 @@ picture_task_id, frame_state.render_tasks, RenderTargetKind::Color, - ClearMode::Transparent, Some(&mut blur_tasks), device_rect.size.to_i32(), ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/renderer.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/renderer.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/renderer.rs 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/renderer.rs 2020-11-17 19:31:30.000000000 +0000 @@ -4119,7 +4119,7 @@ if use_batch_upload { let (allocator, buffers) = batch_upload_buffers.entry(texture.get_format()) - .or_insert_with(|| (ArrayAllocationTracker::new(), Vec::new())); + .or_insert_with(|| (ArrayAllocationTracker::new(None), Vec::new())); // Allocate a region within the staging buffer for this update. If there is // no room in an existing buffer then allocate another texture and buffer. @@ -5990,11 +5990,11 @@ let transformed_dirty_rect = if let Some(transform) = tile.transform { transform.outer_transformed_rect(&tile_dirty_rect) } else { - Some(tile_dirty_rect) + Some(tile_dirty_rect) }; if let Some(dirty_rect) = transformed_dirty_rect { - combined_dirty_rect = combined_dirty_rect.union(&dirty_rect); + combined_dirty_rect = combined_dirty_rect.union(&dirty_rect); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/render_target.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/render_target.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/render_target.rs 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/render_target.rs 2020-11-17 19:31:29.000000000 +0000 @@ -20,7 +20,7 @@ use crate::prim_store::{PrimitiveStore, DeferredResolve, PrimitiveScratchBuffer}; use crate::prim_store::gradient::GRADIENT_FP_STOPS; use crate::render_backend::DataStores; -use crate::render_task::{RenderTaskKind, RenderTaskAddress, ClearMode, BlitSource}; +use crate::render_task::{RenderTaskKind, RenderTaskAddress, BlitSource}; use crate::render_task::{RenderTask, ScalingTask, SvgFilterInfo}; use crate::render_task_graph::{RenderTaskGraph, RenderTaskId}; use crate::resource_cache::ResourceCache; @@ -190,7 +190,7 @@ max_dynamic_size: DeviceIntSize::new(0, 0), targets: Vec::new(), saved_index: None, - alloc_tracker: ArrayAllocationTracker::new(), + alloc_tracker: ArrayAllocationTracker::new(None), gpu_supports_fast_clears, } } @@ -342,15 +342,6 @@ profile_scope!("alpha_task"); let task = &render_tasks[*task_id]; - match task.clear_mode { - ClearMode::One | - ClearMode::Zero => { - panic!("bug: invalid clear mode for color task"); - } - ClearMode::DontCare | - ClearMode::Transparent => {} - } - match task.kind { RenderTaskKind::Picture(ref pic_task) => { let pic = &ctx.prim_store.pictures[pic_task.pic_index.0]; @@ -619,19 +610,6 @@ let task = &render_tasks[task_id]; let (target_rect, _) = task.get_target_rect(); - match task.clear_mode { - ClearMode::Zero => { - self.zero_clears.push(task_id); - } - ClearMode::One => { - self.one_clears.push(task_id); - } - ClearMode::DontCare => {} - ClearMode::Transparent => { - panic!("bug: invalid clear mode for alpha task"); - } - } - match task.kind { RenderTaskKind::Readback | RenderTaskKind::Picture(..) | @@ -643,6 +621,7 @@ panic!("BUG: should not be added to alpha target!"); } RenderTaskKind::VerticalBlur(..) => { + self.zero_clears.push(task_id); add_blur_instances( &mut self.vertical_blurs, BlurDirection::Vertical, @@ -651,6 +630,7 @@ ); } RenderTaskKind::HorizontalBlur(..) => { + self.zero_clears.push(task_id); add_blur_instances( &mut self.horizontal_blurs, BlurDirection::Horizontal, @@ -659,6 +639,9 @@ ); } RenderTaskKind::CacheMask(ref task_info) => { + if task_info.clear_to_one { + self.one_clears.push(task_id); + } self.clip_batcher.add( task_info.clip_node_range, task_info.root_spatial_node_index, @@ -676,6 +659,9 @@ ); } RenderTaskKind::ClipRegion(ref region_task) => { + if region_task.clear_to_one { + self.one_clears.push(task_id); + } let device_rect = DeviceRect::new( DevicePoint::zero(), target_rect.size.to_f32(), diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/render_task.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/render_task.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/render_task.rs 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/render_task.rs 2020-11-17 19:31:29.000000000 +0000 @@ -129,6 +129,7 @@ pub root_spatial_node_index: SpatialNodeIndex, pub clip_node_range: ClipNodeRange, pub device_pixel_scale: DevicePixelScale, + pub clear_to_one: bool, } #[derive(Debug)] @@ -138,6 +139,7 @@ pub local_pos: LayoutPoint, pub device_pixel_scale: DevicePixelScale, pub clip_data: ClipData, + pub clear_to_one: bool, } #[cfg_attr(feature = "capture", derive(Serialize))] @@ -309,20 +311,6 @@ } } -#[derive(Debug, Copy, Clone, PartialEq)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub enum ClearMode { - // Applicable to color and alpha targets. - Zero, - One, - /// This task doesn't care what it is cleared to - it will completely overwrite it. - DontCare, - - // Applicable to color targets only. - Transparent, -} - /// In order to avoid duplicating the down-scaling and blur passes when a picture has several blurs, /// we use a local (primitive-level) cache of the render tasks generated for a single shadowed primitive /// in a single frame. @@ -361,7 +349,6 @@ pub location: RenderTaskLocation, pub children: TaskDependencies, pub kind: RenderTaskKind, - pub clear_mode: ClearMode, pub saved_index: Option, } @@ -371,7 +358,6 @@ size: DeviceIntSize, children: TaskDependencies, kind: RenderTaskKind, - clear_mode: ClearMode, ) -> Self { render_task_sanity_check(&size); @@ -379,7 +365,6 @@ location: RenderTaskLocation::Dynamic(None, size), children, kind, - clear_mode, saved_index: None, } } @@ -394,7 +379,6 @@ location, children, kind: RenderTaskKind::Test(target), - clear_mode: ClearMode::Transparent, saved_index: None, } } @@ -438,7 +422,6 @@ scissor_rect, valid_rect, }), - clear_mode: ClearMode::Transparent, saved_index: None, } } @@ -459,7 +442,6 @@ start_point, end_point, }), - ClearMode::DontCare, ) } @@ -468,7 +450,6 @@ size, TaskDependencies::new(), RenderTaskKind::Readback, - ClearMode::Transparent, ) } @@ -501,7 +482,6 @@ source, padding, }), - ClearMode::Transparent, ) } @@ -521,7 +501,6 @@ wavy_line_thickness, local_size, }), - ClearMode::Transparent, ) } @@ -593,7 +572,6 @@ mask_task_id, render_tasks, RenderTargetKind::Alpha, - ClearMode::Zero, None, cache_size, ) @@ -618,12 +596,6 @@ // If we have a potentially tiled clip mask, clear the mask area first. Otherwise, // the first (primary) clip mask will overwrite all the clip mask pixels with // blending disabled to set to the initial value. - let clear_mode = if needs_clear { - ClearMode::One - } else { - ClearMode::DontCare - }; - render_tasks.add().init( RenderTask::with_dynamic_location( outer_rect.size.to_i32(), @@ -633,8 +605,8 @@ clip_node_range, root_spatial_node_index, device_pixel_scale, + clear_to_one: needs_clear, }), - clear_mode, ) ) } @@ -646,12 +618,6 @@ device_pixel_scale: DevicePixelScale, fb_config: &FrameBuilderConfig, ) -> Self { - let clear_mode = if fb_config.gpu_supports_fast_clears { - ClearMode::One - } else { - ClearMode::DontCare - }; - RenderTask::with_dynamic_location( size, TaskDependencies::new(), @@ -659,8 +625,8 @@ local_pos, device_pixel_scale, clip_data, + clear_to_one: fb_config.gpu_supports_fast_clears, }), - clear_mode, ) } @@ -706,7 +672,6 @@ src_task_id: RenderTaskId, render_tasks: &mut RenderTaskGraph, target_kind: RenderTargetKind, - clear_mode: ClearMode, mut blur_cache: Option<&mut BlurTaskCache>, blur_region: DeviceIntSize, ) -> RenderTaskId { @@ -772,7 +737,6 @@ blur_region, uv_rect_kind, }), - clear_mode, )); render_tasks.add().init(RenderTask::with_dynamic_location( @@ -785,7 +749,6 @@ blur_region, uv_rect_kind, }), - clear_mode, )) }); @@ -806,7 +769,6 @@ RenderTaskKind::Border(BorderTask { instances, }), - ClearMode::Transparent, ) } @@ -847,7 +809,6 @@ uv_rect_kind, padding, }), - ClearMode::DontCare, ) ) } @@ -981,7 +942,6 @@ )), render_tasks, RenderTargetKind::Color, - ClearMode::Transparent, None, content_size, ) @@ -1050,7 +1010,6 @@ offset_task_id, render_tasks, RenderTargetKind::Color, - ClearMode::Transparent, None, content_size, ); @@ -1167,7 +1126,6 @@ uv_rect_kind, info, }), - ClearMode::Transparent, ) } @@ -1547,7 +1505,6 @@ } } - pt.add_item(format!("clear to: {:?}", self.clear_mode)); pt.add_item(format!("dimensions: {:?}", self.location.size())); for &child_id in &self.children { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/resource_cache.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/resource_cache.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/resource_cache.rs 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/resource_cache.rs 2020-11-17 19:31:29.000000000 +0000 @@ -1168,7 +1168,6 @@ pub fn block_until_all_resources_added( &mut self, gpu_cache: &mut GpuCache, - render_tasks: &mut RenderTaskGraph, profile: &mut TransactionProfile, ) { profile_scope!("block_until_all_resources_added"); @@ -1180,8 +1179,6 @@ &mut self.cached_glyphs, &mut self.texture_cache, gpu_cache, - &mut self.cached_render_tasks, - render_tasks, profile, ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/texture_allocator.rs firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/texture_allocator.rs --- firefox-trunk-84.0~a1~hg20201115r557261/gfx/wr/webrender/src/texture_allocator.rs 2020-11-15 14:37:58.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/gfx/wr/webrender/src/texture_allocator.rs 2020-11-17 19:31:29.000000000 +0000 @@ -64,14 +64,23 @@ } impl ArrayAllocationTracker { - pub fn new() -> Self { - ArrayAllocationTracker { + pub fn new(initial_size: Option) -> Self { + let mut allocator = ArrayAllocationTracker { bins: [ Vec::new(), Vec::new(), Vec::new(), ], + }; + + if let Some(initial_size) = initial_size { + allocator.push( + FreeRectSlice(0), + initial_size.into(), + ); } + + allocator } fn push(&mut self, slice: FreeRectSlice, rect: DeviceIntRect) { @@ -213,7 +222,7 @@ DeviceIntSize::new(texture_size, texture_size), ); let mut rng = thread_rng(); - let mut allocator = ArrayAllocationTracker::new(); + let mut allocator = ArrayAllocationTracker::new(None); // check for empty allocation assert_eq!( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/ipc/glue/BackgroundParentImpl.cpp firefox-trunk-85.0~a1~hg20201117r557492/ipc/glue/BackgroundParentImpl.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/ipc/glue/BackgroundParentImpl.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/ipc/glue/BackgroundParentImpl.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -761,7 +761,7 @@ } auto BackgroundParentImpl::AllocPUDPSocketParent( - const Maybe& /* unused */, const nsCString& /* unused */) + const Maybe& /* unused */, const nsCString & /* unused */) -> PUDPSocketParent* { RefPtr p = new UDPSocketParent(this); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/ipc/mscom/AsyncInvoker.h firefox-trunk-85.0~a1~hg20201117r557492/ipc/mscom/AsyncInvoker.h --- firefox-trunk-84.0~a1~hg20201115r557261/ipc/mscom/AsyncInvoker.h 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/ipc/mscom/AsyncInvoker.h 2020-11-17 19:31:30.000000000 +0000 @@ -370,17 +370,14 @@ * performance penalty associated with that. */ explicit AsyncInvoker(SyncInterface* aSyncObj, - const Maybe& aIsProxy = Nothing()) - : mSyncObj(ResolveIsProxy(aSyncObj, aIsProxy) ? nullptr : aSyncObj) { + const Maybe& aIsProxy = Nothing()) { MOZ_ASSERT(aSyncObj); - if (mSyncObj) { - return; - } - RefPtr callFactory; - if (FAILED(aSyncObj->QueryInterface(IID_ICallFactory, + if ((aIsProxy.isSome() && !aIsProxy.value()) || + FAILED(aSyncObj->QueryInterface(IID_ICallFactory, getter_AddRefs(callFactory)))) { + mSyncObj = aSyncObj; return; } @@ -436,13 +433,6 @@ AsyncInvoker& operator=(AsyncInvoker&& aOther) = delete; private: - static bool ResolveIsProxy(SyncInterface* aSyncObj, - const Maybe& aIsProxy) { - MOZ_ASSERT(aSyncObj); - return aIsProxy.isSome() ? aIsProxy.value() : IsProxy(aSyncObj); - } - - private: RefPtr mSyncObj; }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/ipc/mscom/ProfilerMarkers.cpp firefox-trunk-85.0~a1~hg20201117r557492/ipc/mscom/ProfilerMarkers.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/ipc/mscom/ProfilerMarkers.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/ipc/mscom/ProfilerMarkers.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -11,11 +11,13 @@ #include "mozilla/Assertions.h" #include "mozilla/Atomics.h" #include "mozilla/DebugOnly.h" +#include "mozilla/mscom/Utils.h" #include "mozilla/Services.h" #include "nsCOMPtr.h" #include "nsIObserver.h" #include "nsIObserverService.h" #include "nsISupportsImpl.h" +#include "nsString.h" #include "nsXULAppAPI.h" #include @@ -31,7 +33,7 @@ ~ProfilerMarkerChannelHook() = default; public: - ProfilerMarkerChannelHook() : mRefCnt(0), mMainThreadORPCDepth(0) {} + ProfilerMarkerChannelHook() : mRefCnt(0) {} // IUnknown STDMETHODIMP QueryInterface(REFIID aIid, void** aOutInterface) override; @@ -58,10 +60,6 @@ * * Finally, our implementation responds to any request matching our extension * ID, however we only care about main thread COM calls. - * - * Further note that COM allows re-entrancy, however for our purposes we only - * care about the outermost IPC call on the main thread, so we use the - * mMainThreadORPCDepth variable to track that. */ // IChannelHook @@ -92,8 +90,10 @@ void* aDataBuf, HRESULT aFault) override {} private: + void BuildMarkerName(REFIID aIid, nsACString& aOutMarkerName); + + private: mozilla::Atomic mRefCnt; - ULONG mMainThreadORPCDepth; }; HRESULT ProfilerMarkerChannelHook::QueryInterface(REFIID aIid, @@ -118,16 +118,23 @@ return result; } +void ProfilerMarkerChannelHook::BuildMarkerName(REFIID aIid, + nsACString& aOutMarkerName) { + aOutMarkerName.AssignLiteral("ORPC Call for "); + + nsAutoCString iidStr; + mozilla::mscom::DiagnosticNameForIID(aIid, iidStr); + aOutMarkerName.Append(iidStr); +} + void ProfilerMarkerChannelHook::ClientGetSize(REFGUID aExtensionId, REFIID aIid, ULONG* aOutDataSize) { if (aExtensionId == GUID_MozProfilerMarkerExtension) { if (NS_IsMainThread()) { - if (!mMainThreadORPCDepth) { - PROFILER_TRACING_MARKER("MSCOM", "ORPC Call", IPC, - TRACING_INTERVAL_START); - } - - ++mMainThreadORPCDepth; + nsAutoCString markerName; + BuildMarkerName(aIid, markerName); + PROFILER_TRACING_MARKER("MSCOM", markerName.get(), IPC, + TRACING_INTERVAL_START); } if (aOutDataSize) { @@ -140,12 +147,11 @@ void ProfilerMarkerChannelHook::ClientNotify(REFGUID aExtensionId, REFIID aIid, ULONG aDataSize, void* aDataBuffer, DWORD aDataRep, HRESULT aFault) { - if (aExtensionId == GUID_MozProfilerMarkerExtension && NS_IsMainThread()) { - MOZ_ASSERT(mMainThreadORPCDepth > 0); - --mMainThreadORPCDepth; - if (!mMainThreadORPCDepth) { - PROFILER_TRACING_MARKER("MSCOM", "ORPC Call", IPC, TRACING_INTERVAL_END); - } + if (NS_IsMainThread() && aExtensionId == GUID_MozProfilerMarkerExtension) { + nsAutoCString markerName; + BuildMarkerName(aIid, markerName); + PROFILER_TRACING_MARKER("MSCOM", markerName.get(), IPC, + TRACING_INTERVAL_END); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/ipc/mscom/Utils.cpp firefox-trunk-85.0~a1~hg20201117r557492/ipc/mscom/Utils.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/ipc/mscom/Utils.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/ipc/mscom/Utils.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -28,6 +28,8 @@ #include #include +#include + #if defined(_MSC_VER) extern "C" IMAGE_DOS_HEADER __ImageBase; #endif @@ -317,6 +319,82 @@ } } +// Undocumented IIDs that are relevant for diagnostic purposes +static const IID IID_ISCMLocalActivator = { + 0x00000136, + 0x0000, + 0x0000, + {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; +static const IID IID_IRundown = { + 0x00000134, + 0x0000, + 0x0000, + {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; +static const IID IID_IRemUnknown = { + 0x00000131, + 0x0000, + 0x0000, + {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; +static const IID IID_IRemUnknown2 = { + 0x00000143, + 0x0000, + 0x0000, + {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}}; + +struct IIDToLiteralMapEntry { + constexpr IIDToLiteralMapEntry(REFIID aIid, nsLiteralCString&& aStr) + : mIid(aIid), mStr(std::forward(aStr)) {} + + REFIID mIid; + const nsLiteralCString mStr; +}; + +/** + * Given the name of an interface, the IID_ENTRY macro generates a pair + * containing a reference to the interface ID and a stringified version of + * the interface name. + * + * For example: + * + * {IID_ENTRY(IUnknown)} + * is expanded to: + * {IID_IUnknown, "IUnknown"_ns} + * + */ +// clang-format off +# define IID_ENTRY_STRINGIFY(iface) #iface##_ns +# define IID_ENTRY(iface) IID_##iface, IID_ENTRY_STRINGIFY(iface) +// clang-format on + +// Mapping of selected IIDs to friendly, human readable descriptions for each +// interface. +static constexpr IIDToLiteralMapEntry sIidDiagStrs[] = { + {IID_ENTRY(IUnknown)}, + {IID_IRemUnknown, "cross-apartment IUnknown"_ns}, + {IID_IRundown, "cross-apartment object management"_ns}, + {IID_ISCMLocalActivator, "out-of-process object instantiation"_ns}, + {IID_IRemUnknown2, "cross-apartment IUnknown"_ns}}; + +# undef IID_ENTRY +# undef IID_ENTRY_STRINGIFY + +void DiagnosticNameForIID(REFIID aIid, nsACString& aOutString) { + // If the IID matches something in sIidDiagStrs, output its string. + for (const auto& curEntry : sIidDiagStrs) { + if (curEntry.mIid == aIid) { + aOutString.Assign(curEntry.mStr); + return; + } + } + + // Otherwise just convert the IID to string form and output that. + nsAutoString strIid; + GUIDToString(aIid, strIid); + + aOutString.AssignLiteral("IID "); + AppendUTF16toUTF8(strIid, aOutString); +} + #else void GUIDToString(REFGUID aGuid, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/ipc/mscom/Utils.h firefox-trunk-85.0~a1~hg20201117r557492/ipc/mscom/Utils.h --- firefox-trunk-84.0~a1~hg20201115r557261/ipc/mscom/Utils.h 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/ipc/mscom/Utils.h 2020-11-17 19:31:30.000000000 +0000 @@ -105,6 +105,15 @@ bool IsClassThreadAwareInprocServer(REFCLSID aClsid); void GUIDToString(REFGUID aGuid, nsAString& aOutString); + +/** + * Converts an IID to a human-readable string for the purposes of diagnostic + * tools such as the profiler. For some special cases, we output a friendly + * string that describes the purpose of the interface. If no such description + * exists, we simply fall back to outputting the IID as a string formatted by + * GUIDToString(). + */ +void DiagnosticNameForIID(REFIID aIid, nsACString& aOutString); #else void GUIDToString(REFGUID aGuid, wchar_t (&aOutBuf)[kGuidRegFormatCharLenInclNul]); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/builtin/TestingFunctions.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/builtin/TestingFunctions.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/builtin/TestingFunctions.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/builtin/TestingFunctions.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -5960,95 +5960,6 @@ return true; } -static bool MonitorType(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - RootedObject callee(cx, &args.callee()); - - // First argument must be either a scripted function or null/undefined (in - // this case we use the caller's script). - RootedFunction fun(cx); - RootedScript script(cx); - if (args.get(0).isNullOrUndefined()) { - script = cx->currentScript(); - if (!script) { - ReportUsageErrorASCII(cx, callee, "No scripted caller"); - return false; - } - } else { - if (!IsFunctionObject(args.get(0), fun.address()) || - !fun->isInterpreted()) { - ReportUsageErrorASCII( - cx, callee, - "First argument must be a scripted function or null/undefined"); - return false; - } - - script = JSFunction::getOrCreateScript(cx, fun); - if (!script) { - return false; - } - } - - int32_t index; - if (!ToInt32(cx, args.get(1), &index)) { - return false; - } - - if (index < 0 || uint32_t(index) >= jit::JitScript::NumTypeSets(script)) { - ReportUsageErrorASCII(cx, callee, "Index out of range"); - return false; - } - - RootedValue val(cx, args.get(2)); - - // If val is "unknown" or "unknownObject" we mark the TypeSet as unknown or - // unknownObject, respectively. - bool unknown = false; - bool unknownObject = false; - if (val.isString()) { - if (!JS_StringEqualsLiteral(cx, val.toString(), "unknown", &unknown)) { - return false; - } - if (!JS_StringEqualsLiteral(cx, val.toString(), "unknownObject", - &unknownObject)) { - return false; - } - } - - // Avoid assertion failures if TI or Baseline Interpreter is disabled or if we - // can't Baseline Interpret this script. - if (!IsTypeInferenceEnabled() || !jit::IsBaselineInterpreterEnabled() || - !jit::CanBaselineInterpretScript(script)) { - args.rval().setUndefined(); - return true; - } - - AutoRealm ar(cx, script); - - if (!cx->realm()->ensureJitRealmExists(cx)) { - return false; - } - - jit::AutoKeepJitScripts keepJitScript(cx); - if (!script->ensureHasJitScript(cx, keepJitScript)) { - return false; - } - - AutoEnterAnalysis enter(cx); - AutoSweepJitScript sweep(script); - StackTypeSet* typeSet = script->jitScript()->typeArray(sweep) + index; - if (unknown) { - typeSet->addType(sweep, cx, TypeSet::UnknownType()); - } else if (unknownObject) { - typeSet->addType(sweep, cx, TypeSet::AnyObjectType()); - } else { - typeSet->addType(sweep, cx, TypeSet::GetValueType(val)); - } - - args.rval().setUndefined(); - return true; -} - static bool MarkObjectPropertiesUnknown(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); @@ -7297,14 +7208,6 @@ " Returns an object containing a copy of all global lexical bindings.\n" " Example use: let x = 1; assertEq(globalLexicals().x, 1);\n"), - JS_FN_HELP("monitorType", MonitorType, 3, 0, -"monitorType(fun, index, val)", -" Adds val's type to the index'th StackTypeSet of the function's\n" -" JitScript.\n" -" If fun is null or undefined, the caller's script is used.\n" -" If the value is the string 'unknown' or 'unknownObject'\n" -" the TypeSet is marked as unknown or unknownObject, respectively.\n"), - JS_FN_HELP("baselineCompile", BaselineCompile, 2, 0, "baselineCompile([fun/code], forceDebugInstrumentation=false)", " Baseline-compiles the given JS function or script.\n" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/devtools/automation/variants/nowarpdebug firefox-trunk-85.0~a1~hg20201117r557492/js/src/devtools/automation/variants/nowarpdebug --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/devtools/automation/variants/nowarpdebug 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/devtools/automation/variants/nowarpdebug 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -{ - "configure-args": "--enable-rust-simd", - "debug": true, - "compiler": "clang", - "env": { - "JSTESTS_EXTRA_ARGS": "--jitflags=nowarp" - }, - "conditional-configure-args": { - "linux64": "--enable-clang-plugin" - } -} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/devtools/automation/variants/warpdebug firefox-trunk-85.0~a1~hg20201117r557492/js/src/devtools/automation/variants/warpdebug --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/devtools/automation/variants/warpdebug 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/devtools/automation/variants/warpdebug 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -{ - "configure-args": "--enable-rust-simd", - "debug": true, - "env": { - "JITTEST_EXTRA_ARGS": "--jitflags=warp" - }, - "skip-tests": { - "all": ["jstests", "jsapitests"] - } -} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/BytecodeEmitter.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/BytecodeEmitter.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/BytecodeEmitter.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/BytecodeEmitter.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -1549,12 +1549,9 @@ return findInnermostNestableControl(); } -bool BytecodeEmitter::checkRunOnceContext() { - return sc->treatAsRunOnce() && !isInLoop(); -} - bool BytecodeEmitter::checkSingletonContext() { - return sc->isTopLevelContext() && checkRunOnceContext(); + MOZ_ASSERT_IF(sc->treatAsRunOnce(), sc->isTopLevelContext()); + return sc->treatAsRunOnce() && !isInLoop(); } bool BytecodeEmitter::needsImplicitThis() { @@ -5742,33 +5739,6 @@ funbox->setMemberInitializers(*memberInitializers); } - // A function is a run-once lambda if the following all hold: - // - Enclosing script must be run-once lambda or run-once top-level. - // `SharedContext::treatAsRunOnce()` - // - Function definition must not be in a loop. - // `BytecodeEmitter::isInLoop() == false` - // - Function must be an IIFE like "(function(){ })()". - // `CallOrNewEmitter::state == State::FunctionCallee` - // - Function must not match `shouldSuppressRunOnce` conditions. - // - // NOTE: This is a heuristic and through trick such as `fun.caller` it may - // still be run more than once. The VM must accomodate this. - // NOTE: For a lazy function, this will be applied to any existing function - // in UpdateEmittedInnerFunctions(). - bool isRunOnceLambda = - emittingRunOnceLambda && !funbox->shouldSuppressRunOnce(); - funbox->setTreatAsRunOnce(isRunOnceLambda); - - // Mark functions which are expected to only have one instance as singletons - // functions. These function instances will then always have a unique script - // of which they are the canonical function. This improves type-inferrence - // precision. CloneFunctionObject will make a deep clone of the function and - // script as needed if our prediction is wrong. - // - // NOTE: This heuristic is arbitrary, but some debugger tests rely on the - // current behaviour and need to be updated if the condiditons change. - funbox->setIsSingleton(checkRunOnceContext()); - if (!funbox->emitBytecode) { return fe.emitLazy(); // [stack] FUN? diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/BytecodeEmitter.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/BytecodeEmitter.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/BytecodeEmitter.h 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/BytecodeEmitter.h 2020-11-17 19:31:31.000000000 +0000 @@ -135,9 +135,6 @@ // Script contains finally block. bool hasTryFinally = false; - // True while emitting a lambda which is only expected to run once. - bool emittingRunOnceLambda = false; - enum EmitterMode { Normal, @@ -273,10 +270,6 @@ bool isInLoop(); MOZ_MUST_USE bool checkSingletonContext(); - // Check whether our function is in a run-once context (a toplevel - // run-one script or a run-once lambda). - MOZ_MUST_USE bool checkRunOnceContext(); - bool needsImplicitThis(); MOZ_MUST_USE bool emitThisEnvironmentCallee(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/CallOrNewEmitter.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/CallOrNewEmitter.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/CallOrNewEmitter.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/CallOrNewEmitter.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -17,16 +17,6 @@ using mozilla::Maybe; -AutoEmittingRunOnceLambda::AutoEmittingRunOnceLambda(BytecodeEmitter* bce) - : bce_(bce) { - MOZ_ASSERT(!bce_->emittingRunOnceLambda); - bce_->emittingRunOnceLambda = true; -} - -AutoEmittingRunOnceLambda::~AutoEmittingRunOnceLambda() { - bce_->emittingRunOnceLambda = false; -} - CallOrNewEmitter::CallOrNewEmitter(BytecodeEmitter* bce, JSOp op, ArgumentsKind argumentsKind, ValueUsage valueUsage) @@ -83,18 +73,6 @@ bool CallOrNewEmitter::prepareForFunctionCallee() { MOZ_ASSERT(state_ == State::Start); - // Top level lambdas which are immediately invoked should be treated as - // only running once. Every time they execute we will create new types and - // scripts for their contents, to increase the quality of type information - // within them and enable more backend optimizations. Note that this does - // not depend on the lambda being invoked at most once (it may be named or - // be accessed via foo.caller indirection), as multiple executions will - // just cause the inner scripts to be repeatedly cloned. - MOZ_ASSERT(!bce_->emittingRunOnceLambda); - if (bce_->checkRunOnceContext()) { - autoEmittingRunOnceLambda_.emplace(bce_); - } - state_ = State::FunctionCallee; return true; } @@ -151,7 +129,6 @@ } break; case State::FunctionCallee: - autoEmittingRunOnceLambda_.reset(); needsThis = true; break; case State::SuperCallee: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/CallOrNewEmitter.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/CallOrNewEmitter.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/CallOrNewEmitter.h 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/CallOrNewEmitter.h 2020-11-17 19:31:31.000000000 +0000 @@ -25,14 +25,6 @@ struct BytecodeEmitter; -class MOZ_RAII AutoEmittingRunOnceLambda { - BytecodeEmitter* bce_; - - public: - explicit AutoEmittingRunOnceLambda(BytecodeEmitter* bce); - ~AutoEmittingRunOnceLambda(); -}; - // Class for emitting bytecode for call or new expression. // // Usage: (check for the return value is omitted for simplicity) @@ -170,8 +162,6 @@ // The branch for spread call optimization. mozilla::Maybe ifNotOptimizable_; - mozilla::Maybe autoEmittingRunOnceLambda_; - mozilla::Maybe poe_; mozilla::Maybe eoe_; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/FoldConstants.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/FoldConstants.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/FoldConstants.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/FoldConstants.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -1242,11 +1242,8 @@ // Replace with concatenation if we multiple nodes. if (accum.length() > 1) { // Construct the concatenated atom. - const ParserAtom* combination = - info.parserAtoms - .concatAtoms(info.cx, - mozilla::Range(accum.begin(), accum.length())) - .unwrapOr(nullptr); + const ParserAtom* combination = info.parserAtoms.concatAtoms( + info.cx, mozilla::Range(accum.begin(), accum.length())); if (!combination) { return false; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/Frontend2.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/Frontend2.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/Frontend2.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/Frontend2.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -65,7 +65,7 @@ smoosh_get_atom_at(result, i)); auto len = smoosh_get_atom_len_at(result, i); const ParserAtom* atom = - compilationState.parserAtoms.internUtf8(cx, s, len).unwrapOr(nullptr); + compilationState.parserAtoms.internUtf8(cx, s, len); if (!atom) { return false; } @@ -310,8 +310,7 @@ const mozilla::Utf8Unit* sUtf8 = reinterpret_cast(s); const ParserAtom* atom = - compilationState.parserAtoms.internUtf8(cx, sUtf8, len) - .unwrapOr(nullptr); + compilationState.parserAtoms.internUtf8(cx, sUtf8, len); if (!atom) { return false; } @@ -479,9 +478,7 @@ script.lazyFunctionEnclosingScopeIndex_ = mozilla::Some(ScopeIndex( smooshScript.lazy_function_enclosing_scope_index.AsSome())); } - script.isStandaloneFunction = smooshScript.is_standalone_function; script.wasFunctionEmitted = smooshScript.was_function_emitted; - script.isSingletonFunction = smooshScript.is_singleton_function; } if (!ConvertGCThings(cx, result, smooshScript, compilationInfo.stencil.alloc, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/ParserAtom.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/ParserAtom.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/ParserAtom.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/ParserAtom.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -109,8 +109,6 @@ namespace js { namespace frontend { -static JS::OOM PARSER_ATOMS_OOM; - JSAtom* GetWellKnownAtom(JSContext* cx, WellKnownAtomId atomId) { #define ASSERT_OFFSET_(idpart, id, text) \ static_assert(offsetof(JSAtomState, id) == \ @@ -132,19 +130,15 @@ return (&cx->names().abort)[int32_t(atomId)]; } -mozilla::GenericErrorResult RaiseParserAtomsOOMError(JSContext* cx) { - js::ReportOutOfMemory(cx); - return mozilla::Err(PARSER_ATOMS_OOM); -} - template -/* static */ JS::Result ParserAtomEntry::allocate( +/* static */ ParserAtomEntry* ParserAtomEntry::allocate( JSContext* cx, LifoAlloc& alloc, InflatedChar16Sequence seq, uint32_t length, HashNumber hash) { constexpr size_t HeaderSize = sizeof(ParserAtomEntry); void* raw = alloc.alloc(HeaderSize + (sizeof(CharT) * length)); if (!raw) { - return RaiseParserAtomsOOMError(cx); + js::ReportOutOfMemory(cx); + return nullptr; } constexpr bool hasTwoByteChars = (sizeof(CharT) == 2); @@ -307,47 +301,54 @@ alloc_(alloc), entries_(entries) {} -JS::Result ParserAtomsTable::addEntry( - JSContext* cx, EntrySet::AddPtr& addPtr, ParserAtomEntry* entry) { +const ParserAtom* ParserAtomsTable::addEntry(JSContext* cx, + EntrySet::AddPtr& addPtr, + ParserAtomEntry* entry) { MOZ_ASSERT(!addPtr); ParserAtomIndex index = ParserAtomIndex(entries_.length()); if (size_t(index) >= TaggedParserAtomIndex::IndexLimit) { ReportAllocationOverflow(cx); - return mozilla::Err(PARSER_ATOMS_OOM); + return nullptr; } if (!entries_.append(entry)) { - return RaiseParserAtomsOOMError(cx); + js::ReportOutOfMemory(cx); + return nullptr; } entry->setParserAtomIndex(index); if (!entrySet_.add(addPtr, entry)) { - return RaiseParserAtomsOOMError(cx); + js::ReportOutOfMemory(cx); + return nullptr; } return entry->asAtom(); } template -JS::Result ParserAtomsTable::internChar16Seq( +const ParserAtom* ParserAtomsTable::internChar16Seq( JSContext* cx, EntrySet::AddPtr& addPtr, HashNumber hash, InflatedChar16Sequence seq, uint32_t length) { MOZ_ASSERT(!addPtr); - ParserAtomEntry* entry; - MOZ_TRY_VAR(entry, ParserAtomEntry::allocate(cx, alloc_, seq, - length, hash)); + ParserAtomEntry* entry = + ParserAtomEntry::allocate(cx, alloc_, seq, length, hash); + if (!entry) { + return nullptr; + } return addEntry(cx, addPtr, entry); } static const uint16_t MAX_LATIN1_CHAR = 0xff; -JS::Result ParserAtomsTable::internAscii( - JSContext* cx, const char* asciiPtr, uint32_t length) { +const ParserAtom* ParserAtomsTable::internAscii(JSContext* cx, + const char* asciiPtr, + uint32_t length) { // ASCII strings are strict subsets of Latin1 strings. const Latin1Char* latin1Ptr = reinterpret_cast(asciiPtr); return internLatin1(cx, latin1Ptr, length); } -JS::Result ParserAtomsTable::internLatin1( - JSContext* cx, const Latin1Char* latin1Ptr, uint32_t length) { +const ParserAtom* ParserAtomsTable::internLatin1(JSContext* cx, + const Latin1Char* latin1Ptr, + uint32_t length) { // Check for tiny strings which are abundant in minified code. if (const ParserAtom* tiny = wellKnownTable_.lookupTiny(latin1Ptr, length)) { return tiny; @@ -388,13 +389,13 @@ return true; } -JS::Result ParserAtomVectorBuilder::internLatin1At( +const ParserAtom* ParserAtomVectorBuilder::internLatin1At( JSContext* cx, const Latin1Char* latin1Ptr, HashNumber hash, uint32_t length, ParserAtomIndex index) { return internAt(cx, latin1Ptr, hash, length, index); } -JS::Result ParserAtomVectorBuilder::internChar16At( +const ParserAtom* ParserAtomVectorBuilder::internChar16At( JSContext* cx, LittleEndianChars twoByteLE, HashNumber hash, uint32_t length, ParserAtomIndex index) { #ifdef DEBUG @@ -415,9 +416,11 @@ } template -JS::Result ParserAtomVectorBuilder::internAt( - JSContext* cx, InputCharsT chars, HashNumber hash, uint32_t length, - ParserAtomIndex index) { +const ParserAtom* ParserAtomVectorBuilder::internAt(JSContext* cx, + InputCharsT chars, + HashNumber hash, + uint32_t length, + ParserAtomIndex index) { InflatedChar16Sequence seq(chars, length); #ifdef DEBUG @@ -427,17 +430,21 @@ MOZ_ASSERT(wellKnownTable_.lookupChar16Seq(lookup) == nullptr); #endif - ParserAtomEntry* entry; - MOZ_TRY_VAR(entry, - ParserAtomEntry::allocate(cx, *alloc_, seq, length, hash)); + ParserAtomEntry* entry = + ParserAtomEntry::allocate(cx, *alloc_, seq, length, hash); + if (!entry) { + return nullptr; + } + entry->setParserAtomIndex(index); entries_[index] = entry; return entry->asAtom(); } -JS::Result ParserAtomsTable::internUtf8( - JSContext* cx, const mozilla::Utf8Unit* utf8Ptr, uint32_t nbyte) { +const ParserAtom* ParserAtomsTable::internUtf8(JSContext* cx, + const mozilla::Utf8Unit* utf8Ptr, + uint32_t nbyte) { // Check for tiny strings which are abundant in minified code. // NOTE: The tiny atoms are all ASCII-only so we can directly look at the // UTF-8 data without worrying about surrogates. @@ -485,8 +492,9 @@ length); } -JS::Result ParserAtomsTable::internChar16( - JSContext* cx, const char16_t* char16Ptr, uint32_t length) { +const ParserAtom* ParserAtomsTable::internChar16(JSContext* cx, + const char16_t* char16Ptr, + uint32_t length) { // Check for tiny strings which are abundant in minified code. if (const ParserAtom* tiny = wellKnownTable_.lookupTiny(char16Ptr, length)) { return tiny; @@ -524,20 +532,19 @@ length); } -JS::Result ParserAtomsTable::internJSAtom( +const ParserAtom* ParserAtomsTable::internJSAtom( JSContext* cx, CompilationInfo& compilationInfo, JSAtom* atom) { const ParserAtom* parserAtom; { JS::AutoCheckCannotGC nogc; - auto result = + parserAtom = atom->hasLatin1Chars() ? internLatin1(cx, atom->latin1Chars(nogc), atom->length()) : internChar16(cx, atom->twoByteChars(nogc), atom->length()); - if (result.isErr()) { - return result; + if (!parserAtom) { + return nullptr; } - parserAtom = result.unwrap(); } if (parserAtom->isParserAtomIndex()) { @@ -546,7 +553,7 @@ if (!atomCache.hasAtomAt(index)) { if (!atomCache.setAtomAt(cx, index, atom)) { - return mozilla::Err(PARSER_ATOMS_OOM); + return nullptr; } } } @@ -557,7 +564,7 @@ return parserAtom; } -JS::Result ParserAtomsTable::concatAtoms( +const ParserAtom* ParserAtomsTable::concatAtoms( JSContext* cx, mozilla::Range atoms) { MOZ_ASSERT(atoms.length() >= 2, "concatAtoms should only be used for multiple inputs"); @@ -571,7 +578,8 @@ } // Overflow check here, length if (atom->length() >= (ParserAtomEntry::MAX_LENGTH - catLen)) { - return RaiseParserAtomsOOMError(cx); + js::ReportOutOfMemory(cx); + return nullptr; } catLen += atom->length(); } @@ -907,7 +915,7 @@ /* Decode the character data. */ MOZ_ASSERT(mode == XDR_DECODE); JSContext* cx = xdr->cx(); - JS::Result mbAtom(nullptr); + const ParserAtom* atom = nullptr; if (latin1) { const Latin1Char* chars = nullptr; if (length) { @@ -915,19 +923,16 @@ MOZ_TRY(xdr->peekData(&ptr, length * sizeof(Latin1Char))); chars = reinterpret_cast(ptr); } - mbAtom = - xdr->frontendAtoms().internLatin1At(cx, chars, hash, length, index); + atom = xdr->frontendAtoms().internLatin1At(cx, chars, hash, length, index); } else { const uint8_t* twoByteCharsLE = nullptr; if (length) { MOZ_TRY(xdr->peekData(&twoByteCharsLE, length * sizeof(char16_t))); } LittleEndianChars leTwoByte(twoByteCharsLE); - mbAtom = + atom = xdr->frontendAtoms().internChar16At(cx, leTwoByte, hash, length, index); } - - const ParserAtom* atom = mbAtom.unwrapOr(nullptr); if (!atom) { return xdr->fail(JS::TranscodeResult_Throw); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/ParserAtom.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/ParserAtom.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/ParserAtom.h 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/ParserAtom.h 2020-11-17 19:31:31.000000000 +0000 @@ -33,8 +33,6 @@ class ParserAtomsTable; -mozilla::GenericErrorResult RaiseParserAtomsOOMError(JSContext* cx); - // An index to map WellKnownParserAtoms to cx->names(). // This is consistent across multiple compilation. // @@ -256,9 +254,9 @@ ParserAtomEntry(ParserAtomEntry&& other) = delete; template - static JS::Result allocate( - JSContext* cx, LifoAlloc& alloc, InflatedChar16Sequence seq, - uint32_t length, HashNumber hash); + static ParserAtomEntry* allocate(JSContext* cx, LifoAlloc& alloc, + InflatedChar16Sequence seq, + uint32_t length, HashNumber hash); ParserAtom* asAtom() { return reinterpret_cast(this); } const ParserAtom* asAtom() const { @@ -674,34 +672,33 @@ private: // Internal APIs for interning to the table after well-known atoms cases have // been tested. - JS::Result addEntry(JSContext* cx, - EntrySet::AddPtr& addPtr, - ParserAtomEntry* entry); + const ParserAtom* addEntry(JSContext* cx, EntrySet::AddPtr& addPtr, + ParserAtomEntry* entry); template - JS::Result internChar16Seq( - JSContext* cx, EntrySet::AddPtr& addPtr, HashNumber hash, - InflatedChar16Sequence seq, uint32_t length); + const ParserAtom* internChar16Seq(JSContext* cx, EntrySet::AddPtr& addPtr, + HashNumber hash, + InflatedChar16Sequence seq, + uint32_t length); public: - JS::Result internAscii(JSContext* cx, - const char* asciiPtr, - uint32_t length); + const ParserAtom* internAscii(JSContext* cx, const char* asciiPtr, + uint32_t length); - JS::Result internLatin1( - JSContext* cx, const JS::Latin1Char* latin1Ptr, uint32_t length); + const ParserAtom* internLatin1(JSContext* cx, const JS::Latin1Char* latin1Ptr, + uint32_t length); - JS::Result internUtf8( - JSContext* cx, const mozilla::Utf8Unit* utf8Ptr, uint32_t nbyte); + const ParserAtom* internUtf8(JSContext* cx, const mozilla::Utf8Unit* utf8Ptr, + uint32_t nbyte); - JS::Result internChar16(JSContext* cx, - const char16_t* char16Ptr, - uint32_t length); + const ParserAtom* internChar16(JSContext* cx, const char16_t* char16Ptr, + uint32_t length); - JS::Result internJSAtom( - JSContext* cx, CompilationInfo& compilationInfo, JSAtom* atom); + const ParserAtom* internJSAtom(JSContext* cx, + CompilationInfo& compilationInfo, + JSAtom* atom); - JS::Result concatAtoms( - JSContext* cx, mozilla::Range atoms); + const ParserAtom* concatAtoms(JSContext* cx, + mozilla::Range atoms); const ParserAtom* getWellKnown(WellKnownAtomId atomId) const; const ParserAtom* getStatic1(StaticParserString1 s) const; @@ -726,19 +723,20 @@ bool resize(JSContext* cx, size_t count); size_t length() const { return entries_.length(); } - JS::Result internLatin1At( - JSContext* cx, const JS::Latin1Char* latin1Ptr, HashNumber hash, - uint32_t length, ParserAtomIndex index); - - JS::Result internChar16At( - JSContext* cx, const LittleEndianChars twoByteLE, HashNumber hash, - uint32_t length, ParserAtomIndex index); + const ParserAtom* internLatin1At(JSContext* cx, + const JS::Latin1Char* latin1Ptr, + HashNumber hash, uint32_t length, + ParserAtomIndex index); + + const ParserAtom* internChar16At(JSContext* cx, + const LittleEndianChars twoByteLE, + HashNumber hash, uint32_t length, + ParserAtomIndex index); private: template - JS::Result internAt(JSContext* cx, InputCharsT chars, - HashNumber hash, uint32_t length, - ParserAtomIndex index); + const ParserAtom* internAt(JSContext* cx, InputCharsT chars, HashNumber hash, + uint32_t length, ParserAtomIndex index); public: const ParserAtom* getWellKnown(WellKnownAtomId atomId) const; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/Parser.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/Parser.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/Parser.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/Parser.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -842,14 +842,14 @@ // TODO-Stencil // After closed-over-bindings are snapshotted in the handler, // remove this. - auto mbNameId = this->compilationState_.parserAtoms.internJSAtom( - cx_, this->getCompilationInfo(), name); - if (mbNameId.isErr()) { + const ParserAtom* parserAtom = + this->compilationState_.parserAtoms.internJSAtom( + cx_, this->getCompilationInfo(), name); + if (!parserAtom) { return false; } - const ParserName* nameId = mbNameId.unwrap()->asName(); - scope.lookupDeclaredName(nameId)->value()->setClosedOver(); + scope.lookupDeclaredName(parserAtom->asName())->value()->setClosedOver(); MOZ_ASSERT(slotCount > 0); slotCount--; } @@ -2158,7 +2158,7 @@ } // Function is not syntactically part of another script. - funbox->setIsStandalone(true); + MOZ_ASSERT(funbox->index() == CompilationInfo::TopLevelIndex); funbox->initStandalone(this->compilationState_.scopeContext, flags, syntaxKind); @@ -2399,8 +2399,7 @@ const ParserAtom* atoms[2] = {prefix, propAtom}; auto atomsRange = mozilla::Range(atoms, 2); - return this->compilationState_.parserAtoms.concatAtoms(cx_, atomsRange) - .unwrapOr(nullptr); + return this->compilationState_.parserAtoms.concatAtoms(cx_, atomsRange); } template @@ -2744,10 +2743,8 @@ // TODO-Stencil: Consider for snapshotting. const ParserAtom* displayAtom = nullptr; if (fun->displayAtom()) { - displayAtom = - this->compilationState_.parserAtoms - .internJSAtom(cx_, this->compilationInfo_, fun->displayAtom()) - .unwrapOr(nullptr); + displayAtom = this->compilationState_.parserAtoms.internJSAtom( + cx_, this->compilationInfo_, fun->displayAtom()); if (!displayAtom) { return false; } @@ -3236,10 +3233,8 @@ // TODO-Stencil: Consider for snapshotting. const ParserAtom* displayAtom = nullptr; if (fun->displayAtom()) { - displayAtom = - this->compilationState_.parserAtoms - .internJSAtom(cx_, this->compilationInfo_, fun->displayAtom()) - .unwrapOr(nullptr); + displayAtom = this->compilationState_.parserAtoms.internJSAtom( + cx_, this->compilationInfo_, fun->displayAtom()); if (!displayAtom) { return null(); } @@ -6639,7 +6634,6 @@ uint32_t begin = pos().begin; MOZ_ASSERT(pc_->isFunctionBox()); - pc_->functionBox()->usesReturn = true; // Parse an optional operand. // @@ -7900,7 +7894,6 @@ handler_.setFunctionFormalParametersAndBody(funNode, argsbody); setFunctionStartAtCurrentToken(funbox); funbox->setArgCount(0); - funbox->usesThis = true; // Note both the stored private method body and it's private name as being // used in the initializer. They will be emitted into the method body in the @@ -8037,7 +8030,6 @@ handler_.setFunctionFormalParametersAndBody(funNode, argsbody); funbox->setArgCount(0); - funbox->usesThis = true; NameNodeType thisName = newThisName(); if (!thisName) { return null(); @@ -9998,9 +9990,6 @@ // syntax. if (prop == cx_->parserNames().apply) { op = JSOp::FunApply; - if (pc_->isFunctionBox()) { - pc_->functionBox()->usesApply = true; - } } else if (prop == cx_->parserNames().call) { op = JSOp::FunCall; } @@ -10296,9 +10285,8 @@ } } - const ParserAtom* atom = this->compilationState_.parserAtoms - .internChar16(cx_, chars.begin(), chars.length()) - .unwrapOr(nullptr); + const ParserAtom* atom = this->compilationState_.parserAtoms.internChar16( + cx_, chars.begin(), chars.length()); if (!atom) { return nullptr; } @@ -11430,9 +11418,6 @@ case TokenKind::False: return handler_.newBooleanLiteral(false, pos()); case TokenKind::This: { - if (pc_->isFunctionBox()) { - pc_->functionBox()->usesThis = true; - } NameNodeType thisName = null(); if (pc_->sc()->hasFunctionThisBinding()) { thisName = newThisName(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/SharedContext.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/SharedContext.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/SharedContext.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/SharedContext.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -234,18 +234,13 @@ funcDataIndex_(index), flags_(FunctionFlags::clearMutableflags(flags)), emitBytecode(false), - isStandalone_(false), wasEmitted_(false), - isSingleton_(false), isAnnexB(false), useAsm(false), hasParameterExprs(false), hasDestructuringArgs(false), hasDuplicateParameters(false), hasExprBody_(false), - usesApply(false), - usesThis(false), - usesReturn(false), isFunctionFieldCopiedToStencil(false) { setFlag(ImmutableFlags::IsGenerator, generatorKind == GeneratorKind::Generator); @@ -410,8 +405,6 @@ using ImmutableFlags = ImmutableScriptFlagsEnum; immutableFlags_.setFlag(ImmutableFlags::HasMappedArgsObj, hasMappedArgsObj()); - immutableFlags_.setFlag(ImmutableFlags::IsLikelyConstructorWrapper, - isLikelyConstructorWrapper()); } void FunctionBox::copyScriptFields(ScriptStencil& script) { @@ -436,9 +429,7 @@ script.functionFlags = flags_; script.nargs = nargs_; script.lazyFunctionEnclosingScopeIndex_ = enclosingScopeIndex_; - script.isStandaloneFunction = isStandalone_; script.wasFunctionEmitted = wasEmitted_; - script.isSingletonFunction = isSingleton_; isFunctionFieldCopiedToStencil = true; } @@ -477,10 +468,5 @@ script.wasFunctionEmitted = wasEmitted_; } -void FunctionBox::copyUpdatedIsSingleton() { - ScriptStencil& script = functionStencil(); - script.isSingletonFunction = isSingleton_; -} - } // namespace frontend } // namespace js diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/SharedContext.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/SharedContext.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/SharedContext.h 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/SharedContext.h 2020-11-17 19:31:31.000000000 +0000 @@ -375,19 +375,11 @@ // compilation. bool emitBytecode : 1; - // This function is a standalone function that is not syntactically part of - // another script. Eg. Created by `new Function("")`. - bool isStandalone_ : 1; - // This is set by the BytecodeEmitter of the enclosing script when a reference // to this function is generated. This is also used to determine a hoisted // function already is referenced by the bytecode. bool wasEmitted_ : 1; - // This function should be marked as a singleton. It is expected to be defined - // at most once. This is a heuristic only and does not affect correctness. - bool isSingleton_ : 1; - // Need to emit a synthesized Annex B assignment bool isAnnexB : 1; @@ -403,11 +395,6 @@ // Arrow function with expression body like: `() => 1`. bool hasExprBody_ : 1; - // Analysis for use in heuristics. - bool usesApply : 1; // Contains an f.apply() call - bool usesThis : 1; // Contains 'this' - bool usesReturn : 1; // Contains a 'return' statement - // Tracks if function-related fields are already copied to ScriptStencil. // If this field is true, modification to those fields should be synced with // ScriptStencil by copyUpdated* methods. @@ -450,12 +437,6 @@ void setEnclosingScopeForInnerLazyFunction(ScopeIndex scopeIndex); - bool isStandalone() const { return isStandalone_; } - void setIsStandalone(bool isStandalone) { - MOZ_ASSERT(!isFunctionFieldCopiedToStencil); - isStandalone_ = isStandalone; - } - bool wasEmitted() const { return wasEmitted_; } void setWasEmitted(bool wasEmitted) { wasEmitted_ = wasEmitted; @@ -464,14 +445,6 @@ } } - bool isSingleton() const { return isSingleton_; } - void setIsSingleton(bool isSingleton) { - isSingleton_ = isSingleton; - if (isFunctionFieldCopiedToStencil) { - copyUpdatedIsSingleton(); - } - } - MOZ_MUST_USE bool setAsmJSModule(const JS::WasmModule* module); bool isAsmJSModule() const { return flags_.isAsmJSNative(); } @@ -494,7 +467,6 @@ IMMUTABLE_FLAG_GETTER_SETTER(argumentsHasVarBinding, ArgumentsHasVarBinding) // AlwaysNeedsArgsObj: custom logic below. // HasMappedArgsObj: custom logic below. - // IsLikelyConstructorWrapper: custom logic below. bool needsCallObjectRegardlessOfBindings() const { // Always create a CallObject if: @@ -510,10 +482,6 @@ return funHasExtensibleScope(); } - bool isLikelyConstructorWrapper() const { - return argumentsHasVarBinding() && usesApply && usesThis && !usesReturn; - } - GeneratorKind generatorKind() const { return isGenerator() ? GeneratorKind::Generator : GeneratorKind::NotGenerator; @@ -606,13 +574,6 @@ setFlag(ImmutableFlags::IsFieldInitializer); } - void setTreatAsRunOnce(bool treatAsRunOnce) { - immutableFlags_.setFlag(ImmutableFlags::TreatAsRunOnce, treatAsRunOnce); - if (isScriptFieldCopiedToStencil) { - copyUpdatedImmutableFlags(); - } - } - bool hasSimpleParameterList() const { return !hasRest() && !hasParameterExprs && !hasDestructuringArgs; } @@ -621,15 +582,6 @@ return !strict() && hasSimpleParameterList(); } - bool shouldSuppressRunOnce() const { - // These heuristics suppress the run-once optimization if we expect that - // script-cloning will have more impact than TI type-precision would gain. - // - // See also: Bug 864218 - return explicitName() || argumentsHasVarBinding() || isGenerator() || - isAsync(); - } - // Return whether this or an enclosing function is being parsed and // validated as asm.js. Note: if asm.js validation fails, this will be false // while the function is being reparsed. This flag can be used to disable @@ -695,8 +647,6 @@ void copyScriptFields(ScriptStencil& script); void copyFunctionFields(ScriptStencil& script); - // * setTreatAsRunOnce can be called to a lazy function, while emitting - // enclosing script // * setCtorFunctionHasThisBinding can be called to a class constructor // with a lazy function, while parsing enclosing class void copyUpdatedImmutableFlags(); @@ -722,10 +672,6 @@ // * setWasEmitted can be called to a lazy function, while emitting // enclosing script void copyUpdatedWasEmitted(); - - // * setIsSingleton can be called to a lazy function, while emitting - // enclosing script - void copyUpdatedIsSingleton(); }; #undef FLAG_GETTER_SETTER diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/Stencil.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/Stencil.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/Stencil.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/Stencil.cpp 2020-11-17 19:31:30.000000000 +0000 @@ -336,60 +336,6 @@ return true; } -// JSFunctions have a default ObjectGroup when they are created. Once their -// enclosing script is compiled, we have more precise heuristic information and -// now compute their final group. These functions have not been exposed to -// script before this point. -// -// As well, anonymous functions may have either an "inferred" or a "guessed" -// name assigned to them. This name isn't known until the enclosing function is -// compiled so we must update it here. -static bool SetTypeAndNameForExposedFunctions(JSContext* cx, - CompilationInfo& compilationInfo, - CompilationGCOutput& gcOutput) { - Rooted fun(cx); - for (auto item : compilationInfo.functionScriptStencils(gcOutput)) { - auto& scriptStencil = item.script; - fun = item.function; - if (!scriptStencil.functionFlags.hasBaseScript()) { - continue; - } - - // If the function was not referenced by enclosing script's bytecode, we do - // not generate a BaseScript for it. For example, `(function(){});`. - if (!scriptStencil.wasFunctionEmitted && - !scriptStencil.isStandaloneFunction) { - continue; - } - - if (!JSFunction::setTypeForScriptedFunction( - cx, fun, scriptStencil.isSingletonFunction)) { - return false; - } - - // Inferred and Guessed names are computed by BytecodeEmitter and so may - // need to be applied to existing JSFunctions during delazification. - if (fun->displayAtom() == nullptr) { - JSAtom* funcAtom = nullptr; - if (scriptStencil.functionFlags.hasInferredName() || - scriptStencil.functionFlags.hasGuessedAtom()) { - funcAtom = compilationInfo.input.atomCache.getExistingAtomAt( - cx, scriptStencil.functionAtom); - MOZ_ASSERT(funcAtom); - } - if (scriptStencil.functionFlags.hasInferredName()) { - fun->setInferredName(funcAtom); - } - - if (scriptStencil.functionFlags.hasGuessedAtom()) { - fun->setGuessedAtom(funcAtom); - } - } - } - - return true; -} - // Instantiate js::BaseScripts from ScriptStencils for inner functions of the // compilation. Note that standalone functions and functions being delazified // are handled below with other top-levels. @@ -513,7 +459,8 @@ // to update it with information determined by the BytecodeEmitter. This applies // to both initial and delazification parses. The functions being update may or // may not have bytecode at this point. -static void UpdateEmittedInnerFunctions(CompilationInfo& compilationInfo, +static void UpdateEmittedInnerFunctions(JSContext* cx, + CompilationInfo& compilationInfo, CompilationGCOutput& gcOutput) { for (auto item : compilationInfo.functionScriptStencils(gcOutput)) { auto& scriptStencil = item.script; @@ -533,12 +480,28 @@ ScopeIndex index = *scriptStencil.lazyFunctionEnclosingScopeIndex_; Scope* scope = gcOutput.scopes[index]; script->setEnclosingScope(scope); - script->initTreatAsRunOnce(scriptStencil.immutableFlags.hasFlag( - ImmutableScriptFlagsEnum::TreatAsRunOnce)); if (scriptStencil.memberInitializers) { script->setMemberInitializers(*scriptStencil.memberInitializers); } + + // Inferred and Guessed names are computed by BytecodeEmitter and so may + // need to be applied to existing JSFunctions during delazification. + if (fun->displayAtom() == nullptr) { + JSAtom* funcAtom = nullptr; + if (scriptStencil.functionFlags.hasInferredName() || + scriptStencil.functionFlags.hasGuessedAtom()) { + funcAtom = compilationInfo.input.atomCache.getExistingAtomAt( + cx, scriptStencil.functionAtom); + MOZ_ASSERT(funcAtom); + } + if (scriptStencil.functionFlags.hasInferredName()) { + fun->setInferredName(funcAtom); + } + if (scriptStencil.functionFlags.hasGuessedAtom()) { + fun->setGuessedAtom(funcAtom); + } + } } } } @@ -581,13 +544,7 @@ BaseScript* script = fun->baseScript(); - // TreatAsRunOnce is updated by UpdateEmittedInnerFunctions. - uint32_t acceptableDifferenceForScript = - uint32_t(ImmutableScriptFlagsEnum::TreatAsRunOnce); - MOZ_ASSERT( - (uint32_t(script->immutableFlags()) | acceptableDifferenceForScript) == - (uint32_t(scriptStencil.immutableFlags) | - acceptableDifferenceForScript)); + MOZ_ASSERT(script->immutableFlags() == scriptStencil.immutableFlags); MOZ_ASSERT(script->extent().sourceStart == scriptStencil.extent.sourceStart); @@ -599,7 +556,7 @@ MOZ_ASSERT(script->extent().lineno == scriptStencil.extent.lineno); MOZ_ASSERT(script->extent().column == scriptStencil.extent.column); - // Names are updated by SetTypeAndNameForExposedFunctions. + // Names are updated by UpdateInnerFunctions. constexpr uint16_t HAS_INFERRED_NAME = uint16_t(FunctionFlags::Flags::HAS_INFERRED_NAME); constexpr uint16_t HAS_GUESSED_ATOM = @@ -700,9 +657,7 @@ return false; } - if (!SetTypeAndNameForExposedFunctions(cx, *this, gcOutput)) { - return false; - } + MOZ_RELEASE_ASSERT(!IsTypeInferenceEnabled()); if (!input.lazy) { if (!InstantiateScriptStencils(cx, *this, gcOutput)) { @@ -716,7 +671,7 @@ // Must be infallible from here forward. - UpdateEmittedInnerFunctions(*this, gcOutput); + UpdateEmittedInnerFunctions(cx, *this, gcOutput); if (!input.lazy) { LinkEnclosingLazyScript(*this, gcOutput); @@ -999,6 +954,7 @@ GenericPrinter& out = json.beginStringProperty("atom"); WellKnownParserAtoms::getStatic2(index)->dumpCharsNoQuote(out); json.endString(); + return; } MOZ_ASSERT(taggedIndex.isNull()); @@ -1397,9 +1353,6 @@ case ImmutableScriptFlagsEnum::HasMappedArgsObj: json.value("HasMappedArgsObj"); break; - case ImmutableScriptFlagsEnum::IsLikelyConstructorWrapper: - json.value("IsLikelyConstructorWrapper"); - break; default: json.value("Unknown(%x)", i); break; @@ -1594,9 +1547,8 @@ json.property("lazyFunctionEnclosingScopeIndex", "Nothing"); } - json.boolProperty("isStandaloneFunction", isStandaloneFunction); json.boolProperty("wasFunctionEmitted", wasFunctionEmitted); - json.boolProperty("isSingletonFunction", isSingletonFunction); + json.boolProperty("allowRelazify", allowRelazify); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/Stencil.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/Stencil.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/Stencil.h 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/Stencil.h 2020-11-17 19:31:31.000000000 +0000 @@ -594,18 +594,10 @@ // successfully.) mozilla::Maybe lazyFunctionEnclosingScopeIndex_; - // This function is a standalone function that is not syntactically part of - // another script. Eg. Created by `new Function("")`. - bool isStandaloneFunction : 1; - // This is set by the BytecodeEmitter of the enclosing script when a reference // to this function is generated. bool wasFunctionEmitted : 1; - // This function should be marked as a singleton. It is expected to be defined - // at most once. This is a heuristic only and does not affect correctness. - bool isSingletonFunction : 1; - // If this is for the root of delazification, this represents // MutableScriptFlagsEnum::AllowRelazify value of the script *after* // delazification. @@ -614,11 +606,7 @@ // End of fields. - ScriptStencil() - : isStandaloneFunction(false), - wasFunctionEmitted(false), - isSingletonFunction(false), - allowRelazify(false) {} + ScriptStencil() : wasFunctionEmitted(false), allowRelazify(false) {} bool isFunction() const { bool result = functionFlags.toRaw() != 0x0000; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/StencilXdr.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/StencilXdr.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/StencilXdr.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/StencilXdr.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -23,9 +23,7 @@ HasSharedData, HasFunctionAtom, HasScopeIndex, - IsStandaloneFunction, WasFunctionEmitted, - IsSingletonFunction, AllowRelazify, }; @@ -71,15 +69,9 @@ xdrFields.scopeIndex = stencil.lazyFunctionEnclosingScopeIndex_.valueOr(ScopeIndex()); - if (stencil.isStandaloneFunction) { - xdrFlags |= 1 << uint8_t(XdrFlags::IsStandaloneFunction); - } if (stencil.wasFunctionEmitted) { xdrFlags |= 1 << uint8_t(XdrFlags::WasFunctionEmitted); } - if (stencil.isSingletonFunction) { - xdrFlags |= 1 << uint8_t(XdrFlags::IsSingletonFunction); - } if (stencil.allowRelazify) { xdrFlags |= 1 << uint8_t(XdrFlags::AllowRelazify); } @@ -136,15 +128,9 @@ stencil.lazyFunctionEnclosingScopeIndex_.emplace(xdrFields.scopeIndex); } - if (xdrFlags & (1 << uint8_t(XdrFlags::IsStandaloneFunction))) { - stencil.isStandaloneFunction = true; - } if (xdrFlags & (1 << uint8_t(XdrFlags::WasFunctionEmitted))) { stencil.wasFunctionEmitted = true; } - if (xdrFlags & (1 << uint8_t(XdrFlags::IsSingletonFunction))) { - stencil.isSingletonFunction = true; - } if (xdrFlags & (1 << uint8_t(XdrFlags::AllowRelazify))) { stencil.allowRelazify = true; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/TokenStream.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/TokenStream.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/TokenStream.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/TokenStream.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -552,11 +552,10 @@ : TokenStreamCharsShared(cx, pasrerAtoms), sourceUnits(units, length, startOffset) {} -template <> -MOZ_MUST_USE bool TokenStreamCharsBase:: - fillCharBufferFromSourceNormalizingAsciiLineBreaks(const char16_t* cur, - const char16_t* end) { - MOZ_ASSERT(this->charBuffer.length() == 0); +bool FillCharBufferFromSourceNormalizingAsciiLineBreaks(CharBuffer& charBuffer, + const char16_t* cur, + const char16_t* end) { + MOZ_ASSERT(charBuffer.length() == 0); while (cur < end) { char16_t ch = *cur++; @@ -567,7 +566,7 @@ } } - if (!this->charBuffer.append(ch)) { + if (!charBuffer.append(ch)) { return false; } } @@ -576,11 +575,10 @@ return true; } -template <> -MOZ_MUST_USE bool TokenStreamCharsBase:: - fillCharBufferFromSourceNormalizingAsciiLineBreaks(const Utf8Unit* cur, - const Utf8Unit* end) { - MOZ_ASSERT(this->charBuffer.length() == 0); +bool FillCharBufferFromSourceNormalizingAsciiLineBreaks(CharBuffer& charBuffer, + const Utf8Unit* cur, + const Utf8Unit* end) { + MOZ_ASSERT(charBuffer.length() == 0); while (cur < end) { Utf8Unit unit = *cur++; @@ -593,7 +591,7 @@ } } - if (!this->charBuffer.append(ch)) { + if (!charBuffer.append(ch)) { return false; } @@ -604,7 +602,7 @@ MOZ_ASSERT(ch.isSome(), "provided source text should already have been validated"); - if (!appendCodePointToCharBuffer(ch.value())) { + if (!AppendCodePointToCharBuffer(charBuffer, ch.value())) { return false; } } @@ -1736,26 +1734,22 @@ return true; } - // We might have hit an error while processing some source code feature - // that's accumulating text into |this->charBuffer| -- e.g. we could be - // halfway into a regular expression literal, then encounter invalid UTF-8. - // Thus we must clear |this->charBuffer| of prior work. - this->charBuffer.clear(); + CharBuffer lineOfContext(cx); const Unit* encodedWindow = sourceUnits.codeUnitPtrAt(encodedWindowStart); - if (!fillCharBufferFromSourceNormalizingAsciiLineBreaks( - encodedWindow, encodedWindow + encodedWindowLength)) { + if (!FillCharBufferFromSourceNormalizingAsciiLineBreaks( + lineOfContext, encodedWindow, encodedWindow + encodedWindowLength)) { return false; } - size_t utf16WindowLength = this->charBuffer.length(); + size_t utf16WindowLength = lineOfContext.length(); // The windowed string is null-terminated. - if (!this->charBuffer.append('\0')) { + if (!lineOfContext.append('\0')) { return false; } - err->lineOfContext.reset(this->charBuffer.extractOrCopyRawBuffer()); + err->lineOfContext.reset(lineOfContext.extractOrCopyRawBuffer()); if (!err->lineOfContext) { return false; } @@ -2080,7 +2074,7 @@ "maintain line-info/flags for EOL"); this->sourceUnits.consumeKnownCodePoint(peeked); - if (!appendCodePointToCharBuffer(peeked.codePoint())) { + if (!AppendCodePointToCharBuffer(this->charBuffer, peeked.codePoint())) { return false; } } while (true); @@ -2167,8 +2161,11 @@ return false; }; -MOZ_MUST_USE bool TokenStreamCharsShared::appendCodePointToCharBuffer( - uint32_t codePoint) { +bool AppendCodePointToCharBuffer(CharBuffer& charBuffer, uint32_t codePoint) { + MOZ_ASSERT(codePoint <= unicode::NonBMPMax, + "should only be processing code points validly decoded from UTF-8 " + "or WTF-16 source text (surrogate code points permitted)"); + char16_t units[2]; unsigned numUnits = 0; unicode::UTF16Encode(codePoint, units, &numUnits); @@ -2231,7 +2228,7 @@ } } - if (!appendCodePointToCharBuffer(codePoint)) { + if (!AppendCodePointToCharBuffer(this->charBuffer, codePoint)) { return false; } } while (true); @@ -2617,7 +2614,7 @@ return false; } - return this->appendCodePointToCharBuffer(codePoint); + return AppendCodePointToCharBuffer(this->charBuffer, codePoint); }; auto ReportUnterminatedRegExp = [this](int32_t unit) { @@ -2741,7 +2738,7 @@ if (unit == '_') { continue; } - if (!this->appendCodePointToCharBuffer(unit)) { + if (!AppendCodePointToCharBuffer(this->charBuffer, unit)) { return false; } } @@ -3438,7 +3435,7 @@ MOZ_ASSERT(!IsLineTerminator(cp)); } - if (!appendCodePointToCharBuffer(cp)) { + if (!AppendCodePointToCharBuffer(this->charBuffer, cp)) { return false; } @@ -3468,7 +3465,8 @@ // LineContinuation represents no code points, so don't append // in this case. if (codePoint != '\n') { - if (!appendCodePointToCharBuffer(AssertedCast(codePoint))) { + if (!AppendCodePointToCharBuffer(this->charBuffer, + AssertedCast(codePoint))) { return false; } } @@ -3595,7 +3593,7 @@ } MOZ_ASSERT(code <= unicode::NonBMPMax); - if (!appendCodePointToCharBuffer(code)) { + if (!AppendCodePointToCharBuffer(this->charBuffer, code)) { return false; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/TokenStream.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/TokenStream.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/frontend/TokenStream.h 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/frontend/TokenStream.h 2020-11-17 19:31:30.000000000 +0000 @@ -1502,12 +1502,44 @@ MOZ_ASSERT(last == 0xA8 || last == 0xA9); } -class TokenStreamCharsShared { - // Using char16_t (not Unit) is a simplifying decision that hopefully - // eliminates the need for a UTF-8 regular expression parser and makes - // |copyCharBufferTo| markedly simpler. - using CharBuffer = Vector; +/** + * An all-purpose buffer type for accumulating text during tokenizing. + * + * In principle we could make this buffer contain |char16_t|, |Utf8Unit|, or + * |Unit|. We use |char16_t| because: + * + * * we don't have a UTF-8 regular expression parser, so in general regular + * expression text must be copied to a separate UTF-16 buffer to parse it, + * and + * * |TokenStreamCharsShared::copyCharBufferTo|, which copies a shared + * |CharBuffer| to a |char16_t*|, is simpler if it doesn't have to convert. + */ +using CharBuffer = Vector; + +/** + * Append the provided code point (in the range [U+0000, U+10FFFF], surrogate + * code points included) to the buffer. + */ +extern MOZ_MUST_USE bool AppendCodePointToCharBuffer(CharBuffer& charBuffer, + uint32_t codePoint); + +/** + * Accumulate the range of UTF-16 text (lone surrogates permitted, because JS + * allows them in source text) into |charBuffer|. Normalize '\r', '\n', and + * "\r\n" into '\n'. + */ +extern MOZ_MUST_USE bool FillCharBufferFromSourceNormalizingAsciiLineBreaks( + CharBuffer& charBuffer, const char16_t* cur, const char16_t* end); + +/** + * Accumulate the range of previously-validated UTF-8 text into |charBuffer|. + * Normalize '\r', '\n', and "\r\n" into '\n'. + */ +extern MOZ_MUST_USE bool FillCharBufferFromSourceNormalizingAsciiLineBreaks( + CharBuffer& charBuffer, const mozilla::Utf8Unit* cur, + const mozilla::Utf8Unit* end); +class TokenStreamCharsShared { protected: JSContext* cx; @@ -1525,8 +1557,6 @@ explicit TokenStreamCharsShared(JSContext* cx, ParserAtomsTable* parserAtoms) : cx(cx), charBuffer(cx), parserAtoms(parserAtoms) {} - MOZ_MUST_USE bool appendCodePointToCharBuffer(uint32_t codePoint); - MOZ_MUST_USE bool copyCharBufferTo( JSContext* cx, UniquePtr* destination); @@ -1542,14 +1572,14 @@ const ParserAtom* drainCharBufferIntoAtom() { // Add to parser atoms table. - auto maybeId = this->parserAtoms->internChar16(cx, charBuffer.begin(), - charBuffer.length()); - if (maybeId.isErr()) { + const ParserAtom* atom = this->parserAtoms->internChar16( + cx, charBuffer.begin(), charBuffer.length()); + if (!atom) { return nullptr; } charBuffer.clear(); - return maybeId.unwrap(); + return atom; } protected: @@ -1655,14 +1685,6 @@ inline void consumeKnownCodeUnit(T) = delete; /** - * Accumulate the provided range of already-validated text (valid UTF-8, or - * anything if Unit is char16_t because JS allows lone surrogates) into - * |charBuffer|. Normalize '\r', '\n', and "\r\n" into '\n'. - */ - MOZ_MUST_USE bool fillCharBufferFromSourceNormalizingAsciiLineBreaks( - const Unit* cur, const Unit* end); - - /** * Add a null-terminated line of context to error information, for the line * in |sourceUnits| that contains |offset|. Also record the window's * length and the offset of the error in the window. (Don't bother adding @@ -1700,16 +1722,14 @@ MOZ_ALWAYS_INLINE const ParserAtom* TokenStreamCharsBase::atomizeSourceChars( mozilla::Span units) { - return this->parserAtoms->internChar16(cx, units.data(), units.size()) - .unwrapOr(nullptr); + return this->parserAtoms->internChar16(cx, units.data(), units.size()); } template <> /* static */ MOZ_ALWAYS_INLINE const ParserAtom* TokenStreamCharsBase::atomizeSourceChars( mozilla::Span units) { - return this->parserAtoms->internUtf8(cx, units.data(), units.size()) - .unwrapOr(nullptr); + return this->parserAtoms->internUtf8(cx, units.data(), units.size()); } template @@ -1918,7 +1938,6 @@ protected: using CharsBase::addLineOfContext; - using CharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks; using CharsBase::matchCodeUnit; using CharsBase::matchLineTerminator; using TokenStreamCharsShared::drainCharBufferIntoAtom; @@ -2146,7 +2165,8 @@ // Template literals normalize only '\r' and "\r\n" to '\n'; Unicode // separators don't need special handling. // https://tc39.github.io/ecma262/#sec-static-semantics-tv-and-trv - if (!fillCharBufferFromSourceNormalizingAsciiLineBreaks(cur, end)) { + if (!FillCharBufferFromSourceNormalizingAsciiLineBreaks(this->charBuffer, + cur, end)) { return nullptr; } @@ -2433,10 +2453,8 @@ private: using CharsBase::atomizeSourceChars; using GeneralCharsBase::badToken; - using TokenStreamCharsShared::appendCodePointToCharBuffer; // Deliberately don't |using| |charBuffer| because of bug 1472569. :-( using CharsBase::consumeKnownCodeUnit; - using CharsBase::fillCharBufferFromSourceNormalizingAsciiLineBreaks; using CharsBase::matchCodeUnit; using CharsBase::matchLineTerminator; using CharsBase::peekCodeUnit; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/AliasAnalysis.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/AliasAnalysis.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/AliasAnalysis.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/AliasAnalysis.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -236,16 +236,8 @@ return MDefinition::AliasType::MayAlias; } - if (!loadObject->resultTypeSet() || !storeObject->resultTypeSet()) { - return MDefinition::AliasType::MayAlias; - } - - if (loadObject->resultTypeSet()->objectsIntersect( - storeObject->resultTypeSet())) { - return MDefinition::AliasType::MayAlias; - } - - return MDefinition::AliasType::NoAlias; + // TODO(no-TI): remove this function. + return MDefinition::AliasType::MayAlias; } // Whether there might be a path from src to dest, excluding loop backedges. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/arm/SharedICHelpers-arm.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/arm/SharedICHelpers-arm.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/arm/SharedICHelpers-arm.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/arm/SharedICHelpers-arm.h 2020-11-17 19:31:32.000000000 +0000 @@ -39,22 +39,6 @@ *callOffset = CodeOffset(masm.currentOffset()); } -inline void EmitEnterTypeMonitorIC( - MacroAssembler& masm, - size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub()) { - // This is expected to be called from within an IC, when ICStubReg is - // properly initialized to point to the stub. - masm.loadPtr(Address(ICStubReg, (uint32_t)monitorStubOffset), ICStubReg); - - // Load stubcode pointer from BaselineStubEntry. - // R2 won't be active when we call ICs, so we can use r0. - static_assert(R2 == ValueOperand(r1, r0)); - masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), r0); - - // Jump to the stubcode. - masm.branch(r0); -} - inline void EmitReturnFromIC(MacroAssembler& masm) { masm.ma_mov(lr, pc); } inline void EmitBaselineLeaveStubFrame(MacroAssembler& masm, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/arm64/SharedICHelpers-arm64.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/arm64/SharedICHelpers-arm64.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/arm64/SharedICHelpers-arm64.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/arm64/SharedICHelpers-arm64.h 2020-11-17 19:31:32.000000000 +0000 @@ -39,22 +39,6 @@ *callOffset = CodeOffset(masm.currentOffset()); } -inline void EmitEnterTypeMonitorIC( - MacroAssembler& masm, - size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub()) { - // This is expected to be called from within an IC, when ICStubReg is - // properly initialized to point to the stub. - masm.loadPtr(Address(ICStubReg, (uint32_t)monitorStubOffset), ICStubReg); - - // Load stubcode pointer from BaselineStubEntry. - // R2 won't be active when we call ICs, so we can use r0. - static_assert(R2 == ValueOperand(r0)); - masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), r0); - - // Jump to the stubcode. - masm.Br(x0); -} - inline void EmitReturnFromIC(MacroAssembler& masm) { masm.abiret(); // Defaults to lr. } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineBailouts.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineBailouts.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineBailouts.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineBailouts.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -366,8 +366,6 @@ void setResumeAddr(void* resumeAddr) { header_->resumeAddr = resumeAddr; } - void setMonitorPC(jsbytecode* pc) { header_->monitorPC = pc; } - void setFrameSizeOfInnerMostFrame(uint32_t size) { header_->frameSizeOfInnerMostFrame = size; } @@ -616,6 +614,7 @@ // the function's initial environment. This will be fixed up // later if needed in |FinishBailoutToBaseline|, which calls // |EnsureHasEnvironmentObjects|. + // TODO(no-TI): remove ArgumentCheck kind. JitSpew(JitSpew_BaselineBailouts, " BailoutKind::ArgumentCheck! Using function's environment"); envChain = fun_->environment(); @@ -1146,16 +1145,6 @@ return false; } - // Ensure we have a TypeMonitor fallback stub so we don't crash in JIT code - // when we try to enter it. See callers of offsetOfFallbackMonitorStub. - if (BytecodeOpHasTypeSet(op_) && IsTypeInferenceEnabled()) { - ICFallbackStub* fallbackStub = icEntry.fallbackStub(); - if (!fallbackStub->toMonitoredFallbackStub()->getFallbackMonitorStub( - cx_, script_)) { - return false; - } - } - // Push return address into ICCall_Scripted stub, immediately after the call. void* baselineCallReturnAddr = getStubReturnAddress(); MOZ_ASSERT(baselineCallReturnAddr); @@ -1312,11 +1301,6 @@ blFrame()->setInterpreterFields(script_, throwPC); resumeAddr = baselineInterp.interpretOpAddr().value; } else { - // If the opcode is monitored we should monitor the top stack value when - // we finish the bailout in FinishBailoutToBaseline. - if (resumeAfter() && BytecodeOpHasTypeSet(op_)) { - setMonitorPC(pc_); - } jsbytecode* resumePC = getResumePC(); blFrame()->setInterpreterFields(script_, resumePC); resumeAddr = baselineInterp.interpretOpAddr().value; @@ -1964,29 +1948,6 @@ return false; } - // Monitor the top stack value if we are resuming after a JOF_TYPESET op. - if (jsbytecode* monitorPC = bailoutInfo->monitorPC) { - MOZ_ASSERT(BytecodeOpHasTypeSet(JSOp(*monitorPC))); - MOZ_ASSERT(GetNextPc(monitorPC) == topFrame->interpreterPC()); - - RootedScript script(cx, topFrame->script()); - uint32_t monitorOffset = script->pcToOffset(monitorPC); - ICEntry& icEntry = script->jitScript()->icEntryFromPCOffset(monitorOffset); - ICFallbackStub* fallbackStub = icEntry.fallbackStub(); - - // Not every monitored op has a monitored fallback stub, e.g. - // JSOp::NewObject, which always returns the same type for a - // particular script/pc location. - if (fallbackStub->isMonitoredFallback()) { - ICMonitoredFallbackStub* stub = fallbackStub->toMonitoredFallbackStub(); - uint32_t frameSize = bailoutInfo->frameSizeOfInnerMostFrame; - RootedValue val(cx, topFrame->topStackValue(frameSize)); - if (!TypeMonitorResult(cx, stub, topFrame, script, monitorPC, val)) { - return false; - } - } - } - // Create arguments objects for bailed out frames, to maintain the invariant // that script->needsArgsObj() implies frame->hasArgsObj(). RootedScript innerScript(cx, nullptr); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineCacheIRCompiler.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineCacheIRCompiler.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineCacheIRCompiler.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineCacheIRCompiler.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -140,10 +140,6 @@ switch (kind) { case BaselineCacheIRStubKind::Regular: return ICCacheIR_Regular::offsetOfEnteredCount(); - case BaselineCacheIRStubKind::Updated: - return ICCacheIR_Updated::offsetOfEnteredCount(); - case BaselineCacheIRStubKind::Monitored: - return ICCacheIR_Monitored::offsetOfEnteredCount(); } MOZ_CRASH("unhandled BaselineCacheIRStubKind"); } @@ -866,60 +862,7 @@ // Ensure the stack is empty for the VM call below. allocator.discardStack(masm); - if (!IsTypeInferenceEnabled()) { - return true; - } - - // R0 contains the value that needs to be typechecked. - MOZ_ASSERT(val == R0); - MOZ_ASSERT(scratch == R1.scratchReg()); - -#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) - static const bool CallClobbersTailReg = false; -#else - static const bool CallClobbersTailReg = true; -#endif - - // Call the first type update stub. - if (CallClobbersTailReg) { - masm.push(ICTailCallReg); - } - masm.push(ICStubReg); - masm.loadPtr(Address(ICStubReg, ICCacheIR_Updated::offsetOfFirstUpdateStub()), - ICStubReg); - masm.call(Address(ICStubReg, ICStub::offsetOfStubCode())); - masm.pop(ICStubReg); - if (CallClobbersTailReg) { - masm.pop(ICTailCallReg); - } - - // The update IC will store 0 or 1 in |scratch|, R1.scratchReg(), reflecting - // if the value in R0 type-checked properly or not. - Label done; - masm.branch32(Assembler::Equal, scratch, Imm32(1), &done); - - AutoStubFrame stubFrame(*this); - stubFrame.enter(masm, scratch, CallCanGC::CanNotGC); - - masm.PushRegsInMask(saveRegs); - - masm.Push(val); - masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(obj))); - masm.Push(ICStubReg); - - // Load previous frame pointer, push BaselineFrame*. - masm.loadPtr(Address(BaselineFrameReg, 0), scratch); - masm.pushBaselineFramePtr(scratch, scratch); - - using Fn = bool (*)(JSContext*, BaselineFrame*, ICCacheIR_Updated*, - HandleValue, HandleValue); - callVM(masm); - - masm.PopRegsInMask(saveRegs); - - stubFrame.leave(masm); - - masm.bind(&done); + // TODO(no-TI): clean up. return true; } @@ -2221,11 +2164,8 @@ bool BaselineCacheIRCompiler::emitTypeMonitorResult() { JitSpew(JitSpew_Codegen, "%s", __FUNCTION__); allocator.discardStack(masm); - if (IsTypeInferenceEnabled()) { - EmitEnterTypeMonitorIC(masm); - } else { - EmitReturnFromIC(masm); - } + // TODO(no-TI): remove CacheIR instruction. + EmitReturnFromIC(masm); return true; } @@ -2468,12 +2408,6 @@ case ICStub::CacheIR_Regular: iter->toCacheIR_Regular()->resetEnteredCount(); break; - case ICStub::CacheIR_Updated: - iter->toCacheIR_Updated()->resetEnteredCount(); - break; - case ICStub::CacheIR_Monitored: - iter->toCacheIR_Monitored()->resetEnteredCount(); - break; default: break; } @@ -2502,17 +2436,12 @@ MOZ_ASSERT(stub->numOptimizedStubs() < MaxOptimizedCacheIRStubs); #endif + // TODO(no-TI): remove stubKind argument. uint32_t stubDataOffset = 0; switch (stubKind) { - case BaselineCacheIRStubKind::Monitored: - stubDataOffset = sizeof(ICCacheIR_Monitored); - break; case BaselineCacheIRStubKind::Regular: stubDataOffset = sizeof(ICCacheIR_Regular); break; - case BaselineCacheIRStubKind::Updated: - stubDataOffset = sizeof(ICCacheIR_Updated); - break; } JitZone* jitZone = cx->zone()->jitZone(); @@ -2581,32 +2510,6 @@ } break; } - case BaselineCacheIRStubKind::Monitored: { - if (!iter->isCacheIR_Monitored()) { - continue; - } - auto otherStub = iter->toCacheIR_Monitored(); - if (otherStub->stubInfo() != stubInfo) { - continue; - } - if (!writer.stubDataEquals(otherStub->stubDataStart())) { - continue; - } - break; - } - case BaselineCacheIRStubKind::Updated: { - if (!iter->isCacheIR_Updated()) { - continue; - } - auto otherStub = iter->toCacheIR_Updated(); - if (otherStub->stubInfo() != stubInfo) { - continue; - } - if (!writer.stubDataEquals(otherStub->stubDataStart())) { - continue; - } - break; - } } // We found a stub that's exactly the same as the stub we're about to @@ -2656,36 +2559,6 @@ *attached = true; return newStub; } - case BaselineCacheIRStubKind::Monitored: { - ICStub* monitorStub = nullptr; - if (IsTypeInferenceEnabled()) { - ICTypeMonitor_Fallback* typeMonitorFallback = - stub->toMonitoredFallbackStub()->getFallbackMonitorStub( - cx, outerScript); - if (!typeMonitorFallback) { - cx->recoverFromOutOfMemory(); - return nullptr; - } - monitorStub = typeMonitorFallback->firstMonitorStub(); - } - auto newStub = - new (newStubMem) ICCacheIR_Monitored(code, monitorStub, stubInfo); - writer.copyStubData(newStub->stubDataStart()); - stub->addNewStub(newStub); - *attached = true; - return newStub; - } - case BaselineCacheIRStubKind::Updated: { - auto newStub = new (newStubMem) ICCacheIR_Updated(code, stubInfo); - if (!newStub->initUpdatingChain(cx, stubSpace)) { - cx->recoverFromOutOfMemory(); - return nullptr; - } - writer.copyStubData(newStub->stubDataStart()); - stub->addNewStub(newStub); - *attached = true; - return newStub; - } } MOZ_CRASH("Invalid kind"); @@ -2697,7 +2570,6 @@ } template uint8_t* ICCacheIR_Trait::stubDataStart(); -template uint8_t* ICCacheIR_Trait::stubDataStart(); bool BaselineCacheIRCompiler::emitCallStringObjectConcatResult( ValOperandId lhsId, ValOperandId rhsId) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineCacheIRCompiler.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineCacheIRCompiler.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineCacheIRCompiler.h 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineCacheIRCompiler.h 2020-11-17 19:31:32.000000000 +0000 @@ -19,7 +19,8 @@ class ICFallbackStub; class ICStub; -enum class BaselineCacheIRStubKind { Regular, Monitored, Updated }; +// TODO(no-TI): remove. +enum class BaselineCacheIRStubKind { Regular }; ICStub* AttachBaselineCacheIRStub(JSContext* cx, const CacheIRWriter& writer, CacheKind kind, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineCodeGen.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineCodeGen.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineCodeGen.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineCodeGen.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -561,7 +561,7 @@ } while (entry->pcOffset() < pcOffset); MOZ_RELEASE_ASSERT(entry->pcOffset() == pcOffset); - MOZ_ASSERT_IF(!entry->isForPrologue(), BytecodeOpHasIC(JSOp(*handler.pc()))); + MOZ_ASSERT(BytecodeOpHasIC(JSOp(*handler.pc()))); // Load stub pointer into ICStubReg. if (JitOptions.warpBuilder) { @@ -576,10 +576,7 @@ CodeOffset returnOffset; EmitCallIC(masm, &returnOffset); - RetAddrEntry::Kind kind = entry->isForPrologue() - ? RetAddrEntry::Kind::PrologueIC - : RetAddrEntry::Kind::IC; - + RetAddrEntry::Kind kind = RetAddrEntry::Kind::IC; if (!handler.retAddrEntries().emplaceBack(pcOffset, kind, returnOffset)) { ReportOutOfMemory(cx); return false; @@ -3687,13 +3684,6 @@ bool BaselineCodeGen::emit_GetAliasedVar() { emitGetAliasedVar(R0); - if (IsTypeInferenceEnabled() && handler.maybeIonCompileable()) { - // No need to monitor types if we know Ion can't compile this script. - if (!emitNextIC()) { - return false; - } - } - frame.push(R0); return true; } @@ -3907,13 +3897,6 @@ } } - if (IsTypeInferenceEnabled() && handler.maybeIonCompileable()) { - // No need to monitor types if we know Ion can't compile this script. - if (!emitNextIC()) { - return false; - } - } - frame.push(R0); return true; } @@ -3936,11 +3919,6 @@ return false; } - // Enter the type monitor IC. - if (IsTypeInferenceEnabled() && !emitNextIC()) { - return false; - } - frame.push(R0); return true; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineDebugModeOSR.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineDebugModeOSR.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineDebugModeOSR.cpp 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineDebugModeOSR.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -179,8 +179,6 @@ switch (kind) { case RetAddrEntry::Kind::IC: return "IC"; - case RetAddrEntry::Kind::PrologueIC: - return "prologue IC"; case RetAddrEntry::Kind::CallVM: return "callVM"; case RetAddrEntry::Kind::StackCheck: @@ -354,7 +352,6 @@ pc); break; } - case RetAddrEntry::Kind::PrologueIC: case RetAddrEntry::Kind::NonOpCallVM: case RetAddrEntry::Kind::Invalid: // These cannot trigger BaselineDebugModeOSR. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineIC.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineIC.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineIC.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineIC.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -109,28 +109,6 @@ script->getWarmUpCount(), stub->numOptimizedStubs(), fmtbuf); } } - -void TypeFallbackICSpew(JSContext* cx, ICTypeMonitor_Fallback* stub, - const char* fmt, ...) { - if (JitSpewEnabled(JitSpew_BaselineICFallback)) { - RootedScript script(cx, GetTopJitJSScript(cx)); - jsbytecode* pc = stub->icEntry()->pc(script); - - char fmtbuf[100]; - va_list args; - va_start(args, fmt); - (void)VsprintfLiteral(fmtbuf, fmt, args); - va_end(args); - - JitSpew(JitSpew_BaselineICFallback, - "Type monitor fallback hit for (%s:%u:%u) " - "(pc=%zu,line=%u,uses=%u,stubs=%d): %s", - script->filename(), script->lineno(), script->column(), - script->pcToOffset(pc), PCToLineNumber(script, pc), - script->getWarmUpCount(), (int)stub->numOptimizedMonitorStubs(), - fmtbuf); - } -} #endif // JS_JITSPEW ICFallbackStub* ICEntry::fallbackStub() const { @@ -170,6 +148,7 @@ // Helper method called by lambda expressions `addIC` and `addPrologueIC` in // `JitScript::initICEntriesAndBytecodeTypeMap`. +// TODO(no-TI): inline into addIC, fix comment. static bool AddICImpl(JSContext* cx, ICScript* icScript, uint32_t offset, ICStub* stub, uint32_t& icEntryIndex) { if (!stub) { @@ -184,12 +163,7 @@ new (&entryRef) ICEntry(stub, offset); // Fix up pointers from fallback stubs to the ICEntry. - if (stub->isFallback()) { - stub->toFallbackStub()->fixupICEntry(&entryRef); - } else { - stub->toTypeMonitor_Fallback()->fixupICEntry(&entryRef); - } - + stub->toFallbackStub()->fixupICEntry(&entryRef); return true; } @@ -212,32 +186,6 @@ return AddICImpl(cx, this, offset, stub, icEntryIndex); }; - // Lambda expression for adding ICs for non-op ICs - auto addPrologueIC = [cx, this, &icEntryIndex](ICStub* stub) { - return AddICImpl(cx, this, ICEntry::ProloguePCOffset, stub, icEntryIndex); - }; - - if (IsTypeInferenceEnabled()) { - // Add ICEntries and fallback stubs for this/argument type checks. - // Note: we pass a nullptr pc to indicate this is a non-op IC. - // See ICEntry::NonOpPCOffset. - if (JSFunction* fun = script->function()) { - ICStub* stub = - alloc.newStub(Kind::TypeMonitor, nullptr, 0); - if (!addPrologueIC(stub)) { - return false; - } - - for (size_t i = 0; i < fun->nargs(); i++) { - ICStub* stub = alloc.newStub(Kind::TypeMonitor, - nullptr, i + 1); - if (!addPrologueIC(stub)) { - return false; - } - } - } - } - // For JOF_IC ops: initialize ICEntries and fallback stubs. for (BytecodeLocation loc : js::AllBytecodesIterable(script)) { JSOp op = loc.getOp(); @@ -426,15 +374,6 @@ } break; } - case JSOp::GetAliasedVar: - case JSOp::GetImport: { - ICStub* stub = - alloc.newStub(Kind::TypeMonitor, nullptr); - if (!addIC(loc, stub)) { - return false; - } - break; - } case JSOp::GetIntrinsic: { ICStub* stub = alloc.newStub(Kind::GetIntrinsic); @@ -604,10 +543,6 @@ switch (kind()) { case CacheIR_Regular: return toCacheIR_Regular()->stubInfo()->makesGCCalls(); - case CacheIR_Monitored: - return toCacheIR_Monitored()->stubInfo()->makesGCCalls(); - case CacheIR_Updated: - return toCacheIR_Updated()->stubInfo()->makesGCCalls(); default: return NonCacheIRStubMakesGCCalls(kind()); } @@ -617,10 +552,6 @@ switch (kind()) { case CacheIR_Regular: return toCacheIR_Regular()->enteredCount(); - case CacheIR_Updated: - return toCacheIR_Updated()->enteredCount(); - case CacheIR_Monitored: - return toCacheIR_Monitored()->enteredCount(); default: return toFallbackStub()->enteredCount(); } @@ -663,51 +594,7 @@ TraceManuallyBarrieredEdge(trc, &stubJitCode, "baseline-ic-stub-code"); } - // If the stub is a monitored fallback stub, then trace the monitor ICs - // hanging off of that stub. We don't need to worry about the regular - // monitored stubs, because the regular monitored stubs will always have a - // monitored fallback stub that references the same stub chain. - if (isMonitoredFallback()) { - ICTypeMonitor_Fallback* lastMonStub = - toMonitoredFallbackStub()->maybeFallbackMonitorStub(); - if (lastMonStub) { - for (ICStubConstIterator iter(lastMonStub->firstMonitorStub()); - !iter.atEnd(); iter++) { - MOZ_ASSERT_IF(iter->next() == nullptr, *iter == lastMonStub); - iter->trace(trc); - } - } - } - - if (isUpdated()) { - for (ICStubConstIterator iter(toUpdatedStub()->firstUpdateStub()); - !iter.atEnd(); iter++) { - MOZ_ASSERT_IF(iter->next() == nullptr, iter->isTypeUpdate_Fallback()); - iter->trace(trc); - } - } - switch (kind()) { - case ICStub::TypeMonitor_SingleObject: { - ICTypeMonitor_SingleObject* monitorStub = toTypeMonitor_SingleObject(); - TraceEdge(trc, &monitorStub->object(), "baseline-monitor-singleton"); - break; - } - case ICStub::TypeMonitor_ObjectGroup: { - ICTypeMonitor_ObjectGroup* monitorStub = toTypeMonitor_ObjectGroup(); - TraceEdge(trc, &monitorStub->group(), "baseline-monitor-group"); - break; - } - case ICStub::TypeUpdate_SingleObject: { - ICTypeUpdate_SingleObject* updateStub = toTypeUpdate_SingleObject(); - TraceEdge(trc, &updateStub->object(), "baseline-update-singleton"); - break; - } - case ICStub::TypeUpdate_ObjectGroup: { - ICTypeUpdate_ObjectGroup* updateStub = toTypeUpdate_ObjectGroup(); - TraceEdge(trc, &updateStub->group(), "baseline-update-group"); - break; - } case ICStub::NewArray_Fallback: { ICNewArray_Fallback* stub = toNewArray_Fallback(); TraceNullableEdge(trc, &stub->templateObject(), @@ -730,17 +617,6 @@ case ICStub::CacheIR_Regular: TraceCacheIRStub(trc, this, toCacheIR_Regular()->stubInfo()); break; - case ICStub::CacheIR_Monitored: - TraceCacheIRStub(trc, this, toCacheIR_Monitored()->stubInfo()); - break; - case ICStub::CacheIR_Updated: { - ICCacheIR_Updated* stub = toCacheIR_Updated(); - TraceNullableEdge(trc, &stub->updateStubGroup(), - "baseline-update-stub-group"); - TraceEdge(trc, &stub->updateStubId(), "baseline-update-stub-id"); - TraceCacheIRStub(trc, this, stub->stubInfo()); - break; - } default: break; } @@ -806,17 +682,6 @@ stub->trace(zone->barrierTracer()); } - if (IsTypeInferenceEnabled() && stub->makesGCCalls() && stub->isMonitored()) { - // This stub can make calls so we can return to it if it's on the stack. - // We just have to reset its firstMonitorStub_ field to avoid a stale - // pointer when purgeOptimizedStubs destroys all optimized monitor - // stubs (unlinked stubs won't be updated). - ICTypeMonitor_Fallback* monitorFallback = - toMonitoredFallbackStub()->maybeFallbackMonitorStub(); - MOZ_ASSERT(monitorFallback); - stub->toMonitoredStub()->resetFirstMonitorStub(monitorFallback); - } - #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED stub->checkTraceMagic(); #endif @@ -837,120 +702,6 @@ } } -void ICTypeMonitor_Fallback::resetMonitorStubChain(Zone* zone) { - if (zone->needsIncrementalBarrier()) { - // We are removing edges from monitored stubs to gcthings (JitCode). - // Perform one final trace of all monitor stubs for incremental GC, - // as it must know about those edges. - for (ICStub* s = firstMonitorStub_; !s->isTypeMonitor_Fallback(); - s = s->next()) { - s->trace(zone->barrierTracer()); - } - } - - firstMonitorStub_ = this; - numOptimizedMonitorStubs_ = 0; - - if (hasFallbackStub_) { - lastMonitorStubPtrAddr_ = nullptr; - - // Reset firstMonitorStub_ field of all monitored stubs. - for (ICStubConstIterator iter = mainFallbackStub_->beginChainConst(); - !iter.atEnd(); iter++) { - if (!iter->isMonitored()) { - continue; - } - iter->toMonitoredStub()->resetFirstMonitorStub(this); - } - } else { - icEntry_->setFirstStub(this); - lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub(); - } -} - -void ICCacheIR_Updated::resetUpdateStubChain(Zone* zone) { - while (!firstUpdateStub_->isTypeUpdate_Fallback()) { - if (zone->needsIncrementalBarrier()) { - // We are removing edges from update stubs to gcthings (JitCode). - // Perform one final trace of all update stubs for incremental GC, - // as it must know about those edges. - firstUpdateStub_->trace(zone->barrierTracer()); - } - firstUpdateStub_ = firstUpdateStub_->next(); - } - - numOptimizedStubs_ = 0; -} - -ICMonitoredStub::ICMonitoredStub(Kind kind, JitCode* stubCode, - ICStub* firstMonitorStub) - : ICStub(kind, ICStub::Monitored, stubCode), - firstMonitorStub_(firstMonitorStub) { - if (IsTypeInferenceEnabled()) { - // In order to silence Coverity - null pointer dereference checker - MOZ_ASSERT(firstMonitorStub_); - // If the first monitored stub is a ICTypeMonitor_Fallback stub, then - // double check that _its_ firstMonitorStub is the same as this one. - MOZ_ASSERT_IF( - firstMonitorStub_->isTypeMonitor_Fallback(), - firstMonitorStub_->toTypeMonitor_Fallback()->firstMonitorStub() == - firstMonitorStub_); - } else { - MOZ_ASSERT(!firstMonitorStub_); - } -} - -bool ICMonitoredFallbackStub::initMonitoringChain(JSContext* cx, - JSScript* script) { - MOZ_ASSERT(fallbackMonitorStub_ == nullptr); - MOZ_ASSERT(IsTypeInferenceEnabled()); - - ICStubSpace* space = script->jitScript()->fallbackStubSpace(); - FallbackStubAllocator alloc(cx, *space); - auto* stub = alloc.newStub( - BaselineICFallbackKind::TypeMonitor, this); - if (!stub) { - return false; - } - - fallbackMonitorStub_ = stub; - return true; -} - -bool TypeMonitorResult(JSContext* cx, ICMonitoredFallbackStub* stub, - BaselineFrame* frame, HandleScript script, - jsbytecode* pc, HandleValue val) { - if (!IsTypeInferenceEnabled()) { - return true; - } - - ICTypeMonitor_Fallback* typeMonitorFallback = - stub->getFallbackMonitorStub(cx, script); - if (!typeMonitorFallback) { - return false; - } - - AutoSweepJitScript sweep(script); - StackTypeSet* types = script->jitScript()->bytecodeTypes(sweep, script, pc); - JitScript::MonitorBytecodeType(cx, script, pc, types, val); - - return typeMonitorFallback->addMonitorStubForValue(cx, frame, types, val); -} - -bool ICCacheIR_Updated::initUpdatingChain(JSContext* cx, ICStubSpace* space) { - MOZ_ASSERT(firstUpdateStub_ == nullptr); - - FallbackStubAllocator alloc(cx, *space); - auto* stub = - alloc.newStub(BaselineICFallbackKind::TypeUpdate); - if (!stub) { - return false; - } - - firstUpdateStub_ = stub; - return true; -} - /* static */ ICStubSpace* ICStubCompiler::StubSpaceForStub(bool makesGCCalls, JSScript* script, @@ -973,45 +724,6 @@ #endif } -JitCode* ICStubCompiler::getStubCode() { - JitRealm* realm = cx->realm()->jitRealm(); - - // Check for existing cached stubcode. - uint32_t stubKey = getKey(); - JitCode* stubCode = realm->getStubCode(stubKey); - if (stubCode) { - return stubCode; - } - - // Compile new stubcode. - JitContext jctx(cx, nullptr); - StackMacroAssembler masm; - InitMacroAssemblerForICStub(masm); - - if (!generateStubCode(masm)) { - return nullptr; - } - Linker linker(masm); - Rooted newStubCode(cx, linker.newCode(cx, CodeKind::Baseline)); - if (!newStubCode) { - return nullptr; - } - - // Cache newly compiled stubcode. - if (!realm->putStubCode(cx, stubKey, newStubCode)) { - return nullptr; - } - - MOZ_ASSERT(entersStubFrame_ == ICStub::NonCacheIRStubMakesGCCalls(kind)); - MOZ_ASSERT(!inStubFrame_); - -#ifdef JS_ION_PERF - writePerfSpewerJitCodeProfile(newStubCode, "BaselineIC"); -#endif - - return newStubCode; -} - bool ICStubCompilerBase::tailCallVMInternal(MacroAssembler& masm, TailCallVMFunctionId id) { TrampolinePtr code = cx->runtime()->jitRuntime()->getVMWrapper(id); @@ -1102,632 +814,7 @@ masm.adjustFrame(sizeof(intptr_t)); } -// TypeMonitor_Fallback -// - -bool ICTypeMonitor_Fallback::addMonitorStubForValue(JSContext* cx, - BaselineFrame* frame, - StackTypeSet* types, - HandleValue val) { - MOZ_ASSERT(types); - - if (MOZ_UNLIKELY(val.isMagic())) { - return true; - } - - // Don't attach too many SingleObject/ObjectGroup stubs. If the value is a - // primitive or if we will attach an any-object stub, we can handle this - // with a single PrimitiveSet or AnyValue stub so we always optimize. - if (numOptimizedMonitorStubs_ >= MAX_OPTIMIZED_STUBS && val.isObject() && - !types->unknownObject()) { - return true; - } - - bool wasDetachedMonitorChain = lastMonitorStubPtrAddr_ == nullptr; - MOZ_ASSERT_IF(wasDetachedMonitorChain, numOptimizedMonitorStubs_ == 0); - - if (types->unknown()) { - // The TypeSet got marked as unknown so attach a stub that always - // succeeds. - - // Check for existing TypeMonitor_AnyValue stubs. - for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) { - if (iter->isTypeMonitor_AnyValue()) { - return true; - } - } - - // Discard existing stubs. - resetMonitorStubChain(cx->zone()); - wasDetachedMonitorChain = (lastMonitorStubPtrAddr_ == nullptr); - - ICTypeMonitor_AnyValue::Compiler compiler(cx); - ICStub* stub = compiler.getStub(compiler.getStubSpace(frame->script())); - if (!stub) { - ReportOutOfMemory(cx); - return false; - } - - JitSpew(JitSpew_BaselineIC, " Added TypeMonitor stub %p for any value", - stub); - addOptimizedMonitorStub(stub); - - } else if (val.isPrimitive() || types->unknownObject()) { - ValueType type = val.type(); - - // Check for existing TypeMonitor stub. - ICTypeMonitor_PrimitiveSet* existingStub = nullptr; - for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) { - if (iter->isTypeMonitor_PrimitiveSet()) { - existingStub = iter->toTypeMonitor_PrimitiveSet(); - if (existingStub->containsType(type)) { - return true; - } - } - } - - if (val.isObject()) { - // Check for existing SingleObject/ObjectGroup stubs and discard - // stubs if we find one. Ideally we would discard just these stubs, - // but unlinking individual type monitor stubs is somewhat - // complicated. - MOZ_ASSERT(types->unknownObject()); - bool hasObjectStubs = false; - for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); - iter++) { - if (iter->isTypeMonitor_SingleObject() || - iter->isTypeMonitor_ObjectGroup()) { - hasObjectStubs = true; - break; - } - } - if (hasObjectStubs) { - resetMonitorStubChain(cx->zone()); - wasDetachedMonitorChain = (lastMonitorStubPtrAddr_ == nullptr); - existingStub = nullptr; - } - } - - ICTypeMonitor_PrimitiveSet::Compiler compiler(cx, existingStub, type); - ICStub* stub = - existingStub ? compiler.updateStub() - : compiler.getStub(compiler.getStubSpace(frame->script())); - if (!stub) { - ReportOutOfMemory(cx); - return false; - } - - JitSpew(JitSpew_BaselineIC, - " %s TypeMonitor stub %p for primitive type %u", - existingStub ? "Modified existing" : "Created new", stub, - static_cast(type)); - - if (!existingStub) { - MOZ_ASSERT(!hasStub(TypeMonitor_PrimitiveSet)); - addOptimizedMonitorStub(stub); - } - - } else if (val.toObject().isSingleton()) { - RootedObject obj(cx, &val.toObject()); - - // Check for existing TypeMonitor stub. - for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) { - if (iter->isTypeMonitor_SingleObject() && - iter->toTypeMonitor_SingleObject()->object() == obj) { - return true; - } - } - - ICTypeMonitor_SingleObject::Compiler compiler(cx, obj); - ICStub* stub = compiler.getStub(compiler.getStubSpace(frame->script())); - if (!stub) { - ReportOutOfMemory(cx); - return false; - } - - JitSpew(JitSpew_BaselineIC, " Added TypeMonitor stub %p for singleton %p", - stub, obj.get()); - - addOptimizedMonitorStub(stub); - - } else { - RootedObjectGroup group(cx, val.toObject().group()); - - // Check for existing TypeMonitor stub. - for (ICStubConstIterator iter(firstMonitorStub()); !iter.atEnd(); iter++) { - if (iter->isTypeMonitor_ObjectGroup() && - iter->toTypeMonitor_ObjectGroup()->group() == group) { - return true; - } - } - - ICTypeMonitor_ObjectGroup::Compiler compiler(cx, group); - ICStub* stub = compiler.getStub(compiler.getStubSpace(frame->script())); - if (!stub) { - ReportOutOfMemory(cx); - return false; - } - - JitSpew(JitSpew_BaselineIC, - " Added TypeMonitor stub %p for ObjectGroup %p", stub, - group.get()); - - addOptimizedMonitorStub(stub); - } - - bool firstMonitorStubAdded = - wasDetachedMonitorChain && (numOptimizedMonitorStubs_ > 0); - - if (firstMonitorStubAdded) { - // Was an empty monitor chain before, but a new stub was added. This is the - // only time that any main stubs' firstMonitorStub fields need to be updated - // to refer to the newly added monitor stub. - ICStub* firstStub = mainFallbackStub_->icEntry()->firstStub(); - for (ICStubConstIterator iter(firstStub); !iter.atEnd(); iter++) { - // Non-monitored stubs are used if the result has always the same type, - // e.g. a StringLength stub will always return int32. - if (!iter->isMonitored()) { - continue; - } - - // Since we just added the first optimized monitoring stub, any - // existing main stub's |firstMonitorStub| MUST be pointing to the - // fallback monitor stub (i.e. this stub). - MOZ_ASSERT(iter->toMonitoredStub()->firstMonitorStub() == this); - iter->toMonitoredStub()->updateFirstMonitorStub(firstMonitorStub_); - } - } - - return true; -} - -bool DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, - ICTypeMonitor_Fallback* stub, HandleValue value, - MutableHandleValue res) { - MOZ_ASSERT(IsTypeInferenceEnabled()); - - JSScript* script = frame->script(); - jsbytecode* pc = stub->icEntry()->pc(script); - TypeFallbackICSpew(cx, stub, "TypeMonitor"); - - // Copy input value to res. - res.set(value); - - JitScript* jitScript = script->jitScript(); - AutoSweepJitScript sweep(script); - - StackTypeSet* types; - uint32_t argument; - if (stub->monitorsArgument(&argument)) { - MOZ_ASSERT(pc == script->code()); - types = jitScript->argTypes(sweep, script, argument); - JitScript::MonitorArgType(cx, script, argument, value); - } else if (stub->monitorsThis()) { - MOZ_ASSERT(pc == script->code()); - types = jitScript->thisTypes(sweep, script); - JitScript::MonitorThisType(cx, script, value); - } else { - types = jitScript->bytecodeTypes(sweep, script, pc); - JitScript::MonitorBytecodeType(cx, script, pc, types, value); - } - - return stub->addMonitorStubForValue(cx, frame, types, value); -} - -bool FallbackICCodeCompiler::emit_TypeMonitor() { - static_assert(R0 == JSReturnOperand); - - // Restore the tail call register. - EmitRestoreTailCallReg(masm); - - masm.pushValue(R0); - masm.push(ICStubReg); - masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg()); - - using Fn = bool (*)(JSContext*, BaselineFrame*, ICTypeMonitor_Fallback*, - HandleValue, MutableHandleValue); - return tailCallVM(masm); -} - -bool ICTypeMonitor_PrimitiveSet::Compiler::generateStubCode( - MacroAssembler& masm) { - Label success; - if ((flags_ & TypeToFlag(ValueType::Int32)) && - !(flags_ & TypeToFlag(ValueType::Double))) { - masm.branchTestInt32(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Double)) { - masm.branchTestNumber(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Undefined)) { - masm.branchTestUndefined(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Boolean)) { - masm.branchTestBoolean(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::String)) { - masm.branchTestString(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Symbol)) { - masm.branchTestSymbol(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::BigInt)) { - masm.branchTestBigInt(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Object)) { - masm.branchTestObject(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Null)) { - masm.branchTestNull(Assembler::Equal, R0, &success); - } - - EmitStubGuardFailure(masm); - - masm.bind(&success); - EmitReturnFromIC(masm); - return true; -} - -static void MaybeWorkAroundAmdBug(MacroAssembler& masm) { - // Attempt to work around an AMD bug (see bug 1034706 and bug 1281759), by - // inserting 32-bytes of NOPs. -#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) - if (CPUInfo::NeedAmdBugWorkaround()) { - masm.nop(9); - masm.nop(9); - masm.nop(9); - masm.nop(5); - } -#endif -} - -bool ICTypeMonitor_SingleObject::Compiler::generateStubCode( - MacroAssembler& masm) { - Label failure; - masm.branchTestObject(Assembler::NotEqual, R0, &failure); - MaybeWorkAroundAmdBug(masm); - - // Guard on the object's identity. - Register obj = masm.extractObject(R0, ExtractTemp0); - Address expectedObject(ICStubReg, - ICTypeMonitor_SingleObject::offsetOfObject()); - masm.branchPtr(Assembler::NotEqual, expectedObject, obj, &failure); - MaybeWorkAroundAmdBug(masm); - - EmitReturnFromIC(masm); - MaybeWorkAroundAmdBug(masm); - - masm.bind(&failure); - EmitStubGuardFailure(masm); - return true; -} - -bool ICTypeMonitor_ObjectGroup::Compiler::generateStubCode( - MacroAssembler& masm) { - Label failure; - masm.branchTestObject(Assembler::NotEqual, R0, &failure); - MaybeWorkAroundAmdBug(masm); - - // Guard on the object's ObjectGroup. No Spectre mitigations are needed - // here: we're just recording type information for Ion compilation and - // it's safe to speculatively return. - Register obj = masm.extractObject(R0, ExtractTemp0); - Address expectedGroup(ICStubReg, ICTypeMonitor_ObjectGroup::offsetOfGroup()); - masm.branchTestObjGroupNoSpectreMitigations( - Assembler::NotEqual, obj, expectedGroup, R1.scratchReg(), &failure); - MaybeWorkAroundAmdBug(masm); - - EmitReturnFromIC(masm); - MaybeWorkAroundAmdBug(masm); - - masm.bind(&failure); - EmitStubGuardFailure(masm); - return true; -} - -bool ICTypeMonitor_AnyValue::Compiler::generateStubCode(MacroAssembler& masm) { - EmitReturnFromIC(masm); - return true; -} - -bool ICCacheIR_Updated::addUpdateStubForValue(JSContext* cx, - HandleScript outerScript, - HandleObject obj, - HandleObjectGroup group, - HandleId id, HandleValue val) { - MOZ_ASSERT(IsTypeInferenceEnabled()); - - EnsureTrackPropertyTypes(cx, obj, id); - - // Make sure that undefined values are explicitly included in the property - // types for an object if generating a stub to write an undefined value. - if (val.isUndefined() && CanHaveEmptyPropertyTypesForOwnProperty(obj)) { - MOZ_ASSERT(obj->group() == group); - AddTypePropertyId(cx, obj, id, val); - } - - bool unknown = false, unknownObject = false; - AutoSweepObjectGroup sweep(group); - if (group->unknownProperties(sweep)) { - unknown = unknownObject = true; - } else { - if (HeapTypeSet* types = group->maybeGetProperty(sweep, id)) { - unknown = types->unknown(); - unknownObject = types->unknownObject(); - } else { - // We don't record null/undefined types for certain TypedObject - // properties. In these cases |types| is allowed to be nullptr - // without implying unknown types. See DoTypeUpdateFallback. - MOZ_ASSERT(obj->is()); - MOZ_ASSERT(val.isNullOrUndefined()); - } - } - MOZ_ASSERT_IF(unknown, unknownObject); - - // Don't attach too many SingleObject/ObjectGroup stubs unless we can - // replace them with a single PrimitiveSet or AnyValue stub. - if (numOptimizedStubs_ >= MAX_OPTIMIZED_STUBS && val.isObject() && - !unknownObject) { - return true; - } - - if (unknown) { - // Attach a stub that always succeeds. We should not have a - // TypeUpdate_AnyValue stub yet. - MOZ_ASSERT(!hasTypeUpdateStub(TypeUpdate_AnyValue)); - - // Discard existing stubs. - resetUpdateStubChain(cx->zone()); - - ICTypeUpdate_AnyValue::Compiler compiler(cx); - ICStub* stub = compiler.getStub(compiler.getStubSpace(outerScript)); - if (!stub) { - return false; - } - - JitSpew(JitSpew_BaselineIC, " Added TypeUpdate stub %p for any value", - stub); - addOptimizedUpdateStub(stub); - - } else if (val.isPrimitive() || unknownObject) { - ValueType type = val.type(); - - // Check for existing TypeUpdate stub. - ICTypeUpdate_PrimitiveSet* existingStub = nullptr; - for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) { - if (iter->isTypeUpdate_PrimitiveSet()) { - existingStub = iter->toTypeUpdate_PrimitiveSet(); - MOZ_ASSERT(!existingStub->containsType(type)); - } - } - - if (val.isObject()) { - // Discard existing ObjectGroup/SingleObject stubs. - resetUpdateStubChain(cx->zone()); - if (existingStub) { - addOptimizedUpdateStub(existingStub); - } - } - - ICTypeUpdate_PrimitiveSet::Compiler compiler(cx, existingStub, type); - ICStub* stub = existingStub - ? compiler.updateStub() - : compiler.getStub(compiler.getStubSpace(outerScript)); - if (!stub) { - return false; - } - if (!existingStub) { - MOZ_ASSERT(!hasTypeUpdateStub(TypeUpdate_PrimitiveSet)); - addOptimizedUpdateStub(stub); - } - - JitSpew(JitSpew_BaselineIC, " %s TypeUpdate stub %p for primitive type %d", - existingStub ? "Modified existing" : "Created new", stub, - static_cast(type)); - - } else if (val.toObject().isSingleton()) { - RootedObject obj(cx, &val.toObject()); - -#ifdef DEBUG - // We should not have a stub for this object. - for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) { - MOZ_ASSERT_IF(iter->isTypeUpdate_SingleObject(), - iter->toTypeUpdate_SingleObject()->object() != obj); - } -#endif - - ICTypeUpdate_SingleObject::Compiler compiler(cx, obj); - ICStub* stub = compiler.getStub(compiler.getStubSpace(outerScript)); - if (!stub) { - return false; - } - - JitSpew(JitSpew_BaselineIC, " Added TypeUpdate stub %p for singleton %p", - stub, obj.get()); - - addOptimizedUpdateStub(stub); - - } else { - RootedObjectGroup group(cx, val.toObject().group()); - -#ifdef DEBUG - // We should not have a stub for this group. - for (ICStubConstIterator iter(firstUpdateStub_); !iter.atEnd(); iter++) { - MOZ_ASSERT_IF(iter->isTypeUpdate_ObjectGroup(), - iter->toTypeUpdate_ObjectGroup()->group() != group); - } -#endif - - ICTypeUpdate_ObjectGroup::Compiler compiler(cx, group); - ICStub* stub = compiler.getStub(compiler.getStubSpace(outerScript)); - if (!stub) { - return false; - } - - JitSpew(JitSpew_BaselineIC, " Added TypeUpdate stub %p for ObjectGroup %p", - stub, group.get()); - - addOptimizedUpdateStub(stub); - } - - return true; -} - -// -// TypeUpdate_Fallback -// -bool DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, - ICCacheIR_Updated* stub, HandleValue objval, - HandleValue value) { - // This can get called from optimized stubs. Therefore it is not allowed to - // gc. - JS::AutoCheckCannotGC nogc; - - MOZ_ASSERT(IsTypeInferenceEnabled()); - - FallbackICSpew(cx, stub->getChainFallback(), "TypeUpdate(%s)", - ICStub::KindString(stub->kind())); - - MOZ_ASSERT(stub->isCacheIR_Updated()); - - RootedScript script(cx, frame->script()); - RootedObject obj(cx, &objval.toObject()); - - RootedId id(cx, stub->toCacheIR_Updated()->updateStubId()); - MOZ_ASSERT(id.get() != JSID_EMPTY); - - // The group should match the object's group. - RootedObjectGroup group(cx, stub->toCacheIR_Updated()->updateStubGroup()); -#ifdef DEBUG - MOZ_ASSERT(obj->group() == group); -#endif - - JSObject* maybeSingleton = obj->isSingleton() ? obj.get() : nullptr; - AddTypePropertyId(cx, group, maybeSingleton, id, value); - - if (MOZ_UNLIKELY( - !stub->addUpdateStubForValue(cx, script, obj, group, id, value))) { - // The calling JIT code assumes this function is infallible (for - // instance we may reallocate dynamic slots before calling this), - // so ignore OOMs if we failed to attach a stub. - cx->recoverFromOutOfMemory(); - } - - return true; -} - -bool FallbackICCodeCompiler::emit_TypeUpdate() { - // Just store false into R1.scratchReg() and return. - masm.move32(Imm32(0), R1.scratchReg()); - EmitReturnFromIC(masm); - return true; -} - -bool ICTypeUpdate_PrimitiveSet::Compiler::generateStubCode( - MacroAssembler& masm) { - Label success; - if ((flags_ & TypeToFlag(ValueType::Int32)) && - !(flags_ & TypeToFlag(ValueType::Double))) { - masm.branchTestInt32(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Double)) { - masm.branchTestNumber(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Undefined)) { - masm.branchTestUndefined(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Boolean)) { - masm.branchTestBoolean(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::String)) { - masm.branchTestString(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Symbol)) { - masm.branchTestSymbol(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::BigInt)) { - masm.branchTestBigInt(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Object)) { - masm.branchTestObject(Assembler::Equal, R0, &success); - } - - if (flags_ & TypeToFlag(ValueType::Null)) { - masm.branchTestNull(Assembler::Equal, R0, &success); - } - - EmitStubGuardFailure(masm); - - // Type matches, load true into R1.scratchReg() and return. - masm.bind(&success); - masm.mov(ImmWord(1), R1.scratchReg()); - EmitReturnFromIC(masm); - - return true; -} - -bool ICTypeUpdate_SingleObject::Compiler::generateStubCode( - MacroAssembler& masm) { - Label failure; - masm.branchTestObject(Assembler::NotEqual, R0, &failure); - - // Guard on the object's identity. - Register obj = masm.extractObject(R0, R1.scratchReg()); - Address expectedObject(ICStubReg, - ICTypeUpdate_SingleObject::offsetOfObject()); - masm.branchPtr(Assembler::NotEqual, expectedObject, obj, &failure); - - // Identity matches, load true into R1.scratchReg() and return. - masm.mov(ImmWord(1), R1.scratchReg()); - EmitReturnFromIC(masm); - - masm.bind(&failure); - EmitStubGuardFailure(masm); - return true; -} - -bool ICTypeUpdate_ObjectGroup::Compiler::generateStubCode( - MacroAssembler& masm) { - Label failure; - - Register scratch1 = R1.scratchReg(); - masm.fallibleUnboxObject(R0, scratch1, &failure); - - // Guard on the object's ObjectGroup. - Address expectedGroup(ICStubReg, ICTypeUpdate_ObjectGroup::offsetOfGroup()); - masm.branchTestObjGroup(Assembler::NotEqual, scratch1, expectedGroup, - scratch1, R0.payloadOrValueReg(), &failure); - - // Group matches, load true into R1.scratchReg() and return. - masm.mov(ImmWord(1), R1.scratchReg()); - EmitReturnFromIC(masm); - - masm.bind(&failure); - EmitStubGuardFailure(masm); - return true; -} - -bool ICTypeUpdate_AnyValue::Compiler::generateStubCode(MacroAssembler& masm) { - // AnyValue always matches so return true. - masm.mov(ImmWord(1), R1.scratchReg()); - EmitReturnFromIC(masm); - return true; -} +// TODO(no-TI): maybe remove NeedAmdBugWorkaround. // // ToBool_Fallback @@ -1766,31 +853,6 @@ return tailCallVM(masm); } -static void StripPreliminaryObjectStubs(JSContext* cx, ICFallbackStub* stub, - JSScript* script) { - // Before the new script properties analysis has been performed on a type, - // all instances of that type have the maximum number of fixed slots. - // Afterwards, the objects (even the preliminary ones) might be changed - // to reduce the number of fixed slots they have. If we generate stubs for - // both the old and new number of fixed slots, the stub will look - // polymorphic to IonBuilder when it is actually monomorphic. To avoid - // this, strip out any stubs for preliminary objects before attaching a new - // stub which isn't on a preliminary object. - - for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++) { - if (iter->isCacheIR_Regular() && - iter->toCacheIR_Regular()->hasPreliminaryObject()) { - iter.unlink(cx, script); - } else if (iter->isCacheIR_Monitored() && - iter->toCacheIR_Monitored()->hasPreliminaryObject()) { - iter.unlink(cx, script); - } else if (iter->isCacheIR_Updated() && - iter->toCacheIR_Updated()->hasPreliminaryObject()) { - iter.unlink(cx, script); - } - } -} - static bool TryAttachGetPropStub(const char* name, JSContext* cx, BaselineFrame* frame, ICFallbackStub* stub, CacheKind kind, HandleValue val, @@ -1812,15 +874,10 @@ case AttachDecision::Attach: { ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), - BaselineCacheIRStubKind::Monitored, - script, icScript, stub, &attached); + BaselineCacheIRStubKind::Regular, script, + icScript, stub, &attached); if (newStub) { JitSpew(JitSpew_BaselineIC, " Attached %s CacheIR stub", name); - if (gen.shouldNotePreliminaryObjectStub()) { - newStub->toCacheIR_Monitored()->notePreliminaryObject(); - } else if (gen.shouldUnlinkPreliminaryObjectStubs()) { - StripPreliminaryObjectStubs(cx, stub, frame->invalidationScript()); - } } } break; case AttachDecision::NoAction: @@ -1868,11 +925,6 @@ &isOptimizedArgs)) { return false; } - if (isOptimizedArgs) { - if (!TypeMonitorResult(cx, stub, frame, script, pc, res)) { - return false; - } - } } bool attached = TryAttachGetPropStub("GetElem", cx, frame, stub, @@ -1882,10 +934,6 @@ if (!GetElementOperation(cx, op, lhsCopy, rhs, res)) { return false; } - - if (!TypeMonitorResult(cx, stub, frame, script, pc, res)) { - return false; - } } if (attached) { @@ -1934,10 +982,6 @@ return false; } - if (!TypeMonitorResult(cx, stub, frame, script, pc, res)) { - return false; - } - if (attached) { return true; } @@ -2021,22 +1065,7 @@ leaveStubFrame(masm, true); - if (!IsTypeInferenceEnabled()) { - EmitReturnFromIC(masm); - return true; - } - - // When we get here, ICStubReg contains the ICGetElem_Fallback stub, - // which we can't use to enter the TypeMonitor IC, because it's a - // MonitoredFallbackStub instead of a MonitoredStub. So, we cheat. Note that - // we must have a non-null fallbackMonitorStub here because - // BaselineStackBuilder::buildStubFrame delazifies the stub when bailing out. - masm.loadPtr(Address(ICStubReg, - ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()), - ICStubReg); - EmitEnterTypeMonitorIC(masm, - ICTypeMonitor_Fallback::offsetOfFirstMonitorStub()); - + EmitReturnFromIC(masm); return true; } @@ -2048,14 +1077,6 @@ return emitGetElem(/* hasReceiver = */ true); } -static void SetUpdateStubData(ICCacheIR_Updated* stub, - const PropertyTypeCheckInfo* info) { - if (info->isSet()) { - stub->updateStubGroup() = info->group(); - stub->updateStubId() = info->id(); - } -} - bool DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub, Value* stack, HandleValue objv, HandleValue index, HandleValue rhs) { @@ -2106,19 +1127,11 @@ case AttachDecision::Attach: { ICStub* newStub = AttachBaselineCacheIRStub( cx, gen.writerRef(), gen.cacheKind(), - BaselineCacheIRStubKind::Updated, frame->script(), icScript, stub, + BaselineCacheIRStubKind::Regular, frame->script(), icScript, stub, &attached); if (newStub) { JitSpew(JitSpew_BaselineIC, " Attached SetElem CacheIR stub"); - SetUpdateStubData(newStub->toCacheIR_Updated(), gen.typeCheckInfo()); - - if (gen.shouldNotePreliminaryObjectStub()) { - newStub->toCacheIR_Updated()->notePreliminaryObject(); - } else if (gen.shouldUnlinkPreliminaryObjectStubs()) { - StripPreliminaryObjectStubs(cx, stub, frame->invalidationScript()); - } - if (gen.attachedTypedArrayOOBStub()) { stub->noteHasTypedArrayOOB(); } @@ -2157,8 +1170,8 @@ return false; } } else { - if (!SetObjectElement(cx, obj, index, rhs, objv, - JSOp(*pc) == JSOp::StrictSetElem, script, pc)) { + if (!SetObjectElementWithReceiver(cx, obj, index, rhs, objv, + JSOp(*pc) == JSOp::StrictSetElem)) { return false; } } @@ -2197,18 +1210,10 @@ ICScript* icScript = frame->icScript(); ICStub* newStub = AttachBaselineCacheIRStub( cx, gen.writerRef(), gen.cacheKind(), - BaselineCacheIRStubKind::Updated, frame->script(), icScript, stub, + BaselineCacheIRStubKind::Regular, frame->script(), icScript, stub, &attached); if (newStub) { JitSpew(JitSpew_BaselineIC, " Attached SetElem CacheIR stub"); - - SetUpdateStubData(newStub->toCacheIR_Updated(), gen.typeCheckInfo()); - - if (gen.shouldNotePreliminaryObjectStub()) { - newStub->toCacheIR_Updated()->notePreliminaryObject(); - } else if (gen.shouldUnlinkPreliminaryObjectStubs()) { - StripPreliminaryObjectStubs(cx, stub, frame->invalidationScript()); - } } } break; case AttachDecision::NoAction: @@ -2419,8 +1424,8 @@ RootedPropertyName name(cx, script->getName(pc)); TryAttachStub("GetName", cx, frame, stub, - BaselineCacheIRStubKind::Monitored, - envChain, name); + BaselineCacheIRStubKind::Regular, envChain, + name); static_assert(JSOpLength_GetGName == JSOpLength_GetName, "Otherwise our check for JSOp::Typeof isn't ok"); @@ -2434,7 +1439,7 @@ } } - return TypeMonitorResult(cx, stub, frame, script, pc, res); + return true; } bool FallbackICCodeCompiler::emit_GetName() { @@ -2515,12 +1520,6 @@ return false; } - // An intrinsic operation will always produce the same result, so only - // needs to be monitored once. Attach a stub to load the resulting constant - // directly. - - JitScript::MonitorBytecodeType(cx, script, pc, res); - TryAttachStub("GetIntrinsic", cx, frame, stub, BaselineCacheIRStubKind::Regular, res); @@ -2598,7 +1597,7 @@ return false; } - return TypeMonitorResult(cx, stub, frame, script, pc, res); + return true; } bool DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame, @@ -2624,7 +1623,7 @@ return false; } - return TypeMonitorResult(cx, stub, frame, script, pc, res); + return true; } bool FallbackICCodeCompiler::emitGetProp(bool hasReceiver) { @@ -2675,22 +1674,7 @@ leaveStubFrame(masm, true); - if (!IsTypeInferenceEnabled()) { - EmitReturnFromIC(masm); - return true; - } - - // When we get here, ICStubReg contains the ICGetProp_Fallback stub, - // which we can't use to enter the TypeMonitor IC, because it's a - // MonitoredFallbackStub instead of a MonitoredStub. So, we cheat. Note that - // we must have a non-null fallbackMonitorStub here because - // BaselineStackBuilder::buildStubFrame delazifies the stub when bailing out. - masm.loadPtr(Address(ICStubReg, - ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()), - ICStubReg); - EmitEnterTypeMonitorIC(masm, - ICTypeMonitor_Fallback::offsetOfFirstMonitorStub()); - + EmitReturnFromIC(masm); return true; } @@ -2754,18 +1738,10 @@ ICScript* icScript = frame->icScript(); ICStub* newStub = AttachBaselineCacheIRStub( cx, gen.writerRef(), gen.cacheKind(), - BaselineCacheIRStubKind::Updated, frame->script(), icScript, stub, + BaselineCacheIRStubKind::Regular, frame->script(), icScript, stub, &attached); if (newStub) { JitSpew(JitSpew_BaselineIC, " Attached SetProp CacheIR stub"); - - SetUpdateStubData(newStub->toCacheIR_Updated(), gen.typeCheckInfo()); - - if (gen.shouldNotePreliminaryObjectStub()) { - newStub->toCacheIR_Updated()->notePreliminaryObject(); - } else if (gen.shouldUnlinkPreliminaryObjectStubs()) { - StripPreliminaryObjectStubs(cx, stub, frame->invalidationScript()); - } } } break; case AttachDecision::NoAction: @@ -2839,18 +1815,10 @@ ICScript* icScript = frame->icScript(); ICStub* newStub = AttachBaselineCacheIRStub( cx, gen.writerRef(), gen.cacheKind(), - BaselineCacheIRStubKind::Updated, frame->script(), icScript, stub, + BaselineCacheIRStubKind::Regular, frame->script(), icScript, stub, &attached); if (newStub) { JitSpew(JitSpew_BaselineIC, " Attached SetElem CacheIR stub"); - - SetUpdateStubData(newStub->toCacheIR_Updated(), gen.typeCheckInfo()); - - if (gen.shouldNotePreliminaryObjectStub()) { - newStub->toCacheIR_Updated()->notePreliminaryObject(); - } else if (gen.shouldUnlinkPreliminaryObjectStubs()) { - StripPreliminaryObjectStubs(cx, stub, frame->invalidationScript()); - } } } break; case AttachDecision::NoAction: @@ -2966,16 +1934,10 @@ case AttachDecision::Attach: { ICScript* icScript = frame->icScript(); ICStub* newStub = AttachBaselineCacheIRStub( - cx, gen.writerRef(), gen.cacheKind(), gen.cacheIRStubKind(), script, - icScript, stub, &handled); + cx, gen.writerRef(), gen.cacheKind(), + BaselineCacheIRStubKind::Regular, script, icScript, stub, &handled); if (newStub) { JitSpew(JitSpew_BaselineIC, " Attached Call CacheIR stub"); - - // If it's an updated stub, initialize it. - if (gen.cacheIRStubKind() == BaselineCacheIRStubKind::Updated) { - SetUpdateStubData(newStub->toCacheIR_Updated(), - gen.typeCheckInfo()); - } } } break; case AttachDecision::TemporarilyUnoptimizable: @@ -3014,10 +1976,6 @@ res.set(callArgs.rval()); } - if (!TypeMonitorResult(cx, stub, frame, script, pc, res)) { - return false; - } - // Try to transition again in case we called this IC recursively. if (stub->state().maybeTransition()) { stub->discardStubs(cx, frame->invalidationScript()); @@ -3033,16 +1991,10 @@ case AttachDecision::Attach: { ICScript* icScript = frame->icScript(); ICStub* newStub = AttachBaselineCacheIRStub( - cx, gen.writerRef(), gen.cacheKind(), gen.cacheIRStubKind(), script, - icScript, stub, &handled); + cx, gen.writerRef(), gen.cacheKind(), + BaselineCacheIRStubKind::Regular, script, icScript, stub, &handled); if (newStub) { JitSpew(JitSpew_BaselineIC, " Attached Call CacheIR stub"); - - // If it's an updated stub, initialize it. - if (gen.cacheIRStubKind() == BaselineCacheIRStubKind::Updated) { - SetUpdateStubData(newStub->toCacheIR_Updated(), - gen.typeCheckInfo()); - } } } break; case AttachDecision::NoAction: @@ -3103,17 +2055,11 @@ case AttachDecision::Attach: { ICScript* icScript = frame->icScript(); ICStub* newStub = AttachBaselineCacheIRStub( - cx, gen.writerRef(), gen.cacheKind(), gen.cacheIRStubKind(), script, - icScript, stub, &handled); + cx, gen.writerRef(), gen.cacheKind(), + BaselineCacheIRStubKind::Regular, script, icScript, stub, &handled); if (newStub) { JitSpew(JitSpew_BaselineIC, " Attached Spread Call CacheIR stub"); - - // If it's an updated stub, initialize it. - if (gen.cacheIRStubKind() == BaselineCacheIRStubKind::Updated) { - SetUpdateStubData(newStub->toCacheIR_Updated(), - gen.typeCheckInfo()); - } } } break; case AttachDecision::TemporarilyUnoptimizable: @@ -3128,12 +2074,8 @@ } } - if (!SpreadCallOperation(cx, script, pc, thisv, callee, arr, newTarget, - res)) { - return false; - } - - return TypeMonitorResult(cx, stub, frame, script, pc, res); + return SpreadCallOperation(cx, script, pc, thisv, callee, arr, newTarget, + res); } void ICStubCompilerBase::pushCallArguments(MacroAssembler& masm, @@ -3293,23 +2235,7 @@ masm.bind(&skipThisReplace); } - if (!IsTypeInferenceEnabled()) { - EmitReturnFromIC(masm); - return true; - } - - // At this point, ICStubReg points to the ICCall_Fallback stub, which is NOT - // a MonitoredStub, but rather a MonitoredFallbackStub. To use - // EmitEnterTypeMonitorIC, first load the ICTypeMonitor_Fallback stub into - // ICStubReg. Then, use EmitEnterTypeMonitorIC with a custom struct offset. - // Note that we must have a non-null fallbackMonitorStub here because - // BaselineStackBuilder::buildStubFrame delazifies the stub when bailing out. - masm.loadPtr(Address(ICStubReg, - ICMonitoredFallbackStub::offsetOfFallbackMonitorStub()), - ICStubReg); - EmitEnterTypeMonitorIC(masm, - ICTypeMonitor_Fallback::offsetOfFirstMonitorStub()); - + EmitReturnFromIC(masm); return true; } @@ -3521,22 +2447,6 @@ return tailCallVM(masm); } -ICTypeMonitor_SingleObject::ICTypeMonitor_SingleObject(JitCode* stubCode, - JSObject* obj) - : ICStub(TypeMonitor_SingleObject, stubCode), obj_(obj) {} - -ICTypeMonitor_ObjectGroup::ICTypeMonitor_ObjectGroup(JitCode* stubCode, - ObjectGroup* group) - : ICStub(TypeMonitor_ObjectGroup, stubCode), group_(group) {} - -ICTypeUpdate_SingleObject::ICTypeUpdate_SingleObject(JitCode* stubCode, - JSObject* obj) - : ICStub(TypeUpdate_SingleObject, stubCode), obj_(obj) {} - -ICTypeUpdate_ObjectGroup::ICTypeUpdate_ObjectGroup(JitCode* stubCode, - ObjectGroup* group) - : ICStub(TypeUpdate_ObjectGroup, stubCode), group_(group) {} - // // Rest_Fallback // @@ -4028,10 +2938,6 @@ switch (kind()) { case ICStub::CacheIR_Regular: return toCacheIR_Regular()->stubInfo(); - case ICStub::CacheIR_Monitored: - return toCacheIR_Monitored()->stubInfo(); - case ICStub::CacheIR_Updated: - return toCacheIR_Updated()->stubInfo(); default: MOZ_CRASH("Not a CacheIR stub"); } @@ -4041,10 +2947,6 @@ switch (kind()) { case ICStub::CacheIR_Regular: return toCacheIR_Regular()->stubDataStart(); - case ICStub::CacheIR_Monitored: - return toCacheIR_Monitored()->stubDataStart(); - case ICStub::CacheIR_Updated: - return toCacheIR_Updated()->stubDataStart(); default: MOZ_CRASH("Not a CacheIR stub"); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineIC.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineIC.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineIC.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineIC.h 2020-11-17 19:31:31.000000000 +0000 @@ -35,8 +35,6 @@ namespace js { -class StackTypeSet; - MOZ_COLD void ReportOutOfMemory(JSContext* cx); namespace jit { @@ -110,116 +108,6 @@ // Shared // Stub Code // -// -// Type ICs -// ======== -// -// Type ICs are otherwise regular ICs that are actually nested within -// other IC chains. They serve to optimize locations in the code where the -// baseline compiler would have otherwise had to perform a type Monitor -// operation (e.g. the result of GetProp, GetElem, etc.), or locations where the -// baseline compiler would have had to modify a heap typeset using the type of -// an input value (e.g. SetProp, SetElem, etc.) -// -// There are two kinds of Type ICs: Monitor and Update. -// -// Note that type stub bodies are no-ops. The stubs only exist for their -// guards, and their existence simply signifies that the typeset (implicit) -// that is being checked already contains that type. -// -// TypeMonitor ICs -// --------------- -// Monitor ICs are shared between stubs in the general IC, and monitor the -// resulting types of getter operations (call returns, getprop outputs, etc.) -// -// +-----------+ +-----------+ +-----------+ +-----------+ -// ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub | -// +-----------+ +-----------+ +-----------+ +-----------+ -// | | | | -// |------------------/-----------------/ | -// v | -// +-----------+ +-----------+ +-----------+ | -// | Type 1 |---->| Type 2 |---->| Type FB | | -// +-----------+ +-----------+ +-----------+ | -// | | | | -// <----------/-----------------/------------------/------------------/ -// r e t u r n p a t h -// -// After an optimized IC stub successfully executes, it passes control to the -// type stub chain to check the resulting type. If no type stub succeeds, and -// the monitor fallback stub is reached, the monitor fallback stub performs a -// manual monitor, and also adds the appropriate type stub to the chain. -// -// The IC's main fallback, in addition to generating new mainline stubs, also -// generates type stubs as reflected by its returned value. -// -// NOTE: The type IC chain returns directly to the mainline code, not back to -// the stub it was entered from. Thus, entering a type IC is a matter of a -// |jump|, not a |call|. This allows us to safely call a VM Monitor function -// from within the monitor IC's fallback chain, since the return address (needed -// for stack inspection) is preserved. -// -// -// TypeUpdate ICs -// -------------- -// Update ICs update heap typesets and monitor the input types of setter -// operations (setelem, setprop inputs, etc.). Unlike monitor ICs, they are not -// shared between stubs on an IC, but instead are kept track of on a per-stub -// basis. -// -// This is because the main stubs for the operation will each identify a -// potentially different ObjectGroup to update. New input types must be tracked -// on a group-to- group basis. -// -// Type-update ICs cannot be called in tail position (they must return to the -// the stub that called them so that the stub may continue to perform its -// original purpose). This means that any VMCall to perform a manual type -// update from C++ must be done from within the main IC stub. This necessitates -// that the stub enter a "BaselineStub" frame before making the call. -// -// If the type-update IC chain could itself make the VMCall, then the -// BaselineStub frame must be entered before calling the type-update chain, and -// exited afterward. This is very expensive for a common case where we expect -// the type-update fallback to not be called. To avoid the cost of entering and -// exiting a BaselineStub frame when using the type-update IC chain, we design -// the chain to not perform any VM-calls in its fallback. -// -// Instead, the type-update IC chain is responsible for returning 1 or 0, -// depending on if a type is represented in the chain or not. The fallback stub -// simply returns 0, and all other optimized stubs return 1. If the chain -// returns 1, then the IC stub goes ahead and performs its operation. If the -// chain returns 0, then the IC stub performs a call to the fallback function -// inline (doing the requisite BaselineStub frame enter/exit). -// This allows us to avoid the expensive subfram enter/exit in the common case. -// -// r e t u r n p a t h -// <--------------.-----------------.-----------------.-----------------. -// | | | | -// +-----------+ +-----------+ +-----------+ +-----------+ -// ---->| Stub 1 |---->| Stub 2 |---->| Stub 3 |---->| FB Stub | -// +-----------+ +-----------+ +-----------+ +-----------+ -// | ^ | ^ | ^ -// | | | | | | -// | | | | | |----------------. -// | | | | v |1 |0 -// | | | | +-----------+ +-----------+ -// | | | | | Type 3.1 |--->| FB 3 | -// | | | | +-----------+ +-----------+ -// | | | | -// | | | \-------------.-----------------. -// | | | | | | -// | | v |1 |1 |0 -// | | +-----------+ +-----------+ +-----------+ -// | | | Type 2.1 |---->| Type 2.2 |---->| FB 2 | -// | | +-----------+ +-----------+ +-----------+ -// | | -// | \-------------.-----------------. -// | | | | -// v |1 |1 |0 -// +-----------+ +-----------+ +-----------+ -// | Type 1.1 |---->| Type 1.2 |---->| FB 1 | -// +-----------+ +-----------+ +-----------+ -// class ICStub; class ICFallbackStub; @@ -231,11 +119,8 @@ #ifdef JS_JITSPEW void FallbackICSpew(JSContext* cx, ICFallbackStub* stub, const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4); -void TypeFallbackICSpew(JSContext* cx, ICTypeMonitor_Fallback* stub, - const char* fmt, ...) MOZ_FORMAT_PRINTF(3, 4); #else # define FallbackICSpew(...) -# define TypeFallbackICSpew(...) #endif // An entry in the BaselineScript IC descriptor table. There's one ICEntry per @@ -244,8 +129,7 @@ // A pointer to the first IC stub for this instruction. ICStub* firstStub_; - // The PC offset of this IC's bytecode op within the JSScript or - // ProloguePCOffset if this is a prologue IC. + // The PC offset of this IC's bytecode op within the JSScript. uint32_t pcOffset_; #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED @@ -258,11 +142,6 @@ #endif public: - // Prologue ICs are Baseline ICs used for function argument/this type - // monitoring in the script's prologue. Note: the last bytecode op in a script - // is always a return so UINT32_MAX is never a valid bytecode offset. - static constexpr uint32_t ProloguePCOffset = UINT32_MAX; - ICEntry(ICStub* firstStub, uint32_t pcOffset) : firstStub_(firstStub), pcOffset_(pcOffset) {} @@ -275,9 +154,7 @@ void setFirstStub(ICStub* stub) { firstStub_ = stub; } - uint32_t pcOffset() const { - return pcOffset_ == ProloguePCOffset ? 0 : pcOffset_; - } + uint32_t pcOffset() const { return pcOffset_; } jsbytecode* pc(JSScript* script) const { return script->offsetToPC(pcOffset()); } @@ -288,14 +165,9 @@ inline ICStub** addressOfFirstStub() { return &firstStub_; } - bool isForPrologue() const { return pcOffset_ == ProloguePCOffset; } - void trace(JSTracer* trc); }; -class ICMonitoredStub; -class ICMonitoredFallbackStub; - // Constant iterator that traverses arbitrary chains of ICStubs. // No requirements are made of the ICStub used to construct this // iterator, aside from that the stub be part of a nullptr-terminated @@ -416,10 +288,7 @@ }; static bool IsValidKind(Kind k) { return (k > INVALID) && (k < LIMIT); } - static bool IsCacheIRKind(Kind k) { - return k == CacheIR_Regular || k == CacheIR_Monitored || - k == CacheIR_Updated; - } + static bool IsCacheIRKind(Kind k) { return k == CacheIR_Regular; } static const char* KindString(Kind k) { switch (k) { @@ -433,19 +302,15 @@ } } + // TODO(no-TI): remove enum enum Trait : uint16_t { Regular = 0x0, Fallback = 0x1, - Monitored = 0x2, - MonitoredFallback = 0x3, - Updated = 0x4 }; void updateCode(JitCode* stubCode); void trace(JSTracer* trc); - static const uint16_t EXPECTED_TRACE_MAGIC = 0b1100011; - template static T* New(JSContext* cx, ICStubSpace* space, JitCode* code, Args&&... args) { @@ -488,12 +353,12 @@ static const uint16_t TRAIT_BITS = 3; static const uint16_t TRAIT_MASK = (1 << TRAIT_BITS) - 1; static const uint16_t KIND_OFFSET = TRAIT_OFFSET + TRAIT_BITS; - static const uint16_t KIND_BITS = 6; + static const uint16_t KIND_BITS = 5; static const uint16_t KIND_MASK = (1 << KIND_BITS) - 1; static const uint16_t MAGIC_OFFSET = KIND_OFFSET + KIND_BITS; - static const uint16_t MAGIC_BITS = 7; + static const uint16_t MAGIC_BITS = 8; static const uint16_t MAGIC_MASK = (1 << MAGIC_BITS) - 1; - static const uint16_t EXPECTED_MAGIC = 0b1100011; + static const uint16_t EXPECTED_MAGIC = 0b11100011; static_assert(LIMIT <= (1 << KIND_BITS), "Not enough kind bits"); static_assert(LIMIT > (1 << (KIND_BITS - 1)), "Too many kind bits"); @@ -540,17 +405,7 @@ return (Kind)((traitKindBits_ >> KIND_OFFSET) & KIND_MASK); } - inline bool isFallback() const { - return trait() == Fallback || trait() == MonitoredFallback; - } - - inline bool isMonitored() const { return trait() == Monitored; } - - inline bool isUpdated() const { return trait() == Updated; } - - inline bool isMonitoredFallback() const { - return trait() == MonitoredFallback; - } + inline bool isFallback() const { return trait() == Fallback; } inline const ICFallbackStub* toFallbackStub() const { MOZ_ASSERT(isFallback()); @@ -562,36 +417,6 @@ return reinterpret_cast(this); } - inline const ICMonitoredStub* toMonitoredStub() const { - MOZ_ASSERT(isMonitored()); - return reinterpret_cast(this); - } - - inline ICMonitoredStub* toMonitoredStub() { - MOZ_ASSERT(isMonitored()); - return reinterpret_cast(this); - } - - inline const ICMonitoredFallbackStub* toMonitoredFallbackStub() const { - MOZ_ASSERT(isMonitoredFallback()); - return reinterpret_cast(this); - } - - inline ICMonitoredFallbackStub* toMonitoredFallbackStub() { - MOZ_ASSERT(isMonitoredFallback()); - return reinterpret_cast(this); - } - - inline const ICCacheIR_Updated* toUpdatedStub() const { - MOZ_ASSERT(isUpdated()); - return reinterpret_cast(this); - } - - inline ICCacheIR_Updated* toUpdatedStub() { - MOZ_ASSERT(isUpdated()); - return reinterpret_cast(this); - } - #define KIND_METHODS(kindName) \ inline bool is##kindName() const { return kind() == kindName; } \ inline const IC##kindName* to##kindName() const { \ @@ -609,18 +434,14 @@ inline bool hasNext() const { return next_ != nullptr; } - inline void setNext(ICStub* stub) { - // Note: next_ only needs to be changed under the compilation lock for - // non-type-monitor/update ICs. - next_ = stub; - } + inline void setNext(ICStub* stub) { next_ = stub; } inline ICStub** addressOfNext() { return &next_; } bool usesTrampolineCode() const { // All fallback code is stored in a single JitCode instance, so we can't // call JitCode::FromExecutable on the raw pointer. - return isFallback() || isTypeMonitor_Fallback() || isTypeUpdate_Fallback(); + return isFallback(); } JitCode* jitCode() { MOZ_ASSERT(!usesTrampolineCode()); @@ -629,7 +450,6 @@ inline uint8_t* rawStubCode() const { return stubCode_; } - // This method is not valid on TypeUpdate stub chains! inline ICFallbackStub* getChainFallback() { ICStub* lastStub = this; while (lastStub->next_) { @@ -695,7 +515,7 @@ ICFallbackStub(Kind kind, Trait trait, TrampolinePtr stubCode) : ICStub(kind, trait, stubCode.value) { - MOZ_ASSERT(trait == ICStub::Fallback || trait == ICStub::MonitoredFallback); + MOZ_ASSERT(trait == ICStub::Fallback); } public: @@ -799,6 +619,7 @@ }; // Base class for Trait::Regular CacheIR stubs +// TODO(no-TI): remove trait class. class ICCacheIR_Regular : public ICCacheIR_Trait { using Base = ICCacheIR_Trait; @@ -807,116 +628,6 @@ : Base(stubInfo, ICStub::CacheIR_Regular, stubCode) {} }; -// Monitored stubs are IC stubs that feed a single resulting value out to a -// type monitor operation. -class ICMonitoredStub : public ICStub { - protected: - // Pointer to the start of the type monitoring stub chain. - ICStub* firstMonitorStub_; - - ICMonitoredStub(Kind kind, JitCode* stubCode, ICStub* firstMonitorStub); - - public: - inline void updateFirstMonitorStub(ICStub* monitorStub) { - // This should only be called once: when the first optimized monitor stub - // is added to the type monitor IC chain. - MOZ_ASSERT(firstMonitorStub_ && - firstMonitorStub_->isTypeMonitor_Fallback()); - firstMonitorStub_ = monitorStub; - } - inline void resetFirstMonitorStub(ICStub* monitorFallback) { - MOZ_ASSERT(monitorFallback->isTypeMonitor_Fallback()); - firstMonitorStub_ = monitorFallback; - } - inline ICStub* firstMonitorStub() const { return firstMonitorStub_; } - - static inline size_t offsetOfFirstMonitorStub() { - return offsetof(ICMonitoredStub, firstMonitorStub_); - } -}; - -class ICCacheIR_Monitored : public ICCacheIR_Trait { - using Base = ICCacheIR_Trait; - - public: - ICCacheIR_Monitored(JitCode* stubCode, ICStub* firstMonitorStub, - const CacheIRStubInfo* stubInfo) - : Base(stubInfo, ICStub::CacheIR_Monitored, stubCode, firstMonitorStub) {} -}; - -class ICCacheIR_Updated : public ICCacheIR_Trait { - using Base = ICCacheIR_Trait; - - uint32_t numOptimizedStubs_; - - GCPtrObjectGroup updateStubGroup_; - GCPtrId updateStubId_; - - // Pointer to the start of the type updating stub chain. - ICStub* firstUpdateStub_; - - static const uint32_t MAX_OPTIMIZED_STUBS = 8; - - public: - ICCacheIR_Updated(JitCode* stubCode, const CacheIRStubInfo* stubInfo) - : Base(stubInfo, ICStub::CacheIR_Updated, ICStub::Updated, stubCode), - numOptimizedStubs_(0), - updateStubGroup_(nullptr), - updateStubId_(JSID_EMPTY), - firstUpdateStub_(nullptr) {} - - GCPtrObjectGroup& updateStubGroup() { return updateStubGroup_; } - GCPtrId& updateStubId() { return updateStubId_; } - - inline ICStub* firstUpdateStub() const { return firstUpdateStub_; } - - static inline size_t offsetOfFirstUpdateStub() { - return offsetof(ICCacheIR_Updated, firstUpdateStub_); - } - - inline uint32_t numOptimizedStubs() const { return numOptimizedStubs_; } - - MOZ_MUST_USE bool initUpdatingChain(JSContext* cx, ICStubSpace* space); - - MOZ_MUST_USE bool addUpdateStubForValue(JSContext* cx, HandleScript script, - HandleObject obj, - HandleObjectGroup group, HandleId id, - HandleValue val); - - void addOptimizedUpdateStub(ICStub* stub) { - if (firstUpdateStub_->isTypeUpdate_Fallback()) { - stub->setNext(firstUpdateStub_); - firstUpdateStub_ = stub; - } else { - ICStub* iter = firstUpdateStub_; - MOZ_ASSERT(iter->next() != nullptr); - while (!iter->next()->isTypeUpdate_Fallback()) { - iter = iter->next(); - } - MOZ_ASSERT(iter->next()->next() == nullptr); - stub->setNext(iter->next()); - iter->setNext(stub); - } - - numOptimizedStubs_++; - } - - void resetUpdateStubChain(Zone* zone); - - bool hasTypeUpdateStub(ICStub::Kind kind) { - ICStub* stub = firstUpdateStub_; - do { - if (stub->kind() == kind) { - return true; - } - - stub = stub->next(); - } while (stub); - - return false; - } -}; - // Base class for stubcode compilers. class ICStubCompilerBase { protected: @@ -1002,6 +713,7 @@ } }; +// TODO(no-TI): remove/cleanup with ICStubCompilerBase. class ICStubCompiler : public ICStubCompilerBase { // Prevent GC in the middle of stub compilation. js::gc::AutoSuppressGC suppressGC; @@ -1014,8 +726,6 @@ virtual MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) = 0; - JitCode* getStubCode(); - ICStubCompiler(JSContext* cx, ICStub::Kind kind) : ICStubCompilerBase(cx), suppressGC(cx), kind(kind) {} @@ -1030,497 +740,6 @@ static ICStubSpace* StubSpaceForStub(bool makesGCCalls, JSScript* script, ICScript* icScript); - - ICStubSpace* getStubSpace(JSScript* outerScript) { - MOZ_ASSERT(IsTypeInferenceEnabled()); - return StubSpaceForStub(ICStub::NonCacheIRStubMakesGCCalls(kind), - outerScript, /*icScript = */ nullptr); - } -}; - -// Monitored fallback stubs - as the name implies. -class ICMonitoredFallbackStub : public ICFallbackStub { - protected: - // Pointer to the fallback monitor stub. Created lazily by - // getFallbackMonitorStub if needed. - ICTypeMonitor_Fallback* fallbackMonitorStub_; - - ICMonitoredFallbackStub(Kind kind, TrampolinePtr stubCode) - : ICFallbackStub(kind, ICStub::MonitoredFallback, stubCode), - fallbackMonitorStub_(nullptr) {} - - public: - MOZ_MUST_USE bool initMonitoringChain(JSContext* cx, JSScript* script); - - ICTypeMonitor_Fallback* maybeFallbackMonitorStub() const { - return fallbackMonitorStub_; - } - ICTypeMonitor_Fallback* getFallbackMonitorStub(JSContext* cx, - JSScript* script) { - if (!fallbackMonitorStub_ && !initMonitoringChain(cx, script)) { - return nullptr; - } - MOZ_ASSERT(fallbackMonitorStub_); - return fallbackMonitorStub_; - } - - static inline size_t offsetOfFallbackMonitorStub() { - return offsetof(ICMonitoredFallbackStub, fallbackMonitorStub_); - } -}; - -// TypeCheckPrimitiveSetStub -// Base class for IC stubs (TypeUpdate or TypeMonitor) that check that a given -// value's type falls within a set of primitive types. - -class TypeCheckPrimitiveSetStub : public ICStub { - friend class ICStubSpace; - - protected: - inline static uint16_t TypeToFlag(ValueType type) { - return 1u << static_cast(type); - } - - inline static uint16_t ValidFlags() { - return ((TypeToFlag(ValueType::Object) << 1) - 1) & - ~(TypeToFlag(ValueType::Magic) | - TypeToFlag(ValueType::PrivateGCThing)); - } - - TypeCheckPrimitiveSetStub(Kind kind, JitCode* stubCode, uint16_t flags) - : ICStub(kind, stubCode) { - MOZ_ASSERT(kind == TypeMonitor_PrimitiveSet || - kind == TypeUpdate_PrimitiveSet); - MOZ_ASSERT(flags && !(flags & ~ValidFlags())); - extra_ = flags; - } - - TypeCheckPrimitiveSetStub* updateTypesAndCode(uint16_t flags, JitCode* code) { - MOZ_ASSERT(flags && !(flags & ~ValidFlags())); - if (!code) { - return nullptr; - } - extra_ = flags; - updateCode(code); - return this; - } - - public: - uint16_t typeFlags() const { return extra_; } - - bool containsType(ValueType type) const { - MOZ_ASSERT(type != ValueType::Magic && type != ValueType::PrivateGCThing); - return extra_ & TypeToFlag(type); - } - - ICTypeMonitor_PrimitiveSet* toMonitorStub() { - return toTypeMonitor_PrimitiveSet(); - } - - ICTypeUpdate_PrimitiveSet* toUpdateStub() { - return toTypeUpdate_PrimitiveSet(); - } - - class Compiler : public ICStubCompiler { - protected: - TypeCheckPrimitiveSetStub* existingStub_; - uint16_t flags_; - - virtual int32_t getKey() const override { - return static_cast(kind) | (static_cast(flags_) << 16); - } - - public: - Compiler(JSContext* cx, Kind kind, TypeCheckPrimitiveSetStub* existingStub, - ValueType type) - : ICStubCompiler(cx, kind), - existingStub_(existingStub), - flags_((existingStub ? existingStub->typeFlags() : 0) | - TypeToFlag(type)) { - MOZ_ASSERT_IF(existingStub_, flags_ != existingStub_->typeFlags()); - } - - TypeCheckPrimitiveSetStub* updateStub() { - MOZ_ASSERT(existingStub_); - return existingStub_->updateTypesAndCode(flags_, getStubCode()); - } - }; -}; - -// TypeMonitor - -// The TypeMonitor fallback stub is not always a regular fallback stub. When -// used for monitoring the values pushed by a bytecode it doesn't hold a -// pointer to the IC entry, but rather back to the main fallback stub for the -// IC (from which a pointer to the IC entry can be retrieved). When monitoring -// the types of 'this', arguments or other values with no associated IC, there -// is no main fallback stub, and the IC entry is referenced directly. -class ICTypeMonitor_Fallback : public ICStub { - friend class ICStubSpace; - - static const uint32_t MAX_OPTIMIZED_STUBS = 8; - - // Pointer to the main fallback stub for the IC or to the main IC entry, - // depending on hasFallbackStub. - union { - ICMonitoredFallbackStub* mainFallbackStub_; - ICEntry* icEntry_; - }; - - // Pointer to the first monitor stub. - ICStub* firstMonitorStub_; - - // Address of the last monitor stub's field pointing to this - // fallback monitor stub. This will get updated when new - // monitor stubs are created and added. - ICStub** lastMonitorStubPtrAddr_; - - // Count of optimized type monitor stubs in this chain. - uint32_t numOptimizedMonitorStubs_ : 7; - - // Whether this has a fallback stub referring to the IC entry. - bool hasFallbackStub_ : 1; - - // Index of 'this' or argument which is being monitored, or BYTECODE_INDEX - // if this is monitoring the types of values pushed at some bytecode. - uint32_t argumentIndex_ : 23; - - static const uint32_t BYTECODE_INDEX = (1 << 23) - 1; - - ICTypeMonitor_Fallback(TrampolinePtr stubCode, - ICMonitoredFallbackStub* mainFallbackStub, - uint32_t argumentIndex = BYTECODE_INDEX) - : ICStub(ICStub::TypeMonitor_Fallback, stubCode.value), - mainFallbackStub_(mainFallbackStub), - firstMonitorStub_(thisFromCtor()), - lastMonitorStubPtrAddr_(nullptr), - numOptimizedMonitorStubs_(0), - hasFallbackStub_(mainFallbackStub != nullptr), - argumentIndex_(argumentIndex) {} - - ICTypeMonitor_Fallback* thisFromCtor() { return this; } - - void addOptimizedMonitorStub(ICStub* stub) { - stub->setNext(this); - - MOZ_ASSERT((lastMonitorStubPtrAddr_ != nullptr) == - (numOptimizedMonitorStubs_ || !hasFallbackStub_)); - - if (lastMonitorStubPtrAddr_) { - *lastMonitorStubPtrAddr_ = stub; - } - - if (numOptimizedMonitorStubs_ == 0) { - MOZ_ASSERT(firstMonitorStub_ == this); - firstMonitorStub_ = stub; - } else { - MOZ_ASSERT(firstMonitorStub_ != nullptr); - } - - lastMonitorStubPtrAddr_ = stub->addressOfNext(); - numOptimizedMonitorStubs_++; - } - - public: - bool hasStub(ICStub::Kind kind) { - ICStub* stub = firstMonitorStub_; - do { - if (stub->kind() == kind) { - return true; - } - - stub = stub->next(); - } while (stub); - - return false; - } - - inline ICFallbackStub* mainFallbackStub() const { - MOZ_ASSERT(hasFallbackStub_); - return mainFallbackStub_; - } - - inline ICEntry* icEntry() const { - return hasFallbackStub_ ? mainFallbackStub()->icEntry() : icEntry_; - } - - inline ICStub* firstMonitorStub() const { return firstMonitorStub_; } - - static inline size_t offsetOfFirstMonitorStub() { - return offsetof(ICTypeMonitor_Fallback, firstMonitorStub_); - } - - inline uint32_t numOptimizedMonitorStubs() const { - return numOptimizedMonitorStubs_; - } - - inline bool monitorsThis() const { return argumentIndex_ == 0; } - - inline bool monitorsArgument(uint32_t* pargument) const { - if (argumentIndex_ > 0 && argumentIndex_ < BYTECODE_INDEX) { - *pargument = argumentIndex_ - 1; - return true; - } - return false; - } - - inline bool monitorsBytecode() const { - return argumentIndex_ == BYTECODE_INDEX; - } - - // Fixup the IC entry as for a normal fallback stub, for this/arguments. - void fixupICEntry(ICEntry* icEntry) { - MOZ_ASSERT(!hasFallbackStub_); - MOZ_ASSERT(icEntry_ == nullptr); - MOZ_ASSERT(lastMonitorStubPtrAddr_ == nullptr); - icEntry_ = icEntry; - lastMonitorStubPtrAddr_ = icEntry_->addressOfFirstStub(); - } - - // Create a new monitor stub for the type of the given value, and - // add it to this chain. - MOZ_MUST_USE bool addMonitorStubForValue(JSContext* cx, BaselineFrame* frame, - StackTypeSet* types, - HandleValue val); - - void resetMonitorStubChain(Zone* zone); -}; - -class ICTypeMonitor_PrimitiveSet : public TypeCheckPrimitiveSetStub { - friend class ICStubSpace; - - ICTypeMonitor_PrimitiveSet(JitCode* stubCode, uint16_t flags) - : TypeCheckPrimitiveSetStub(TypeMonitor_PrimitiveSet, stubCode, flags) {} - - public: - class Compiler : public TypeCheckPrimitiveSetStub::Compiler { - protected: - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override; - - public: - Compiler(JSContext* cx, ICTypeMonitor_PrimitiveSet* existingStub, - ValueType type) - : TypeCheckPrimitiveSetStub::Compiler(cx, TypeMonitor_PrimitiveSet, - existingStub, type) {} - - ICTypeMonitor_PrimitiveSet* updateStub() { - TypeCheckPrimitiveSetStub* stub = - this->TypeCheckPrimitiveSetStub::Compiler::updateStub(); - if (!stub) { - return nullptr; - } - return stub->toMonitorStub(); - } - - ICTypeMonitor_PrimitiveSet* getStub(ICStubSpace* space) override { - MOZ_ASSERT(!existingStub_); - return newStub(space, getStubCode(), flags_); - } - }; -}; - -class ICTypeMonitor_SingleObject : public ICStub { - friend class ICStubSpace; - - GCPtrObject obj_; - - ICTypeMonitor_SingleObject(JitCode* stubCode, JSObject* obj); - - public: - GCPtrObject& object() { return obj_; } - - static size_t offsetOfObject() { - return offsetof(ICTypeMonitor_SingleObject, obj_); - } - - class Compiler : public ICStubCompiler { - protected: - HandleObject obj_; - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override; - - public: - Compiler(JSContext* cx, HandleObject obj) - : ICStubCompiler(cx, TypeMonitor_SingleObject), obj_(obj) {} - - ICTypeMonitor_SingleObject* getStub(ICStubSpace* space) override { - return newStub(space, getStubCode(), obj_); - } - }; -}; - -class ICTypeMonitor_ObjectGroup : public ICStub { - friend class ICStubSpace; - - GCPtrObjectGroup group_; - - ICTypeMonitor_ObjectGroup(JitCode* stubCode, ObjectGroup* group); - - public: - GCPtrObjectGroup& group() { return group_; } - - static size_t offsetOfGroup() { - return offsetof(ICTypeMonitor_ObjectGroup, group_); - } - - class Compiler : public ICStubCompiler { - protected: - HandleObjectGroup group_; - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override; - - public: - Compiler(JSContext* cx, HandleObjectGroup group) - : ICStubCompiler(cx, TypeMonitor_ObjectGroup), group_(group) {} - - ICTypeMonitor_ObjectGroup* getStub(ICStubSpace* space) override { - return newStub(space, getStubCode(), group_); - } - }; -}; - -class ICTypeMonitor_AnyValue : public ICStub { - friend class ICStubSpace; - - explicit ICTypeMonitor_AnyValue(JitCode* stubCode) - : ICStub(TypeMonitor_AnyValue, stubCode) {} - - public: - class Compiler : public ICStubCompiler { - protected: - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override; - - public: - explicit Compiler(JSContext* cx) - : ICStubCompiler(cx, TypeMonitor_AnyValue) {} - - ICTypeMonitor_AnyValue* getStub(ICStubSpace* space) override { - return newStub(space, getStubCode()); - } - }; -}; - -// TypeUpdate - -// The TypeUpdate fallback is not a regular fallback, since it just -// forwards to a different entry point in the main fallback stub. -class ICTypeUpdate_Fallback : public ICStub { - friend class ICStubSpace; - - explicit ICTypeUpdate_Fallback(TrampolinePtr stubCode) - : ICStub(ICStub::TypeUpdate_Fallback, stubCode.value) {} -}; - -class ICTypeUpdate_PrimitiveSet : public TypeCheckPrimitiveSetStub { - friend class ICStubSpace; - - ICTypeUpdate_PrimitiveSet(JitCode* stubCode, uint16_t flags) - : TypeCheckPrimitiveSetStub(TypeUpdate_PrimitiveSet, stubCode, flags) {} - - public: - class Compiler : public TypeCheckPrimitiveSetStub::Compiler { - protected: - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override; - - public: - Compiler(JSContext* cx, ICTypeUpdate_PrimitiveSet* existingStub, - ValueType type) - : TypeCheckPrimitiveSetStub::Compiler(cx, TypeUpdate_PrimitiveSet, - existingStub, type) {} - - ICTypeUpdate_PrimitiveSet* updateStub() { - TypeCheckPrimitiveSetStub* stub = - this->TypeCheckPrimitiveSetStub::Compiler::updateStub(); - if (!stub) { - return nullptr; - } - return stub->toUpdateStub(); - } - - ICTypeUpdate_PrimitiveSet* getStub(ICStubSpace* space) override { - MOZ_ASSERT(!existingStub_); - return newStub(space, getStubCode(), flags_); - } - }; -}; - -// Type update stub to handle a singleton object. -class ICTypeUpdate_SingleObject : public ICStub { - friend class ICStubSpace; - - GCPtrObject obj_; - - ICTypeUpdate_SingleObject(JitCode* stubCode, JSObject* obj); - - public: - GCPtrObject& object() { return obj_; } - - static size_t offsetOfObject() { - return offsetof(ICTypeUpdate_SingleObject, obj_); - } - - class Compiler : public ICStubCompiler { - protected: - HandleObject obj_; - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override; - - public: - Compiler(JSContext* cx, HandleObject obj) - : ICStubCompiler(cx, TypeUpdate_SingleObject), obj_(obj) {} - - ICTypeUpdate_SingleObject* getStub(ICStubSpace* space) override { - return newStub(space, getStubCode(), obj_); - } - }; -}; - -// Type update stub to handle a single ObjectGroup. -class ICTypeUpdate_ObjectGroup : public ICStub { - friend class ICStubSpace; - - GCPtrObjectGroup group_; - - ICTypeUpdate_ObjectGroup(JitCode* stubCode, ObjectGroup* group); - - public: - GCPtrObjectGroup& group() { return group_; } - - static size_t offsetOfGroup() { - return offsetof(ICTypeUpdate_ObjectGroup, group_); - } - - class Compiler : public ICStubCompiler { - protected: - HandleObjectGroup group_; - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override; - - public: - Compiler(JSContext* cx, HandleObjectGroup group) - : ICStubCompiler(cx, TypeUpdate_ObjectGroup), group_(group) {} - - ICTypeUpdate_ObjectGroup* getStub(ICStubSpace* space) override { - return newStub(space, getStubCode(), group_); - } - }; -}; - -class ICTypeUpdate_AnyValue : public ICStub { - friend class ICStubSpace; - - explicit ICTypeUpdate_AnyValue(JitCode* stubCode) - : ICStub(TypeUpdate_AnyValue, stubCode) {} - - public: - class Compiler : public ICStubCompiler { - protected: - MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm) override; - - public: - explicit Compiler(JSContext* cx) - : ICStubCompiler(cx, TypeUpdate_AnyValue) {} - - ICTypeUpdate_AnyValue* getStub(ICStubSpace* space) override { - return newStub(space, getStubCode()); - } - }; }; // ToBool @@ -1540,11 +759,11 @@ // JSOp::GetElem // JSOp::GetElemSuper -class ICGetElem_Fallback : public ICMonitoredFallbackStub { +class ICGetElem_Fallback : public ICFallbackStub { friend class ICStubSpace; explicit ICGetElem_Fallback(TrampolinePtr stubCode) - : ICMonitoredFallbackStub(ICStub::GetElem_Fallback, stubCode) {} + : ICFallbackStub(ICStub::GetElem_Fallback, stubCode) {} static const uint16_t EXTRA_NEGATIVE_INDEX = 0x1; static const uint16_t SAW_NON_INTEGER_INDEX_BIT = 0x2; @@ -1608,11 +827,11 @@ // GetName // JSOp::GetName // JSOp::GetGName -class ICGetName_Fallback : public ICMonitoredFallbackStub { +class ICGetName_Fallback : public ICFallbackStub { friend class ICStubSpace; explicit ICGetName_Fallback(TrampolinePtr stubCode) - : ICMonitoredFallbackStub(ICStub::GetName_Fallback, stubCode) {} + : ICFallbackStub(ICStub::GetName_Fallback, stubCode) {} }; // BindName @@ -1626,22 +845,22 @@ // GetIntrinsic // JSOp::GetIntrinsic -class ICGetIntrinsic_Fallback : public ICMonitoredFallbackStub { +class ICGetIntrinsic_Fallback : public ICFallbackStub { friend class ICStubSpace; explicit ICGetIntrinsic_Fallback(TrampolinePtr stubCode) - : ICMonitoredFallbackStub(ICStub::GetIntrinsic_Fallback, stubCode) {} + : ICFallbackStub(ICStub::GetIntrinsic_Fallback, stubCode) {} }; // GetProp // JSOp::GetProp // JSOp::GetPropSuper -class ICGetProp_Fallback : public ICMonitoredFallbackStub { +class ICGetProp_Fallback : public ICFallbackStub { friend class ICStubSpace; explicit ICGetProp_Fallback(TrampolinePtr stubCode) - : ICMonitoredFallbackStub(ICStub::GetProp_Fallback, stubCode) {} + : ICFallbackStub(ICStub::GetProp_Fallback, stubCode) {} public: // Whether this bytecode op called a getter. This is used by IonBuilder. @@ -1683,7 +902,7 @@ // JSOp::SpreadEval // JSOp::SpreadStrictEval -class ICCall_Fallback : public ICMonitoredFallbackStub { +class ICCall_Fallback : public ICFallbackStub { friend class ICStubSpace; public: @@ -1691,7 +910,7 @@ private: explicit ICCall_Fallback(TrampolinePtr stubCode) - : ICMonitoredFallbackStub(ICStub::Call_Fallback, stubCode) {} + : ICFallbackStub(ICStub::Call_Fallback, stubCode) {} }; // IC for constructing an iterator from an input value. @@ -1857,16 +1076,6 @@ struct IonOsrTempData; -extern MOZ_MUST_USE bool TypeMonitorResult(JSContext* cx, - ICMonitoredFallbackStub* stub, - BaselineFrame* frame, - HandleScript script, jsbytecode* pc, - HandleValue val); - -extern bool DoTypeUpdateFallback(JSContext* cx, BaselineFrame* frame, - ICCacheIR_Updated* stub, HandleValue objval, - HandleValue value); - extern bool DoCallFallback(JSContext* cx, BaselineFrame* frame, ICCall_Fallback* stub, uint32_t argc, Value* vp, MutableHandleValue res); @@ -1875,10 +1084,6 @@ ICCall_Fallback* stub, Value* vp, MutableHandleValue res); -extern bool DoTypeMonitorFallback(JSContext* cx, BaselineFrame* frame, - ICTypeMonitor_Fallback* stub, - HandleValue value, MutableHandleValue res); - extern bool DoToBoolFallback(JSContext* cx, BaselineFrame* frame, ICToBool_Fallback* stub, HandleValue arg, MutableHandleValue ret); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineICList.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineICList.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineICList.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineICList.h 2020-11-17 19:31:31.000000000 +0000 @@ -13,18 +13,6 @@ // List of Baseline IC stub kinds. The stub kind determines the structure of the // ICStub data. #define IC_BASELINE_STUB_KIND_LIST(_) \ - _(TypeMonitor_Fallback) \ - _(TypeMonitor_SingleObject) \ - _(TypeMonitor_ObjectGroup) \ - _(TypeMonitor_PrimitiveSet) \ - _(TypeMonitor_AnyValue) \ - \ - _(TypeUpdate_Fallback) \ - _(TypeUpdate_SingleObject) \ - _(TypeUpdate_ObjectGroup) \ - _(TypeUpdate_PrimitiveSet) \ - _(TypeUpdate_AnyValue) \ - \ _(NewArray_Fallback) \ _(NewObject_Fallback) \ \ @@ -67,9 +55,7 @@ \ _(GetProp_Fallback) \ \ - _(CacheIR_Regular) \ - _(CacheIR_Monitored) \ - _(CacheIR_Updated) + _(CacheIR_Regular) // List of fallback trampolines. Each of these fallback trampolines exists as // part of the JitRuntime. Note that some fallback stubs in previous list may @@ -77,8 +63,6 @@ // constructing/spread variants here with different calling conventions needing // different trampolines. #define IC_BASELINE_FALLBACK_CODE_KIND_LIST(_) \ - _(TypeMonitor) \ - _(TypeUpdate) \ _(NewArray) \ _(NewObject) \ _(ToBool) \ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineInspector.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineInspector.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineInspector.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineInspector.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,1614 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "jit/BaselineInspector.h" - -#include "mozilla/Array.h" -#include "mozilla/DebugOnly.h" - -#include "jit/BaselineIC.h" -#include "jit/CacheIRCompiler.h" - -#include "vm/EnvironmentObject-inl.h" -#include "vm/JSScript-inl.h" -#include "vm/ObjectGroup-inl.h" -#include "vm/ReceiverGuard-inl.h" - -using namespace js; -using namespace js::jit; - -using mozilla::DebugOnly; - -bool SetElemICInspector::sawOOBDenseWrite() const { - if (!icEntry_) { - return false; - } - - // Check for a write hole bit on the SetElem_Fallback stub. - ICStub* stub = icEntry_->fallbackStub(); - if (stub->isSetElem_Fallback()) { - return stub->toSetElem_Fallback()->hasDenseAdd(); - } - - return false; -} - -bool SetElemICInspector::sawOOBTypedArrayWrite() const { - if (!icEntry_) { - return false; - } - - ICStub* stub = icEntry_->fallbackStub(); - if (stub->isSetElem_Fallback()) { - return stub->toSetElem_Fallback()->hasTypedArrayOOB(); - } - - return false; -} - -template -static bool VectorAppendNoDuplicate(S& list, T value) { - for (size_t i = 0; i < list.length(); i++) { - if (list[i] == value) { - return true; - } - } - return list.append(value); -} - -static bool AddReceiver(const ReceiverGuard& receiver, - BaselineInspector::ReceiverVector& receivers) { - return VectorAppendNoDuplicate(receivers, receiver); -} - -static bool GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, - ReceiverGuard* receiver) { - // We match: - // - // GuardToObject 0 - // GuardShape 0 - // LoadFixedSlotResult 0 or LoadDynamicSlotResult 0 - - *receiver = ReceiverGuard(); - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId objId = ObjOperandId(0); - if (!reader.matchOp(CacheOp::GuardToObject, objId)) { - return false; - } - - if (reader.matchOp(CacheOp::GuardShape, objId)) { - receiver->setShape( - stub->stubInfo()->getStubField(stub, reader.stubOffset())); - return reader.matchOpEither(CacheOp::LoadFixedSlotResult, - CacheOp::LoadDynamicSlotResult); - } - - return false; -} - -static bool GetCacheIRReceiverForNativeSetSlot(ICCacheIR_Updated* stub, - ReceiverGuard* receiver) { - // We match: - // - // GuardToObject 0 - // GuardGroup 0 - // GuardShape 0 - // StoreFixedSlot 0 or StoreDynamicSlot 0 - *receiver = ReceiverGuard(); - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId objId = ObjOperandId(0); - if (!reader.matchOp(CacheOp::GuardToObject, objId)) { - return false; - } - - if (!reader.matchOp(CacheOp::GuardGroup, objId)) { - return false; - } - ObjectGroup* group = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::GuardShape, objId)) { - return false; - } - Shape* shape = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOpEither(CacheOp::StoreFixedSlot, - CacheOp::StoreDynamicSlot)) { - return false; - } - - *receiver = ReceiverGuard(group, shape); - return true; -} - -JitScript* BaselineInspector::jitScript() const { return script->jitScript(); } - -ICEntry& BaselineInspector::icEntryFromPC(jsbytecode* pc) { - ICEntry* entry = maybeICEntryFromPC(pc); - MOZ_ASSERT(entry); - return *entry; -} - -ICEntry* BaselineInspector::maybeICEntryFromPC(jsbytecode* pc) { - MOZ_ASSERT(isValidPC(pc)); - ICEntry* ent = jitScript()->maybeICEntryFromPCOffset(script->pcToOffset(pc), - prevLookedUpEntry); - if (!ent) { - return nullptr; - } - - MOZ_ASSERT(!ent->isForPrologue()); - prevLookedUpEntry = ent; - return ent; -} - -bool BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, - ReceiverVector& receivers) { - // Return a list of the receivers seen by the baseline IC for the current - // op. Empty lists indicate no receivers are known, or there was an - // uncacheable access. - MOZ_ASSERT(receivers.empty()); - - MOZ_ASSERT(isValidPC(pc)); - const ICEntry& entry = icEntryFromPC(pc); - - ICStub* stub = entry.firstStub(); - while (stub->next()) { - ReceiverGuard receiver; - if (stub->isCacheIR_Monitored()) { - if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), - &receiver)) { - receivers.clear(); - return true; - } - } else if (stub->isCacheIR_Updated()) { - if (!GetCacheIRReceiverForNativeSetSlot(stub->toCacheIR_Updated(), - &receiver)) { - receivers.clear(); - return true; - } - } else { - receivers.clear(); - return true; - } - - if (!AddReceiver(receiver, receivers)) { - return false; - } - - stub = stub->next(); - } - - if (stub->toFallbackStub()->state().hasFailures()) { - receivers.clear(); - } - - // Don't inline if there are more than 5 receivers. - if (receivers.length() > 5) { - receivers.clear(); - } - - return true; -} - -ICStub* BaselineInspector::monomorphicStub(jsbytecode* pc) { - // IonBuilder::analyzeNewLoopTypes may call this (via expectedResultType - // below) on code that's unreachable, according to BytecodeAnalysis. Use - // maybeICEntryFromPC to handle this. - const ICEntry* entry = maybeICEntryFromPC(pc); - if (!entry) { - return nullptr; - } - - ICStub* stub = entry->firstStub(); - ICStub* next = stub->next(); - - if (!next || !next->isFallback()) { - return nullptr; - } - - return stub; -} - -bool BaselineInspector::dimorphicStub(jsbytecode* pc, ICStub** pfirst, - ICStub** psecond) { - const ICEntry& entry = icEntryFromPC(pc); - - ICStub* stub = entry.firstStub(); - ICStub* next = stub->next(); - ICStub* after = next ? next->next() : nullptr; - - if (!after || !after->isFallback()) { - return false; - } - - *pfirst = stub; - *psecond = next; - return true; -} - -// Process the type guards in the stub in order to reveal the -// underlying operation. -static void SkipBinaryGuards(CacheIRReader& reader, bool* sawStringOperand) { - while (true) { - // Two skip opcodes - if (reader.matchOp(CacheOp::GuardNonDoubleType) || - reader.matchOp(CacheOp::TruncateDoubleToUInt32) || - reader.matchOp(CacheOp::GuardBooleanToInt32) || - reader.matchOp(CacheOp::LoadInt32Constant)) { - reader.skip(); // Skip over operandId - reader.skip(); // Skip over result/type. - continue; - } - if (reader.matchOp(CacheOp::GuardStringToNumber) || - reader.matchOp(CacheOp::GuardStringToInt32)) { - if (sawStringOperand) { - *sawStringOperand = true; - } - reader.skip(); // Skip over operandId - reader.skip(); // Skip over result. - continue; - } - - // One skip - if (reader.matchOp(CacheOp::GuardToInt32) || - reader.matchOp(CacheOp::GuardIsNumber) || - reader.matchOp(CacheOp::GuardToString) || - reader.matchOp(CacheOp::GuardToObject) || - reader.matchOp(CacheOp::GuardToBigInt) || - reader.matchOp(CacheOp::GuardToBoolean) || - reader.matchOp(CacheOp::GuardIsNullOrUndefined)) { - reader.skip(); // Skip over operandId - continue; - } - return; - } -} - -static MIRType ParseCacheIRStub(ICStub* stub, - bool* sawStringOperand = nullptr) { - ICCacheIR_Regular* cacheirStub = stub->toCacheIR_Regular(); - CacheIRReader reader(cacheirStub->stubInfo()); - SkipBinaryGuards(reader, sawStringOperand); - switch (reader.readOp()) { - case CacheOp::LoadUndefinedResult: - return MIRType::Undefined; - case CacheOp::LoadBooleanResult: - return MIRType::Boolean; - case CacheOp::LoadStringResult: - case CacheOp::CallStringConcatResult: - case CacheOp::CallStringObjectConcatResult: - case CacheOp::CallInt32ToString: - case CacheOp::BooleanToString: - case CacheOp::CallNumberToString: - return MIRType::String; - case CacheOp::LoadDoubleResult: - case CacheOp::DoubleAddResult: - case CacheOp::DoubleSubResult: - case CacheOp::DoubleMulResult: - case CacheOp::DoubleDivResult: - case CacheOp::DoubleModResult: - case CacheOp::DoublePowResult: - case CacheOp::DoubleNegationResult: - case CacheOp::DoubleIncResult: - case CacheOp::DoubleDecResult: - return MIRType::Double; - case CacheOp::LoadInt32Result: - case CacheOp::Int32AddResult: - case CacheOp::Int32SubResult: - case CacheOp::Int32MulResult: - case CacheOp::Int32DivResult: - case CacheOp::Int32ModResult: - case CacheOp::Int32PowResult: - case CacheOp::Int32BitOrResult: - case CacheOp::Int32BitXorResult: - case CacheOp::Int32BitAndResult: - case CacheOp::Int32LeftShiftResult: - case CacheOp::Int32RightShiftResult: - case CacheOp::Int32NotResult: - case CacheOp::Int32NegationResult: - case CacheOp::Int32IncResult: - case CacheOp::Int32DecResult: - return MIRType::Int32; - // Int32URightShiftResult may return a double under some - // circumstances. - case CacheOp::Int32URightShiftResult: - reader.skip(); // Skip over lhs - reader.skip(); // Skip over rhs - return reader.readByte() == 0 ? MIRType::Int32 : MIRType::Double; - case CacheOp::BigIntAddResult: - case CacheOp::BigIntSubResult: - case CacheOp::BigIntMulResult: - case CacheOp::BigIntDivResult: - case CacheOp::BigIntModResult: - case CacheOp::BigIntPowResult: - case CacheOp::BigIntBitOrResult: - case CacheOp::BigIntBitXorResult: - case CacheOp::BigIntBitAndResult: - case CacheOp::BigIntLeftShiftResult: - case CacheOp::BigIntRightShiftResult: - case CacheOp::BigIntNotResult: - case CacheOp::BigIntNegationResult: - case CacheOp::BigIntIncResult: - case CacheOp::BigIntDecResult: - return MIRType::BigInt; - case CacheOp::LoadValueResult: - return MIRType::Value; - default: - MOZ_CRASH("Unknown op"); - return MIRType::None; - } -} - -MIRType BaselineInspector::expectedResultType(jsbytecode* pc) { - // Look at the IC entries for this op to guess what type it will produce, - // returning MIRType::None otherwise. Note that IonBuilder may call this - // for bytecode ops that are unreachable and don't have a Baseline IC, see - // comment in monomorphicStub. - - ICStub* stub = monomorphicStub(pc); - if (!stub) { - return MIRType::None; - } - - switch (stub->kind()) { - case ICStub::CacheIR_Regular: - return ParseCacheIRStub(stub); - default: - return MIRType::None; - } -} - -// Return the MIRtype corresponding to the guard the reader is pointing -// to, and ensure that afterwards the reader is pointing to the next op -// (consume operands). -// -// An expected parameter is provided to allow GuardType to check we read -// the guard from the expected operand in debug builds. -static bool GuardType(CacheIRReader& reader, - mozilla::Array& guardType) { - CacheOp op = reader.readOp(); - uint8_t guardOperand = reader.readByte(); - - // We only have two entries for guard types. - if (guardOperand > 1) { - return false; - } - - // Already assigned this guard a type, fail. - if (guardType[guardOperand] != MIRType::None) { - return false; - } - - switch (op) { - // 0 Skip cases - case CacheOp::GuardToString: - guardType[guardOperand] = MIRType::String; - break; - case CacheOp::GuardToSymbol: - guardType[guardOperand] = MIRType::Symbol; - break; - case CacheOp::GuardToBigInt: - guardType[guardOperand] = MIRType::BigInt; - break; - case CacheOp::GuardToBoolean: - guardType[guardOperand] = MIRType::Boolean; - break; - case CacheOp::GuardToInt32: - guardType[guardOperand] = MIRType::Int32; - break; - case CacheOp::GuardIsNumber: - guardType[guardOperand] = MIRType::Double; - break; - case CacheOp::GuardIsUndefined: - guardType[guardOperand] = MIRType::Undefined; - break; - // 1 skip - case CacheOp::GuardBooleanToInt32: - guardType[guardOperand] = MIRType::Boolean; - // Skip over result - reader.skip(); - break; - // Unknown op -- - default: - return false; - } - return true; -} - -// This code works for all Compare ICs where the pattern is -// -// -// -// -// -// in other cases (like StrictlyDifferentTypes) it will just -// return CompareUnknown -static MCompare::CompareType ParseCacheIRStubForCompareType( - ICCacheIR_Regular* stub) { - CacheIRReader reader(stub->stubInfo()); - - // Two element array to allow parsing the guards - // in whichever order they appear. - mozilla::Array guards = {MIRType::None, MIRType::None}; - - // Parse out two guards - if (!GuardType(reader, guards)) { - return MCompare::Compare_Unknown; - } - if (!GuardType(reader, guards)) { - return MCompare::Compare_Unknown; - } - - // The lhs and rhs ids are asserted in - // CompareIRGenerator::tryAttachStub. - MIRType lhs_guard = guards[0]; - MIRType rhs_guard = guards[1]; - - if (lhs_guard == rhs_guard) { - if (lhs_guard == MIRType::Int32) { - return MCompare::Compare_Int32; - } - if (lhs_guard == MIRType::Double) { - return MCompare::Compare_Double; - } - return MCompare::Compare_Unknown; - } - - if ((lhs_guard == MIRType::Int32 && rhs_guard == MIRType::Boolean) || - (lhs_guard == MIRType::Boolean && rhs_guard == MIRType::Int32)) { - // RHS is converting - if (rhs_guard == MIRType::Boolean) { - return MCompare::Compare_Int32MaybeCoerceRHS; - } - - return MCompare::Compare_Int32MaybeCoerceLHS; - } - - if ((lhs_guard == MIRType::Double && rhs_guard == MIRType::Undefined) || - (lhs_guard == MIRType::Undefined && rhs_guard == MIRType::Double)) { - // RHS is converting - if (rhs_guard == MIRType::Undefined) { - return MCompare::Compare_DoubleMaybeCoerceRHS; - } - - return MCompare::Compare_DoubleMaybeCoerceLHS; - } - - return MCompare::Compare_Unknown; -} - -static bool CoercingCompare(MCompare::CompareType type) { - // Prefer the coercing types if they exist, otherwise just use first's type. - if (type == MCompare::Compare_DoubleMaybeCoerceLHS || - type == MCompare::Compare_DoubleMaybeCoerceRHS || - type == MCompare::Compare_Int32MaybeCoerceLHS || - type == MCompare::Compare_Int32MaybeCoerceRHS) { - return true; - } - return false; -} - -static MCompare::CompareType CompatibleType(MCompare::CompareType first, - MCompare::CompareType second) { - // Caller should have dealt with this case. - MOZ_ASSERT(first != second); - - // Prefer the coercing types if they exist, otherwise, return Double, - // which is the general cover. - if (CoercingCompare(first)) { - return first; - } - - if (CoercingCompare(second)) { - return second; - } - - // At this point we expect a Double/Int32 pair, so we return Double. - MOZ_ASSERT(first == MCompare::Compare_Int32 || - first == MCompare::Compare_Double); - MOZ_ASSERT(second == MCompare::Compare_Int32 || - second == MCompare::Compare_Double); - MOZ_ASSERT(first != second); - - return MCompare::Compare_Double; -} - -MCompare::CompareType BaselineInspector::expectedCompareType(jsbytecode* pc) { - ICStub* first = monomorphicStub(pc); - ICStub* second = nullptr; - if (!first && !dimorphicStub(pc, &first, &second)) { - return MCompare::Compare_Unknown; - } - - if (ICStub* fallback = second ? second->next() : first->next()) { - MOZ_ASSERT(fallback->isFallback()); - if (fallback->toFallbackStub()->state().hasFailures()) { - return MCompare::Compare_Unknown; - } - } - - MCompare::CompareType first_type = - ParseCacheIRStubForCompareType(first->toCacheIR_Regular()); - if (!second) { - return first_type; - } - - MCompare::CompareType second_type = - ParseCacheIRStubForCompareType(second->toCacheIR_Regular()); - - if (first_type == MCompare::Compare_Unknown || - second_type == MCompare::Compare_Unknown) { - return MCompare::Compare_Unknown; - } - - if (first_type == second_type) { - return first_type; - } - - return CompatibleType(first_type, second_type); -} - -static bool TryToSpecializeBinaryArithOp(ICStub** stubs, uint32_t nstubs, - MIRType* result) { - DebugOnly sawInt32 = false; - bool sawDouble = false; - bool sawOther = false; - bool sawStringOperand = false; - - for (uint32_t i = 0; i < nstubs; i++) { - switch (stubs[i]->kind()) { - case ICStub::CacheIR_Regular: - switch (ParseCacheIRStub(stubs[i], &sawStringOperand)) { - case MIRType::Double: - sawDouble = true; - break; - case MIRType::Int32: - sawInt32 = true; - break; - default: - sawOther = true; - break; - } - break; - default: - sawOther = true; - break; - } - } - - if (sawOther) { - return false; - } - - // Ion doesn't support string operands for binary arithmetic operations, so - // return false when we did see one. We don't test for strings in Ion itself, - // because Ion generally doesn't have sufficient type information when it - // falls back to the baseline inspector. - if (sawStringOperand) { - return false; - } - - if (sawDouble) { - *result = MIRType::Double; - return true; - } - - MOZ_ASSERT(sawInt32); - *result = MIRType::Int32; - return true; -} - -MIRType BaselineInspector::expectedBinaryArithSpecialization(jsbytecode* pc) { - MIRType result; - ICStub* stubs[2]; - - const ICEntry& entry = icEntryFromPC(pc); - ICFallbackStub* stub = entry.fallbackStub(); - if (stub->state().hasFailures()) { - return MIRType::None; - } - - stubs[0] = monomorphicStub(pc); - if (stubs[0]) { - if (TryToSpecializeBinaryArithOp(stubs, 1, &result)) { - return result; - } - } - - if (dimorphicStub(pc, &stubs[0], &stubs[1])) { - if (TryToSpecializeBinaryArithOp(stubs, 2, &result)) { - return result; - } - } - - return MIRType::None; -} - -bool BaselineInspector::hasSeenNonIntegerIndex(jsbytecode* pc) { - const ICEntry& entry = icEntryFromPC(pc); - ICStub* stub = entry.fallbackStub(); - - MOZ_ASSERT(stub->isGetElem_Fallback()); - - return stub->toGetElem_Fallback()->sawNonIntegerIndex(); -} - -bool BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode* pc) { - const ICEntry& entry = icEntryFromPC(pc); - ICStub* stub = entry.fallbackStub(); - - if (stub->isGetElem_Fallback()) { - return stub->toGetElem_Fallback()->hasNegativeIndex(); - } - return false; -} - -bool BaselineInspector::hasSeenAccessedGetter(jsbytecode* pc) { - const ICEntry& entry = icEntryFromPC(pc); - ICStub* stub = entry.fallbackStub(); - - if (stub->isGetProp_Fallback()) { - return stub->toGetProp_Fallback()->hasAccessedGetter(); - } - return false; -} - -bool BaselineInspector::hasSeenDoubleResult(jsbytecode* pc) { - const ICEntry& entry = icEntryFromPC(pc); - ICStub* stub = entry.fallbackStub(); - - MOZ_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback()); - - if (stub->isUnaryArith_Fallback()) { - return stub->toUnaryArith_Fallback()->sawDoubleResult(); - } - return stub->toBinaryArith_Fallback()->sawDoubleResult(); -} - -static bool MaybeArgumentReader(ICStub* stub, CacheOp targetOp, - mozilla::Maybe& argReader) { - MOZ_ASSERT(ICStub::IsCacheIRKind(stub->kind())); - - CacheIRReader stubReader(stub->cacheIRStubInfo()); - while (stubReader.more()) { - CacheOp op = stubReader.readOp(); - uint32_t argLength = CacheIROpInfos[size_t(op)].argLength; - - if (op == targetOp) { - MOZ_ASSERT(argReader.isNothing(), - "Multiple instances of an op are not currently supported"); - const uint8_t* argStart = stubReader.currentPosition(); - argReader.emplace(argStart, argStart + argLength); - } - - // Advance to next opcode. - stubReader.skip(argLength); - } - return argReader.isSome(); -} - -template -JSObject* MaybeTemplateObject(ICStub* stub, MetaTwoByteKind kind, - Filter filter) { - const CacheIRStubInfo* stubInfo = stub->cacheIRStubInfo(); - mozilla::Maybe argReader; - if (!MaybeArgumentReader(stub, CacheOp::MetaTwoByte, argReader) || - argReader->metaKind() != kind || - !filter(*argReader, stubInfo)) { - return nullptr; - } - return stubInfo->getStubField(stub, argReader->stubOffset()); -} - -JSObject* BaselineInspector::getTemplateObject(jsbytecode* pc) { - const ICEntry& entry = icEntryFromPC(pc); - for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { - switch (stub->kind()) { - case ICStub::NewArray_Fallback: - return stub->toNewArray_Fallback()->templateObject(); - case ICStub::NewObject_Fallback: - return stub->toNewObject_Fallback()->templateObject(); - case ICStub::Rest_Fallback: - return stub->toRest_Fallback()->templateObject(); - case ICStub::CacheIR_Regular: - case ICStub::CacheIR_Monitored: - case ICStub::CacheIR_Updated: { - auto filter = [](CacheIRReader& reader, const CacheIRStubInfo* info) { - mozilla::Unused << reader.stubOffset(); // Skip callee - return true; - }; - JSObject* result = MaybeTemplateObject( - stub, MetaTwoByteKind::ScriptedTemplateObject, filter); - if (result) { - return result; - } - } break; - default: - break; - } - } - - return nullptr; -} - -ObjectGroup* BaselineInspector::getTemplateObjectGroup(jsbytecode* pc) { - const ICEntry& entry = icEntryFromPC(pc); - for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { - switch (stub->kind()) { - case ICStub::NewArray_Fallback: - return stub->toNewArray_Fallback()->templateGroup(); - default: - break; - } - } - - return nullptr; -} - -JSFunction* BaselineInspector::getSingleCallee(jsbytecode* pc) { - MOZ_ASSERT(IsConstructPC(pc)); - - const ICEntry& entry = icEntryFromPC(pc); - ICStub* stub = entry.firstStub(); - - if (entry.fallbackStub()->state().hasFailures()) { - return nullptr; - } - - if (stub->next() != entry.fallbackStub()) { - return nullptr; - } - - if (ICStub::IsCacheIRKind(stub->kind())) { - const CacheIRStubInfo* stubInfo = stub->cacheIRStubInfo(); - mozilla::Maybe argReader; - if (!MaybeArgumentReader(stub, CacheOp::MetaTwoByte, argReader) || - argReader->metaKind() != - MetaTwoByteKind::ScriptedTemplateObject) { - return nullptr; - } - // The callee is the first stub field in a ScriptedTemplateObject meta op. - return stubInfo->getStubField(stub, argReader->stubOffset()); - } - return nullptr; -} - -JSObject* BaselineInspector::getTemplateObjectForNative(jsbytecode* pc, - Native native) { - const ICEntry& entry = icEntryFromPC(pc); - for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { - if (ICStub::IsCacheIRKind(stub->kind())) { - auto filter = [stub, native](CacheIRReader& reader, - const CacheIRStubInfo* info) { - JSFunction* callee = - info->getStubField(stub, reader.stubOffset()); - return callee->native() == native; - }; - JSObject* result = MaybeTemplateObject( - stub, MetaTwoByteKind::NativeTemplateObject, filter); - if (result) { - return result; - } - } - } - - return nullptr; -} - -LexicalEnvironmentObject* BaselineInspector::templateNamedLambdaObject() { - JSObject* res = jitScript()->templateEnvironment(); - if (script->bodyScope()->hasEnvironment()) { - res = res->enclosingEnvironment(); - } - MOZ_ASSERT(res); - - return &res->as(); -} - -CallObject* BaselineInspector::templateCallObject() { - JSObject* res = jitScript()->templateEnvironment(); - MOZ_ASSERT(res); - - return &res->as(); -} - -static bool MatchCacheIRReceiverGuard(CacheIRReader& reader, ICStub* stub, - const CacheIRStubInfo* stubInfo, - ObjOperandId objId, - ReceiverGuard* receiver) { - // This matches the CacheIR emitted in TestMatchingReceiver. - // - // Either: - // - // GuardShape objId - // - *receiver = ReceiverGuard(); - - if (reader.matchOp(CacheOp::GuardShape, objId)) { - // The first case. - receiver->setShape( - stubInfo->getStubField(stub, reader.stubOffset())); - return true; - } - return false; -} - -static bool AddCacheIRGlobalGetter(ICCacheIR_Monitored* stub, bool innerized, - JSObject** holder_, Shape** holderShape_, - JSFunction** commonGetter, - Shape** globalShape_, bool* isOwnProperty, - BaselineInspector::ReceiverVector& receivers, - JSScript* script) { - // We are matching on the IR generated by tryAttachGlobalNameGetter: - // - // GuardShape objId - // globalId = LoadEnclosingEnvironment objId - // GuardShape globalId - // > - // - // CallNativeGetterResult globalId - - if (innerized) { - return false; - } - - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId objId = ObjOperandId(0); - if (!reader.matchOp(CacheOp::GuardShape, objId)) { - return false; - } - Shape* globalLexicalShape = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::LoadEnclosingEnvironment, objId)) { - return false; - } - ObjOperandId globalId = reader.objOperandId(); - - if (!reader.matchOp(CacheOp::GuardShape, globalId)) { - return false; - } - Shape* globalShape = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - MOZ_ASSERT(globalShape->getObjectClass()->flags & JSCLASS_IS_GLOBAL); - - JSObject* holder = &script->global(); - Shape* holderShape = globalShape; - if (reader.matchOp(CacheOp::LoadObject)) { - ObjOperandId holderId = reader.objOperandId(); - holder = stub->stubInfo() - ->getStubField(stub, reader.stubOffset()) - .get(); - - if (!reader.matchOp(CacheOp::GuardShape, holderId)) { - return false; - } - holderShape = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - } - - // This guard will always fail, try the next stub. - if (holder->as().lastProperty() != holderShape) { - return true; - } - - if (!reader.matchOp(CacheOp::CallNativeGetterResult, globalId)) { - return false; - } - size_t offset = reader.stubOffset(); - JSFunction* getter = &stub->stubInfo() - ->getStubField(stub, offset) - ->as(); - - ReceiverGuard receiver; - receiver.setShape(globalLexicalShape); - if (!AddReceiver(receiver, receivers)) { - return false; - } - - if (!*commonGetter) { - *holder_ = holder; - *holderShape_ = holderShape; - *commonGetter = getter; - *globalShape_ = globalShape; - - // This is always false, because the getters never live on the - // globalLexical. - *isOwnProperty = false; - } else if (*isOwnProperty || holderShape != *holderShape_ || - globalShape != *globalShape_) { - return false; - } else { - MOZ_ASSERT(*commonGetter == getter); - } - - return true; -} - -static bool GuardSpecificAtomOrSymbol(CacheIRReader& reader, ICStub* stub, - const CacheIRStubInfo* stubInfo, - ValOperandId keyId, jsid id) { - // Try to match an id guard emitted by IRGenerator::emitIdGuard. - if (JSID_IS_ATOM(id)) { - if (!reader.matchOp(CacheOp::GuardToString, keyId)) { - return false; - } - if (!reader.matchOp(CacheOp::GuardSpecificAtom, keyId)) { - return false; - } - JSString* str = - stubInfo->getStubField(stub, reader.stubOffset()).get(); - if (AtomToId(&str->asAtom()) != id) { - return false; - } - } else { - MOZ_ASSERT(JSID_IS_SYMBOL(id)); - if (!reader.matchOp(CacheOp::GuardToSymbol, keyId)) { - return false; - } - if (!reader.matchOp(CacheOp::GuardSpecificSymbol, keyId)) { - return false; - } - JS::Symbol* sym = - stubInfo->getStubField(stub, reader.stubOffset()).get(); - if (SYMBOL_TO_JSID(sym) != id) { - return false; - } - } - - return true; -} - -static bool AddCacheIRGetPropFunction( - ICCacheIR_Monitored* stub, jsid id, bool innerized, JSObject** holder, - Shape** holderShape, JSFunction** commonGetter, Shape** globalShape, - bool* isOwnProperty, BaselineInspector::ReceiverVector& receivers, - JSScript* script) { - // We match either an own getter: - // - // GuardToObject objId - // [..Id Guard..] - // [..WindowProxy innerization..] - // - // (Call(Scripted|Native)Getter|TypedArrayLength)Result objId - // - // Or a getter on the prototype: - // - // GuardToObject objId - // [..Id Guard..] - // [..WindowProxy innerization..] - // - // LoadObject holderId - // GuardShape holderId - // (Call(Scripted|Native)Getter|TypedArrayLength)Result objId - // - // If |innerized| is true, we replaced a WindowProxy with the Window - // object and we're only interested in Baseline getter stubs that performed - // the same optimization. This means we expect the following ops for the - // [..WindowProxy innerization..] above: - // - // GuardClass objId WindowProxy - // objId = LoadWrapperTarget objId - // GuardSpecificObject objId, - // - // If we test for a specific jsid, [..Id Guard..] is implemented through: - // GuardIs(String|Symbol) keyId - // GuardSpecific(Atom|Symbol) keyId, - - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId objId = ObjOperandId(0); - if (!reader.matchOp(CacheOp::GuardToObject, objId)) { - return AddCacheIRGlobalGetter(stub, innerized, holder, holderShape, - commonGetter, globalShape, isOwnProperty, - receivers, script); - } - - if (!JSID_IS_EMPTY(id)) { - ValOperandId keyId = ValOperandId(1); - if (!GuardSpecificAtomOrSymbol(reader, stub, stub->stubInfo(), keyId, id)) { - return false; - } - } - - if (innerized) { - if (!reader.matchOp(CacheOp::GuardClass, objId) || - reader.guardClassKind() != GuardClassKind::WindowProxy) { - return false; - } - - if (!reader.matchOp(CacheOp::LoadWrapperTarget, objId)) { - return false; - } - objId = reader.objOperandId(); - - if (!reader.matchOp(CacheOp::GuardSpecificObject, objId)) { - return false; - } - DebugOnly obj = - stub->stubInfo() - ->getStubField(stub, reader.stubOffset()) - .get(); - MOZ_ASSERT(obj->is()); - } - - ReceiverGuard receiver; - if (!MatchCacheIRReceiverGuard(reader, stub, stub->stubInfo(), objId, - &receiver)) { - return false; - } - - if (reader.matchOp(CacheOp::CallScriptedGetterResult, objId) || - reader.matchOp(CacheOp::CallNativeGetterResult, objId) || - reader.matchOp(CacheOp::LoadTypedArrayLengthResult, objId)) { - // This is an own property getter, the first case. - MOZ_ASSERT(receiver.getShape()); - MOZ_ASSERT(!receiver.getGroup()); - - size_t offset = reader.stubOffset(); - JSFunction* getter = &stub->stubInfo() - ->getStubField(stub, offset) - ->as(); - - if (*commonGetter && (!*isOwnProperty || *globalShape || - *holderShape != receiver.getShape())) { - return false; - } - - MOZ_ASSERT_IF(*commonGetter, *commonGetter == getter); - *holder = nullptr; - *holderShape = receiver.getShape(); - *commonGetter = getter; - *isOwnProperty = true; - return true; - } - - if (!reader.matchOp(CacheOp::LoadObject)) { - return false; - } - ObjOperandId holderId = reader.objOperandId(); - JSObject* obj = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::GuardShape, holderId)) { - return false; - } - Shape* objShape = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::CallScriptedGetterResult, objId) && - !reader.matchOp(CacheOp::CallNativeGetterResult, objId) && - !reader.matchOp(CacheOp::LoadTypedArrayLengthResult, objId)) { - return false; - } - - // A getter on the prototype. - size_t offset = reader.stubOffset(); - JSFunction* getter = &stub->stubInfo() - ->getStubField(stub, offset) - ->as(); - - Shape* thisGlobalShape = nullptr; - if (getter->isNative() && receiver.getShape() && - (receiver.getShape()->getObjectClass()->flags & JSCLASS_IS_GLOBAL)) { - thisGlobalShape = receiver.getShape(); - } - - if (*commonGetter && (*isOwnProperty || *globalShape != thisGlobalShape || - *holderShape != objShape)) { - return false; - } - - MOZ_ASSERT_IF(*commonGetter, *commonGetter == getter); - - if (obj->as().lastProperty() != objShape) { - // Skip this stub as the shape is no longer correct. - return true; - } - - if (!AddReceiver(receiver, receivers)) { - return false; - } - - *holder = obj; - *holderShape = objShape; - *commonGetter = getter; - *isOwnProperty = false; - return true; -} - -bool BaselineInspector::commonGetPropFunction( - jsbytecode* pc, jsid id, bool innerized, JSObject** holder, - Shape** holderShape, JSFunction** commonGetter, Shape** globalShape, - bool* isOwnProperty, ReceiverVector& receivers) { - MOZ_ASSERT(IsGetPropPC(pc) || IsGetElemPC(pc) || JSOp(*pc) == JSOp::GetGName); - MOZ_ASSERT(receivers.empty()); - - // Only GetElem operations need to guard against a specific property id. - if (!IsGetElemPC(pc)) { - id = JSID_EMPTY; - } - - *globalShape = nullptr; - *commonGetter = nullptr; - const ICEntry& entry = icEntryFromPC(pc); - - for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { - if (stub->isCacheIR_Monitored()) { - if (!AddCacheIRGetPropFunction( - stub->toCacheIR_Monitored(), id, innerized, holder, holderShape, - commonGetter, globalShape, isOwnProperty, receivers, script)) { - return false; - } - } else if (stub->isFallback()) { - // If we have an unoptimizable access, don't try to optimize. - if (stub->toFallbackStub()->state().hasFailures()) { - return false; - } - } else { - return false; - } - } - - if (!*commonGetter) { - return false; - } - - MOZ_ASSERT(*isOwnProperty == !*holder); - MOZ_ASSERT(*isOwnProperty == receivers.empty()); - return true; -} - -static JSFunction* GetMegamorphicGetterSetterFunction( - ICStub* stub, const CacheIRStubInfo* stubInfo, jsid id, bool isGetter) { - // We match: - // - // GuardToObject objId - // [..Id Guard..] - // GuardHasGetterSetter objId propShape - // - // propShape has the getter/setter we're interested in. - // - // If we test for a specific jsid, [..Id Guard..] is implemented through: - // GuardIs(String|Symbol) keyId - // GuardSpecific(Atom|Symbol) keyId, - - CacheIRReader reader(stubInfo); - - ObjOperandId objId = ObjOperandId(0); - if (!reader.matchOp(CacheOp::GuardToObject, objId)) { - return nullptr; - } - - if (!JSID_IS_EMPTY(id)) { - ValOperandId keyId = ValOperandId(1); - if (!GuardSpecificAtomOrSymbol(reader, stub, stubInfo, keyId, id)) { - return nullptr; - } - } - - if (!reader.matchOp(CacheOp::GuardHasGetterSetter, objId)) { - return nullptr; - } - Shape* propShape = stubInfo->getStubField(stub, reader.stubOffset()); - - JSObject* obj = - isGetter ? propShape->getterObject() : propShape->setterObject(); - return &obj->as(); -} - -bool BaselineInspector::megamorphicGetterSetterFunction( - jsbytecode* pc, jsid id, bool isGetter, JSFunction** getterOrSetter) { - MOZ_ASSERT(IsGetPropPC(pc) || IsGetElemPC(pc) || IsSetPropPC(pc) || - JSOp(*pc) == JSOp::GetGName || JSOp(*pc) == JSOp::InitGLexical || - JSOp(*pc) == JSOp::InitProp || JSOp(*pc) == JSOp::InitLockedProp || - JSOp(*pc) == JSOp::InitHiddenProp); - - // Only GetElem operations need to guard against a specific property id. - if (!IsGetElemPC(pc)) { - id = JSID_EMPTY; - } - - *getterOrSetter = nullptr; - const ICEntry& entry = icEntryFromPC(pc); - - for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { - if (stub->isCacheIR_Monitored()) { - MOZ_ASSERT(isGetter); - JSFunction* getter = GetMegamorphicGetterSetterFunction( - stub, stub->toCacheIR_Monitored()->stubInfo(), id, isGetter); - if (!getter || (*getterOrSetter && *getterOrSetter != getter)) { - return false; - } - *getterOrSetter = getter; - continue; - } - if (stub->isCacheIR_Updated()) { - MOZ_ASSERT(!isGetter); - JSFunction* setter = GetMegamorphicGetterSetterFunction( - stub, stub->toCacheIR_Updated()->stubInfo(), id, isGetter); - if (!setter || (*getterOrSetter && *getterOrSetter != setter)) { - return false; - } - *getterOrSetter = setter; - continue; - } - if (stub->isFallback()) { - if (stub->toFallbackStub()->state().hasFailures()) { - return false; - } - if (stub->toFallbackStub()->state().mode() != - ICState::Mode::Megamorphic) { - return false; - } - continue; - } - - return false; - } - - if (!*getterOrSetter) { - return false; - } - - return true; -} - -static bool AddCacheIRSetPropFunction( - ICCacheIR_Updated* stub, JSObject** holder, Shape** holderShape, - JSFunction** commonSetter, bool* isOwnProperty, - BaselineInspector::ReceiverVector& receivers) { - // We match either an own setter: - // - // GuardToObject objId - // - // Call(Scripted|Native)Setter objId - // - // Or a setter on the prototype: - // - // GuardToObject objId - // - // LoadObject holderId - // GuardShape holderId - // Call(Scripted|Native)Setter objId - - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId objId = ObjOperandId(0); - if (!reader.matchOp(CacheOp::GuardToObject, objId)) { - return false; - } - - ReceiverGuard receiver; - if (!MatchCacheIRReceiverGuard(reader, stub, stub->stubInfo(), objId, - &receiver)) { - return false; - } - - if (reader.matchOp(CacheOp::CallScriptedSetter, objId) || - reader.matchOp(CacheOp::CallNativeSetter, objId)) { - // This is an own property setter, the first case. - MOZ_ASSERT(receiver.getShape()); - MOZ_ASSERT(!receiver.getGroup()); - - size_t offset = reader.stubOffset(); - JSFunction* setter = &stub->stubInfo() - ->getStubField(stub, offset) - ->as(); - - if (*commonSetter && - (!*isOwnProperty || *holderShape != receiver.getShape())) { - return false; - } - - MOZ_ASSERT_IF(*commonSetter, *commonSetter == setter); - *holder = nullptr; - *holderShape = receiver.getShape(); - *commonSetter = setter; - *isOwnProperty = true; - return true; - } - - if (!reader.matchOp(CacheOp::LoadObject)) { - return false; - } - ObjOperandId holderId = reader.objOperandId(); - JSObject* obj = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::GuardShape, holderId)) { - return false; - } - Shape* objShape = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::CallScriptedSetter, objId) && - !reader.matchOp(CacheOp::CallNativeSetter, objId)) { - return false; - } - - // A setter on the prototype. - size_t offset = reader.stubOffset(); - JSFunction* setter = &stub->stubInfo() - ->getStubField(stub, offset) - ->as(); - - if (*commonSetter && (*isOwnProperty || *holderShape != objShape)) { - return false; - } - - MOZ_ASSERT_IF(*commonSetter, *commonSetter == setter); - - if (obj->as().lastProperty() != objShape) { - // Skip this stub as the shape is no longer correct. - return true; - } - - if (!AddReceiver(receiver, receivers)) { - return false; - } - - *holder = obj; - *holderShape = objShape; - *commonSetter = setter; - *isOwnProperty = false; - return true; -} - -bool BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, - Shape** holderShape, - JSFunction** commonSetter, - bool* isOwnProperty, - ReceiverVector& receivers) { - MOZ_ASSERT(IsSetPropPC(pc) || JSOp(*pc) == JSOp::InitGLexical || - JSOp(*pc) == JSOp::InitProp || JSOp(*pc) == JSOp::InitLockedProp || - JSOp(*pc) == JSOp::InitHiddenProp); - MOZ_ASSERT(receivers.empty()); - - *commonSetter = nullptr; - const ICEntry& entry = icEntryFromPC(pc); - - for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { - if (stub->isCacheIR_Updated()) { - if (!AddCacheIRSetPropFunction(stub->toCacheIR_Updated(), holder, - holderShape, commonSetter, isOwnProperty, - receivers)) { - return false; - } - } else if (!stub->isFallback() || - stub->toFallbackStub()->state().hasFailures()) { - // We have an unoptimizable access, so don't try to optimize. - return false; - } - } - - if (!*commonSetter) { - return false; - } - - MOZ_ASSERT(*isOwnProperty == !*holder); - return true; -} - -static bool GetCacheIRReceiverForProtoReadSlot(ICCacheIR_Monitored* stub, - ReceiverGuard* receiver, - JSObject** holderResult) { - // We match: - // - // GuardToObject 0 - // - // 1: LoadObject holder - // GuardShape 1 - // LoadFixedSlotResult 1 or LoadDynamicSlotResult 1 - - *receiver = ReceiverGuard(); - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId objId = ObjOperandId(0); - if (!reader.matchOp(CacheOp::GuardToObject, objId)) { - return false; - } - - if (!MatchCacheIRReceiverGuard(reader, stub, stub->stubInfo(), objId, - receiver)) { - return false; - } - - if (!reader.matchOp(CacheOp::LoadObject)) { - return false; - } - ObjOperandId holderId = reader.objOperandId(); - JSObject* holder = stub->stubInfo() - ->getStubField(stub, reader.stubOffset()) - .get(); - - if (!reader.matchOp(CacheOp::GuardShape, holderId)) { - return false; - } - Shape* holderShape = - stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOpEither(CacheOp::LoadFixedSlotResult, - CacheOp::LoadDynamicSlotResult)) { - return false; - } - if (reader.objOperandId() != holderId) { - return false; - } - - if (holder->shape() != holderShape) { - return false; - } - if (*holderResult && *holderResult != holder) { - return false; - } - - *holderResult = holder; - return true; -} - -bool BaselineInspector::maybeInfoForProtoReadSlot(jsbytecode* pc, - ReceiverVector& receivers, - JSObject** holder) { - // This is like maybeInfoForPropertyOp, but for when the property exists on - // the prototype. - - MOZ_ASSERT(receivers.empty()); - MOZ_ASSERT(!*holder); - - MOZ_ASSERT(isValidPC(pc)); - const ICEntry& entry = icEntryFromPC(pc); - - ICStub* stub = entry.firstStub(); - while (stub->next()) { - ReceiverGuard receiver; - if (stub->isCacheIR_Monitored()) { - if (!GetCacheIRReceiverForProtoReadSlot(stub->toCacheIR_Monitored(), - &receiver, holder)) { - receivers.clear(); - return true; - } - } else { - receivers.clear(); - return true; - } - - if (!AddReceiver(receiver, receivers)) { - return false; - } - - stub = stub->next(); - } - - if (stub->toFallbackStub()->state().hasFailures()) { - receivers.clear(); - } - - // Don't inline if there are more than 5 receivers. - if (receivers.length() > 5) { - receivers.clear(); - } - - MOZ_ASSERT_IF(!receivers.empty(), *holder); - return true; -} - -static MIRType GetCacheIRExpectedInputType(ICCacheIR_Monitored* stub) { - CacheIRReader reader(stub->stubInfo()); - - if (reader.matchOp(CacheOp::GuardToObject, ValOperandId(0))) { - return MIRType::Object; - } - if (reader.matchOp(CacheOp::GuardToString, ValOperandId(0))) { - return MIRType::String; - } - if (reader.matchOp(CacheOp::GuardIsNumber, ValOperandId(0))) { - return MIRType::Double; - } - if (reader.matchOp(CacheOp::GuardNonDoubleType, ValOperandId(0))) { - ValueType type = reader.valueType(); - return MIRTypeFromValueType(JSValueType(type)); - } - if (reader.matchOp(CacheOp::GuardMagicValue)) { - // This can happen if we attached a lazy-args Baseline IC stub but then - // called JSScript::argumentsOptimizationFailed. - return MIRType::Value; - } - - MOZ_ASSERT_UNREACHABLE("Unexpected instruction"); - return MIRType::Value; -} - -MIRType BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) { - const ICEntry& entry = icEntryFromPC(pc); - MIRType type = MIRType::None; - - for (ICStub* stub = entry.firstStub(); stub; stub = stub->next()) { - MIRType stubType = MIRType::None; - if (stub->isCacheIR_Monitored()) { - stubType = GetCacheIRExpectedInputType(stub->toCacheIR_Monitored()); - if (stubType == MIRType::Value) { - return MIRType::Value; - } - } else if (stub->isGetElem_Fallback() || stub->isGetProp_Fallback()) { - // If we have an unoptimizable access, don't try to optimize. - if (stub->toFallbackStub()->state().hasFailures()) { - return MIRType::Value; - } - } else { - MOZ_CRASH("Unexpected stub"); - } - - if (type != MIRType::None) { - if (type != stubType) { - return MIRType::Value; - } - } else { - type = stubType; - } - } - - return (type == MIRType::None) ? MIRType::Value : type; -} - -bool BaselineInspector::instanceOfData(jsbytecode* pc, Shape** shape, - uint32_t* slot, - JSObject** prototypeObject) { - MOZ_ASSERT(JSOp(*pc) == JSOp::Instanceof); - - const ICEntry& entry = icEntryFromPC(pc); - ICStub* firstStub = entry.firstStub(); - - // Ensure singleton instanceof stub - if (!firstStub->next() || !firstStub->isCacheIR_Regular() || - !firstStub->next()->isInstanceOf_Fallback() || - firstStub->next()->toInstanceOf_Fallback()->state().hasFailures()) { - return false; - } - - ICCacheIR_Regular* stub = entry.firstStub()->toCacheIR_Regular(); - CacheIRReader reader(stub->stubInfo()); - - ObjOperandId rhsId = ObjOperandId(1); - ObjOperandId resId = ObjOperandId(2); - - if (!reader.matchOp(CacheOp::GuardToObject, rhsId)) { - return false; - } - - if (!reader.matchOp(CacheOp::GuardShape, rhsId)) { - return false; - } - - *shape = stub->stubInfo()->getStubField(stub, reader.stubOffset()); - - if (!reader.matchOp(CacheOp::LoadObject, resId)) { - return false; - } - - *prototypeObject = stub->stubInfo() - ->getStubField(stub, reader.stubOffset()) - .get(); - - if (IsInsideNursery(*prototypeObject)) { - return false; - } - - if (!reader.matchOp(CacheOp::GuardDynamicSlotIsSpecificObject, rhsId)) { - return false; - } - - reader.skip(); // Skip over the protoID; - - *slot = stub->stubInfo()->getStubRawWord(stub, reader.stubOffset()); - - return true; -} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineInspector.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineInspector.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineInspector.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineInspector.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,133 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef jit_BaselineInspector_h -#define jit_BaselineInspector_h - -#include "jit/BaselineIC.h" -#include "jit/BaselineJIT.h" -#include "jit/MIR.h" - -namespace js { -namespace jit { - -class BaselineInspector; - -class ICInspector { - protected: - BaselineInspector* inspector_; - jsbytecode* pc_; - ICEntry* icEntry_; - - ICInspector(BaselineInspector* inspector, jsbytecode* pc, ICEntry* icEntry) - : inspector_(inspector), pc_(pc), icEntry_(icEntry) {} -}; - -class SetElemICInspector : public ICInspector { - public: - SetElemICInspector(BaselineInspector* inspector, jsbytecode* pc, - ICEntry* icEntry) - : ICInspector(inspector, pc, icEntry) {} - - bool sawOOBDenseWrite() const; - bool sawOOBTypedArrayWrite() const; -}; - -class BaselineInspector { - private: - JSScript* script; - ICEntry* prevLookedUpEntry; - - public: - explicit BaselineInspector(JSScript* script) - : script(script), prevLookedUpEntry(nullptr) { - MOZ_ASSERT(script); - } - - JitScript* jitScript() const; - - private: -#ifdef DEBUG - bool isValidPC(jsbytecode* pc) { return script->containsPC(pc); } -#endif - - ICEntry& icEntryFromPC(jsbytecode* pc); - ICEntry* maybeICEntryFromPC(jsbytecode* pc); - - template - ICInspectorType makeICInspector(jsbytecode* pc, - ICStub::Kind expectedFallbackKind) { - ICEntry* ent = &icEntryFromPC(pc); - MOZ_ASSERT(ent->fallbackStub()->kind() == expectedFallbackKind); - return ICInspectorType(this, pc, ent); - } - - ICStub* monomorphicStub(jsbytecode* pc); - MOZ_MUST_USE bool dimorphicStub(jsbytecode* pc, ICStub** pfirst, - ICStub** psecond); - - public: - typedef Vector ReceiverVector; - typedef Vector ObjectGroupVector; - MOZ_MUST_USE bool maybeInfoForPropertyOp(jsbytecode* pc, - ReceiverVector& receivers); - - MOZ_MUST_USE bool maybeInfoForProtoReadSlot(jsbytecode* pc, - ReceiverVector& receivers, - JSObject** holder); - - SetElemICInspector setElemICInspector(jsbytecode* pc) { - return makeICInspector(pc, ICStub::SetElem_Fallback); - } - - MIRType expectedResultType(jsbytecode* pc); - MCompare::CompareType expectedCompareType(jsbytecode* pc); - MIRType expectedBinaryArithSpecialization(jsbytecode* pc); - MIRType expectedPropertyAccessInputType(jsbytecode* pc); - - bool hasSeenNegativeIndexGetElement(jsbytecode* pc); - bool hasSeenNonIntegerIndex(jsbytecode* pc); - bool hasSeenAccessedGetter(jsbytecode* pc); - bool hasSeenDoubleResult(jsbytecode* pc); - - JSObject* getTemplateObject(jsbytecode* pc); - JSObject* getTemplateObjectForNative(jsbytecode* pc, Native native); - - // Sometimes the group a template object will have is known, even if the - // object itself isn't. - ObjectGroup* getTemplateObjectGroup(jsbytecode* pc); - - JSFunction* getSingleCallee(jsbytecode* pc); - - LexicalEnvironmentObject* templateNamedLambdaObject(); - CallObject* templateCallObject(); - - // If |innerized| is true, we're doing a GETPROP on a WindowProxy and - // IonBuilder unwrapped/innerized it to do the lookup on the Window (the - // global object) instead. In this case we should only look for Baseline - // stubs that performed the same optimization. - MOZ_MUST_USE bool commonGetPropFunction( - jsbytecode* pc, jsid id, bool innerized, JSObject** holder, - Shape** holderShape, JSFunction** commonGetter, Shape** globalShape, - bool* isOwnProperty, ReceiverVector& receivers); - - MOZ_MUST_USE bool megamorphicGetterSetterFunction( - jsbytecode* pc, jsid id, bool isGetter, JSFunction** getterOrSetter); - - MOZ_MUST_USE bool commonSetPropFunction(jsbytecode* pc, JSObject** holder, - Shape** holderShape, - JSFunction** commonSetter, - bool* isOwnProperty, - ReceiverVector& receivers); - - MOZ_MUST_USE bool instanceOfData(jsbytecode* pc, Shape** shape, - uint32_t* slot, JSObject** prototypeObject); -}; - -} // namespace jit -} // namespace js - -#endif /* jit_BaselineInspector_h */ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineJIT.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineJIT.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/BaselineJIT.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/BaselineJIT.h 2020-11-17 19:31:32.000000000 +0000 @@ -113,9 +113,6 @@ // An IC for a JOF_IC op. IC, - // A prologue IC. - PrologueIC, - // A callVM for an op. CallVM, @@ -463,10 +460,6 @@ // The native code address to resume into. void* resumeAddr = nullptr; - // If non-null, we have to type monitor the top stack value for this pc (we - // resume right after it). - jsbytecode* monitorPC = nullptr; - // The bytecode pc of try block and fault block. jsbytecode* tryPC = nullptr; jsbytecode* faultPC = nullptr; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/CacheIR.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/CacheIR.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/CacheIR.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/CacheIR.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -446,6 +446,7 @@ // effects and produce a result which the MIR in the calling code is able // to handle, since we do not have a pc to explicitly monitor the result. + // TODO(no-TI): remove idempotent ICs. MOZ_ASSERT(idempotent()); RootedObject obj(cx_, &val_.toObject()); @@ -1018,10 +1019,6 @@ } writer.typeMonitorResult(); } else { - // Normally for this op, the result would have to be monitored by TI. - // However, since this stub ALWAYS returns UndefinedValue(), and we can be - // sure that undefined is already registered with the type-set, this can be - // avoided. writer.returnFromIC(); } } @@ -1830,8 +1827,6 @@ } if (obj->is()) { - // Make sure int32 is added to the TypeSet before we attach a stub, so - // the stub can return int32 values without monitoring the result. if (obj->as().length() > INT32_MAX) { return AttachDecision::NoAction; } @@ -1969,17 +1964,11 @@ writer.guardClass(objId, GuardClassKind::JSFunction); if (isLength) { writer.loadFunctionLengthResult(objId); - - // Doesn't need to be monitored, because it always returns an int32. writer.returnFromIC(); - trackAttached("FunctionLength"); } else { writer.loadFunctionNameResult(objId); - - // Doesn't need to be monitored, because it always returns a string. writer.returnFromIC(); - trackAttached("FunctionName"); } return AttachDecision::Attach; @@ -5138,8 +5127,7 @@ thisval_(thisval), newTarget_(newTarget), args_(args), - typeCheckInfo_(cx, /* needsTypeBarrier = */ true), - cacheIRStubKind_(BaselineCacheIRStubKind::Regular) {} + typeCheckInfo_(cx, /* needsTypeBarrier = */ true) {} void CallIRGenerator::emitNativeCalleeGuard(HandleFunction callee) { // Note: we rely on GuardSpecificFunction to also guard against the same @@ -5256,8 +5244,6 @@ // Set the type-check info, and the stub kind to Updated typeCheckInfo_.set(thisobj->group(), JSID_VOID); - cacheIRStubKind_ = BaselineCacheIRStubKind::Updated; - trackAttached("ArrayPush"); return AttachDecision::Attach; } @@ -5309,7 +5295,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("ArrayPopShift"); return AttachDecision::Attach; @@ -5360,13 +5345,6 @@ writer.returnFromIC(); - // The result of this stub does not need to be monitored because it will - // always return a string. We will add String to the stack typeset when - // attaching this stub. - - // Set the stub kind to Regular - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; - trackAttached("ArrayJoin"); return AttachDecision::Attach; } @@ -5443,7 +5421,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("ArraySlice"); return AttachDecision::Attach; @@ -5464,11 +5441,7 @@ // Check if the argument is an Array and return result. ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); writer.isArrayResult(argId); - - // This stub does not need to be monitored, because it always - // returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("ArrayIsArray"); return AttachDecision::Attach; @@ -5541,11 +5514,7 @@ writer.loadDataViewValueResult(objId, int32OffsetId, boolLittleEndianId, type, allowDoubleForUint32); - - // This stub does not need to be monitored, because it returns the same type - // as this call. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("DataViewGet"); return AttachDecision::Attach; @@ -5617,10 +5586,7 @@ writer.storeDataViewValueResult(objId, int32OffsetId, numericValueId, boolLittleEndianId, type); - - // This stub doesn't need type monitoring, it always returns |undefined|. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("DataViewSet"); return AttachDecision::Attach; @@ -5674,7 +5640,6 @@ // For simplicity just monitor all stubs. writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("UnsafeGetReservedSlot"); return AttachDecision::Attach; @@ -5714,7 +5679,6 @@ // This stub always returns undefined. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("UnsafeSetReservedSlot"); return AttachDecision::Attach; @@ -5743,11 +5707,6 @@ writer.callIsSuspendedGeneratorResult(valId); writer.returnFromIC(); - // This stub does not need to be monitored, because it always - // returns Boolean. The stack typeset will be updated when we - // attach the stub. - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; - trackAttached("IsSuspendedGenerator"); return AttachDecision::Attach; } @@ -5782,7 +5741,6 @@ // Monitor the returned object. writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; if (native == InlinableNative::IntrinsicToObject) { trackAttached("ToObject"); @@ -5816,11 +5774,7 @@ // Return the int32. writer.loadInt32Result(int32Id); - - // This stub does not need to be monitored, because it always - // returns an int32. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("ToInteger"); return AttachDecision::Attach; @@ -5847,11 +5801,7 @@ bool isMax = true; Int32OperandId maxId = writer.int32MinMax(isMax, int32ArgId, zeroId); writer.loadInt32Result(maxId); - - // This stub does not need to be monitored, because it always returns an - // int32. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("ToLength"); return AttachDecision::Attach; @@ -5869,11 +5819,7 @@ // Type check the argument and return result. ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); writer.isObjectResult(argId); - - // This stub does not need to be monitored, because it always - // returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("IsObject"); return AttachDecision::Attach; @@ -5893,11 +5839,7 @@ ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); ObjOperandId objArgId = writer.guardToObject(argId); writer.isPackedArrayResult(objArgId); - - // This stub does not need to be monitored, because it always - // returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("IsPackedArray"); return AttachDecision::Attach; @@ -5915,11 +5857,7 @@ // Check if the argument is callable and return result. ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); writer.isCallableResult(argId); - - // This stub does not need to be monitored, because it always - // returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("IsCallable"); return AttachDecision::Attach; @@ -5945,11 +5883,7 @@ // Check if the argument is a constructor and return result. writer.isConstructorResult(objId); - - // This stub does not need to be monitored, because it always - // returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("IsConstructor"); return AttachDecision::Attach; @@ -5974,10 +5908,7 @@ ObjOperandId objId = writer.guardToObject(argId); writer.guardIsNotProxy(objId); writer.isCrossRealmArrayConstructorResult(objId); - - // This stub does not need to be monitored, it always returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("IsCrossRealmArrayConstructor"); return AttachDecision::Attach; @@ -6012,7 +5943,6 @@ // Monitor the returned object. writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("GuardToClass"); return AttachDecision::Attach; @@ -6044,10 +5974,7 @@ } writer.hasClassResult(objId, clasp); - - // Return without type monitoring, because this always returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("HasClass"); return AttachDecision::Attach; @@ -6085,7 +6012,6 @@ case InlinableNative::RegExpMatcher: writer.callRegExpMatcherResult(reId, inputId, lastIndexId); writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("RegExpMatcher"); break; @@ -6093,7 +6019,6 @@ // No type monitoring because this always returns an int32. writer.callRegExpSearcherResult(reId, inputId, lastIndexId); writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("RegExpSearcher"); break; @@ -6101,7 +6026,6 @@ // No type monitoring because this always returns an int32. writer.callRegExpTesterResult(reId, inputId, lastIndexId); writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("RegExpTester"); break; @@ -6127,10 +6051,7 @@ ObjOperandId protoId = writer.guardToObject(arg0Id); writer.regExpPrototypeOptimizableResult(protoId); - - // No type monitoring because this always returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("RegExpPrototypeOptimizable"); return AttachDecision::Attach; @@ -6155,10 +6076,7 @@ ObjOperandId protoId = writer.guardToObject(arg1Id); writer.regExpInstanceOptimizableResult(regexpId, protoId); - - // No type monitoring because this always returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("RegExpInstanceOptimizable"); return AttachDecision::Attach; @@ -6179,10 +6097,7 @@ StringOperandId strId = writer.guardToString(arg0Id); writer.getFirstDollarIndexResult(strId); - - // No type monitoring because this always returns an int32. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("GetFirstDollarIndex"); return AttachDecision::Attach; @@ -6211,10 +6126,7 @@ Int32OperandId lengthId = writer.guardToInt32(arg2Id); writer.callSubstringKernelResult(strId, beginId, lengthId); - - // No type monitoring because this always returns a string. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("SubstringKernel"); return AttachDecision::Attach; @@ -6245,10 +6157,7 @@ writer.guardProto(objId, proto); writer.loadBooleanResult(true); - - // No type monitoring because this always returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("ObjectHasPrototype"); return AttachDecision::Attach; @@ -6273,11 +6182,7 @@ // Return the string. writer.loadStringResult(strId); - - // This stub does not need to be monitored, because it always - // returns a string. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("String"); return AttachDecision::Attach; @@ -6319,7 +6224,6 @@ writer.newStringObjectResult(templateObj, strId); writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("StringConstructor"); return AttachDecision::Attach; @@ -6350,10 +6254,7 @@ // Return the string writer.loadStringResult(strId); - - // This stub doesn't need to be monitored, because it always returns a string. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("StringToStringValueOf"); return AttachDecision::Attach; @@ -6382,10 +6283,7 @@ StringOperandId replacementId = writer.guardToString(arg2Id); writer.stringReplaceStringResult(strId, patternId, replacementId); - - // No type monitoring because this always returns a string. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("StringReplaceString"); return AttachDecision::Attach; @@ -6416,9 +6314,7 @@ StringOperandId separatorId = writer.guardToString(arg1Id); writer.stringSplitStringResult(strId, separatorId, group); - writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("StringSplitString"); return AttachDecision::Attach; @@ -6460,11 +6356,6 @@ writer.returnFromIC(); - // This stub does not need to be monitored, because it always - // returns a string for charAt or int32_t for charCodeAt. - // The stack typeset will be updated when we attach the stub. - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; - if (kind == StringChar::CodeAt) { trackAttached("StringCharCodeAt"); } else { @@ -6502,11 +6393,7 @@ // Return string created from code. writer.stringFromCharCodeResult(codeId); - - // This stub does not need to be monitored, because it always - // returns a string. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("StringFromCharCode"); return AttachDecision::Attach; @@ -6537,10 +6424,7 @@ // Return string created from code point. writer.stringFromCodePointResult(codeId); - - // This stub doesn't need to be monitored, because it always returns a string. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("StringFromCodePoint"); return AttachDecision::Attach; @@ -6571,10 +6455,7 @@ // Return string converted to lower-case. writer.stringToLowerCaseResult(strId); - - // This stub doesn't need to be monitored, because it always returns a string. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("StringToLowerCase"); return AttachDecision::Attach; @@ -6605,10 +6486,7 @@ // Return string converted to upper-case. writer.stringToUpperCaseResult(strId); - - // This stub doesn't need to be monitored, because it always returns a string. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("StringToUpperCase"); return AttachDecision::Attach; @@ -6634,7 +6512,6 @@ writer.mathRandomResult(rng); writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("MathRandom"); return AttachDecision::Attach; @@ -6668,11 +6545,7 @@ writer.mathAbsNumberResult(numberId); } - // The INT_MIN case and implementation details of the C++ abs - // make this a bit tricky. We probably can just remove monitoring - // in the future completely, so do the easy thing right now. writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("MathAbs"); return AttachDecision::Attach; @@ -6701,10 +6574,7 @@ int32Id = writer.truncateDoubleToUInt32(numId); } writer.mathClz32Result(int32Id); - - // Math.clz32 always returns an int32 so we don't need type monitoring. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("MathClz32"); return AttachDecision::Attach; @@ -6742,10 +6612,7 @@ } } - // The stub's return type matches the current return value so we don't need - // type monitoring. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("MathSign"); return AttachDecision::Attach; @@ -6778,10 +6645,7 @@ int32Arg1Id = writer.truncateDoubleToUInt32(numArg1Id); } writer.mathImulResult(int32Arg0Id, int32Arg1Id); - - // Math.imul always returns int32 so we don't need type monitoring. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("MathImul"); return AttachDecision::Attach; @@ -6815,7 +6679,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("MathFloor"); return AttachDecision::Attach; @@ -6849,7 +6712,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("MathCeil"); return AttachDecision::Attach; @@ -6883,7 +6745,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("MathTrunc"); return AttachDecision::Attach; @@ -6917,7 +6778,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("MathRound"); return AttachDecision::Attach; @@ -6942,7 +6802,6 @@ // Math.sqrt always returns a double so we don't need type monitoring. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("MathSqrt"); return AttachDecision::Attach; @@ -6964,10 +6823,7 @@ writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); NumberOperandId numberId = writer.guardIsNumber(argumentId); writer.mathFRoundNumberResult(numberId); - - // Math.fround always returns a double so we don't need type monitoring. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("MathFRound"); return AttachDecision::Attach; @@ -7023,7 +6879,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("MathPow"); return AttachDecision::Attach; @@ -7079,9 +6934,7 @@ MOZ_CRASH("Unexpected number of arguments to hypot function."); } - // Math.hypot always returns a double so we don't need type monitoring. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("MathHypot"); return AttachDecision::Attach; @@ -7106,10 +6959,7 @@ NumberOperandId xNumberId = writer.guardIsNumber(xId); writer.mathAtan2NumberResult(yNumberId, xNumberId); - - // Math.atan2 always returns a double so we don't need type monitoring. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("MathAtan2"); return AttachDecision::Attach; @@ -7160,7 +7010,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached(isMax ? "MathMax" : "MathMin"); return AttachDecision::Attach; @@ -7187,10 +7036,7 @@ writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); NumberOperandId numberId = writer.guardIsNumber(argumentId); writer.mathFunctionNumberResult(numberId, fun); - - // These functions always return a double so we don't need type monitoring. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("MathFunction"); return AttachDecision::Attach; @@ -7238,10 +7084,7 @@ // Return the string. writer.loadStringResult(strId); - - // This stub doesn't need to be monitored, because it always returns a string. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("NumberToString"); return AttachDecision::Attach; @@ -7269,9 +7112,7 @@ ObjOperandId objId = writer.guardToObject(argumentId); writer.reflectGetPrototypeOfResult(objId); - writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("ReflectGetPrototypeOf"); return AttachDecision::Attach; @@ -7376,11 +7217,7 @@ writer.atomicsCompareExchangeResult(objId, int32IndexId, int32ExpectedId, int32ReplacementId, typedArray->type()); - - // This stub doesn't need to be monitored, because it always returns an int32 - // or, for uint32, a double. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsCompareExchange"); return AttachDecision::Attach; @@ -7457,11 +7294,7 @@ writer.atomicsExchangeResult(objId, int32IndexId, int32ValueId, typedArray->type()); - - // This stub doesn't need to be monitored, because it always returns an int32 - // or, for uint32, a double. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsExchange"); return AttachDecision::Attach; @@ -7479,11 +7312,7 @@ writer.atomicsAddResult(objId, int32IndexId, int32ValueId, typedArray->type()); - - // This stub doesn't need to be monitored, because it always returns an int32 - // or, for uint32, a double. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsAdd"); return AttachDecision::Attach; @@ -7501,11 +7330,7 @@ writer.atomicsSubResult(objId, int32IndexId, int32ValueId, typedArray->type()); - - // This stub doesn't need to be monitored, because it always returns an int32 - // or, for uint32, a double. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsSub"); return AttachDecision::Attach; @@ -7523,11 +7348,7 @@ writer.atomicsAndResult(objId, int32IndexId, int32ValueId, typedArray->type()); - - // This stub doesn't need to be monitored, because it always returns an int32 - // or, for uint32, a double. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsAnd"); return AttachDecision::Attach; @@ -7544,11 +7365,7 @@ auto* typedArray = &args_[0].toObject().as(); writer.atomicsOrResult(objId, int32IndexId, int32ValueId, typedArray->type()); - - // This stub doesn't need to be monitored, because it always returns an int32 - // or, for uint32, a double. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsOr"); return AttachDecision::Attach; @@ -7566,11 +7383,7 @@ writer.atomicsXorResult(objId, int32IndexId, int32ValueId, typedArray->type()); - - // This stub doesn't need to be monitored, because it always returns an int32 - // or, for uint32, a double. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsXor"); return AttachDecision::Attach; @@ -7615,11 +7428,7 @@ Int32OperandId int32IndexId = writer.guardToInt32Index(indexId); writer.atomicsLoadResult(objId, int32IndexId, typedArray->type()); - - // This stub doesn't need to be monitored, because it always returns an int32 - // or, for uint32, a double. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsLoad"); return AttachDecision::Attach; @@ -7687,11 +7496,7 @@ writer.atomicsStoreResult(objId, int32IndexId, int32ValueId, typedArray->type()); - - // This stub doesn't need to be monitored, because it always returns an int32 - // or the result is not observed. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsStore"); return AttachDecision::Attach; @@ -7720,10 +7525,7 @@ Int32OperandId int32ValueId = writer.guardToInt32(valueId); writer.atomicsIsLockFreeResult(int32ValueId); - - // This stub doesn't need to be monitored, because it always returns a bool. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AtomicsIsLockFree"); return AttachDecision::Attach; @@ -7750,9 +7552,7 @@ writer.loadValueTruthyResult(valId); } - // This stub doesn't need to be monitored, because it always returns a bool. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("Boolean"); return AttachDecision::Attach; @@ -7772,10 +7572,7 @@ writer.bailout(); writer.loadUndefinedResult(); - - // This stub doesn't need to be monitored, it always returns undefined. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("Bailout"); return AttachDecision::Attach; @@ -7797,10 +7594,7 @@ // NOP when not in IonMonkey. writer.loadUndefinedResult(); - - // This stub doesn't need to be monitored, it always returns undefined. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AssertFloat32"); return AttachDecision::Attach; @@ -7826,10 +7620,7 @@ ValOperandId valId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); writer.assertRecoveredOnBailoutResult(valId, mustBeRecovered); - - // This stub doesn't need to be monitored, it always returns undefined. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("AssertRecoveredOnBailout"); return AttachDecision::Attach; @@ -7927,10 +7718,7 @@ } } - // This stub does not need to be monitored, because it always returns a - // boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("ObjectIs"); return AttachDecision::Attach; @@ -7962,11 +7750,7 @@ ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); writer.loadInstanceOfObjectResult(argId, thisObjId); - - // This stub does not need to be monitored, because it always returns a - // boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("ObjectIsPrototypeOf"); return AttachDecision::Attach; @@ -8029,7 +7813,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; if (isScripted) { trackAttached("Scripted fun_call"); @@ -8054,10 +7837,7 @@ ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); ObjOperandId objArgId = writer.guardToObject(argId); writer.isTypedArrayResult(objArgId, isPossiblyWrapped); - - // This stub does not need to be monitored because it always returns a bool. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached(isPossiblyWrapped ? "IsPossiblyWrappedTypedArray" : "IsTypedArray"); @@ -8078,10 +7858,7 @@ ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); ObjOperandId objArgId = writer.guardToObject(argId); writer.isTypedArrayConstructorResult(objArgId); - - // This stub does not need to be monitored because it always returns a bool. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("IsTypedArrayConstructor"); return AttachDecision::Attach; @@ -8102,10 +7879,7 @@ ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); ObjOperandId objArgId = writer.guardToObject(argId); writer.typedArrayByteOffsetResult(objArgId); - - // This stub does not need to be monitored because it always returns int32. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("TypedArrayByteOffset"); return AttachDecision::Attach; @@ -8126,10 +7900,7 @@ ValOperandId argId = writer.loadArgumentFixedSlot(ArgumentKind::Arg0, argc_); ObjOperandId objArgId = writer.guardToObject(argId); writer.typedArrayElementShiftResult(objArgId); - - // This stub does not need to be monitored because it always returns int32. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("TypedArrayElementShift"); return AttachDecision::Attach; @@ -8164,10 +7935,7 @@ // Note: the "getter" argument is a hint for IonBuilder. Just pass |callee|, // the field isn't used for this intrinsic call. writer.loadTypedArrayLengthResult(objArgId, callee); - - // This stub does not need to be monitored because it always returns int32. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("TypedArrayLength"); return AttachDecision::Attach; @@ -8200,10 +7968,7 @@ } writer.loadArrayBufferByteLengthInt32Result(objArgId); - - // This stub does not need to be monitored because it always returns int32. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("ArrayBufferByteLength"); return AttachDecision::Attach; @@ -8220,10 +7985,7 @@ // Note: we don't need to call emitNativeCalleeGuard for intrinsics. writer.frameIsConstructingResult(); - - // This stub does not need to be monitored, it always returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("IsConstructing"); return AttachDecision::Attach; @@ -8253,10 +8015,7 @@ ObjOperandId objResultArrId = writer.guardToObject(resultArrId); writer.getNextMapSetEntryForIteratorResult(objIterId, objResultArrId, isMap); - - // This stub does not need to be monitored, it always returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("GetNextMapSetEntryForIterator"); return AttachDecision::Attach; @@ -8290,10 +8049,7 @@ writer.finishBoundFunctionInitResult(objBoundId, objTargetId, int32ArgCountId); - - // This stub does not need to be monitored, it always returns |undefined|. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("FinishBoundFunctionInit"); return AttachDecision::Attach; @@ -8321,7 +8077,6 @@ } writer.newArrayIteratorResult(templateObj); writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("NewArrayIterator"); return AttachDecision::Attach; @@ -8349,7 +8104,6 @@ } writer.newStringIteratorResult(templateObj); writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("NewStringIterator"); return AttachDecision::Attach; @@ -8377,7 +8131,6 @@ } writer.newRegExpStringIteratorResult(templateObj); writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("NewRegExpStringIterator"); return AttachDecision::Attach; @@ -8412,10 +8165,7 @@ // Ensure that proto[slot] == nextFun. writer.guardDynamicSlotIsSpecificObject(protoId, nextId, slot); writer.loadBooleanResult(true); - - // This stub does not need to be monitored, it always returns a boolean. writer.returnFromIC(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Regular; trackAttached("ArrayIteratorPrototypeOptimizable"); return AttachDecision::Attach; @@ -8459,7 +8209,6 @@ writer.objectCreateResult(templateObj); writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("ObjectCreate"); return AttachDecision::Attach; @@ -8521,7 +8270,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("ArrayConstructor"); return AttachDecision::Attach; @@ -8624,7 +8372,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("TypedArrayConstructor"); return AttachDecision::Attach; @@ -8717,7 +8464,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; if (isScripted) { trackAttached("Scripted fun_apply"); @@ -8845,7 +8591,6 @@ inst.object()); writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("WasmCall"); return AttachDecision::Attach; @@ -9413,7 +9158,6 @@ writer.callScriptedFunction(calleeObjId, argcId, flags); writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; if (isSpecialized) { trackAttached("Call scripted func"); } else { @@ -9594,7 +9338,6 @@ } writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; if (templateObj) { MOZ_ASSERT(isSpecialized); @@ -9644,7 +9387,6 @@ writer.callClassHook(calleeObjId, argcId, hook, flags); writer.typeMonitorResult(); - cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored; trackAttached("Call native func"); return AttachDecision::Attach; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/CacheIR.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/CacheIR.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/CacheIR.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/CacheIR.h 2020-11-17 19:31:31.000000000 +0000 @@ -1447,6 +1447,7 @@ }; // Information used by SetProp/SetElem stubs to check/update property types. +// TODO(no-TI): remove. class MOZ_RAII PropertyTypeCheckInfo { RootedObjectGroup group_; RootedId id_; @@ -1745,7 +1746,6 @@ HandleValue newTarget_; HandleValueArray args_; PropertyTypeCheckInfo typeCheckInfo_; - BaselineCacheIRStubKind cacheIRStubKind_; ScriptedThisResult getThisForScripted(HandleFunction calleeFunc, MutableHandleObject result); @@ -1887,8 +1887,6 @@ AttachDecision tryAttachDeferredStub(HandleValue result); - BaselineCacheIRStubKind cacheIRStubKind() const { return cacheIRStubKind_; } - const PropertyTypeCheckInfo* typeCheckInfo() const { return &typeCheckInfo_; } }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/CodeGenerator.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/CodeGenerator.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/CodeGenerator.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/CodeGenerator.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -1406,7 +1406,8 @@ int(mightBeString) + int(mightBeSymbol) + int(mightBeDouble) + int(mightBeBigInt); - MOZ_ASSERT_IF(!valueMIR->emptyResultTypeSet(), tagCount > 0); + // TODO(no-TI): clean up this function. + MOZ_ASSERT(tagCount > 0); // If we know we're null or undefined, we're definitely falsy, no // need to even check the tag. @@ -5110,51 +5111,6 @@ emitCreateBigInt(lir, Scalar::BigInt64, input, output, temp); } -void CodeGenerator::visitTypeBarrierV(LTypeBarrierV* lir) { - ValueOperand operand = ToValue(lir, LTypeBarrierV::Input); - Register unboxScratch = ToTempRegisterOrInvalid(lir->unboxTemp()); - Register objScratch = ToTempRegisterOrInvalid(lir->objTemp()); - - // guardObjectType may zero the payload/Value register on speculative paths - // (we should have a defineReuseInput allocation in this case). - Register spectreRegToZero = operand.payloadOrValueReg(); - - Label miss; - masm.guardTypeSet(operand, lir->mir()->resultTypeSet(), - lir->mir()->barrierKind(), unboxScratch, objScratch, - spectreRegToZero, &miss); - bailoutFrom(&miss, lir->snapshot()); -} - -void CodeGenerator::visitTypeBarrierO(LTypeBarrierO* lir) { - Register obj = ToRegister(lir->object()); - Register scratch = ToTempRegisterOrInvalid(lir->temp()); - Label miss, ok; - - if (lir->mir()->type() == MIRType::ObjectOrNull) { - masm.comment("Object or Null"); - Label* nullTarget = - lir->mir()->resultTypeSet()->mightBeMIRType(MIRType::Null) ? &ok - : &miss; - masm.branchTestPtr(Assembler::Zero, obj, obj, nullTarget); - } else { - MOZ_ASSERT(lir->mir()->type() == MIRType::Object); - MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly); - } - - if (lir->mir()->barrierKind() != BarrierKind::TypeTagOnly) { - masm.comment("Type tag only"); - // guardObjectType may zero the object register on speculative paths - // (we should have a defineReuseInput allocation in this case). - Register spectreRegToZero = obj; - masm.guardObjectType(obj, lir->mir()->resultTypeSet(), scratch, - spectreRegToZero, &miss); - } - - bailoutFrom(&miss, lir->snapshot()); - masm.bind(&ok); -} - void CodeGenerator::visitGuardValue(LGuardValue* lir) { ValueOperand input = ToValue(lir, LGuardValue::Input); Value expected = lir->mir()->expected(); @@ -6647,89 +6603,6 @@ callVM(lir); } -void CodeGenerator::generateArgumentsChecks(bool assert) { - // This function can be used the normal way to check the argument types, - // before entering the function and bailout when arguments don't match. - // For debug purpose, this is can also be used to force/check that the - // arguments are correct. Upon fail it will hit a breakpoint. - - if (!IsTypeInferenceEnabled()) { - return; - } - - MIRGraph& mir = gen->graph(); - MResumePoint* rp = mir.entryResumePoint(); - - // No registers are allocated yet, so it's safe to grab anything. - AllocatableGeneralRegisterSet temps(GeneralRegisterSet::All()); - Register temp1 = temps.takeAny(); - Register temp2 = temps.takeAny(); - - masm.debugAssertContextRealm(gen->realm->realmPtr(), temp1); - - const CompileInfo& info = gen->outerInfo(); - - Label miss; - for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) { - // All initial parameters are guaranteed to be MParameters. - MParameter* param = rp->getOperand(i)->toParameter(); - const TypeSet* types = param->resultTypeSet(); - if (!types || types->unknown()) { - continue; - } - - // Calculate the offset on the stack of the argument. - // (i - info.startArgSlot()) - Compute index of arg within arg vector. - // ... * sizeof(Value) - Scale by value size. - // ArgToStackOffset(...) - Compute displacement within arg vector. - int32_t offset = - ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value)); - Address argAddr(masm.getStackPointer(), offset); - - // guardObjectType will zero the stack pointer register on speculative - // paths. - Register spectreRegToZero = AsRegister(masm.getStackPointer()); - masm.guardTypeSet(argAddr, types, BarrierKind::TypeSet, temp1, temp2, - spectreRegToZero, &miss); - } - - if (miss.used()) { - if (assert) { -#ifdef DEBUG - Label success; - masm.jump(&success); - masm.bind(&miss); - - // Check for cases where the type set guard might have missed due to - // changing object groups. - for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) { - MParameter* param = rp->getOperand(i)->toParameter(); - const TemporaryTypeSet* types = param->resultTypeSet(); - if (!types || types->unknown()) { - continue; - } - - Label skip; - Address addr( - masm.getStackPointer(), - ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value))); - masm.branchTestObject(Assembler::NotEqual, addr, &skip); - Register obj = masm.extractObject(addr, temp1); - masm.guardTypeSetMightBeIncomplete(types, obj, temp1, &success); - masm.bind(&skip); - } - - masm.assumeUnreachable("Argument check fail."); - masm.bind(&success); -#else - MOZ_CRASH("Shouldn't get here in opt builds"); -#endif - } else { - bailoutFrom(&miss, graph.entrySnapshot()); - } - } -} - // Out-of-line path to report over-recursed error and fail. class CheckOverRecursedFailure : public OutOfLineCodeBase { LInstruction* lir_; @@ -6970,37 +6843,6 @@ Label done; branchIfInvalidated(temp, &done); - const TemporaryTypeSet* typeset = mir->resultTypeSet(); - if ((type == MIRType::Object || type == MIRType::ObjectOrNull) && typeset && - !typeset->unknownObject()) { - // We have a result TypeSet, assert this object is in it. - Label miss, ok; - if (type == MIRType::ObjectOrNull) { - masm.branchPtr(Assembler::Equal, input, ImmWord(0), &ok); - } - if (typeset->getObjectCount() > 0) { - masm.guardObjectType(input, typeset, temp, input, &miss); - } else { - masm.jump(&miss); - } - masm.jump(&ok); - - masm.bind(&miss); - masm.guardTypeSetMightBeIncomplete(typeset, input, temp, &ok); - - switch (mir->op()) { -# define MIR_OP(op) \ - case MDefinition::Opcode::op: \ - masm.assumeUnreachable( \ - #op " instruction returned object with unexpected type"); \ - break; - MIR_OPCODE_LIST(MIR_OP) -# undef MIR_OP - } - - masm.bind(&ok); - } - # ifndef JS_SIMULATOR // Check that we have a valid GC pointer. // Disable for wasm because we don't have a context on wasm compilation @@ -7067,37 +6909,6 @@ Label done; branchIfInvalidated(temp1, &done); - const TemporaryTypeSet* typeset = mir->resultTypeSet(); - if (typeset && !typeset->unknown()) { - // We have a result TypeSet, assert this value is in it. - Label miss, ok; - masm.guardTypeSet(input, typeset, BarrierKind::TypeSet, temp1, temp2, - input.payloadOrValueReg(), &miss); - masm.jump(&ok); - - masm.bind(&miss); - - // Check for cases where the type set guard might have missed due to - // changing object groups. - Label realMiss; - masm.branchTestObject(Assembler::NotEqual, input, &realMiss); - Register payload = masm.extractObject(input, temp1); - masm.guardTypeSetMightBeIncomplete(typeset, payload, temp1, &ok); - masm.bind(&realMiss); - - switch (mir->op()) { -# define MIR_OP(op) \ - case MDefinition::Opcode::op: \ - masm.assumeUnreachable( \ - #op " instruction returned value with unexpected type"); \ - break; - MIR_OPCODE_LIST(MIR_OP) -# undef MIR_OP - } - - masm.bind(&ok); - } - // Check that we have a valid GC pointer. if (JitOptions.fullDebugChecks) { saveVolatile(); @@ -11516,11 +11327,6 @@ return false; } - // Before generating any code, we generate type checks for all parameters. - // This comes before deoptTable_, because we can't use deopt tables without - // creating the actual frame. - generateArgumentsChecks(); - if (frameClass_ != FrameSizeClass::None()) { deoptTable_.emplace(gen->jitRuntime()->getBailoutTable(frameClass_)); } @@ -11542,11 +11348,6 @@ masm.bind(&skipPrologue); } -#ifdef DEBUG - // Assert that the argument types are correct. - generateArgumentsChecks(/* assert = */ true); -#endif - // Reset native => bytecode map table with top-level script and startPc. if (!addNativeToBytecodeEntry(startSite)) { return false; @@ -11672,16 +11473,10 @@ // skip the current compilation. bool isValid = false; - if (JitOptions.warpBuilder) { - // If an inlined script is invalidated (for example, by attaching - // a debugger), we must also invalidate the parent IonScript. - if (!AddInlinedCompilations(script, compilationId, snapshot, &isValid)) { - return false; - } - } else { - if (!FinishCompilation(cx, script, constraints, compilationId, &isValid)) { - return false; - } + // If an inlined script is invalidated (for example, by attaching + // a debugger), we must also invalidate the parent IonScript. + if (!AddInlinedCompilations(script, compilationId, snapshot, &isValid)) { + return false; } if (!isValid) { return true; @@ -12316,38 +12111,8 @@ static GetPropertyResultFlags IonGetPropertyICFlags( const MGetPropertyCache* mir) { - GetPropertyResultFlags flags = GetPropertyResultFlags::None; - if (mir->monitoredResult()) { - flags |= GetPropertyResultFlags::Monitored; - } - - if (mir->type() == MIRType::Value) { - if (TemporaryTypeSet* types = mir->resultTypeSet()) { - if (types->hasType(TypeSet::UndefinedType())) { - flags |= GetPropertyResultFlags::AllowUndefined; - } - if (types->hasType(TypeSet::Int32Type())) { - flags |= GetPropertyResultFlags::AllowInt32; - } - if (types->hasType(TypeSet::DoubleType())) { - flags |= GetPropertyResultFlags::AllowDouble; - } - } else { - flags |= GetPropertyResultFlags::AllowUndefined | - GetPropertyResultFlags::AllowInt32 | - GetPropertyResultFlags::AllowDouble; - } - } else if (mir->type() == MIRType::Int32) { - flags |= GetPropertyResultFlags::AllowInt32; - } else if (mir->type() == MIRType::Double) { - flags |= GetPropertyResultFlags::AllowInt32 | - GetPropertyResultFlags::AllowDouble; - } - - // If WarpBuilder is enabled the IC should support all possible results. - MOZ_ASSERT_IF(JitOptions.warpBuilder, flags == GetPropertyResultFlags::All); - - return flags; + // TODO(no-TI): remove this. + return GetPropertyResultFlags::All; } void CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV* ins) { @@ -12546,7 +12311,8 @@ unsigned(testNull) + unsigned(testString) + unsigned(testSymbol) + unsigned(testBigInt); - MOZ_ASSERT_IF(!input->emptyResultTypeSet(), numTests > 0); + // TODO(no-TI): clean this up. + MOZ_ASSERT(numTests > 0); OutOfLineTypeOfV* ool = nullptr; if (testObject) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/CodeGenerator.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/CodeGenerator.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/CodeGenerator.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/CodeGenerator.h 2020-11-17 19:31:32.000000000 +0000 @@ -69,7 +69,6 @@ class OutOfLineBoxNonStrictThis; class CodeGenerator final : public CodeGeneratorSpecific { - void generateArgumentsChecks(bool assert = false); MOZ_MUST_USE bool generateBody(); ConstantOrRegister toConstantOrRegister(LInstruction* lir, size_t n, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/InlinableNatives.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/InlinableNatives.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/InlinableNatives.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/InlinableNatives.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -16,6 +16,7 @@ # include "builtin/intl/RelativeTimeFormat.h" #endif #include "builtin/MapObject.h" +#include "js/experimental/JitInfo.h" #include "vm/ArrayBufferObject.h" #include "vm/AsyncIteration.h" #include "vm/Iteration.h" @@ -24,6 +25,15 @@ using namespace js; using namespace js::jit; +#define ADD_NATIVE(native) \ + const JSJitInfo js::jit::JitInfo_##native{ \ + {nullptr}, \ + {uint16_t(InlinableNative::native)}, \ + {0}, \ + JSJitInfo::InlinableNative}; +INLINABLE_NATIVE_LIST(ADD_NATIVE) +#undef ADD_NATIVE + const JSClass* js::jit::InlinableNativeGuardToClass(InlinableNative native) { switch (native) { #ifdef JS_HAS_INTL_API diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/InlineScriptTree.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/InlineScriptTree.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/InlineScriptTree.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/InlineScriptTree.h 2020-11-17 19:31:32.000000000 +0000 @@ -44,13 +44,14 @@ children_(nullptr), nextCallee_(nullptr) {} - static InlineScriptTree* New(TempAllocator* allocator, - InlineScriptTree* caller, jsbytecode* callerPc, - JSScript* script); + static inline InlineScriptTree* New(TempAllocator* allocator, + InlineScriptTree* caller, + jsbytecode* callerPc, JSScript* script); - InlineScriptTree* addCallee(TempAllocator* allocator, jsbytecode* callerPc, - JSScript* calleeScript); - void removeCallee(InlineScriptTree* callee); + inline InlineScriptTree* addCallee(TempAllocator* allocator, + jsbytecode* callerPc, + JSScript* calleeScript); + inline void removeCallee(InlineScriptTree* callee); InlineScriptTree* caller() const { return caller_; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/IonAnalysis.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/IonAnalysis.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/IonAnalysis.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/IonAnalysis.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -10,12 +10,10 @@ #include // for ::std::pair #include "jit/AliasAnalysis.h" -#include "jit/BaselineInspector.h" #include "jit/BaselineJIT.h" #include "jit/CompileInfo.h" #include "jit/InlineScriptTree.h" #include "jit/Ion.h" -#include "jit/IonBuilder.h" #include "jit/IonOptimizationLevels.h" #include "jit/LIR.h" #include "jit/Lowering.h" @@ -28,6 +26,7 @@ #include "vm/SelfHosting.h" #include "vm/TypeInference.h" +#include "jit/InlineScriptTree-inl.h" #include "jit/shared/Lowering-shared-inl.h" #include "vm/BytecodeUtil-inl.h" #include "vm/JSObject-inl.h" @@ -723,55 +722,13 @@ // // 1) phi(a, a) // can get replaced by a -// -// 2) phi(filtertypeset(a, type1), filtertypeset(a, type1)) -// equals filtertypeset(a, type1) -// -// 3) phi(a, filtertypeset(a, type1)) -// equals filtertypeset(a, type1 union type(a)) -// equals filtertypeset(a, type(a)) -// equals a -// -// 4) phi(filtertypeset(a, type1), filtertypeset(a, type2)) -// equals filtertypeset(a, type1 union type2) -// -// This is the special case. We can only replace this with 'a' iif -// type(a) == type1 union type2. Since optimizations could have -// happened based on a more specific phi type. static bool IsPhiRedudantFilter(MPhi* phi) { - // Handle (1) and (2) + // TODO(no-TI): clean up. if (phi->operandIfRedundant()) { return true; } - // Handle (3) - bool onlyFilters = false; - MDefinition* a = phi->getOperand(0); - if (a->isFilterTypeSet()) { - a = a->toFilterTypeSet()->input(); - onlyFilters = true; - } - - for (size_t i = 1; i < phi->numOperands(); i++) { - MDefinition* operand = phi->getOperand(i); - if (operand == a) { - onlyFilters = false; - continue; - } - if (operand->isFilterTypeSet() && - operand->toFilterTypeSet()->input() == a) { - continue; - } - return false; - } - if (!onlyFilters) { - return true; - } - - // Handle (4) - MOZ_ASSERT(onlyFilters); - return EqualTypes(a->type(), a->resultTypeSet(), phi->type(), - phi->resultTypeSet()); + return false; } // Determine whether phiBlock/testBlock simply compute a phi and perform a @@ -1001,9 +958,6 @@ if (!redundant) { redundant = (*iter)->getOperand(0); - if (redundant->isFilterTypeSet()) { - redundant = redundant->toFilterTypeSet()->input(); - } } (*iter)->replaceAllUsesWith(redundant); @@ -1201,8 +1155,7 @@ // parameter passing might be live. Rewriting uses of these terms // in resume points may affect the interpreter's behavior. Rather // than doing a more sophisticated analysis, just ignore these. - if (ins->isUnbox() || ins->isParameter() || ins->isTypeBarrier() || - ins->isBoxNonStrictThis() || ins->isFilterTypeSet()) { + if (ins->isUnbox() || ins->isParameter() || ins->isBoxNonStrictThis()) { continue; } @@ -1704,12 +1657,7 @@ } } - // Ignore operands which we've never observed, unless this caused a - // bailout in a previous compilation of this script. - if (in->resultTypeSet() && in->resultTypeSet()->empty()) { - *hasInputsWithEmptyTypes = true; - continue; - } + // TODO(no-TI): remove hasInputsWithEmptyTypes. // See shouldSpecializeOsrPhis comment. This is the first step mentioned // there. @@ -3540,202 +3488,13 @@ return true; } -static void TryEliminateTypeBarrierFromTest(MTypeBarrier* barrier, - bool filtersNull, - bool filtersUndefined, MTest* test, - BranchDirection direction, - bool* eliminated) { - MOZ_ASSERT(filtersNull || filtersUndefined); - - // Watch for code patterns similar to 'if (x.f) { ... = x.f }'. If x.f - // is either an object or null/undefined, there will be a type barrier on - // the latter read as the null/undefined value is never realized there. - // The type barrier can be eliminated, however, by looking at tests - // performed on the result of the first operation that filter out all - // types that have been seen in the first access but not the second. - - // A test 'if (x.f)' filters both null and undefined. - - // Disregard the possible unbox added before the Typebarrier for checking. - MDefinition* input = barrier->input(); - MUnbox* inputUnbox = nullptr; - if (input->isUnbox() && input->toUnbox()->mode() != MUnbox::Fallible) { - inputUnbox = input->toUnbox(); - input = inputUnbox->input(); - } - - MDefinition* subject = nullptr; - bool removeUndefined; - bool removeNull; - test->filtersUndefinedOrNull(direction == TRUE_BRANCH, &subject, - &removeUndefined, &removeNull); - - // The Test doesn't filter undefined nor null. - if (!subject) { - return; - } - - // Make sure the subject equals the input to the TypeBarrier. - if (subject != input) { - return; - } - - // When the TypeBarrier filters undefined, the test must at least also do, - // this, before the TypeBarrier can get removed. - if (!removeUndefined && filtersUndefined) { - return; - } - - // When the TypeBarrier filters null, the test must at least also do, - // this, before the TypeBarrier can get removed. - if (!removeNull && filtersNull) { - return; - } - - // Eliminate the TypeBarrier. The possible TypeBarrier unboxing is kept, - // but made infallible. - *eliminated = true; - if (inputUnbox) { - inputUnbox->makeInfallible(); - } - barrier->replaceAllUsesWith(barrier->input()); -} - -static bool TryEliminateTypeBarrier(MTypeBarrier* barrier, bool* eliminated) { - MOZ_ASSERT(!*eliminated); - - const TemporaryTypeSet* barrierTypes = barrier->resultTypeSet(); - const TemporaryTypeSet* inputTypes = barrier->input()->resultTypeSet(); - - // Disregard the possible unbox added before the Typebarrier. - if (barrier->input()->isUnbox() && - barrier->input()->toUnbox()->mode() != MUnbox::Fallible) { - inputTypes = barrier->input()->toUnbox()->input()->resultTypeSet(); - } - - if (!barrierTypes || !inputTypes) { - return true; - } - - bool filtersNull = barrierTypes->filtersType(inputTypes, TypeSet::NullType()); - bool filtersUndefined = - barrierTypes->filtersType(inputTypes, TypeSet::UndefinedType()); - - if (!filtersNull && !filtersUndefined) { - return true; - } - - MBasicBlock* block = barrier->block(); - while (true) { - BranchDirection direction; - MTest* test = block->immediateDominatorBranch(&direction); - - if (test) { - TryEliminateTypeBarrierFromTest(barrier, filtersNull, filtersUndefined, - test, direction, eliminated); - } - - MBasicBlock* previous = block->immediateDominator(); - if (previous == block) { - break; - } - block = previous; - } - - return true; -} - static bool TryOptimizeLoadObjectOrNull(MDefinition* def, MDefinitionVector* peliminateList) { if (def->type() != MIRType::Value) { return true; } - // Check if this definition can only produce object or null values. - TemporaryTypeSet* types = def->resultTypeSet(); - if (!types) { - return true; - } - if (types->baseFlags() & ~(TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT)) { - return true; - } - - MDefinitionVector eliminateList(def->block()->graph().alloc()); - - for (MUseDefIterator iter(def); iter; ++iter) { - MDefinition* ndef = iter.def(); - switch (ndef->op()) { - case MDefinition::Opcode::Compare: - if (ndef->toCompare()->compareType() != MCompare::Compare_Null) { - return true; - } - break; - case MDefinition::Opcode::Test: - break; - case MDefinition::Opcode::PostWriteBarrier: - break; - case MDefinition::Opcode::StoreFixedSlot: - break; - case MDefinition::Opcode::StoreDynamicSlot: - break; - case MDefinition::Opcode::ToObjectOrNull: - if (!eliminateList.append(ndef->toToObjectOrNull())) { - return false; - } - break; - case MDefinition::Opcode::Unbox: - if (ndef->type() != MIRType::Object) { - return true; - } - break; - case MDefinition::Opcode::TypeBarrier: - // For now, only handle type barriers which are not consumed - // anywhere and only test that the value is null. - if (ndef->hasUses() || - ndef->resultTypeSet()->getKnownMIRType() != MIRType::Null) { - return true; - } - break; - default: - return true; - } - } - - // On punboxing systems we are better off leaving the value boxed if it - // is only stored back to the heap. -#ifdef JS_PUNBOX64 - bool foundUse = false; - for (MUseDefIterator iter(def); iter; ++iter) { - MDefinition* ndef = iter.def(); - if (!ndef->isStoreFixedSlot() && !ndef->isStoreDynamicSlot()) { - foundUse = true; - break; - } - } - if (!foundUse) { - return true; - } -#endif // JS_PUNBOX64 - - def->setResultType(MIRType::ObjectOrNull); - - // Fixup the result type of MTypeBarrier uses. - for (MUseDefIterator iter(def); iter; ++iter) { - MDefinition* ndef = iter.def(); - if (ndef->isTypeBarrier()) { - ndef->setResultType(MIRType::ObjectOrNull); - } - } - - // Eliminate MToObjectOrNull instruction uses. - for (size_t i = 0; i < eliminateList.length(); i++) { - MDefinition* ndef = eliminateList[i]; - ndef->replaceAllUsesWith(def); - if (!peliminateList->append(ndef)) { - return false; - } - } - + // TODO(no-TI): remove more code. return true; } @@ -3806,11 +3565,6 @@ return false; } break; - case MDefinition::Opcode::TypeBarrier: - if (!TryEliminateTypeBarrier(def->toTypeBarrier(), &eliminated)) { - return false; - } - break; case MDefinition::Opcode::LoadFixedSlot: case MDefinition::Opcode::LoadDynamicSlot: if (!TryOptimizeLoadObjectOrNull(def, &eliminateList)) { @@ -4162,362 +3916,11 @@ return def; } -static bool AnalyzePoppedThis(JSContext* cx, DPAConstraintInfo& constraintInfo, - ObjectGroup* group, MDefinition* thisValue, - MInstruction* ins, bool definitelyExecuted, - HandlePlainObject baseobj, - Vector* initializerList, - Vector* accessedProperties, - bool* phandled) { - // Determine the effect that a use of the |this| value when calling |new| - // on a script has on the properties definitely held by the new object. - - if (ins->isCallSetProperty()) { - MCallSetProperty* setprop = ins->toCallSetProperty(); - - if (setprop->object() != thisValue) { - return true; - } - - if (setprop->name() == cx->names().prototype || - setprop->name() == cx->names().proto || - setprop->name() == cx->names().constructor) { - return true; - } - - // Ignore assignments to properties that were already written to. - if (baseobj->lookup(cx, NameToId(setprop->name()))) { - *phandled = true; - return true; - } - - // Don't add definite properties for properties that were already - // read in the constructor. - for (size_t i = 0; i < accessedProperties->length(); i++) { - if ((*accessedProperties)[i] == setprop->name()) { - return true; - } - } - - // Assignments to new properties must always execute. - if (!definitelyExecuted) { - return true; - } - - RootedId id(cx, NameToId(setprop->name())); - bool added = false; - if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, constraintInfo, - group, id, &added)) { - return false; - } - if (!added) { - // The prototype chain already contains a getter/setter for this - // property, or type information is too imprecise. - return true; - } - - // Add the property to the object, being careful not to update type - // information. - DebugOnly slotSpan = baseobj->slotSpan(); - MOZ_ASSERT(!baseobj->containsPure(id)); - if (!NativeObject::addDataProperty(cx, baseobj, id, SHAPE_INVALID_SLOT, - JSPROP_ENUMERATE)) { - return false; - } - MOZ_ASSERT(baseobj->slotSpan() != slotSpan); - MOZ_ASSERT(!baseobj->inDictionaryMode()); - - Vector callerResumePoints(cx); - for (MResumePoint* rp = ins->block()->callerResumePoint(); rp; - rp = rp->block()->callerResumePoint()) { - if (!callerResumePoints.append(rp)) { - return false; - } - } - - for (int i = callerResumePoints.length() - 1; i >= 0; i--) { - MResumePoint* rp = callerResumePoints[i]; - JSScript* script = rp->block()->info().script(); - TypeNewScriptInitializer entry(TypeNewScriptInitializer::SETPROP_FRAME, - script->pcToOffset(rp->pc())); - if (!initializerList->append(entry)) { - return false; - } - } - - JSScript* script = ins->block()->info().script(); - TypeNewScriptInitializer entry( - TypeNewScriptInitializer::SETPROP, - script->pcToOffset(setprop->resumePoint()->pc())); - if (!initializerList->append(entry)) { - return false; - } - - *phandled = true; - return true; - } - - if (ins->isCallGetProperty()) { - MCallGetProperty* get = ins->toCallGetProperty(); - - /* - * Properties can be read from the 'this' object if the following hold: - * - * - The read is not on a getter along the prototype chain, which - * could cause 'this' to escape. - * - * - The accessed property is either already a definite property or - * is not later added as one. Since the definite properties are - * added to the object at the point of its creation, reading a - * definite property before it is assigned could incorrectly hit. - */ - RootedId id(cx, NameToId(get->name())); - if (!baseobj->lookup(cx, id) && !accessedProperties->append(get->name())) { - return false; - } - - bool added = false; - if (!AddClearDefiniteGetterSetterForPrototypeChain(cx, constraintInfo, - group, id, &added)) { - return false; - } - if (!added) { - // The |this| value can escape if any property reads it does go - // through a getter. - return true; - } - - *phandled = true; - return true; - } - - if (ins->isPostWriteBarrier()) { - *phandled = true; - return true; - } - - return true; -} - -static int CmpInstructions(const void* a, const void* b) { - return (*static_cast(a))->id() - - (*static_cast(b))->id(); -} - bool jit::AnalyzeNewScriptDefiniteProperties( JSContext* cx, DPAConstraintInfo& constraintInfo, HandleFunction fun, ObjectGroup* group, HandlePlainObject baseobj, Vector* initializerList) { - MOZ_ASSERT(cx->zone()->types.activeAnalysis); - - // When invoking 'new' on the specified script, try to find some properties - // which will definitely be added to the created object before it has a - // chance to escape and be accessed elsewhere. - - RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun)); - if (!script) { - return false; - } - - if (!jit::IsIonEnabled(cx) || !jit::IsBaselineJitEnabled(cx) || - !CanBaselineInterpretScript(script)) { - return true; - } - - static const uint32_t MAX_SCRIPT_SIZE = 2000; - if (script->length() > MAX_SCRIPT_SIZE) { - return true; - } - - TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx); - TraceLoggerEvent event(TraceLogger_AnnotateScripts, script); - AutoTraceLog logScript(logger, event); - AutoTraceLog logCompile(logger, TraceLogger_IonAnalysis); - - Vector accessedProperties(cx); - - LifoAlloc alloc(TempAllocator::PreferredLifoChunkSize); - TempAllocator temp(&alloc); - JitContext jctx(cx, &temp); - - if (!jit::CanLikelyAllocateMoreExecutableMemory()) { - return true; - } - - if (!cx->realm()->ensureJitRealmExists(cx)) { - return false; - } - - AutoKeepJitScripts keepJitScript(cx); - if (!script->ensureHasJitScript(cx, keepJitScript)) { - return false; - } - - JitScript::MonitorThisType(cx, script, TypeSet::ObjectType(group)); - - MIRGraph graph(&temp); - InlineScriptTree* inlineScriptTree = - InlineScriptTree::New(&temp, nullptr, nullptr, script); - if (!inlineScriptTree) { - return false; - } - - CompileInfo info(CompileRuntime::get(cx->runtime()), script, fun, - /* osrPc = */ nullptr, Analysis_DefiniteProperties, - script->needsArgsObj(), inlineScriptTree); - - const OptimizationInfo* optimizationInfo = - IonOptimizations.get(OptimizationLevel::Full); - - CompilerConstraintList* constraints = NewCompilerConstraintList(temp); - if (!constraints) { - ReportOutOfMemory(cx); - return false; - } - - BaselineInspector inspector(script); - const JitCompileOptions options(cx); - - MIRGenerator mirGen(CompileRealm::get(cx->realm()), options, &temp, &graph, - &info, optimizationInfo); - IonBuilder builder(cx, mirGen, &info, constraints, &inspector, - /* baselineFrame = */ nullptr); - - AbortReasonOr buildResult = builder.build(); - if (buildResult.isErr()) { - AbortReason reason = buildResult.unwrapErr(); - if (cx->isThrowingOverRecursed() || cx->isThrowingOutOfMemory()) { - return false; - } - if (reason == AbortReason::Alloc) { - ReportOutOfMemory(cx); - return false; - } - MOZ_ASSERT(!cx->isExceptionPending()); - return true; - } - - FinishDefinitePropertiesAnalysis(cx, constraints); - - if (!SplitCriticalEdges(graph)) { - ReportOutOfMemory(cx); - return false; - } - - RenumberBlocks(graph); - - if (!BuildDominatorTree(graph)) { - ReportOutOfMemory(cx); - return false; - } - - if (!EliminatePhis(&mirGen, graph, AggressiveObservability)) { - ReportOutOfMemory(cx); - return false; - } - - MDefinition* thisValue = graph.entryBlock()->getSlot(info.thisSlot()); - - // Get a list of instructions using the |this| value in the order they - // appear in the graph. - Vector instructions(cx); - - for (MUseDefIterator uses(thisValue); uses; uses++) { - MDefinition* use = uses.def(); - - // Don't track |this| through assignments to phis. - if (!use->isInstruction()) { - return true; - } - - if (!instructions.append(use->toInstruction())) { - return false; - } - } - - // Sort the instructions to visit in increasing order. - qsort(instructions.begin(), instructions.length(), sizeof(MInstruction*), - CmpInstructions); - - // Find all exit blocks in the graph. - Vector exitBlocks(cx); - for (MBasicBlockIterator block(graph.begin()); block != graph.end(); - block++) { - if (!block->numSuccessors() && !exitBlocks.append(*block)) { - return false; - } - } - - // id of the last block which added a new property. - size_t lastAddedBlock = 0; - - for (size_t i = 0; i < instructions.length(); i++) { - MInstruction* ins = instructions[i]; - - // Track whether the use of |this| is in unconditional code, i.e. - // the block dominates all graph exits. - bool definitelyExecuted = true; - for (size_t i = 0; i < exitBlocks.length(); i++) { - for (MBasicBlock* exit = exitBlocks[i]; exit != ins->block(); - exit = exit->immediateDominator()) { - if (exit == exit->immediateDominator()) { - definitelyExecuted = false; - break; - } - } - } - - // Also check to see if the instruction is inside a loop body. Even if - // an access will always execute in the script, if it executes multiple - // times then we can get confused when rolling back objects while - // clearing the new script information. - if (ins->block()->loopDepth() != 0) { - definitelyExecuted = false; - } - - bool handled = false; - size_t slotSpan = baseobj->slotSpan(); - if (!AnalyzePoppedThis(cx, constraintInfo, group, thisValue, ins, - definitelyExecuted, baseobj, initializerList, - &accessedProperties, &handled)) { - return false; - } - if (!handled) { - break; - } - - if (slotSpan != baseobj->slotSpan()) { - MOZ_ASSERT(ins->block()->id() >= lastAddedBlock); - lastAddedBlock = ins->block()->id(); - } - } - - if (baseobj->slotSpan() != 0) { - // We found some definite properties, but their correctness is still - // contingent on the correct frames being inlined. Add constraints to - // invalidate the definite properties if additional functions could be - // called at the inline frame sites. - for (MBasicBlockIterator block(graph.begin()); block != graph.end(); - block++) { - // Inlining decisions made after the last new property was added to - // the object don't need to be frozen. - if (block->id() > lastAddedBlock) { - break; - } - if (MResumePoint* rp = block->callerResumePoint()) { - if (block->numPredecessors() == 1 && - block->getPredecessor(0) == rp->block()) { - JSScript* caller = rp->block()->info().script(); - JSScript* callee = block->info().script(); - if (!constraintInfo.addInliningConstraint(caller, callee)) { - return false; - } - } - } - } - } - - return true; + MOZ_CRASH("TODO(no-TI): delete"); } static bool ArgumentsUseCanBeLazy(JSContext* cx, JSScript* script, @@ -4662,7 +4065,7 @@ MIRGenerator mirGen(CompileRealm::get(cx->realm()), options, &temp, &graph, &info, optimizationInfo); - if (JitOptions.warpBuilder) { + { WarpOracle oracle(cx, mirGen, script); AbortReasonOr result = oracle.createSnapshot(); @@ -4685,30 +4088,6 @@ ReportOutOfMemory(cx); return false; } - } else { - CompilerConstraintList* constraints = NewCompilerConstraintList(temp); - if (!constraints) { - ReportOutOfMemory(cx); - return false; - } - - BaselineInspector inspector(script); - IonBuilder builder(nullptr, mirGen, &info, constraints, &inspector, - /* baselineFrame = */ nullptr); - - AbortReasonOr buildResult = builder.build(); - if (buildResult.isErr()) { - AbortReason reason = buildResult.unwrapErr(); - if (cx->isThrowingOverRecursed() || cx->isThrowingOutOfMemory()) { - return false; - } - if (reason == AbortReason::Alloc) { - ReportOutOfMemory(cx); - return false; - } - MOZ_ASSERT(!cx->isExceptionPending()); - return true; - } } if (!SplitCriticalEdges(graph)) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/IonBuilder.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/IonBuilder.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/IonBuilder.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/IonBuilder.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,12928 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "jit/IonBuilder.h" - -#include "mozilla/DebugOnly.h" -#include "mozilla/ScopeExit.h" - -#include - -#include "builtin/Eval.h" -#include "builtin/ModuleObject.h" -#include "frontend/SourceNotes.h" -#include "jit/BaselineFrame.h" -#include "jit/BaselineInspector.h" -#include "jit/CacheIR.h" -#include "jit/CompileInfo.h" -#include "jit/InlineScriptTree.h" -#include "jit/Ion.h" -#include "jit/IonOptimizationLevels.h" -#include "jit/JitSpewer.h" -#include "jit/Lowering.h" -#include "jit/MIRGraph.h" -#include "js/experimental/JitInfo.h" // JSJitInfo -#include "js/friend/ErrorMessages.h" // JSMSG_* -#include "js/Object.h" // JS::GetReservedSlot -#include "js/ScalarType.h" // js::Scalar::Type -#include "util/CheckedArithmetic.h" -#include "vm/ArgumentsObject.h" -#include "vm/BuiltinObjectKind.h" -#include "vm/BytecodeIterator.h" -#include "vm/BytecodeLocation.h" -#include "vm/BytecodeUtil.h" -#include "vm/Instrumentation.h" -#include "vm/Opcodes.h" -#include "vm/PlainObject.h" // js::PlainObject -#include "vm/RegExpStatics.h" -#include "vm/SelfHosting.h" -#include "vm/TraceLogging.h" -#include "wasm/TypedObject.h" - -#include "gc/Nursery-inl.h" -#include "jit/CompileInfo-inl.h" -#include "jit/InlineScriptTree-inl.h" -#include "jit/shared/Lowering-shared-inl.h" -#include "vm/BytecodeIterator-inl.h" -#include "vm/BytecodeLocation-inl.h" -#include "vm/BytecodeUtil-inl.h" -#include "vm/EnvironmentObject-inl.h" -#include "vm/JSScript-inl.h" -#include "vm/NativeObject-inl.h" -#include "vm/ObjectGroup-inl.h" - -using namespace js; -using namespace js::jit; - -using mozilla::AssertedCast; -using mozilla::DebugOnly; -using mozilla::Maybe; -using mozilla::Nothing; - -class jit::BaselineFrameInspector { - public: - TypeSet::Type thisType; - JSObject* singletonEnvChain; - - Vector argTypes; - Vector varTypes; - - explicit BaselineFrameInspector(TempAllocator* temp) - : thisType(TypeSet::UndefinedType()), - singletonEnvChain(nullptr), - argTypes(*temp), - varTypes(*temp) {} -}; - -BaselineFrameInspector* jit::NewBaselineFrameInspector(TempAllocator* temp, - BaselineFrame* frame, - uint32_t frameSize) { - MOZ_ASSERT(frame); - - BaselineFrameInspector* inspector = - temp->lifoAlloc()->new_(temp); - if (!inspector) { - return nullptr; - } - - // Note: copying the actual values into a temporary structure for use - // during compilation could capture nursery pointers, so the values' types - // are recorded instead. - - if (frame->isFunctionFrame()) { - inspector->thisType = - TypeSet::GetMaybeUntrackedValueType(frame->thisArgument()); - } - - if (frame->environmentChain()->isSingleton()) { - inspector->singletonEnvChain = frame->environmentChain(); - } - - JSScript* script = frame->script(); - - if (script->function()) { - if (!inspector->argTypes.reserve(frame->numFormalArgs())) { - return nullptr; - } - for (size_t i = 0; i < frame->numFormalArgs(); i++) { - if (script->formalIsAliased(i)) { - inspector->argTypes.infallibleAppend(TypeSet::UndefinedType()); - } else if (!script->argsObjAliasesFormals()) { - TypeSet::Type type = - TypeSet::GetMaybeUntrackedValueType(frame->unaliasedFormal(i)); - inspector->argTypes.infallibleAppend(type); - } else if (frame->hasArgsObj()) { - TypeSet::Type type = - TypeSet::GetMaybeUntrackedValueType(frame->argsObj().arg(i)); - inspector->argTypes.infallibleAppend(type); - } else { - inspector->argTypes.infallibleAppend(TypeSet::UndefinedType()); - } - } - } - - uint32_t numValueSlots = frame->numValueSlots(frameSize); - if (!inspector->varTypes.reserve(numValueSlots)) { - return nullptr; - } - for (size_t i = 0; i < numValueSlots; i++) { - TypeSet::Type type = - TypeSet::GetMaybeUntrackedValueType(*frame->valueSlot(i)); - inspector->varTypes.infallibleAppend(type); - } - - return inspector; -} - -IonBuilder::IonBuilder(JSContext* analysisContext, MIRGenerator& mirGen, - CompileInfo* info, CompilerConstraintList* constraints, - BaselineInspector* inspector, - BaselineFrameInspector* baselineFrame, - size_t inliningDepth, uint32_t loopDepth) - : actionableAbortScript_(nullptr), - actionableAbortPc_(nullptr), - actionableAbortMessage_(nullptr), - analysisContext(analysisContext), - baselineFrame_(baselineFrame), - constraints_(constraints), - mirGen_(mirGen), - tiOracle_(this, constraints), - realm(mirGen.realm), - info_(info), - optimizationInfo_(&mirGen.optimizationInfo()), - alloc_(&mirGen.alloc()), - graph_(&mirGen.graph()), - thisTypes(nullptr), - argTypes(nullptr), - typeArray(nullptr), - typeArrayHint(0), - bytecodeTypeMap(nullptr), - loopDepth_(loopDepth), - loopStack_(*alloc_), - trackedOptimizationSites_(*alloc_), - abortedPreliminaryGroups_(*alloc_), - callerResumePoint_(nullptr), - callerBuilder_(nullptr), - iterators_(*alloc_), - loopHeaders_(*alloc_), - inspector(inspector), - inliningDepth_(inliningDepth), - inlinedBytecodeLength_(0), - numLoopRestarts_(0), - failedBoundsCheck_(info_->script()->failedBoundsCheck()), - failedShapeGuard_(info_->script()->failedShapeGuard()), - failedLexicalCheck_(info_->script()->failedLexicalCheck()), -#ifdef DEBUG - hasLazyArguments_(false), -#endif - inlineCallInfo_(nullptr), - maybeFallbackFunctionGetter_(nullptr) { - script_ = info_->script(); - pc = script_->code(); - - // The script must have a JitScript. Compilation requires a BaselineScript - // too. - MOZ_ASSERT(script_->hasJitScript()); - MOZ_ASSERT_IF(!info_->isAnalysis(), script_->hasBaselineScript()); - - MOZ_ASSERT(!!analysisContext == - (info_->analysisMode() == Analysis_DefiniteProperties)); - MOZ_ASSERT(script_->numBytecodeTypeSets() < JSScript::MaxBytecodeTypeSets); - - if (!info_->isAnalysis()) { - script()->jitScript()->setIonCompiledOrInlined(); - } -} - -mozilla::GenericErrorResult IonBuilder::abort(AbortReason r) { - auto res = mirGen_.abort(r); - [[maybe_unused]] unsigned line, column; -#ifdef DEBUG - line = PCToLineNumber(script(), pc, &column); -#else - line = script()->lineno(); - column = script()->column(); -#endif - JitSpew(JitSpew_IonAbort, "aborted @ %s:%u:%u", script()->filename(), line, - column); - return res; -} - -mozilla::GenericErrorResult IonBuilder::abort(AbortReason r, - const char* message, - ...) { - // Don't call PCToLineNumber in release builds. - va_list ap; - va_start(ap, message); - auto res = mirGen_.abortFmt(r, message, ap); - va_end(ap); - [[maybe_unused]] unsigned line, column; -#ifdef DEBUG - line = PCToLineNumber(script(), pc, &column); -#else - line = script()->lineno(); - column = script()->column(); -#endif - JitSpew(JitSpew_IonAbort, "aborted @ %s:%u:%u", script()->filename(), line, - column); - return res; -} - -IonBuilder* IonBuilder::outermostBuilder() { - IonBuilder* builder = this; - while (builder->callerBuilder_) { - builder = builder->callerBuilder_; - } - return builder; -} - -void IonBuilder::spew(const char* message) { - // Don't call PCToLineNumber in release builds. -#ifdef DEBUG - JitSpew(JitSpew_IonMIR, "%s @ %s:%u", message, script()->filename(), - PCToLineNumber(script(), pc)); -#endif -} - -JSFunction* IonBuilder::getSingleCallTarget(TemporaryTypeSet* calleeTypes) { - if (!calleeTypes) { - return nullptr; - } - - TemporaryTypeSet::ObjectKey* key = calleeTypes->maybeSingleObject(); - if (!key || key->clasp() != &JSFunction::class_) { - return nullptr; - } - - if (key->isSingleton()) { - return &key->singleton()->as(); - } - - if (JSFunction* fun = key->group()->maybeInterpretedFunction()) { - return fun; - } - - return nullptr; -} - -AbortReasonOr IonBuilder::getPolyCallTargets(TemporaryTypeSet* calleeTypes, - bool constructing, - InliningTargets& targets, - uint32_t maxTargets) { - MOZ_ASSERT(targets.empty()); - - if (!calleeTypes) { - return Ok(); - } - - if (calleeTypes->baseFlags() != 0) { - return Ok(); - } - - unsigned objCount = calleeTypes->getObjectCount(); - - if (objCount == 0 || objCount > maxTargets) { - return Ok(); - } - - if (!targets.reserve(objCount)) { - return abort(AbortReason::Alloc); - } - for (unsigned i = 0; i < objCount; i++) { - JSObject* obj = calleeTypes->getSingleton(i); - ObjectGroup* group = nullptr; - if (obj) { - MOZ_ASSERT(obj->isSingleton()); - } else { - group = calleeTypes->getGroup(i); - if (!group) { - continue; - } - - obj = group->maybeInterpretedFunction(); - if (!obj) { - targets.clear(); - return Ok(); - } - - MOZ_ASSERT(!obj->isSingleton()); - } - - // Don't optimize if the callee is not callable or constructable per - // the manner it is being invoked, so that CallKnown does not have to - // handle these cases (they will always throw). - if (constructing ? !obj->isConstructor() : !obj->isCallable()) { - targets.clear(); - return Ok(); - } - - targets.infallibleAppend(InliningTarget(obj, group)); - } - - return Ok(); -} - -IonBuilder::InliningDecision IonBuilder::DontInline(JSScript* targetScript, - const char* reason) { - if (targetScript) { - JitSpew(JitSpew_Inlining, "Cannot inline %s:%u:%u %s", - targetScript->filename(), targetScript->lineno(), - targetScript->column(), reason); - } else { - JitSpew(JitSpew_Inlining, "Cannot inline: %s", reason); - } - - return InliningDecision_DontInline; -} - -/* - * |hasCommonInliningPath| determines whether the current inlining path has been - * seen before based on the sequence of scripts in the chain of |IonBuilder|s. - * - * An inlining path for a function |f| is the sequence of functions whose - * inlinings precede |f| up to any previous occurrences of |f|. - * So, if we have the chain of inlinings - * - * f1 -> f2 -> f -> f3 -> f4 -> f5 -> f - * -------- -------------- - * - * the inlining paths for |f| are [f2, f1] and [f5, f4, f3]. - * When attempting to inline |f|, we find all existing inlining paths for |f| - * and check whether they share a common prefix with the path created were |f| - * inlined. - * - * For example, given mutually recursive functions |f| and |g|, a possible - * inlining is - * - * +---- Inlining stopped here... - * | - * v - * a -> f -> g -> f \ -> g -> f -> g -> ... - * - * where the vertical bar denotes the termination of inlining. - * Inlining is terminated because we have already observed the inlining path - * [f] when inlining function |g|. Note that this will inline recursive - * functions such as |fib| only one level, as |fib| has a zero length inlining - * path which trivially prefixes all inlining paths. - * - */ -bool IonBuilder::hasCommonInliningPath(const JSScript* scriptToInline) { - // Find all previous inlinings of the |scriptToInline| and check for common - // inlining paths with the top of the inlining stack. - for (IonBuilder* it = this->callerBuilder_; it; it = it->callerBuilder_) { - if (it->script() != scriptToInline) { - continue; - } - - // This only needs to check the top of each stack for a match, - // as a match of length one ensures a common prefix. - IonBuilder* path = it->callerBuilder_; - if (!path || this->script() == path->script()) { - return true; - } - } - - return false; -} - -IonBuilder::InliningDecision IonBuilder::canInlineTarget(JSFunction* target, - CallInfo& callInfo) { - if (!optimizationInfo().inlineInterpreted()) { - return InliningDecision_DontInline; - } - - if (TraceLogTextIdEnabled(TraceLogger_InlinedScripts)) { - return DontInline(nullptr, - "Tracelogging of inlined scripts is enabled" - "but Tracelogger cannot do that yet."); - } - - if (!target->isInterpreted()) { - return DontInline(nullptr, "Non-interpreted target"); - } - - // Never inline scripted cross-realm calls. - if (target->realm() != script()->realm()) { - return DontInline(nullptr, "Cross-realm call"); - } - - if (info().analysisMode() != Analysis_DefiniteProperties) { - // If |this| or an argument has an empty resultTypeSet, don't bother - // inlining, as the call is currently unreachable due to incomplete type - // information. This does not apply to the definite properties analysis, - // in that case we want to inline anyway. - - if (callInfo.thisArg()->emptyResultTypeSet()) { - return DontInline(nullptr, "Empty TypeSet for |this|"); - } - - for (size_t i = 0; i < callInfo.argc(); i++) { - if (callInfo.getArg(i)->emptyResultTypeSet()) { - return DontInline(nullptr, "Empty TypeSet for argument"); - } - } - } - - // Allow constructing lazy scripts when performing the definite properties - // analysis, as baseline has not been used to warm the caller up yet. - if (target->isInterpreted() && - info().analysisMode() == Analysis_DefiniteProperties) { - RootedFunction fun(analysisContext, target); - RootedScript script(analysisContext, - JSFunction::getOrCreateScript(analysisContext, fun)); - if (!script) { - return InliningDecision_Error; - } - - if (CanBaselineInterpretScript(script)) { - AutoKeepJitScripts keepJitScript(analysisContext); - if (!script->ensureHasJitScript(analysisContext, keepJitScript)) { - return InliningDecision_Error; - } - } - } - - if (!target->hasBytecode()) { - return DontInline(nullptr, "Lazy script"); - } - - JSScript* inlineScript = target->nonLazyScript(); - if (callInfo.constructing()) { - if (!target->isConstructor()) { - return DontInline(inlineScript, "Callee is not a constructor"); - } - - // Don't inline if creating |this| for this target is complicated, for - // example when the newTarget.prototype lookup may be effectful. - if (!target->constructorNeedsUninitializedThis() && - callInfo.getNewTarget() != callInfo.callee()) { - JSFunction* newTargetFun = - getSingleCallTarget(callInfo.getNewTarget()->resultTypeSet()); - if (!newTargetFun) { - return DontInline(inlineScript, "Constructing with unknown newTarget"); - } - if (!newTargetFun->hasNonConfigurablePrototypeDataProperty()) { - return DontInline(inlineScript, - "Constructing with effectful newTarget.prototype"); - } - } else { - // At this point, the target is either a function that requires an - // uninitialized-this (bound function or derived class constructor) or a - // scripted constructor with a non-configurable .prototype data property - // (self-hosted built-in constructor, non-self-hosted scripted function). - MOZ_ASSERT(target->constructorNeedsUninitializedThis() || - target->hasNonConfigurablePrototypeDataProperty()); - } - } - - if (!callInfo.constructing() && target->isClassConstructor()) { - return DontInline(inlineScript, "Not constructing class constructor"); - } - - if (!CanIonInlineScript(inlineScript)) { - return DontInline(inlineScript, "Disabled Ion compilation"); - } - - if (info().isAnalysis()) { - // Analysis requires only a JitScript. - if (!inlineScript->hasJitScript()) { - return DontInline(inlineScript, "No JitScript"); - } - } else { - // Compilation requires a BaselineScript. - if (!inlineScript->hasBaselineScript()) { - return DontInline(inlineScript, "No baseline jitcode"); - } - } - - // Don't inline functions with a higher optimization level. - if (!isHighestOptimizationLevel()) { - OptimizationLevel level = optimizationLevel(); - if (inlineScript->hasIonScript() && - (inlineScript->ionScript()->isRecompiling() || - inlineScript->ionScript()->optimizationLevel() > level)) { - return DontInline(inlineScript, "More optimized"); - } - if (IonOptimizations.levelForScript(inlineScript, nullptr) > level) { - return DontInline(inlineScript, "Should be more optimized"); - } - } - - if (TooManyFormalArguments(target->nargs())) { - return DontInline(inlineScript, "Too many args"); - } - - // We check the number of actual arguments against the maximum number of - // formal arguments as we do not want to encode all actual arguments in the - // callerResumePoint. - if (TooManyFormalArguments(callInfo.argc())) { - return DontInline(inlineScript, "Too many actual args"); - } - - if (hasCommonInliningPath(inlineScript)) { - return DontInline(inlineScript, "Common inlining path"); - } - - if (inlineScript->uninlineable()) { - return DontInline(inlineScript, "Uninlineable script"); - } - - if (inlineScript->needsArgsObj()) { - return DontInline(inlineScript, "Script that needs an arguments object"); - } - - if (inlineScript->isDebuggee()) { - return DontInline(inlineScript, "Script is debuggee"); - } - - return InliningDecision_Inline; -} - -AbortReasonOr IonBuilder::analyzeNewLoopTypes(MBasicBlock* entry) { - MOZ_ASSERT(!entry->isDead()); - MOZ_ASSERT(JSOp(*pc) == JSOp::LoopHead); - - // The phi inputs at the loop head only reflect types for variables that - // were present at the start of the loop. If the variable changes to a new - // type within the loop body, and that type is carried around to the loop - // head, then we need to know about the new type up front. - // - // Since SSA information hasn't been constructed for the loop body yet, we - // need a separate analysis to pick out the types that might flow around - // the loop header. This is a best-effort analysis that may either over- - // or under-approximate the set of such types. - // - // Over-approximating the types may lead to inefficient generated code, and - // under-approximating the types will cause the loop body to be analyzed - // multiple times as the correct types are deduced (see finishLoop). - - // If we restarted processing of an outer loop then get loop header types - // directly from the last time we have previously processed this loop. This - // both avoids repeated work from the bytecode traverse below, and will - // also pick up types discovered while previously building the loop body. - bool foundEntry = false; - for (size_t i = 0; i < loopHeaders_.length(); i++) { - if (loopHeaders_[i].pc == pc) { - MBasicBlock* oldEntry = loopHeaders_[i].header; - - // If this block has been discarded, its resume points will have - // already discarded their operands. - if (oldEntry->isDead()) { - loopHeaders_[i].header = entry; - foundEntry = true; - break; - } - - MResumePoint* oldEntryRp = oldEntry->entryResumePoint(); - size_t stackDepth = oldEntryRp->stackDepth(); - for (size_t slot = 0; slot < stackDepth; slot++) { - MDefinition* oldDef = oldEntryRp->getOperand(slot); - if (!oldDef->isPhi()) { - MOZ_ASSERT(oldDef->block()->id() < oldEntry->id()); - MOZ_ASSERT(oldDef == entry->getSlot(slot)); - continue; - } - MPhi* oldPhi = oldDef->toPhi(); - MPhi* newPhi = entry->getSlot(slot)->toPhi(); - if (!newPhi->addBackedgeType(alloc(), oldPhi->type(), - oldPhi->resultTypeSet())) { - return abort(AbortReason::Alloc); - } - } - - // Update the most recent header for this loop encountered, in case - // new types flow to the phis and the loop is processed at least - // three times. - loopHeaders_[i].header = entry; - return Ok(); - } - } - if (!foundEntry) { - if (!loopHeaders_.append(LoopHeader(pc, entry))) { - return abort(AbortReason::Alloc); - } - } - - // Get the start and end bytecode locations. - BytecodeLocation start(script_, pc); - BytecodeLocation end(script_, script_->codeEnd()); - - // Iterate the bytecode quickly to seed possible types in the loopheader. - Maybe last; - Maybe earlier; - - for (auto it : BytecodeLocationRange(start, end)) { - if (IsBackedgeForLoopHead(it.toRawBytecode(), pc)) { - break; - } - MOZ_TRY(analyzeNewLoopTypesForLocation(entry, it, last, earlier)); - earlier = last; - last = mozilla::Some(it); - } - - return Ok(); -} - -AbortReasonOr IonBuilder::analyzeNewLoopTypesForLocation( - MBasicBlock* entry, const BytecodeLocation loc, - const Maybe& last_, - const Maybe& earlier) { - // Unfortunately Maybe<> cannot be passed as by-value argument so make a copy - // here. - Maybe last = last_; - - // We're only interested in JSOp::SetLocal and JSOp::SetArg. - uint32_t slot; - if (loc.is(JSOp::SetLocal)) { - slot = info().localSlot(loc.local()); - } else if (loc.is(JSOp::SetArg)) { - slot = info().argSlotUnchecked(loc.arg()); - } else { - return Ok(); - } - if (slot >= info().firstStackSlot()) { - return Ok(); - } - - // Ensure there is a |last| instruction. - if (!last) { - return Ok(); - } - MOZ_ASSERT(last->isValid(script_)); - - // Analyze the |last| bytecode instruction to try to dermine the type of this - // local/argument. - - MPhi* phi = entry->getSlot(slot)->toPhi(); - - auto addPhiBackedgeType = - [&](MIRType type, TemporaryTypeSet* typeSet) -> AbortReasonOr { - if (!phi->addBackedgeType(alloc(), type, typeSet)) { - return abort(AbortReason::Alloc); - } - return Ok(); - }; - - // If it's a JSOp::Pos or JSOp::ToNumeric, use its operand instead. - if (last->is(JSOp::Pos) || last->is(JSOp::ToNumeric)) { - MOZ_ASSERT(earlier); - last = earlier; - } - - // If the |last| op had a TypeSet, use it. - if (last->opHasTypeSet()) { - TemporaryTypeSet* typeSet = bytecodeTypes(last->toRawBytecode()); - if (typeSet->empty()) { - return Ok(); - } - return addPhiBackedgeType(typeSet->getKnownMIRType(), typeSet); - } - - // If the |last| op was a JSOp::GetLocal or JSOp::GetArg, use that slot's - // type. - if (last->is(JSOp::GetLocal) || last->is(JSOp::GetArg)) { - uint32_t slot = (last->is(JSOp::GetLocal)) - ? info().localSlot(last->local()) - : info().argSlotUnchecked(last->arg()); - if (slot >= info().firstStackSlot()) { - return Ok(); - } - MPhi* otherPhi = entry->getSlot(slot)->toPhi(); - if (!otherPhi->hasBackedgeType()) { - return Ok(); - } - return addPhiBackedgeType(otherPhi->type(), otherPhi->resultTypeSet()); - } - - // If the |last| op has a known type (determined statically or from - // BaselineInspector), use that. - MIRType type = MIRType::None; - switch (last->getOp()) { - case JSOp::Void: - case JSOp::Undefined: - type = MIRType::Undefined; - break; - case JSOp::GImplicitThis: - if (!script()->hasNonSyntacticScope()) { - type = MIRType::Undefined; - } - break; - case JSOp::Null: - type = MIRType::Null; - break; - case JSOp::Zero: - case JSOp::One: - case JSOp::Int8: - case JSOp::Int32: - case JSOp::Uint16: - case JSOp::Uint24: - case JSOp::ResumeIndex: - type = MIRType::Int32; - break; - case JSOp::BitAnd: - case JSOp::BitOr: - case JSOp::BitXor: - case JSOp::BitNot: - case JSOp::Rsh: - case JSOp::Lsh: - type = inspector->expectedResultType(last->toRawBytecode()); - break; - case JSOp::Ursh: - // Unsigned right shift is not applicable to BigInts, so we don't need - // to query the baseline inspector for the possible result types. - type = MIRType::Int32; - break; - case JSOp::False: - case JSOp::True: - case JSOp::Eq: - case JSOp::Ne: - case JSOp::Lt: - case JSOp::Le: - case JSOp::Gt: - case JSOp::Ge: - case JSOp::Not: - case JSOp::StrictEq: - case JSOp::StrictNe: - case JSOp::In: - case JSOp::Instanceof: - case JSOp::HasOwn: - type = MIRType::Boolean; - break; - case JSOp::Double: - type = MIRType::Double; - break; - case JSOp::IterNext: - case JSOp::String: - case JSOp::ToString: - case JSOp::Typeof: - case JSOp::TypeofExpr: - type = MIRType::String; - break; - case JSOp::Symbol: - type = MIRType::Symbol; - break; - case JSOp::Add: - case JSOp::Sub: - case JSOp::Mul: - case JSOp::Div: - case JSOp::Mod: - case JSOp::Neg: - case JSOp::Inc: - case JSOp::Dec: - type = inspector->expectedResultType(last->toRawBytecode()); - break; - case JSOp::BigInt: - type = MIRType::BigInt; - break; - default: - break; - } - - if (type == MIRType::None) { - return Ok(); - } - - return addPhiBackedgeType(type, /* typeSet = */ nullptr); -} - -AbortReasonOr IonBuilder::init() { - { - LifoAlloc::AutoFallibleScope fallibleAllocator(alloc().lifoAlloc()); - if (!JitScript::FreezeTypeSets(constraints(), script(), &thisTypes, - &argTypes, &typeArray)) { - return abort(AbortReason::Alloc); - } - } - - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - { - JSContext* cx = TlsContext.get(); - RootedScript rootedScript(cx, script()); - if (!rootedScript->jitScript()->ensureHasCachedIonData(cx, rootedScript)) { - return abort(AbortReason::Error); - } - } - - if (inlineCallInfo_) { - // If we're inlining, the actual this/argument types are not necessarily - // a subset of the script's observed types. |argTypes| is never accessed - // for inlined scripts, so we just null it. - thisTypes = inlineCallInfo_->thisArg()->resultTypeSet(); - argTypes = nullptr; - } - - bytecodeTypeMap = script()->jitScript()->bytecodeTypeMap(); - - return Ok(); -} - -AbortReasonOr IonBuilder::build() { - // Spew IC info for inlined script, but only when actually compiling, - // not when analyzing it. -#ifdef JS_STRUCTURED_SPEW - if (!info().isAnalysis()) { - JitSpewBaselineICStats(script(), "To-Be-Compiled"); - } -#endif - - MOZ_TRY(init()); - - // The JitScript-based inlining heuristics only affect the highest - // optimization level. Other levels do almost no inlining and we don't want to - // overwrite data from the highest optimization tier. - if (isHighestOptimizationLevel()) { - script()->jitScript()->resetMaxInliningDepth(); - } - - MBasicBlock* entry; - MOZ_TRY_VAR(entry, newBlock(info().firstStackSlot(), pc)); - MOZ_TRY(setCurrentAndSpecializePhis(entry)); - -#ifdef JS_JITSPEW - if (info().isAnalysis()) { - JitSpew(JitSpew_IonScripts, "Analyzing script %s:%u:%u (%p) %s", - script()->filename(), script()->lineno(), script()->column(), - (void*)script(), AnalysisModeString(info().analysisMode())); - } else { - JitSpew(JitSpew_IonScripts, - "%sompiling script %s:%u:%u (%p) (warmup-counter=%" PRIu32 - ", level=%s)", - (script()->hasIonScript() ? "Rec" : "C"), script()->filename(), - script()->lineno(), script()->column(), (void*)script(), - script()->getWarmUpCount(), - OptimizationLevelString(optimizationLevel())); - } -#endif - - MOZ_TRY(initParameters()); - initLocals(); - - // Initialize something for the env chain. We can bail out before the - // start instruction, but the snapshot is encoded *at* the start - // instruction, which means generating any code that could load into - // registers is illegal. - MInstruction* env = MConstant::New(alloc(), UndefinedValue()); - current->add(env); - current->initSlot(info().environmentChainSlot(), env); - - // Initialize the return value. - MInstruction* returnValue = MConstant::New(alloc(), UndefinedValue()); - current->add(returnValue); - current->initSlot(info().returnValueSlot(), returnValue); - - // Initialize the arguments object slot to undefined if necessary. - if (info().hasArguments()) { - MInstruction* argsObj = MConstant::New(alloc(), UndefinedValue()); - current->add(argsObj); - current->initSlot(info().argsObjSlot(), argsObj); - } - - // Emit the start instruction, so we can begin real instructions. - current->add(MStart::New(alloc())); - - // Guard against over-recursion. Do this before we start unboxing, since - // this will create an OSI point that will read the incoming argument - // values, which is nice to do before their last real use, to minimize - // register/stack pressure. - MCheckOverRecursed* check = MCheckOverRecursed::New(alloc()); - current->add(check); - MResumePoint* entryRpCopy = - MResumePoint::Copy(alloc(), current->entryResumePoint()); - if (!entryRpCopy) { - return abort(AbortReason::Alloc); - } - check->setResumePoint(entryRpCopy); - - // Parameters have been checked to correspond to the typeset, now we unbox - // what we can in an infallible manner. - MOZ_TRY(rewriteParameters()); - - // It's safe to start emitting actual IR, so now build the env chain. - MOZ_TRY(initEnvironmentChain()); - if (info().needsArgsObj()) { - initArgumentsObject(); - } - - // The type analysis phase attempts to insert unbox operations near - // definitions of values. It also attempts to replace uses in resume points - // with the narrower, unboxed variants. However, we must prevent this - // replacement from happening on values in the entry snapshot. Otherwise we - // could get this: - // - // v0 = MParameter(0) - // v1 = MParameter(1) - // -- ResumePoint(v2, v3) - // v2 = Unbox(v0, INT32) - // v3 = Unbox(v1, INT32) - // - // So we attach the initial resume point to each parameter, which the type - // analysis explicitly checks (this is the same mechanism used for - // effectful operations). - for (uint32_t i = 0; i < info().endArgSlot(); i++) { - MInstruction* ins = current->getEntrySlot(i)->toInstruction(); - if (ins->type() != MIRType::Value) { - continue; - } - - MResumePoint* entryRpCopy = - MResumePoint::Copy(alloc(), current->entryResumePoint()); - if (!entryRpCopy) { - return abort(AbortReason::Alloc); - } - ins->setResumePoint(entryRpCopy); - } - -#ifdef DEBUG - // lazyArguments should never be accessed in |argsObjAliasesFormals| scripts. - if (info().hasArguments() && !info().argsObjAliasesFormals()) { - hasLazyArguments_ = true; - } -#endif - - insertRecompileCheck(pc); - - auto clearLastPriorResumePoint = mozilla::MakeScopeExit([&] { - // Discard unreferenced & pre-allocated resume points. - replaceMaybeFallbackFunctionGetter(nullptr); - }); - - MOZ_TRY(traverseBytecode()); - - if (isHighestOptimizationLevel() && - inlinedBytecodeLength_ > script_->jitScript()->inlinedBytecodeLength()) { - script_->jitScript()->setInlinedBytecodeLength(inlinedBytecodeLength_); - } - - MOZ_TRY(maybeAddOsrTypeBarriers()); - - if (!MPhi::markIteratorPhis(iterators_)) { - return abort(AbortReason::Alloc); - } - - if (!info().isAnalysis() && !abortedPreliminaryGroups().empty()) { - return abort(AbortReason::PreliminaryObjects); - } - - MOZ_ASSERT(loopDepth_ == 0); - MOZ_ASSERT(loopStack_.empty()); - return Ok(); -} - -AbortReasonOr IonBuilder::buildInline(IonBuilder* callerBuilder, - MResumePoint* callerResumePoint, - CallInfo& callInfo) { - inlineCallInfo_ = &callInfo; - - // Spew IC info for inlined script, but only when actually compiling, - // not when analyzing it. -#ifdef JS_STRUCTURED_SPEW - if (!info().isAnalysis()) { - JitSpewBaselineICStats(script(), "To-Be-Inlined"); - } -#endif - - MOZ_TRY(init()); - - JitSpew(JitSpew_IonScripts, "Inlining script %s:%u:%u (%p)", - script()->filename(), script()->lineno(), script()->column(), - (void*)script()); - - callerBuilder_ = callerBuilder; - callerResumePoint_ = callerResumePoint; - - if (callerBuilder->failedBoundsCheck_) { - failedBoundsCheck_ = true; - } - - if (callerBuilder->failedShapeGuard_) { - failedShapeGuard_ = true; - } - - if (callerBuilder->failedLexicalCheck_) { - failedLexicalCheck_ = true; - } - - // Generate single entrance block. - MBasicBlock* entry; - MOZ_TRY_VAR(entry, newBlock(info().firstStackSlot(), pc)); - MOZ_TRY(setCurrentAndSpecializePhis(entry)); - - current->setCallerResumePoint(callerResumePoint); - - // Connect the entrance block to the last block in the caller's graph. - MBasicBlock* predecessor = callerBuilder->current; - MOZ_ASSERT(predecessor == callerResumePoint->block()); - - predecessor->end(MGoto::New(alloc(), current)); - if (!current->addPredecessorWithoutPhis(predecessor)) { - return abort(AbortReason::Alloc); - } - - // Initialize env chain slot to Undefined. It's set later by - // |initEnvironmentChain|. - MInstruction* env = MConstant::New(alloc(), UndefinedValue()); - current->add(env); - current->initSlot(info().environmentChainSlot(), env); - - // Initialize |return value| slot. - MInstruction* returnValue = MConstant::New(alloc(), UndefinedValue()); - current->add(returnValue); - current->initSlot(info().returnValueSlot(), returnValue); - - // Initialize |arguments| slot. - if (info().hasArguments()) { - MInstruction* argsObj = MConstant::New(alloc(), UndefinedValue()); - current->add(argsObj); - current->initSlot(info().argsObjSlot(), argsObj); - } - - // Initialize |this| slot. - current->initSlot(info().thisSlot(), callInfo.thisArg()); - - JitSpew(JitSpew_Inlining, "Initializing %u arg slots", info().nargs()); - - // NB: Ion does not inline functions which |needsArgsObj|. So using argSlot() - // instead of argSlotUnchecked() below is OK - MOZ_ASSERT(!info().needsArgsObj()); - - // Initialize actually set arguments. - uint32_t existing_args = std::min(callInfo.argc(), info().nargs()); - for (size_t i = 0; i < existing_args; ++i) { - MDefinition* arg = callInfo.getArg(i); - current->initSlot(info().argSlot(i), arg); - } - - // Pass Undefined for missing arguments - for (size_t i = callInfo.argc(); i < info().nargs(); ++i) { - MConstant* arg = MConstant::New(alloc(), UndefinedValue()); - current->add(arg); - current->initSlot(info().argSlot(i), arg); - } - - JitSpew(JitSpew_Inlining, "Initializing %u locals", info().nlocals()); - - initLocals(); - - JitSpew(JitSpew_Inlining, - "Inline entry block MResumePoint %p, %u stack slots", - (void*)current->entryResumePoint(), - current->entryResumePoint()->stackDepth()); - - // +2 for the env chain and |this|, maybe another +1 for arguments object - // slot. - MOZ_ASSERT(current->entryResumePoint()->stackDepth() == info().totalSlots()); - -#ifdef DEBUG - if (script_->argumentsHasVarBinding()) { - hasLazyArguments_ = true; - } -#endif - - insertRecompileCheck(pc); - - // Initialize the env chain now that all resume points operands are - // initialized. - MOZ_TRY(initEnvironmentChain(callInfo.callee())); - - auto clearLastPriorResumePoint = mozilla::MakeScopeExit([&] { - // Discard unreferenced & pre-allocated resume points. - replaceMaybeFallbackFunctionGetter(nullptr); - }); - - MOZ_TRY(traverseBytecode()); - - MOZ_ASSERT(iterators_.empty(), "Iterators should be added to outer builder"); - - if (!info().isAnalysis() && !abortedPreliminaryGroups().empty()) { - return abort(AbortReason::PreliminaryObjects); - } - - return Ok(); -} - -void IonBuilder::rewriteParameter(uint32_t slotIdx, MDefinition* param) { - MOZ_ASSERT(param->isParameter() || param->isGetArgumentsObjectArg()); - - TemporaryTypeSet* types = param->resultTypeSet(); - MDefinition* actual = ensureDefiniteType(param, types->getKnownMIRType()); - if (actual == param) { - return; - } - - // Careful! We leave the original MParameter in the entry resume point. The - // arguments still need to be checked unless proven otherwise at the call - // site, and these checks can bailout. We can end up: - // v0 = Parameter(0) - // v1 = Unbox(v0, INT32) - // -- ResumePoint(v0) - // - // As usual, it would be invalid for v1 to be captured in the initial - // resume point, rather than v0. - current->rewriteSlot(slotIdx, actual); -} - -// Apply Type Inference information to parameters early on, unboxing them if -// they have a definitive type. The actual guards will be emitted by the code -// generator, explicitly, as part of the function prologue. -AbortReasonOr IonBuilder::rewriteParameters() { - MOZ_ASSERT(info().environmentChainSlot() == 0); - - // If this JSScript is not the code of a function, then skip the - // initialization of function parameters. - if (!info().funMaybeLazy()) { - return Ok(); - } - - for (uint32_t i = info().startArgSlot(); i < info().endArgSlot(); i++) { - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - MDefinition* param = current->getSlot(i); - rewriteParameter(i, param); - } - - return Ok(); -} - -AbortReasonOr IonBuilder::initParameters() { - // If this JSScript is not the code of a function, then skip the - // initialization of function parameters. - if (!info().funMaybeLazy()) { - return Ok(); - } - - // If we are doing OSR on a frame which initially executed in the - // interpreter and didn't accumulate type information, try to use that OSR - // frame to determine possible initial types for 'this' and parameters. - - if (thisTypes->empty() && baselineFrame_) { - TypeSet::Type type = baselineFrame_->thisType; - if (type.isSingletonUnchecked()) { - checkNurseryObject(type.singleton()); - } - thisTypes->addType(type, alloc_->lifoAlloc()); - } - - MParameter* param = - MParameter::New(alloc(), MParameter::THIS_SLOT, thisTypes); - current->add(param); - current->initSlot(info().thisSlot(), param); - - for (uint32_t i = 0; i < info().nargs(); i++) { - TemporaryTypeSet* types = &argTypes[i]; - if (types->empty() && baselineFrame_ && - !script_->jitScript()->modifiesArguments()) { - TypeSet::Type type = baselineFrame_->argTypes[i]; - if (type.isSingletonUnchecked()) { - checkNurseryObject(type.singleton()); - } - types->addType(type, alloc_->lifoAlloc()); - } - - param = MParameter::New(alloc().fallible(), i, types); - if (!param) { - return abort(AbortReason::Alloc); - } - current->add(param); - current->initSlot(info().argSlotUnchecked(i), param); - } - - return Ok(); -} - -void IonBuilder::initLocals() { - // Initialize all frame slots to undefined. Lexical bindings are temporal - // dead zoned in bytecode. - - if (info().nlocals() == 0) { - return; - } - - MConstant* undef = MConstant::New(alloc(), UndefinedValue()); - current->add(undef); - - for (uint32_t i = 0; i < info().nlocals(); i++) { - current->initSlot(info().localSlot(i), undef); - } -} - -bool IonBuilder::usesEnvironmentChain() { - return script()->jitScript()->usesEnvironmentChain(); -} - -AbortReasonOr IonBuilder::initEnvironmentChain(MDefinition* callee) { - MInstruction* env = nullptr; - - // If the script doesn't use the envchain, then it's already initialized - // from earlier. However, always make a env chain when |needsArgsObj| is true - // for the script, since arguments object construction requires the env chain - // to be passed in. - if (!info().needsArgsObj() && !usesEnvironmentChain()) { - return Ok(); - } - - // The env chain is only tracked in scripts that have NAME opcodes which - // will try to access the env. For other scripts, the env instructions - // will be held live by resume points and code will still be generated for - // them, so just use a constant undefined value. - - if (JSFunction* fun = info().funMaybeLazy()) { - if (!callee) { - MCallee* calleeIns = MCallee::New(alloc()); - current->add(calleeIns); - callee = calleeIns; - } - env = MFunctionEnvironment::New(alloc(), callee); - current->add(env); - - // This reproduce what is done in CallObject::createForFunction. Skip - // this for the arguments analysis, as the script might not have a - // baseline script with template objects yet. - if (fun->needsSomeEnvironmentObject() && - info().analysisMode() != Analysis_ArgumentsUsage) { - if (fun->needsNamedLambdaEnvironment()) { - env = createNamedLambdaObject(callee, env); - } - - // TODO: Parameter expression-induced extra var environment not - // yet handled. - if (fun->needsExtraBodyVarEnvironment()) { - return abort(AbortReason::Disable, "Extra var environment unsupported"); - } - - if (fun->needsCallObject()) { - MOZ_TRY_VAR(env, createCallObject(callee, env)); - } - } - } else if (ModuleObject* module = info().module()) { - // Modules use a pre-created env object. - env = constant(ObjectValue(module->initialEnvironment())); - } else { - // For global scripts without a non-syntactic global scope, the env - // chain is the global lexical env. - MOZ_ASSERT(!script()->isForEval()); - MOZ_ASSERT(!script()->hasNonSyntacticScope()); - env = constant(ObjectValue(script()->global().lexicalEnvironment())); - } - - // Update the environment slot from UndefinedValue only after initial - // environment is created so that bailout doesn't see a partial env. - // See: |BaselineStackBuilder::buildBaselineFrame| - current->setEnvironmentChain(env); - return Ok(); -} - -void IonBuilder::initArgumentsObject() { - JitSpew(JitSpew_IonMIR, - "%s:%u:%u - Emitting code to initialize arguments object! block=%p", - script()->filename(), script()->lineno(), script()->column(), - current); - MOZ_ASSERT(info().needsArgsObj()); - - bool mapped = script()->hasMappedArgsObj(); - ArgumentsObject* templateObj = - script()->realm()->maybeArgumentsTemplateObject(mapped); - - MCreateArgumentsObject* argsObj = MCreateArgumentsObject::New( - alloc(), current->environmentChain(), templateObj); - current->add(argsObj); - current->setArgumentsObject(argsObj); -} - -AbortReasonOr IonBuilder::addOsrValueTypeBarrier( - uint32_t slot, MInstruction** def_, MIRType type, - TemporaryTypeSet* typeSet) { - MInstruction*& def = *def_; - MBasicBlock* osrBlock = def->block(); - - // Clear bogus type information added in newOsrPreheader(). - def->setResultType(MIRType::Value); - def->setResultTypeSet(nullptr); - - if (typeSet && !typeSet->unknown()) { - MInstruction* barrier = MTypeBarrier::New(alloc(), def, typeSet); - osrBlock->insertBefore(osrBlock->lastIns(), barrier); - osrBlock->rewriteSlot(slot, barrier); - def = barrier; - - // If the TypeSet is more precise than |type|, adjust |type| for the - // code below. - if (type == MIRType::Value) { - type = barrier->type(); - } - } else if (type == MIRType::Null || type == MIRType::Undefined || - type == MIRType::MagicOptimizedArguments) { - // No unbox instruction will be added below, so check the type by - // adding a type barrier for a singleton type set. - TypeSet::Type ntype = TypeSet::PrimitiveType(type); - LifoAlloc* lifoAlloc = alloc().lifoAlloc(); - typeSet = lifoAlloc->new_(lifoAlloc, ntype); - if (!typeSet) { - return abort(AbortReason::Alloc); - } - MInstruction* barrier = MTypeBarrier::New(alloc(), def, typeSet); - osrBlock->insertBefore(osrBlock->lastIns(), barrier); - osrBlock->rewriteSlot(slot, barrier); - def = barrier; - } - - // The following guards aren't directly linked into the usedef chain, - // however in the OSR block we need to ensure they're not optimized out, so we - // mark them as implicitly used. - switch (type) { - case MIRType::Null: - case MIRType::Undefined: - case MIRType::MagicOptimizedArguments: - def->setImplicitlyUsed(); - break; - default: - break; - } - - // Unbox the OSR value to the type expected by the loop header. - // - // The only specialized types that can show up here are MIRTypes with a - // corresponding TypeSet::Type because NewBaselineFrameInspector and - // newPendingLoopHeader use TypeSet::Type for Values from the BaselineFrame. - // This means magic values other than MagicOptimizedArguments are represented - // as UnknownType() and MIRType::Value. See also TypeSet::IsUntrackedValue. - switch (type) { - case MIRType::Boolean: - case MIRType::Int32: - case MIRType::Double: - case MIRType::String: - case MIRType::Symbol: - case MIRType::BigInt: - case MIRType::Object: - if (type != def->type()) { - MUnbox* unbox = MUnbox::New(alloc(), def, type, MUnbox::Fallible); - osrBlock->insertBefore(osrBlock->lastIns(), unbox); - osrBlock->rewriteSlot(slot, unbox); - def = unbox; - } - break; - - case MIRType::Value: - // Nothing to do. - break; - - case MIRType::Null: { - MConstant* c = MConstant::New(alloc(), NullValue()); - osrBlock->insertBefore(osrBlock->lastIns(), c); - osrBlock->rewriteSlot(slot, c); - def = c; - break; - } - - case MIRType::Undefined: { - MConstant* c = MConstant::New(alloc(), UndefinedValue()); - osrBlock->insertBefore(osrBlock->lastIns(), c); - osrBlock->rewriteSlot(slot, c); - def = c; - break; - } - - case MIRType::MagicOptimizedArguments: { - MOZ_ASSERT(hasLazyArguments_); - MConstant* lazyArg = - MConstant::New(alloc(), MagicValue(JS_OPTIMIZED_ARGUMENTS)); - osrBlock->insertBefore(osrBlock->lastIns(), lazyArg); - osrBlock->rewriteSlot(slot, lazyArg); - def = lazyArg; - break; - } - - default: - MOZ_CRASH("Unexpected type"); - } - - MOZ_ASSERT(def == osrBlock->getSlot(slot)); - return Ok(); -} - -AbortReasonOr IonBuilder::maybeAddOsrTypeBarriers() { - if (!info().osrPc()) { - return Ok(); - } - - // The loop has successfully been processed, and the loop header phis - // have their final type. Add unboxes and type barriers in the OSR - // block to check that the values have the appropriate type, and update - // the types in the preheader. - - MBasicBlock* osrBlock = graph().osrBlock(); - MOZ_ASSERT(osrBlock); - - MBasicBlock* preheader = osrBlock->getSuccessor(0); - MBasicBlock* header = preheader->getSuccessor(0); - static const size_t OSR_PHI_POSITION = 1; - MOZ_ASSERT(preheader->getPredecessor(OSR_PHI_POSITION) == osrBlock); - - MResumePoint* headerRp = header->entryResumePoint(); - size_t stackDepth = headerRp->stackDepth(); - MOZ_ASSERT(stackDepth == osrBlock->stackDepth()); - for (uint32_t slot = info().startArgSlot(); slot < stackDepth; slot++) { - // Aliased slots are never accessed, since they need to go through - // the callobject. The typebarriers are added there and can be - // discarded here. - if (info().isSlotAliased(slot)) { - continue; - } - - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - MInstruction* def = osrBlock->getSlot(slot)->toInstruction(); - MPhi* preheaderPhi = preheader->getSlot(slot)->toPhi(); - MPhi* headerPhi = headerRp->getOperand(slot)->toPhi(); - - MIRType type = headerPhi->type(); - TemporaryTypeSet* typeSet = headerPhi->resultTypeSet(); - - MOZ_TRY(addOsrValueTypeBarrier(slot, &def, type, typeSet)); - - preheaderPhi->replaceOperand(OSR_PHI_POSITION, def); - preheaderPhi->setResultType(type); - preheaderPhi->setResultTypeSet(typeSet); - } - - return Ok(); -} - -#ifdef DEBUG -// In debug builds, after compiling a bytecode op, this class is used to check -// that all values popped by this opcode either: -// -// (1) Have the ImplicitlyUsed flag set on them. -// (2) Have more uses than before compiling this op (the value is -// used as operand of a new MIR instruction). -// -// This is used to catch problems where IonBuilder pops a value without -// adding any SSA uses and doesn't call setImplicitlyUsedUnchecked on it. -class MOZ_RAII PoppedValueUseChecker { - Vector popped_; - Vector poppedUses_; - MBasicBlock* current_; - jsbytecode* pc_; - - public: - PoppedValueUseChecker(MBasicBlock* current, jsbytecode* pc) - : current_(current), pc_(pc) {} - - MOZ_MUST_USE bool init() { - unsigned nuses = GetUseCount(pc_); - - for (unsigned i = 0; i < nuses; i++) { - MDefinition* def = current_->peek(-int32_t(i + 1)); - if (!popped_.append(def) || !poppedUses_.append(def->defUseCount())) { - return false; - } - } - - return true; - } - - void checkAfterOp() { - JSOp op = JSOp(*pc_); - - // Don't require SSA uses for values popped by these ops. - switch (op) { - case JSOp::Pop: - case JSOp::PopN: - case JSOp::DupAt: - case JSOp::Dup: - case JSOp::Dup2: - case JSOp::Pick: - case JSOp::Unpick: - case JSOp::Swap: - case JSOp::SetArg: - case JSOp::SetLocal: - case JSOp::InitLexical: - case JSOp::SetRval: - case JSOp::Void: - // Basic stack/local/argument management opcodes. - return; - - case JSOp::Case: - case JSOp::Default: - // These ops have to pop the switch value when branching but don't - // actually use it. - return; - - default: - break; - } - - for (size_t i = 0; i < popped_.length(); i++) { - switch (op) { - case JSOp::Pos: - case JSOp::ToNumeric: - case JSOp::ToPropertyKey: - case JSOp::ToString: - // These ops may leave their input on the stack without setting - // the ImplicitlyUsed flag. If this value will be popped immediately, - // we may replace it with |undefined|, but the difference is - // not observable. - MOZ_ASSERT(i == 0); - if (current_->peek(-1) == popped_[0]) { - break; - } - [[fallthrough]]; - - default: - MOZ_ASSERT(popped_[i]->isImplicitlyUsed() || - // First value popped by JSOp::EndIter is not used at all, - // it's similar to JSOp::Pop above. - (op == JSOp::EndIter && i == 0) || - popped_[i]->defUseCount() > poppedUses_[i]); - break; - } - } - } -}; -#endif - -AbortReasonOr IonBuilder::traverseBytecode() { - // See the "Control Flow handling in IonBuilder" comment in IonBuilder.h for - // more information. - - MOZ_TRY(startTraversingBlock(current)); - - const jsbytecode* const codeEnd = script()->codeEnd(); - - while (true) { - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - // Skip unreachable ops (for example code after a 'return' or 'throw') until - // we get to the next jump target. - if (hasTerminatedBlock()) { - while (!BytecodeIsJumpTarget(JSOp(*pc))) { - // Finish any "broken" loops with an unreachable backedge. For example: - // - // do { - // ... - // return; - // ... - // } while (x); - // - // This loop never actually loops. - if (!loopStack_.empty() && - IsBackedgeForLoopHead(pc, loopStack_.back().header()->pc())) { - MOZ_ASSERT(loopDepth_ > 0); - loopDepth_--; - loopStack_.popBack(); - } - - pc = GetNextPc(pc); - if (pc == codeEnd) { - return Ok(); - } - } - } - -#ifdef DEBUG - PoppedValueUseChecker useChecker(current, pc); - if (!useChecker.init()) { - return abort(AbortReason::Alloc); - } -#endif - - MOZ_ASSERT(script()->containsPC(pc)); - nextpc = GetNextPc(pc); - - // Nothing in inspectOpcode() is allowed to advance the pc. - JSOp op = JSOp(*pc); - bool restarted = false; - MOZ_TRY(inspectOpcode(op, &restarted)); - -#ifdef DEBUG - if (!restarted) { - useChecker.checkAfterOp(); - } -#endif - - if (nextpc == codeEnd) { - return Ok(); - } - - pc = nextpc; - MOZ_ASSERT(script()->containsPC(pc)); - - if (!hasTerminatedBlock()) { - current->updateTrackedSite(bytecodeSite(pc)); - } - } - - // The iloop above never breaks, so this point is unreachable. Don't add code - // here, or you'll trigger compile errors about unreachable code with some - // compilers! -} - -AbortReasonOr IonBuilder::startTraversingBlock(MBasicBlock* block) { - block->setLoopDepth(loopDepth_); - - if (block->pc() && script()->hasScriptCounts()) { - block->setHitCount(script()->getHitCount(block->pc())); - } - - // Optimization to move a predecessor that only has this block as successor - // just before this block. Skip this optimization if the previous block is - // not part of the same function, as we might have to backtrack on inlining - // failures. - if (block->numPredecessors() == 1 && - block->getPredecessor(0)->numSuccessors() == 1 && - !block->getPredecessor(0)->outerResumePoint()) { - graph().removeBlockFromList(block->getPredecessor(0)); - graph().addBlock(block->getPredecessor(0)); - } - - MOZ_TRY(setCurrentAndSpecializePhis(block)); - - graph().addBlock(block); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_goto(bool* restarted) { - MOZ_ASSERT(JSOp(*pc) == JSOp::Goto); - - if (IsBackedgePC(pc)) { - return visitBackEdge(restarted); - } - - jsbytecode* target = pc + GET_JUMP_OFFSET(pc); - return visitGoto(target); -} - -AbortReasonOr IonBuilder::addPendingEdge(const PendingEdge& edge, - jsbytecode* target) { - PendingEdgesMap::AddPtr p = pendingEdges_.lookupForAdd(target); - if (p) { - if (!p->value().append(edge)) { - return abort(AbortReason::Alloc); - } - return Ok(); - } - - PendingEdges edges; - static_assert(PendingEdges::InlineLength >= 1, - "Appending one element should be infallible"); - MOZ_ALWAYS_TRUE(edges.append(edge)); - - if (!pendingEdges_.add(p, target, std::move(edges))) { - return abort(AbortReason::Alloc); - } - return Ok(); -} - -AbortReasonOr IonBuilder::visitGoto(jsbytecode* target) { - current->end(MGoto::New(alloc(), nullptr)); - MOZ_TRY(addPendingEdge(PendingEdge::NewGoto(current), target)); - setTerminatedBlock(); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_loophead() { - // All loops have the following bytecode structure: - // - // LoopHead - // ... - // IfNe/Goto to LoopHead - - MOZ_ASSERT(JSOp(*pc) == JSOp::LoopHead); - - if (hasTerminatedBlock()) { - // The whole loop is unreachable. - return Ok(); - } - - bool osr = pc == info().osrPc(); - if (osr) { - MBasicBlock* preheader; - MOZ_TRY_VAR(preheader, newOsrPreheader(current, pc)); - current->end(MGoto::New(alloc(), preheader)); - MOZ_TRY(setCurrentAndSpecializePhis(preheader)); - } - - loopDepth_++; - MBasicBlock* header; - MOZ_TRY_VAR(header, newPendingLoopHeader(current, pc, osr)); - current->end(MGoto::New(alloc(), header)); - - if (!loopStack_.emplaceBack(header)) { - return abort(AbortReason::Alloc); - } - - MOZ_TRY(analyzeNewLoopTypes(header)); - - MOZ_TRY(startTraversingBlock(header)); - return emitLoopHeadInstructions(pc); -} - -AbortReasonOr IonBuilder::visitBackEdge(bool* restarted) { - MOZ_ASSERT(loopDepth_ > 0); - loopDepth_--; - - MBasicBlock* header = loopStack_.back().header(); - current->end(MGoto::New(alloc(), header)); - - // Compute phis in the loop header and propagate them throughout the loop, - // including the successor. - AbortReason r = header->setBackedge(alloc(), current); - switch (r) { - case AbortReason::NoAbort: - loopStack_.popBack(); - setTerminatedBlock(); - return Ok(); - - case AbortReason::Disable: - // If there are types for variables on the backedge that were not - // present at the original loop header, then uses of the variables' - // phis may have generated incorrect nodes. The new types have been - // incorporated into the header phis, so remove all blocks for the - // loop body and restart with the new types. - *restarted = true; - MOZ_TRY(restartLoop(header)); - return Ok(); - - default: - return abort(r); - } -} - -AbortReasonOr IonBuilder::emitLoopHeadInstructions(jsbytecode* pc) { - MOZ_ASSERT(JSOp(*pc) == JSOp::LoopHead); - - MInterruptCheck* check = MInterruptCheck::New(alloc()); - current->add(check); - insertRecompileCheck(pc); - - return Ok(); -} - -AbortReasonOr IonBuilder::inspectOpcode(JSOp op, bool* restarted) { - // Add not yet implemented opcodes at the bottom of the switch! - switch (op) { - case JSOp::NopDestructuring: - case JSOp::Lineno: - case JSOp::Nop: - return Ok(); - - case JSOp::TryDestructuring: - // Set the hasTryBlock flag to turn off optimizations that eliminate dead - // resume points operands because the exception handler code for - // TryNoteKind::Destructuring is effectively a (specialized) catch-block. - graph().setHasTryBlock(); - return Ok(); - - case JSOp::LoopHead: - return jsop_loophead(); - - case JSOp::Undefined: - // If this ever changes, change what JSOp::GImplicitThis does too. - pushConstant(UndefinedValue()); - return Ok(); - - case JSOp::Try: - return visitTry(); - - case JSOp::Default: - current->pop(); - return visitGoto(pc + GET_JUMP_OFFSET(pc)); - - case JSOp::Goto: - return jsop_goto(restarted); - - case JSOp::IfNe: - case JSOp::IfEq: - case JSOp::And: - case JSOp::Or: - case JSOp::Case: - return visitTest(op, restarted); - - case JSOp::Coalesce: - return jsop_coalesce(); - - case JSOp::Return: - case JSOp::RetRval: - return visitReturn(op); - - case JSOp::Throw: - return visitThrow(); - - case JSOp::JumpTarget: - return visitJumpTarget(op); - - case JSOp::TableSwitch: - return visitTableSwitch(); - - case JSOp::BitNot: - return jsop_bitnot(); - - case JSOp::BitAnd: - case JSOp::BitOr: - case JSOp::BitXor: - case JSOp::Lsh: - case JSOp::Rsh: - case JSOp::Ursh: - return jsop_bitop(op); - - case JSOp::Add: - case JSOp::Sub: - case JSOp::Mul: - case JSOp::Div: - case JSOp::Mod: - return jsop_binary_arith(op); - - case JSOp::Pow: - return jsop_pow(); - - case JSOp::Pos: - return jsop_pos(); - - case JSOp::ToNumeric: - return jsop_tonumeric(); - - case JSOp::Neg: - return jsop_neg(); - - case JSOp::Inc: - case JSOp::Dec: - return jsop_inc_or_dec(op); - - case JSOp::ToString: - return jsop_tostring(); - - case JSOp::DefVar: - return jsop_defvar(); - - case JSOp::DefLet: - case JSOp::DefConst: - return jsop_deflexical(); - - case JSOp::DefFun: - return jsop_deffun(); - - case JSOp::CheckGlobalOrEvalDecl: - return jsop_checkGlobalOrEvalDecl(); - - case JSOp::Eq: - case JSOp::Ne: - case JSOp::StrictEq: - case JSOp::StrictNe: - case JSOp::Lt: - case JSOp::Le: - case JSOp::Gt: - case JSOp::Ge: - return jsop_compare(op); - - case JSOp::Double: - pushConstant(GET_INLINE_VALUE(pc)); - return Ok(); - - case JSOp::BigInt: - pushConstant(BigIntValue(info().getBigInt(pc))); - return Ok(); - - case JSOp::String: - pushConstant(StringValue(info().getAtom(pc))); - return Ok(); - - case JSOp::Symbol: { - unsigned which = GET_UINT8(pc); - JS::Symbol* sym = realm->runtime()->wellKnownSymbols().get(which); - pushConstant(SymbolValue(sym)); - return Ok(); - } - - case JSOp::Zero: - pushConstant(Int32Value(0)); - return Ok(); - - case JSOp::One: - pushConstant(Int32Value(1)); - return Ok(); - - case JSOp::Null: - pushConstant(NullValue()); - return Ok(); - - case JSOp::Void: - current->pop(); - pushConstant(UndefinedValue()); - return Ok(); - - case JSOp::Hole: - pushConstant(MagicValue(JS_ELEMENTS_HOLE)); - return Ok(); - - case JSOp::False: - pushConstant(BooleanValue(false)); - return Ok(); - - case JSOp::True: - pushConstant(BooleanValue(true)); - return Ok(); - - case JSOp::Arguments: - return jsop_arguments(); - - case JSOp::Rest: - return jsop_rest(); - - case JSOp::GetArg: - return jsop_getarg(GET_ARGNO(pc)); - - case JSOp::SetArg: - return jsop_setarg(GET_ARGNO(pc)); - - case JSOp::GetLocal: - current->pushLocal(GET_LOCALNO(pc)); - return Ok(); - - case JSOp::SetLocal: - current->setLocal(GET_LOCALNO(pc)); - return Ok(); - - case JSOp::ThrowSetConst: - return jsop_throwsetconst(); - - case JSOp::CheckLexical: - case JSOp::CheckAliasedLexical: - return jsop_checklexical(); - - case JSOp::InitLexical: - current->setLocal(GET_LOCALNO(pc)); - return Ok(); - - case JSOp::InitGLexical: { - MOZ_ASSERT(!script()->hasNonSyntacticScope()); - MDefinition* value = current->pop(); - current->push( - constant(ObjectValue(script()->global().lexicalEnvironment()))); - current->push(value); - return jsop_setprop(info().getAtom(pc)->asPropertyName()); - } - - case JSOp::InitAliasedLexical: - return jsop_setaliasedvar(EnvironmentCoordinate(pc)); - - case JSOp::Uninitialized: - pushConstant(MagicValue(JS_UNINITIALIZED_LEXICAL)); - return Ok(); - - case JSOp::Pop: { - MDefinition* def = current->pop(); - - // Pop opcodes frequently appear where values are killed, e.g. after - // SET* opcodes. Place a resume point afterwards to avoid capturing - // the dead value in later snapshots, except in places where that - // resume point is obviously unnecessary. - if (JSOp(pc[JSOpLength_Pop]) == JSOp::Pop) { - return Ok(); - } - if (def->isConstant()) { - return Ok(); - } - return maybeInsertResume(); - } - - case JSOp::PopN: - for (uint32_t i = 0, n = GET_UINT16(pc); i < n; i++) { - current->pop(); - } - return Ok(); - - case JSOp::DupAt: - current->pushSlot(current->stackDepth() - 1 - GET_UINT24(pc)); - return Ok(); - - case JSOp::NewArray: - return jsop_newarray(GET_UINT32(pc)); - - case JSOp::NewArrayCopyOnWrite: - return jsop_newarray_copyonwrite(); - - case JSOp::NewInit: - case JSOp::NewObject: - case JSOp::NewObjectWithGroup: - return jsop_newobject(); - - case JSOp::InitElem: - case JSOp::InitHiddenElem: - case JSOp::InitLockedElem: - return jsop_initelem(); - - case JSOp::InitElemInc: - return jsop_initelem_inc(); - - case JSOp::InitElemArray: - return jsop_initelem_array(); - - case JSOp::InitProp: - case JSOp::InitLockedProp: - case JSOp::InitHiddenProp: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_initprop(name); - } - - case JSOp::MutateProto: { - return jsop_mutateproto(); - } - - case JSOp::InitPropGetter: - case JSOp::InitHiddenPropGetter: - case JSOp::InitPropSetter: - case JSOp::InitHiddenPropSetter: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_initprop_getter_setter(name); - } - - case JSOp::InitElemGetter: - case JSOp::InitHiddenElemGetter: - case JSOp::InitElemSetter: - case JSOp::InitHiddenElemSetter: - return jsop_initelem_getter_setter(); - - case JSOp::FunCall: - return jsop_funcall(GET_ARGC(pc)); - - case JSOp::FunApply: - return jsop_funapply(GET_ARGC(pc)); - - case JSOp::SpreadCall: - return jsop_spreadcall(); - - case JSOp::SpreadNew: - case JSOp::SpreadSuperCall: - return jsop_spreadnew(); - - case JSOp::Call: - case JSOp::CallIgnoresRv: - case JSOp::CallIter: - case JSOp::New: - case JSOp::SuperCall: - MOZ_TRY(jsop_call(GET_ARGC(pc), - JSOp(*pc) == JSOp::New || JSOp(*pc) == JSOp::SuperCall, - JSOp(*pc) == JSOp::CallIgnoresRv)); - return Ok(); - - case JSOp::Eval: - case JSOp::StrictEval: - return jsop_eval(GET_ARGC(pc)); - - case JSOp::Int8: - pushConstant(Int32Value(GET_INT8(pc))); - return Ok(); - - case JSOp::Uint16: - pushConstant(Int32Value(GET_UINT16(pc))); - return Ok(); - - case JSOp::GetGName: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - if (!script()->hasNonSyntacticScope()) { - return jsop_getgname(name); - } - return jsop_getname(name); - } - - case JSOp::SetGName: - case JSOp::StrictSetGName: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - JSObject* obj = nullptr; - if (!script()->hasNonSyntacticScope()) { - obj = testGlobalLexicalBinding(name); - } - if (obj) { - return setStaticName(obj, name); - } - return jsop_setprop(name); - } - - case JSOp::GetName: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_getname(name); - } - - case JSOp::GetIntrinsic: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_intrinsic(name); - } - - case JSOp::GetImport: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_getimport(name); - } - - case JSOp::BindGName: - if (!script()->hasNonSyntacticScope()) { - if (JSObject* env = testGlobalLexicalBinding(info().getName(pc))) { - pushConstant(ObjectValue(*env)); - return Ok(); - } - } - // Fall through to JSOp::BindName - [[fallthrough]]; - case JSOp::BindName: - return jsop_bindname(info().getName(pc)); - - case JSOp::BindVar: - return jsop_bindvar(); - - case JSOp::Dup: - current->pushSlot(current->stackDepth() - 1); - return Ok(); - - case JSOp::Dup2: - return jsop_dup2(); - - case JSOp::Swap: - current->swapAt(-1); - return Ok(); - - case JSOp::Pick: - current->pick(-GET_INT8(pc)); - return Ok(); - - case JSOp::Unpick: - current->unpick(-GET_INT8(pc)); - return Ok(); - - case JSOp::GetAliasedVar: - return jsop_getaliasedvar(EnvironmentCoordinate(pc)); - - case JSOp::SetAliasedVar: - return jsop_setaliasedvar(EnvironmentCoordinate(pc)); - - case JSOp::Uint24: - case JSOp::ResumeIndex: - pushConstant(Int32Value(GET_UINT24(pc))); - return Ok(); - - case JSOp::Int32: - pushConstant(Int32Value(GET_INT32(pc))); - return Ok(); - - case JSOp::GetElem: - case JSOp::CallElem: - MOZ_TRY(jsop_getelem()); - if (op == JSOp::CallElem) { - MOZ_TRY(improveThisTypesForCall()); - } - return Ok(); - - case JSOp::SetElem: - case JSOp::StrictSetElem: - return jsop_setelem(); - - case JSOp::Length: - return jsop_length(); - - case JSOp::Not: - return jsop_not(); - - case JSOp::FunctionThis: - return jsop_functionthis(); - - case JSOp::GlobalThis: - return jsop_globalthis(); - - case JSOp::Callee: { - MDefinition* callee = getCallee(); - current->push(callee); - return Ok(); - } - - case JSOp::EnvCallee: - return jsop_envcallee(); - - case JSOp::SuperBase: - return jsop_superbase(); - - case JSOp::GetPropSuper: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_getprop_super(name); - } - - case JSOp::GetElemSuper: - return jsop_getelem_super(); - - case JSOp::GetProp: - case JSOp::CallProp: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - MOZ_TRY(jsop_getprop(name)); - if (op == JSOp::CallProp) { - MOZ_TRY(improveThisTypesForCall()); - } - return Ok(); - } - - case JSOp::SetProp: - case JSOp::StrictSetProp: - case JSOp::SetName: - case JSOp::StrictSetName: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_setprop(name); - } - - case JSOp::DelProp: - case JSOp::StrictDelProp: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_delprop(name); - } - - case JSOp::DelElem: - case JSOp::StrictDelElem: - return jsop_delelem(); - - case JSOp::RegExp: - return jsop_regexp(info().getRegExp(pc)); - - case JSOp::CallSiteObj: - pushConstant(ObjectValue(*info().getObject(pc))); - return Ok(); - - case JSOp::Object: - return jsop_object(info().getObject(pc)); - - case JSOp::ClassConstructor: - return jsop_classconstructor(); - - case JSOp::DerivedConstructor: - return jsop_derivedclassconstructor(); - - case JSOp::Typeof: - case JSOp::TypeofExpr: - return jsop_typeof(); - - case JSOp::ToAsyncIter: - return jsop_toasynciter(); - - case JSOp::ToPropertyKey: - return jsop_topropertykey(); - - case JSOp::IterNext: - return jsop_iternext(); - - case JSOp::Lambda: - return jsop_lambda(info().getFunction(pc)); - - case JSOp::LambdaArrow: - return jsop_lambda_arrow(info().getFunction(pc)); - - case JSOp::SetFunName: - return jsop_setfunname(GET_UINT8(pc)); - - case JSOp::PushLexicalEnv: - return jsop_pushlexicalenv(GET_GCTHING_INDEX(pc)); - - case JSOp::PopLexicalEnv: - current->setEnvironmentChain(walkEnvironmentChain(1)); - return Ok(); - - case JSOp::FreshenLexicalEnv: - return jsop_copylexicalenv(true); - - case JSOp::RecreateLexicalEnv: - return jsop_copylexicalenv(false); - - case JSOp::Iter: - return jsop_iter(); - - case JSOp::MoreIter: - return jsop_itermore(); - - case JSOp::IsNoIter: - return jsop_isnoiter(); - - case JSOp::EndIter: - return jsop_iterend(); - - case JSOp::In: - return jsop_in(); - - case JSOp::HasOwn: - return jsop_hasown(); - - case JSOp::CheckPrivateField: - return jsop_checkprivatefield(); - - case JSOp::SetRval: - MOZ_ASSERT(!script()->noScriptRval()); - current->setSlot(info().returnValueSlot(), current->pop()); - return Ok(); - - case JSOp::Instanceof: - return jsop_instanceof(); - - case JSOp::DebugLeaveLexicalEnv: - return Ok(); - - case JSOp::Debugger: - return jsop_debugger(); - - case JSOp::GImplicitThis: - if (!script()->hasNonSyntacticScope()) { - pushConstant(UndefinedValue()); - return Ok(); - } - // Fallthrough to ImplicitThis in non-syntactic scope case - [[fallthrough]]; - case JSOp::ImplicitThis: { - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_implicitthis(name); - } - - case JSOp::NewTarget: - return jsop_newtarget(); - - case JSOp::CheckIsObj: - return jsop_checkisobj(GET_UINT8(pc)); - - case JSOp::CheckObjCoercible: - return jsop_checkobjcoercible(); - - case JSOp::DebugCheckSelfHosted: { -#ifdef DEBUG - MDebugCheckSelfHosted* check = - MDebugCheckSelfHosted::New(alloc(), current->pop()); - current->add(check); - current->push(check); - MOZ_TRY(resumeAfter(check)); -#endif - return Ok(); - } - - case JSOp::IsConstructing: - pushConstant(MagicValue(JS_IS_CONSTRUCTING)); - return Ok(); - - case JSOp::OptimizeSpreadCall: - return jsop_optimize_spreadcall(); - - case JSOp::ImportMeta: - return jsop_importmeta(); - - case JSOp::DynamicImport: - return jsop_dynamic_import(); - - case JSOp::InstrumentationActive: - return jsop_instrumentation_active(); - - case JSOp::InstrumentationCallback: - return jsop_instrumentation_callback(); - - case JSOp::InstrumentationScriptId: - return jsop_instrumentation_scriptid(); - - case JSOp::CheckClassHeritage: - return jsop_checkclassheritage(); - - case JSOp::FunWithProto: - return jsop_funwithproto(info().getFunction(pc)); - - case JSOp::ObjWithProto: - return jsop_objwithproto(); - - case JSOp::BuiltinObject: - return jsop_builtinobject(); - - case JSOp::CheckReturn: - return jsop_checkreturn(); - - case JSOp::CheckThis: - return jsop_checkthis(); - - case JSOp::CheckThisReinit: - return jsop_checkthisreinit(); - - case JSOp::SuperFun: - return jsop_superfun(); - - case JSOp::InitHomeObject: - return jsop_inithomeobject(); - - // ===== NOT Yet Implemented ===== - // Read below! - - // With - case JSOp::EnterWith: - case JSOp::LeaveWith: - - // Spread - case JSOp::SpreadEval: - case JSOp::StrictSpreadEval: - - // Super - case JSOp::SetPropSuper: - case JSOp::SetElemSuper: - case JSOp::StrictSetPropSuper: - case JSOp::StrictSetElemSuper: - - // Environments (bug 1366470) - case JSOp::PushVarEnv: - - // Compound assignment - case JSOp::GetBoundName: - - // Generators / Async (bug 1317690) - case JSOp::Exception: - case JSOp::IsGenClosing: - case JSOp::InitialYield: - case JSOp::Yield: - case JSOp::FinalYieldRval: - case JSOp::Resume: - case JSOp::ResumeKind: - case JSOp::CheckResumeKind: - case JSOp::AfterYield: - case JSOp::Await: - case JSOp::TrySkipAwait: - case JSOp::Generator: - case JSOp::AsyncAwait: - case JSOp::AsyncResolve: - - // Misc - case JSOp::DelName: - case JSOp::Finally: - case JSOp::GetRval: - case JSOp::Gosub: - case JSOp::Retsub: - case JSOp::SetIntrinsic: - case JSOp::ThrowMsg: - // === !! WARNING WARNING WARNING !! === - // Do you really want to sacrifice performance by not implementing this - // operation in the optimizing compiler? - break; - - case JSOp::ForceInterpreter: - // Intentionally not implemented. - break; - } - -#ifdef DEBUG - return abort(AbortReason::Disable, "Unsupported opcode: %s", CodeName(op)); -#else - return abort(AbortReason::Disable, "Unsupported opcode: %d", - int(uint8_t(op))); -#endif -} - -AbortReasonOr IonBuilder::restartLoop(MBasicBlock* header) { - AutoTraceLog logCompile(TraceLoggerForCurrentThread(), - TraceLogger_IonBuilderRestartLoop); - - spew("New types at loop header, restarting loop body"); - - if (JitOptions.limitScriptSize) { - if (++numLoopRestarts_ >= MAX_LOOP_RESTARTS) { - return abort(AbortReason::Disable, - "Aborted while processing control flow"); - } - } - - // Restore slots to entry state. - size_t stackDepth = header->entryResumePoint()->stackDepth(); - for (size_t slot = 0; slot < stackDepth; slot++) { - MDefinition* loopDef = header->entryResumePoint()->getOperand(slot); - header->setSlot(slot, loopDef); - } - - // Remove phi operands. - for (MPhiIterator phi = header->phisBegin(); phi != header->phisEnd(); - phi++) { - phi->removeOperand(phi->numOperands() - 1); - } - - // Discard unreferenced & pre-allocated resume points. - replaceMaybeFallbackFunctionGetter(nullptr); - - // Remove all blocks in the loop body other than the header, which has phis - // of the appropriate type and incoming edges to preserve. - if (!graph().removeSuccessorBlocks(header)) { - return abort(AbortReason::Alloc); - } - graph().removeBlockFromList(header); - - // Remove all instructions from the header itself, and all resume points - // except the entry resume point. - header->discardAllInstructions(); - header->discardAllResumePoints(/* discardEntry = */ false); - header->setStackDepth(header->getPredecessor(0)->stackDepth()); - - loopDepth_ = header->loopDepth(); - - // Don't specializePhis(), as the header has been visited before and the - // phis have already had their type set. - setCurrent(header); - graph().addBlock(current); - - jsbytecode* loopHead = header->pc(); - MOZ_ASSERT(JSOp(*loopHead) == JSOp::LoopHead); - - // Since we discarded the header's instructions above, emit them again. This - // includes the interrupt check. - MOZ_TRY(emitLoopHeadInstructions(loopHead)); - nextpc = GetNextPc(loopHead); - - // Remove loop header and dead blocks from pendingBlocks. - for (PendingEdgesMap::Range r = pendingEdges_.all(); !r.empty(); - r.popFront()) { - PendingEdges& blocks = r.front().value(); - for (size_t i = blocks.length(); i > 0; i--) { - PendingEdge& block = blocks[i - 1]; - if (block.block() == header || block.block()->isDead()) { - blocks.erase(&block); - } - } - } - - return Ok(); -} - -AbortReasonOr IonBuilder::replaceTypeSet(MDefinition* subject, - TemporaryTypeSet* type, - MTest* test) { - if (type->unknown()) { - return Ok(); - } - - MOZ_ASSERT(!type->hasType(TypeSet::MagicArgType())); - - // Don't emit MFilterTypeSet if it doesn't improve the typeset. - if (subject->resultTypeSet()) { - if (subject->resultTypeSet()->equals(type)) { - return Ok(); - } - } else { - TemporaryTypeSet oldTypes(alloc_->lifoAlloc(), subject->type()); - if (oldTypes.equals(type)) { - return Ok(); - } - } - - MInstruction* replace = nullptr; - MDefinition* ins; - - for (uint32_t i = 0; i < current->stackDepth(); i++) { - ins = current->getSlot(i); - - // Instead of creating a new MFilterTypeSet, try to update the old one. - if (ins->isFilterTypeSet() && ins->getOperand(0) == subject && - ins->dependency() == test) { - TemporaryTypeSet* intersect = TypeSet::intersectSets( - ins->resultTypeSet(), type, alloc_->lifoAlloc()); - if (!intersect) { - return abort(AbortReason::Alloc); - } - - ins->toFilterTypeSet()->setResultType(intersect->getKnownMIRType()); - ins->toFilterTypeSet()->setResultTypeSet(intersect); - - if (ins->type() == MIRType::Undefined) { - current->setSlot(i, constant(UndefinedValue())); - } else if (ins->type() == MIRType::Null) { - current->setSlot(i, constant(NullValue())); - } else if (ins->type() == MIRType::MagicOptimizedArguments) { - current->setSlot(i, constant(MagicValue(JS_OPTIMIZED_ARGUMENTS))); - } else { - MOZ_ASSERT(!IsMagicType(ins->type())); - } - continue; - } - - if (ins == subject) { - if (!replace) { - replace = MFilterTypeSet::New(alloc(), subject, type); - current->add(replace); - - // Make sure we don't hoist it above the MTest, we can use the - // 'dependency' of an MInstruction. This is normally used by - // Alias Analysis, but won't get overwritten, since this - // instruction doesn't have an AliasSet. - replace->setDependency(test); - - if (replace->type() == MIRType::Undefined) { - replace = constant(UndefinedValue()); - } else if (replace->type() == MIRType::Null) { - replace = constant(NullValue()); - } else if (replace->type() == MIRType::MagicOptimizedArguments) { - replace = constant(MagicValue(JS_OPTIMIZED_ARGUMENTS)); - } else { - MOZ_ASSERT(!IsMagicType(ins->type())); - } - } - current->setSlot(i, replace); - } - } - return Ok(); -} - -AbortReasonOr IonBuilder::improveTypesAtCompare(MCompare* ins, - bool trueBranch, - MTest* test) { - if (ins->compareType() == MCompare::Compare_Undefined || - ins->compareType() == MCompare::Compare_Null) { - return improveTypesAtNullOrUndefinedCompare(ins, trueBranch, test); - } - - if ((ins->lhs()->isTypeOf() || ins->rhs()->isTypeOf()) && - (ins->lhs()->isConstant() || ins->rhs()->isConstant())) { - return improveTypesAtTypeOfCompare(ins, trueBranch, test); - } - - return Ok(); -} - -AbortReasonOr IonBuilder::improveTypesAtTypeOfCompare(MCompare* ins, - bool trueBranch, - MTest* test) { - MTypeOf* typeOf = - ins->lhs()->isTypeOf() ? ins->lhs()->toTypeOf() : ins->rhs()->toTypeOf(); - MConstant* constant = ins->lhs()->isConstant() ? ins->lhs()->toConstant() - : ins->rhs()->toConstant(); - - if (constant->type() != MIRType::String) { - return Ok(); - } - - bool equal = ins->jsop() == JSOp::Eq || ins->jsop() == JSOp::StrictEq; - bool notEqual = ins->jsop() == JSOp::Ne || ins->jsop() == JSOp::StrictNe; - - if (notEqual) { - trueBranch = !trueBranch; - } - - // Relational compares not supported. - if (!equal && !notEqual) { - return Ok(); - } - - MDefinition* subject = typeOf->input(); - TemporaryTypeSet* inputTypes = subject->resultTypeSet(); - - // Create temporary typeset equal to the type if there is no resultTypeSet. - TemporaryTypeSet tmp; - if (!inputTypes) { - if (subject->type() == MIRType::Value) { - return Ok(); - } - inputTypes = &tmp; - tmp.addType(TypeSet::PrimitiveOrAnyObjectType(subject->type()), - alloc_->lifoAlloc()); - } - - if (inputTypes->unknown() || inputTypes->hasType(TypeSet::MagicArgType())) { - return Ok(); - } - - // Note: we cannot remove the AnyObject type in the false branch, - // since there are multiple ways to get an object. That is the reason - // for the 'trueBranch' test. - TemporaryTypeSet filter; - const JSAtomState& names = mirGen_.runtime->names(); - if (constant->toString() == TypeName(JSTYPE_UNDEFINED, names)) { - filter.addType(TypeSet::UndefinedType(), alloc_->lifoAlloc()); - if (typeOf->inputMaybeCallableOrEmulatesUndefined() && trueBranch) { - filter.addType(TypeSet::AnyObjectType(), alloc_->lifoAlloc()); - } - } else if (constant->toString() == TypeName(JSTYPE_BOOLEAN, names)) { - filter.addType(TypeSet::BooleanType(), alloc_->lifoAlloc()); - } else if (constant->toString() == TypeName(JSTYPE_NUMBER, names)) { - filter.addType(TypeSet::Int32Type(), alloc_->lifoAlloc()); - filter.addType(TypeSet::DoubleType(), alloc_->lifoAlloc()); - } else if (constant->toString() == TypeName(JSTYPE_STRING, names)) { - filter.addType(TypeSet::StringType(), alloc_->lifoAlloc()); - } else if (constant->toString() == TypeName(JSTYPE_SYMBOL, names)) { - filter.addType(TypeSet::SymbolType(), alloc_->lifoAlloc()); - } else if (constant->toString() == TypeName(JSTYPE_BIGINT, names)) { - filter.addType(TypeSet::BigIntType(), alloc_->lifoAlloc()); - } else if (constant->toString() == TypeName(JSTYPE_OBJECT, names)) { - filter.addType(TypeSet::NullType(), alloc_->lifoAlloc()); - if (trueBranch) { - filter.addType(TypeSet::AnyObjectType(), alloc_->lifoAlloc()); - } - } else if (constant->toString() == TypeName(JSTYPE_FUNCTION, names)) { - if (typeOf->inputMaybeCallableOrEmulatesUndefined() && trueBranch) { - filter.addType(TypeSet::AnyObjectType(), alloc_->lifoAlloc()); - } - } else { - return Ok(); - } - - TemporaryTypeSet* type; - if (trueBranch) { - type = TypeSet::intersectSets(&filter, inputTypes, alloc_->lifoAlloc()); - } else { - type = TypeSet::removeSet(inputTypes, &filter, alloc_->lifoAlloc()); - } - - if (!type) { - return abort(AbortReason::Alloc); - } - - return replaceTypeSet(subject, type, test); -} - -AbortReasonOr IonBuilder::improveTypesAtNullOrUndefinedCompare( - MCompare* ins, bool trueBranch, MTest* test) { - MOZ_ASSERT(ins->compareType() == MCompare::Compare_Undefined || - ins->compareType() == MCompare::Compare_Null); - - // altersUndefined/Null represents if we can filter/set Undefined/Null. - bool altersUndefined, altersNull; - JSOp op = ins->jsop(); - - switch (op) { - case JSOp::StrictNe: - case JSOp::StrictEq: - altersUndefined = ins->compareType() == MCompare::Compare_Undefined; - altersNull = ins->compareType() == MCompare::Compare_Null; - break; - case JSOp::Ne: - case JSOp::Eq: - altersUndefined = altersNull = true; - break; - default: - MOZ_CRASH("Relational compares not supported"); - } - - MDefinition* subject = ins->lhs(); - TemporaryTypeSet* inputTypes = subject->resultTypeSet(); - - MOZ_ASSERT(IsNullOrUndefined(ins->rhs()->type())); - - // Create temporary typeset equal to the type if there is no resultTypeSet. - TemporaryTypeSet tmp; - if (!inputTypes) { - if (subject->type() == MIRType::Value) { - return Ok(); - } - inputTypes = &tmp; - tmp.addType(TypeSet::PrimitiveOrAnyObjectType(subject->type()), - alloc_->lifoAlloc()); - } - - if (inputTypes->unknown() || inputTypes->hasType(TypeSet::MagicArgType())) { - return Ok(); - } - - TemporaryTypeSet* type; - - // Decide if we need to filter the type or set it. - if ((op == JSOp::StrictEq || op == JSOp::Eq) ^ trueBranch) { - // Remove undefined/null - TemporaryTypeSet remove; - if (altersUndefined) { - remove.addType(TypeSet::UndefinedType(), alloc_->lifoAlloc()); - } - if (altersNull) { - remove.addType(TypeSet::NullType(), alloc_->lifoAlloc()); - } - - type = TypeSet::removeSet(inputTypes, &remove, alloc_->lifoAlloc()); - } else { - // Set undefined/null. - TemporaryTypeSet base; - if (altersUndefined) { - base.addType(TypeSet::UndefinedType(), alloc_->lifoAlloc()); - // If TypeSet emulates undefined, then we cannot filter the objects. - if (inputTypes->maybeEmulatesUndefined(constraints())) { - base.addType(TypeSet::AnyObjectType(), alloc_->lifoAlloc()); - } - } - - if (altersNull) { - base.addType(TypeSet::NullType(), alloc_->lifoAlloc()); - } - - type = TypeSet::intersectSets(&base, inputTypes, alloc_->lifoAlloc()); - } - - if (!type) { - return abort(AbortReason::Alloc); - } - - return replaceTypeSet(subject, type, test); -} - -AbortReasonOr IonBuilder::improveTypesAtTestSuccessor( - MTest* test, MBasicBlock* successor) { - MOZ_ASSERT(successor->numPredecessors() == 1); - MOZ_ASSERT(test->block() == successor->getPredecessor(0)); - - MOZ_ASSERT(test->ifTrue() == successor || test->ifFalse() == successor); - bool trueBranch = test->ifTrue() == successor; - - return improveTypesAtTest(test->getOperand(0), trueBranch, test); -} - -AbortReasonOr IonBuilder::improveTypesAtTest(MDefinition* ins, - bool trueBranch, MTest* test) { - // We explore the test condition to try and deduce as much type information - // as possible. - - // All branches of this switch that don't want to fall through to the - // default behavior must return. The default behavior assumes that a true - // test means the incoming ins is not null or undefined and that a false - // tests means it's one of null, undefined, false, 0, "", and objects - // emulating undefined - switch (ins->op()) { - case MDefinition::Opcode::Not: - return improveTypesAtTest(ins->toNot()->getOperand(0), !trueBranch, test); - case MDefinition::Opcode::IsObject: { - MDefinition* subject = ins->getOperand(0); - TemporaryTypeSet* oldType = subject->resultTypeSet(); - - // Create temporary typeset equal to the type if there is no - // resultTypeSet. - TemporaryTypeSet tmp; - if (!oldType) { - if (subject->type() == MIRType::Value) { - return Ok(); - } - oldType = &tmp; - tmp.addType(TypeSet::PrimitiveOrAnyObjectType(subject->type()), - alloc_->lifoAlloc()); - } - - if (oldType->unknown() || oldType->hasType(TypeSet::MagicArgType())) { - return Ok(); - } - - TemporaryTypeSet* type = nullptr; - if (trueBranch) { - type = oldType->cloneObjectsOnly(alloc_->lifoAlloc()); - } else { - type = oldType->cloneWithoutObjects(alloc_->lifoAlloc()); - } - - if (!type) { - return abort(AbortReason::Alloc); - } - - return replaceTypeSet(subject, type, test); - } - case MDefinition::Opcode::IsNullOrUndefined: { - MDefinition* subject = ins->getOperand(0); - TemporaryTypeSet* oldType = subject->resultTypeSet(); - - // Create temporary typeset equal to the type if there is no - // resultTypeSet. - TemporaryTypeSet tmp; - if (!oldType) { - if (subject->type() == MIRType::Value) { - return Ok(); - } - oldType = &tmp; - tmp.addType(TypeSet::PrimitiveOrAnyObjectType(subject->type()), - alloc_->lifoAlloc()); - } - - // If ins does not have a typeset we return as we cannot optimize. - if (oldType->unknown() || oldType->hasType(TypeSet::MagicArgType())) { - return Ok(); - } - - // Decide either to set or remove. - TemporaryTypeSet filter; - filter.addType(TypeSet::UndefinedType(), alloc_->lifoAlloc()); - filter.addType(TypeSet::NullType(), alloc_->lifoAlloc()); - - TemporaryTypeSet* type; - if (trueBranch) { - type = TypeSet::intersectSets(&filter, oldType, alloc_->lifoAlloc()); - } else { - type = TypeSet::removeSet(oldType, &filter, alloc_->lifoAlloc()); - } - - if (!type) { - return abort(AbortReason::Alloc); - } - - return replaceTypeSet(subject, type, test); - } - - case MDefinition::Opcode::Compare: - return improveTypesAtCompare(ins->toCompare(), trueBranch, test); - - default: - break; - } - - // By default MTest tests ToBoolean(input). As a result in the true branch we - // can filter undefined and null. In false branch we can only encounter - // undefined, null, false, 0, "" and objects that emulate undefined. - - TemporaryTypeSet* oldType = ins->resultTypeSet(); - TemporaryTypeSet* type; - - // Create temporary typeset equal to the type if there is no resultTypeSet. - TemporaryTypeSet tmp; - if (!oldType) { - if (ins->type() == MIRType::Value) { - return Ok(); - } - oldType = &tmp; - tmp.addType(TypeSet::PrimitiveOrAnyObjectType(ins->type()), - alloc_->lifoAlloc()); - } - - // If ins does not have a typeset we return as we cannot optimize. - if (oldType->unknown() || oldType->hasType(TypeSet::MagicArgType())) { - return Ok(); - } - - // Decide either to set or remove. - if (trueBranch) { - TemporaryTypeSet remove; - remove.addType(TypeSet::UndefinedType(), alloc_->lifoAlloc()); - remove.addType(TypeSet::NullType(), alloc_->lifoAlloc()); - type = TypeSet::removeSet(oldType, &remove, alloc_->lifoAlloc()); - } else { - TemporaryTypeSet base; - base.addType(TypeSet::UndefinedType(), - alloc_->lifoAlloc()); // ToBoolean(undefined) == false - base.addType(TypeSet::NullType(), - alloc_->lifoAlloc()); // ToBoolean(null) == false - base.addType(TypeSet::BooleanType(), - alloc_->lifoAlloc()); // ToBoolean(false) == false - base.addType(TypeSet::Int32Type(), - alloc_->lifoAlloc()); // ToBoolean(0) == false - base.addType(TypeSet::DoubleType(), - alloc_->lifoAlloc()); // ToBoolean(0.0) == false - base.addType(TypeSet::StringType(), - alloc_->lifoAlloc()); // ToBoolean("") == false - base.addType(TypeSet::BigIntType(), - alloc_->lifoAlloc()); // ToBoolean(0n) == false - - // If the typeset does emulate undefined, then we cannot filter out - // objects. - if (oldType->maybeEmulatesUndefined(constraints())) { - base.addType(TypeSet::AnyObjectType(), alloc_->lifoAlloc()); - } - - type = TypeSet::intersectSets(&base, oldType, alloc_->lifoAlloc()); - } - - if (!type) { - return abort(AbortReason::Alloc); - } - - return replaceTypeSet(ins, type, test); -} - -AbortReasonOr IonBuilder::jsop_dup2() { - uint32_t lhsSlot = current->stackDepth() - 2; - uint32_t rhsSlot = current->stackDepth() - 1; - current->pushSlot(lhsSlot); - current->pushSlot(rhsSlot); - return Ok(); -} - -AbortReasonOr IonBuilder::visitTestBackedge(JSOp op, bool* restarted) { - MOZ_ASSERT(op == JSOp::IfNe); - MOZ_ASSERT(loopDepth_ > 0); - - MDefinition* ins = current->pop(); - - jsbytecode* loopHead = pc + GET_JUMP_OFFSET(pc); - MOZ_ASSERT(JSOp(*loopHead) == JSOp::LoopHead); - - jsbytecode* successorPC = GetNextPc(pc); - - // We can finish the loop now. Use the loophead pc instead of the current pc - // because the stack depth at the start of that op matches the current stack - // depth (after popping our operand). - MBasicBlock* backedge; - MOZ_TRY_VAR(backedge, newBlock(current, loopHead)); - - current->end(newTest(ins, backedge, nullptr)); - MOZ_TRY(addPendingEdge(PendingEdge::NewTestFalse(current, op), successorPC)); - - MOZ_TRY(startTraversingBlock(backedge)); - return visitBackEdge(restarted); -} - -AbortReasonOr IonBuilder::visitTest(JSOp op, bool* restarted) { - MOZ_ASSERT(op == JSOp::IfEq || op == JSOp::IfNe || op == JSOp::And || - op == JSOp::Or || op == JSOp::Case); - - if (IsBackedgePC(pc)) { - return visitTestBackedge(op, restarted); - } - - jsbytecode* target1 = GetNextPc(pc); - jsbytecode* target2 = pc + GET_JUMP_OFFSET(pc); - - // JSOp::And and JSOp::Or inspect the top stack value but don't pop it. - // Also note that JSOp::Case must pop a second value on the true-branch (the - // input to the switch-statement). This conditional pop happens in - // visitJumpTarget. - bool mustKeepCondition = (op == JSOp::And || op == JSOp::Or); - MDefinition* ins = mustKeepCondition ? current->peek(-1) : current->pop(); - - // If this op always branches to the same pc we treat this as a JSOp::Goto. - if (target1 == target2) { - ins->setImplicitlyUsedUnchecked(); - return visitGoto(target1); - } - - MTest* mir = newTest(ins, nullptr, nullptr); - current->end(mir); - - if (TestTrueTargetIsJoinPoint(op)) { - std::swap(target1, target2); - } - - MOZ_TRY(addPendingEdge(PendingEdge::NewTestTrue(current, op), target1)); - MOZ_TRY(addPendingEdge(PendingEdge::NewTestFalse(current, op), target2)); - setTerminatedBlock(); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_coalesce() { - jsbytecode* target1 = GetNextPc(pc); - jsbytecode* target2 = pc + GET_JUMP_OFFSET(pc); - MOZ_ASSERT(target2 > target1); - - MDefinition* ins = current->peek(-1); - - MIsNullOrUndefined* isNullOrUndefined = MIsNullOrUndefined::New(alloc(), ins); - current->add(isNullOrUndefined); - - MTest* mir = newTest(isNullOrUndefined, nullptr, nullptr); - current->end(mir); - - MOZ_TRY(addPendingEdge(PendingEdge::NewTestTrue(current, JSOp::Coalesce), - target1)); - MOZ_TRY(addPendingEdge(PendingEdge::NewTestFalse(current, JSOp::Coalesce), - target2)); - setTerminatedBlock(); - - return Ok(); -} - -AbortReasonOr IonBuilder::visitTry() { - // We don't support try-finally. - if (script()->jitScript()->hasTryFinally()) { - return abort(AbortReason::Disable, "Try-finally not supported"); - } - - // Try-catch within inline frames is not yet supported. - if (isInlineBuilder()) { - return abort(AbortReason::Disable, "Try-catch during inlining"); - } - - // Try-catch during analyses is not yet supported. Code within the 'catch' - // block is not accounted for. - if (info().isAnalysis()) { - return abort(AbortReason::Disable, "Try-catch during analysis"); - } - - graph().setHasTryBlock(); - - MBasicBlock* tryBlock; - MOZ_TRY_VAR(tryBlock, newBlock(current, GetNextPc(pc))); - - current->end(MGoto::New(alloc(), tryBlock)); - - return startTraversingBlock(tryBlock); -} - -AbortReasonOr IonBuilder::visitJumpTarget(JSOp op) { - PendingEdgesMap::Ptr p = pendingEdges_.lookup(pc); - if (!p) { - // No (reachable) jumps so this is just a no-op. - return Ok(); - } - - PendingEdges edges(std::move(p->value())); - pendingEdges_.remove(p); - - // Loop-restarts may clear the list rather than remove the map entry entirely. - // This is to reduce allocator churn since it is likely the list will be - // filled in again in the general case. - if (edges.empty()) { - return Ok(); - } - - MBasicBlock* joinBlock = nullptr; - - // Create join block if there's fall-through from the previous bytecode op. - if (!hasTerminatedBlock()) { - MOZ_TRY_VAR(joinBlock, newBlock(current, pc)); - current->end(MGoto::New(alloc(), joinBlock)); - setTerminatedBlock(); - } - - auto addEdge = [&](MBasicBlock* pred, size_t numToPop) -> AbortReasonOr { - if (joinBlock) { - MOZ_ASSERT(pred->stackDepth() - numToPop == joinBlock->stackDepth()); - if (!joinBlock->addPredecessorPopN(alloc(), pred, numToPop)) { - return abort(AbortReason::Alloc); - } - return Ok(); - } - MOZ_TRY_VAR(joinBlock, newBlockPopN(pred, pc, numToPop)); - return Ok(); - }; - - // When a block is terminated with an MTest instruction we can end up with the - // following triangle structure: - // - // testBlock - // / | - // block | - // \ | - // joinBlock - // - // Although this is fine for correctness, it has the following issues: - // - // 1) The FoldTests pass is unable to optimize this pattern. This matters for - // short-circuit operations (JSOp::And, JSOp::Coalesce, etc). - // - // 2) We can't easily use improveTypesAtTest to improve type information in - // this case: - // - // var obj = ...; - // if (obj === null) { - // obj = {}; - // } - // ... obj must be non-null ... - // - // To fix these issues, we create an empty block to get a diamond structure: - // - // testBlock - // / | - // block emptyBlock - // \ | - // joinBlock - auto createEmptyBlockForTest = - [&](MBasicBlock* pred, size_t successor, - size_t numToPop) -> AbortReasonOr { - MOZ_ASSERT(joinBlock); - - MBasicBlock* emptyBlock; - MOZ_TRY_VAR(emptyBlock, newBlockPopN(pred, pc, numToPop)); - MOZ_ASSERT(emptyBlock->stackDepth() == joinBlock->stackDepth()); - - MTest* test = pred->lastIns()->toTest(); - test->initSuccessor(successor, emptyBlock); - - MOZ_TRY(startTraversingBlock(emptyBlock)); - MOZ_TRY(improveTypesAtTestSuccessor(test, emptyBlock)); - - emptyBlock->end(MGoto::New(alloc(), joinBlock)); - setTerminatedBlock(); - - return emptyBlock; - }; - - for (const PendingEdge& edge : edges) { - MBasicBlock* source = edge.block(); - MControlInstruction* lastIns = source->lastIns(); - switch (edge.kind()) { - case PendingEdge::Kind::TestTrue: { - // JSOp::Case must pop the value when branching to the true-target. - // If we create an empty block, we have to pop the value there instead - // of as part of the emptyBlock -> joinBlock edge so stack depths match - // the current depth. - const size_t numToPop = (edge.testOp() == JSOp::Case) ? 1 : 0; - - const size_t successor = 0; // true-branch - if (joinBlock && TestTrueTargetIsJoinPoint(edge.testOp())) { - MBasicBlock* pred; - MOZ_TRY_VAR(pred, - createEmptyBlockForTest(source, successor, numToPop)); - MOZ_TRY(addEdge(pred, 0)); - } else { - MOZ_TRY(addEdge(source, numToPop)); - lastIns->toTest()->initSuccessor(successor, joinBlock); - } - continue; - } - - case PendingEdge::Kind::TestFalse: { - const size_t numToPop = 0; - const size_t successor = 1; // false-branch - if (joinBlock && !TestTrueTargetIsJoinPoint(edge.testOp())) { - MBasicBlock* pred; - MOZ_TRY_VAR(pred, - createEmptyBlockForTest(source, successor, numToPop)); - MOZ_TRY(addEdge(pred, 0)); - } else { - MOZ_TRY(addEdge(source, numToPop)); - lastIns->toTest()->initSuccessor(successor, joinBlock); - } - continue; - } - - case PendingEdge::Kind::Goto: - MOZ_TRY(addEdge(source, 0)); - lastIns->toGoto()->initSuccessor(0, joinBlock); - continue; - } - MOZ_CRASH("Invalid kind"); - } - - MOZ_ASSERT(joinBlock); - MOZ_TRY(startTraversingBlock(joinBlock)); - - // If the join block has just one predecessor with an MTest, try to improve - // type information. - if (joinBlock->numPredecessors() == 1) { - MBasicBlock* pred = joinBlock->getPredecessor(0); - if (pred->lastIns()->isTest()) { - MTest* test = pred->lastIns()->toTest(); - MOZ_TRY(improveTypesAtTestSuccessor(test, joinBlock)); - } - } - - return Ok(); -} - -AbortReasonOr IonBuilder::visitReturn(JSOp op) { - MDefinition* def; - switch (op) { - case JSOp::Return: - // Return the last instruction. - def = current->pop(); - break; - - case JSOp::RetRval: - // Return undefined eagerly if script doesn't use return value. - if (script()->noScriptRval()) { - MInstruction* ins = MConstant::New(alloc(), UndefinedValue()); - current->add(ins); - def = ins; - break; - } - - def = current->getSlot(info().returnValueSlot()); - break; - - default: - MOZ_CRASH("unknown return op"); - } - - MReturn* ret = MReturn::New(alloc(), def); - current->end(ret); - - if (!graph().addReturn(current)) { - return abort(AbortReason::Alloc); - } - - setTerminatedBlock(); - - return Ok(); -} - -AbortReasonOr IonBuilder::visitThrow() { - MDefinition* def = current->pop(); - - MThrow* ins = MThrow::New(alloc(), def); - current->add(ins); - MOZ_TRY(resumeAfter(ins)); - - // Terminate the block. - current->end(MUnreachable::New(alloc())); - setTerminatedBlock(); - - return Ok(); -} - -AbortReasonOr IonBuilder::visitTableSwitch() { - jsbytecode* defaultpc = pc + GET_JUMP_OFFSET(pc); - - int32_t low = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN * 1); - int32_t high = GET_JUMP_OFFSET(pc + JUMP_OFFSET_LEN * 2); - size_t numCases = high - low + 1; - - // Create MIR instruction. - MDefinition* ins = current->pop(); - MTableSwitch* tableswitch = MTableSwitch::New(alloc(), ins, low, high); - current->end(tableswitch); - - MBasicBlock* switchBlock = current; - - // Create |default| block. - { - MBasicBlock* defaultBlock; - MOZ_TRY_VAR(defaultBlock, newBlock(switchBlock, defaultpc)); - - size_t index; - if (!tableswitch->addDefault(defaultBlock, &index)) { - return abort(AbortReason::Alloc); - } - MOZ_ASSERT(index == 0); - - MOZ_TRY(startTraversingBlock(defaultBlock)); - - defaultBlock->end(MGoto::New(alloc(), nullptr)); - MOZ_TRY(addPendingEdge(PendingEdge::NewGoto(defaultBlock), defaultpc)); - } - - // Create blocks for all cases. - for (size_t i = 0; i < numCases; i++) { - jsbytecode* casepc = script()->tableSwitchCasePC(pc, i); - - MBasicBlock* caseBlock; - MOZ_TRY_VAR(caseBlock, newBlock(switchBlock, casepc)); - - size_t index; - if (!tableswitch->addSuccessor(caseBlock, &index)) { - return abort(AbortReason::Alloc); - } - if (!tableswitch->addCase(index)) { - return abort(AbortReason::Alloc); - } - - MOZ_TRY(startTraversingBlock(caseBlock)); - - // If this is an actual case statement, optimize by replacing the - // input to the switch case with the actual number of the case. - MConstant* constant = MConstant::New(alloc(), Int32Value(low + int32_t(i))); - caseBlock->add(constant); - for (uint32_t j = 0; j < caseBlock->stackDepth(); j++) { - if (ins != caseBlock->getSlot(j)) { - continue; - } - - constant->setDependency(ins); - caseBlock->setSlot(j, constant); - } - - caseBlock->end(MGoto::New(alloc(), nullptr)); - MOZ_TRY(addPendingEdge(PendingEdge::NewGoto(caseBlock), casepc)); - } - - setTerminatedBlock(); - - return Ok(); -} - -void IonBuilder::pushConstant(const Value& v) { current->push(constant(v)); } - -static inline bool SimpleBitOpOperand(MDefinition* op) { - return op->definitelyType({MIRType::Undefined, MIRType::Null, - MIRType::Boolean, MIRType::Int32, MIRType::Double, - MIRType::Float32, MIRType::String}); -} - -AbortReasonOr IonBuilder::bitnotTrySpecialized(bool* emitted, - MDefinition* input) { - MOZ_ASSERT(*emitted == false); - - // Try to emit a specialized bitnot instruction based on the input type - // of the operand. - - if (!SimpleBitOpOperand(input)) { - return Ok(); - } - - MBitNot* ins = MBitNot::New(alloc(), input); - - current->add(ins); - current->push(ins); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_bitnot() { - bool emitted = false; - - MDefinition* input = current->pop(); - - if (!forceInlineCaches()) { - MOZ_TRY(bitnotTrySpecialized(&emitted, input)); - if (emitted) { - return Ok(); - } - } - - return arithUnaryBinaryCache(JSOp::BitNot, nullptr, input); -} - -AbortReasonOr IonBuilder::binaryBitOpTrySpecialized(bool* emitted, JSOp op, - MDefinition* left, - MDefinition* right) { - MOZ_ASSERT(*emitted == false); - - // Try to emit a specialized binary instruction based on the input types - // of the operands. - - // Anything complex - objects, symbols, and bigints - are not specialized - if (!SimpleBitOpOperand(left) || !SimpleBitOpOperand(right)) { - return Ok(); - } - - MBinaryBitwiseInstruction* ins; - switch (op) { - case JSOp::BitAnd: - ins = MBitAnd::New(alloc(), left, right, MIRType::Int32); - break; - - case JSOp::BitOr: - ins = MBitOr::New(alloc(), left, right, MIRType::Int32); - break; - - case JSOp::BitXor: - ins = MBitXor::New(alloc(), left, right, MIRType::Int32); - break; - - case JSOp::Lsh: - ins = MLsh::New(alloc(), left, right, MIRType::Int32); - break; - - case JSOp::Rsh: - ins = MRsh::New(alloc(), left, right, MIRType::Int32); - break; - - case JSOp::Ursh: { - MIRType specialization = MIRType::Int32; - if (inspector->hasSeenDoubleResult(pc)) { - specialization = MIRType::Double; - } - ins = MUrsh::New(alloc(), left, right, specialization); - break; - } - - default: - MOZ_CRASH("unexpected bitop"); - } - - current->add(ins); - current->push(ins); - if (ins->isEffectful()) { - MOZ_TRY(resumeAfter(ins)); - } - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_bitop(JSOp op) { - // Pop inputs. - MDefinition* right = current->pop(); - MDefinition* left = current->pop(); - - bool emitted = false; - - if (!forceInlineCaches()) { - MOZ_TRY(binaryBitOpTrySpecialized(&emitted, op, left, right)); - if (emitted) { - return Ok(); - } - } - - return arithUnaryBinaryCache(op, left, right); -} - -MDefinition::Opcode BinaryJSOpToMDefinition(JSOp op) { - switch (op) { - case JSOp::Add: - return MDefinition::Opcode::Add; - case JSOp::Sub: - return MDefinition::Opcode::Sub; - case JSOp::Mul: - return MDefinition::Opcode::Mul; - case JSOp::Div: - return MDefinition::Opcode::Div; - case JSOp::Mod: - return MDefinition::Opcode::Mod; - default: - MOZ_CRASH("unexpected binary opcode"); - } -} - -AbortReasonOr IonBuilder::binaryArithTryConcat(bool* emitted, JSOp op, - MDefinition* left, - MDefinition* right) { - MOZ_ASSERT(*emitted == false); - - // Try to convert an addition into a concat operation if the inputs - // indicate this might be a concatenation. - - // Only try to replace this with concat when we have an addition. - if (op != JSOp::Add) { - return Ok(); - } - - // Make sure one of the inputs is a string. - if (left->type() != MIRType::String && right->type() != MIRType::String) { - return Ok(); - } - - // The non-string input (if present) should be atleast easily coercible to - // string. - std::initializer_list coercibleToString = { - MIRType::Undefined, MIRType::Null, MIRType::Boolean, MIRType::Int32, - MIRType::Double, MIRType::Float32, MIRType::String, MIRType::BigInt, - }; - if (right->type() != MIRType::String && - !right->definitelyType(coercibleToString)) { - return Ok(); - } - if (left->type() != MIRType::String && - !left->definitelyType(coercibleToString)) { - return Ok(); - } - - MConcat* ins = MConcat::New(alloc(), left, right); - current->add(ins); - current->push(ins); - - MOZ_TRY(maybeInsertResume()); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::powTrySpecialized(bool* emitted, - MDefinition* base, - MDefinition* power, - MIRType outputType) { - // Typechecking. - MDefinition* output = nullptr; - MIRType baseType = base->type(); - MIRType powerType = power->type(); - - if (outputType != MIRType::Int32 && outputType != MIRType::Double) { - return Ok(); - } - if (!IsNumberType(baseType)) { - return Ok(); - } - if (!IsNumberType(powerType)) { - return Ok(); - } - - MPow* pow = MPow::New(alloc(), base, power, MIRType::Double); - current->add(pow); - output = pow; - - // Cast to the right type - if (outputType == MIRType::Int32 && output->type() != MIRType::Int32) { - auto* toInt = MToNumberInt32::New(alloc(), output); - current->add(toInt); - output = toInt; - } - if (outputType == MIRType::Double && output->type() != MIRType::Double) { - MToDouble* toDouble = MToDouble::New(alloc(), output); - current->add(toDouble); - output = toDouble; - } - - current->push(output); - *emitted = true; - return Ok(); -} - -MIRType IonBuilder::binaryArithNumberSpecialization(MDefinition* left, - MDefinition* right) { - // Try to specialize as int32. - if (left->type() == MIRType::Int32 && right->type() == MIRType::Int32 && - !inspector->hasSeenDoubleResult(pc)) { - return MIRType::Int32; - } - return MIRType::Double; -} - -AbortReasonOr IonBuilder::binaryArithEmitSpecialized( - MDefinition::Opcode op, MIRType specialization, MDefinition* left, - MDefinition* right) { - auto* ins = - MBinaryArithInstruction::New(alloc(), op, left, right, specialization); - current->add(ins); - current->push(ins); - - MOZ_ASSERT(!ins->isEffectful()); - MOZ_TRY(maybeInsertResume()); - - return ins; -} - -AbortReasonOr IonBuilder::binaryArithTrySpecialized(bool* emitted, JSOp op, - MDefinition* left, - MDefinition* right) { - MOZ_ASSERT(*emitted == false); - - // Try to emit a specialized binary instruction based on the input types - // of the operands. - - // Anything complex - strings, symbols, and objects - are not specialized - if (!SimpleArithOperand(left) || !SimpleArithOperand(right)) { - return Ok(); - } - - // One of the inputs need to be a number. - if (!IsNumberType(left->type()) && !IsNumberType(right->type())) { - return Ok(); - } - - MDefinition::Opcode defOp = BinaryJSOpToMDefinition(op); - MIRType specialization = binaryArithNumberSpecialization(left, right); - MBinaryArithInstruction* ins; - MOZ_TRY_VAR(ins, - binaryArithEmitSpecialized(defOp, specialization, left, right)); - - // Relax int32 to double if, despite the fact that we have int32 operands and - // we've never seen a double result, we know the result may overflow or be a - // double. - if (specialization == MIRType::Int32 && ins->constantDoubleResult(alloc())) { - ins->setSpecialization(MIRType::Double); - } - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::binaryArithTrySpecializedOnBaselineInspector( - bool* emitted, JSOp op, MDefinition* left, MDefinition* right) { - MOZ_ASSERT(*emitted == false); - - // Try to emit a specialized binary instruction speculating the - // type using the baseline caches. - - MIRType specialization = inspector->expectedBinaryArithSpecialization(pc); - if (specialization == MIRType::None) { - return Ok(); - } - - MDefinition::Opcode defOp = BinaryJSOpToMDefinition(op); - MOZ_TRY(binaryArithEmitSpecialized(defOp, specialization, left, right)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::arithUnaryBinaryCache(JSOp op, MDefinition* left, - MDefinition* right) { - MInstruction* stub = nullptr; - switch (JSOp(*pc)) { - case JSOp::Pos: - case JSOp::Neg: - case JSOp::BitNot: - MOZ_ASSERT_IF(op == JSOp::Mul, - left->maybeConstantValue() && - (left->maybeConstantValue()->toInt32() == -1 || - left->maybeConstantValue()->toInt32() == 1)); - MOZ_ASSERT_IF(op != JSOp::Mul, !left); - stub = MUnaryCache::New(alloc(), right); - break; - case JSOp::Add: - case JSOp::Sub: - case JSOp::Mul: - case JSOp::Div: - case JSOp::Mod: - case JSOp::Pow: - case JSOp::BitAnd: - case JSOp::BitOr: - case JSOp::BitXor: - case JSOp::Lsh: - case JSOp::Rsh: - case JSOp::Ursh: - stub = MBinaryCache::New(alloc(), left, right, MIRType::Value); - break; - default: - MOZ_CRASH("unsupported arith"); - } - - current->add(stub); - current->push(stub); - - // Decrease type from 'any type' to 'empty type' when one of the operands - // is 'empty typed'. - maybeMarkEmpty(stub); - - return resumeAfter(stub); -} - -MDefinition* IonBuilder::maybeConvertToNumber(MDefinition* def) { - // Try converting strings to numbers during IonBuilder MIR construction, - // because MIR foldsTo-folding runs off-main thread. - if (def->type() == MIRType::String && def->isConstant()) { - JSContext* cx = TlsContext.get(); - double d; - if (StringToNumberPure(cx, def->toConstant()->toString(), &d)) { - def->setImplicitlyUsedUnchecked(); - return constant(NumberValue(d)); - } - } - return def; -} - -AbortReasonOr IonBuilder::jsop_binary_arith(JSOp op, MDefinition* left, - MDefinition* right) { - bool emitted = false; - - if (!forceInlineCaches()) { - MOZ_TRY(binaryArithTryConcat(&emitted, op, left, right)); - if (emitted) { - return Ok(); - } - - if (op != JSOp::Add) { - left = maybeConvertToNumber(left); - right = maybeConvertToNumber(right); - } - - MOZ_TRY(binaryArithTrySpecialized(&emitted, op, left, right)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(binaryArithTrySpecializedOnBaselineInspector(&emitted, op, left, - right)); - if (emitted) { - return Ok(); - } - } - - return arithUnaryBinaryCache(op, left, right); -} - -AbortReasonOr IonBuilder::jsop_binary_arith(JSOp op) { - MDefinition* right = current->pop(); - MDefinition* left = current->pop(); - - return jsop_binary_arith(op, left, right); -} - -AbortReasonOr IonBuilder::jsop_pow() { - MDefinition* exponent = current->pop(); - MDefinition* base = current->pop(); - - bool emitted = false; - - if (!forceInlineCaches()) { - MOZ_TRY(powTrySpecialized(&emitted, base, exponent, MIRType::Double)); - if (emitted) { - return Ok(); - } - } - - return arithUnaryBinaryCache(JSOp::Pow, base, exponent); -} - -AbortReasonOr IonBuilder::jsop_pos() { - if (IsNumberType(current->peek(-1)->type())) { - // Already int32 or double. Set the operand as implicitly used so it - // doesn't get optimized out if it has no other uses, as we could bail - // out. - current->peek(-1)->setImplicitlyUsedUnchecked(); - return Ok(); - } - - // Compile +x as 1 * x. - MDefinition* value = current->pop(); - MConstant* one = MConstant::New(alloc(), Int32Value(1)); - current->add(one); - - return jsop_binary_arith(JSOp::Mul, one, value); -} - -AbortReasonOr IonBuilder::jsop_neg() { - // Since JSOp::Neg does not use a slot, we cannot push the MConstant. - // The MConstant is therefore passed to JSOp::Mul without slot traffic. - MConstant* negator = MConstant::New(alloc(), Int32Value(-1)); - current->add(negator); - - MDefinition* right = current->pop(); - - return jsop_binary_arith(JSOp::Mul, negator, right); -} - -AbortReasonOr IonBuilder::jsop_tonumeric() { - MDefinition* peeked = current->peek(-1); - - if (IsNumericType(peeked->type())) { - // Elide the ToNumeric as we already unboxed the value. - peeked->setImplicitlyUsedUnchecked(); - return Ok(); - } - - LifoAlloc* lifoAlloc = alloc().lifoAlloc(); - TemporaryTypeSet* types = lifoAlloc->new_(); - if (!types) { - return abort(AbortReason::Alloc); - } - - types->addType(TypeSet::Int32Type(), lifoAlloc); - types->addType(TypeSet::DoubleType(), lifoAlloc); - types->addType(TypeSet::BigIntType(), lifoAlloc); - - if (peeked->type() == MIRType::Value && peeked->resultTypeSet() && - peeked->resultTypeSet()->isSubset(types)) { - // Elide the ToNumeric because the arg is already a boxed numeric. - peeked->setImplicitlyUsedUnchecked(); - return Ok(); - } - - // Otherwise, pop the value and add an MUnaryCache. - MDefinition* popped = current->pop(); - MInstruction* ins = MUnaryCache::New(alloc(), popped); - ins->setResultTypeSet(types); // Improve type information for the result. - current->add(ins); - current->push(ins); - - // ToNumeric is effectful for objects (calls valueOf), so add a resume point. - return resumeAfter(ins); -} - -MDefinition* IonBuilder::unaryArithConvertToBinary(JSOp op, - MDefinition::Opcode* defOp) { - switch (op) { - case JSOp::Inc: { - *defOp = MDefinition::Opcode::Add; - MConstant* right = MConstant::New(alloc(), Int32Value(1)); - current->add(right); - return right; - } - case JSOp::Dec: { - *defOp = MDefinition::Opcode::Sub; - MConstant* right = MConstant::New(alloc(), Int32Value(1)); - current->add(right); - return right; - } - default: - MOZ_CRASH("unexpected unary opcode"); - } -} - -AbortReasonOr IonBuilder::unaryArithTrySpecialized(bool* emitted, JSOp op, - MDefinition* value) { - MOZ_ASSERT(*emitted == false); - - // Try to convert Inc(x) or Dec(x) to Add(x,1) or Sub(x,1) if the operand is a - // number. - - if (!IsNumberType(value->type())) { - return Ok(); - } - - MDefinition::Opcode defOp; - MDefinition* rhs = unaryArithConvertToBinary(op, &defOp); - MIRType specialization = binaryArithNumberSpecialization(value, rhs); - MOZ_TRY(binaryArithEmitSpecialized(defOp, specialization, value, rhs)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::unaryArithTrySpecializedOnBaselineInspector( - bool* emitted, JSOp op, MDefinition* value) { - MOZ_ASSERT(*emitted == false); - - // Try to emit a specialized binary instruction speculating the - // type using the baseline caches. - - MIRType specialization = inspector->expectedBinaryArithSpecialization(pc); - if (specialization == MIRType::None) { - return Ok(); - } - - MDefinition::Opcode defOp; - MDefinition* rhs = unaryArithConvertToBinary(op, &defOp); - MOZ_TRY(binaryArithEmitSpecialized(defOp, specialization, value, rhs)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_inc_or_dec(JSOp op) { - bool emitted = false; - MDefinition* value = current->pop(); - - MOZ_TRY(unaryArithTrySpecialized(&emitted, op, value)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(unaryArithTrySpecializedOnBaselineInspector(&emitted, op, value)); - if (emitted) { - return Ok(); - } - - MInstruction* stub = MUnaryCache::New(alloc(), value); - current->add(stub); - current->push(stub); - - // Decrease type from 'any type' to 'empty type' when one of the operands - // is 'empty typed'. - maybeMarkEmpty(stub); - - return resumeAfter(stub); -} - -AbortReasonOr IonBuilder::jsop_tostring() { - if (current->peek(-1)->type() == MIRType::String) { - return Ok(); - } - - MDefinition* value = current->pop(); - MToString* ins = - MToString::New(alloc(), value, MToString::SideEffectHandling::Supported); - current->add(ins); - current->push(ins); - if (ins->isEffectful()) { - MOZ_TRY(resumeAfter(ins)); - } - return Ok(); -} - -IonBuilder::InliningResult IonBuilder::inlineScriptedCall(CallInfo& callInfo, - JSFunction* target) { - MOZ_ASSERT(target->hasBytecode()); - MOZ_ASSERT(IsIonInlinableOp(JSOp(*pc))); - - MBasicBlock::BackupPoint backup(current); - if (!backup.init(alloc())) { - return abort(AbortReason::Alloc); - } - - callInfo.setImplicitlyUsedUnchecked(); - - // Create new |this| on the caller-side for inlined constructors. - if (callInfo.constructing()) { - MDefinition* thisDefn = - createThis(target, callInfo.callee(), callInfo.getNewTarget(), - /* inlining = */ true); - callInfo.setThis(thisDefn); - } - - // Capture formals in the outer resume point. - if (!callInfo.pushCallStack(current)) { - return abort(AbortReason::Alloc); - } - - MResumePoint* outerResumePoint = - MResumePoint::New(alloc(), current, pc, MResumePoint::Outer); - if (!outerResumePoint) { - return abort(AbortReason::Alloc); - } - current->setOuterResumePoint(outerResumePoint); - - // Pop formals again, except leave |callee| on stack for duration of call. - callInfo.popCallStack(current); - current->push(callInfo.callee()); - - JSScript* calleeScript = target->nonLazyScript(); - BaselineInspector inspector(calleeScript); - - // Improve type information of |this| when not set. - if (callInfo.constructing() && !callInfo.thisArg()->resultTypeSet()) { - AutoSweepJitScript sweep(calleeScript); - StackTypeSet* types = - calleeScript->jitScript()->thisTypes(sweep, calleeScript); - if (!types->unknown()) { - TemporaryTypeSet* clonedTypes = types->clone(alloc_->lifoAlloc()); - if (!clonedTypes) { - return abort(AbortReason::Alloc); - } - MTypeBarrier* barrier = - MTypeBarrier::New(alloc(), callInfo.thisArg(), clonedTypes); - current->add(barrier); - if (barrier->type() == MIRType::Undefined) { - callInfo.setThis(constant(UndefinedValue())); - } else if (barrier->type() == MIRType::Null) { - callInfo.setThis(constant(NullValue())); - } else { - callInfo.setThis(barrier); - } - } - } - - // Start inlining. - LifoAlloc* lifoAlloc = alloc_->lifoAlloc(); - InlineScriptTree* inlineScriptTree = - info().inlineScriptTree()->addCallee(alloc_, pc, calleeScript); - if (!inlineScriptTree) { - return abort(AbortReason::Alloc); - } - CompileInfo* info = lifoAlloc->new_( - mirGen_.runtime, calleeScript, target, (jsbytecode*)nullptr, - this->info().analysisMode(), - /* needsArgsObj = */ false, inlineScriptTree); - if (!info) { - return abort(AbortReason::Alloc); - } - - MIRGraphReturns returns(alloc()); - AutoAccumulateReturns aar(graph(), returns); - - // Build the graph. - IonBuilder inlineBuilder(analysisContext, mirGen_, info, constraints(), - &inspector, nullptr, inliningDepth_ + 1, loopDepth_); - AbortReasonOr result = - inlineBuilder.buildInline(this, outerResumePoint, callInfo); - if (result.isErr()) { - if (analysisContext && analysisContext->isExceptionPending()) { - JitSpew(JitSpew_IonAbort, "Inline builder raised exception."); - MOZ_ASSERT(result.unwrapErr() == AbortReason::Error); - return Err(result.unwrapErr()); - } - - // Inlining the callee failed. Mark the callee as uninlineable only if - // the inlining was aborted for a non-exception reason. - switch (result.unwrapErr()) { - case AbortReason::Disable: - calleeScript->setUninlineable(); - if (!JitOptions.disableInlineBacktracking) { - MBasicBlock* block = backup.restore(); - if (!block) { - return abort(AbortReason::Alloc); - } - setCurrent(block); - return InliningStatus_NotInlined; - } - return abort(AbortReason::Inlining); - - case AbortReason::PreliminaryObjects: { - const ObjectGroupVector& groups = - inlineBuilder.abortedPreliminaryGroups(); - MOZ_ASSERT(!groups.empty()); - for (size_t i = 0; i < groups.length(); i++) { - addAbortedPreliminaryGroup(groups[i]); - } - return Err(result.unwrapErr()); - } - - case AbortReason::Alloc: - case AbortReason::Inlining: - case AbortReason::Error: - return Err(result.unwrapErr()); - - case AbortReason::NoAbort: - MOZ_CRASH("Abort with AbortReason::NoAbort"); - return abort(AbortReason::Error); - } - } - - if (returns.empty()) { - // Inlining of functions that have no exit is not supported. - calleeScript->setUninlineable(); - if (!JitOptions.disableInlineBacktracking) { - MBasicBlock* block = backup.restore(); - if (!block) { - return abort(AbortReason::Alloc); - } - setCurrent(block); - return InliningStatus_NotInlined; - } - return abort(AbortReason::Inlining); - } - - // Create return block. - jsbytecode* postCall = GetNextPc(pc); - MBasicBlock* returnBlock; - MOZ_TRY_VAR(returnBlock, newBlock(current->stackDepth(), postCall)); - graph().addBlock(returnBlock); - returnBlock->setCallerResumePoint(callerResumePoint_); - - // Inherit the slots from current and pop |fun|. - returnBlock->inheritSlots(current); - returnBlock->pop(); - - // Accumulate return values. - MDefinition* retvalDefn = - patchInlinedReturns(target, callInfo, returns, returnBlock); - if (!retvalDefn) { - return abort(AbortReason::Alloc); - } - returnBlock->push(retvalDefn); - - // Initialize entry slots now that the stack has been fixed up. - if (!returnBlock->initEntrySlots(alloc())) { - return abort(AbortReason::Alloc); - } - - MOZ_TRY(setCurrentAndSpecializePhis(returnBlock)); - - return InliningStatus_Inlined; -} - -MDefinition* IonBuilder::patchInlinedReturn(JSFunction* target, - CallInfo& callInfo, - MBasicBlock* exit, - MBasicBlock* bottom) { - // Replaces the MReturn in the exit block with an MGoto. - MDefinition* rdef = exit->lastIns()->toReturn()->input(); - exit->discardLastIns(); - - // Constructors must be patched by the caller to always return an object. - if (callInfo.constructing()) { - if (target->isDerivedClassConstructor()) { - // Derived class constructors contain extra bytecode to ensure an object - // is always returned, so no additional patching is needed. - } else if (rdef->type() == MIRType::Value) { - // Unknown return: dynamically detect objects. - MReturnFromCtor* filter = - MReturnFromCtor::New(alloc(), rdef, callInfo.thisArg()); - exit->add(filter); - rdef = filter; - } else if (rdef->type() != MIRType::Object) { - // Known non-object return: force |this|. - rdef = callInfo.thisArg(); - } - } else if (callInfo.isSetter()) { - // Setters return their argument, not whatever value is returned. - rdef = callInfo.getArg(0); - } - - if (!callInfo.isSetter()) { - rdef = specializeInlinedReturn(rdef, exit); - } - - MGoto* replacement = MGoto::New(alloc(), bottom); - exit->end(replacement); - if (!bottom->addPredecessorWithoutPhis(exit)) { - return nullptr; - } - - return rdef; -} - -MDefinition* IonBuilder::specializeInlinedReturn(MDefinition* rdef, - MBasicBlock* exit) { - // Remove types from the return definition that weren't observed. - TemporaryTypeSet* types = bytecodeTypes(pc); - - // The observed typeset doesn't contain extra information. - if (types->empty() || types->unknown()) { - return rdef; - } - - // Decide if specializing is needed using the result typeset if available, - // else use the result type. - - if (rdef->resultTypeSet()) { - // Don't specialize if return typeset is a subset of the - // observed typeset. The return typeset is already more specific. - if (rdef->resultTypeSet()->isSubset(types)) { - return rdef; - } - } else { - MIRType observedType = types->getKnownMIRType(); - - // Don't specialize if type is MIRType::Float32 and TI reports - // MIRType::Double. Float is more specific than double. - if (observedType == MIRType::Double && rdef->type() == MIRType::Float32) { - return rdef; - } - - // Don't specialize if types are inaccordance, except for MIRType::Value - // and MIRType::Object (when not unknown object), since the typeset - // contains more specific information. - if (observedType == rdef->type() && observedType != MIRType::Value && - (observedType != MIRType::Object || types->unknownObject())) { - return rdef; - } - } - - setCurrent(exit); - - MTypeBarrier* barrier = nullptr; - rdef = addTypeBarrier(rdef, types, BarrierKind::TypeSet, &barrier); - if (barrier) { - barrier->setNotMovable(); - } - - return rdef; -} - -MDefinition* IonBuilder::patchInlinedReturns(JSFunction* target, - CallInfo& callInfo, - MIRGraphReturns& returns, - MBasicBlock* bottom) { - // Replaces MReturns with MGotos, returning the MDefinition - // representing the return value, or nullptr. - MOZ_ASSERT(returns.length() > 0); - - if (returns.length() == 1) { - return patchInlinedReturn(target, callInfo, returns[0], bottom); - } - - // Accumulate multiple returns with a phi. - MPhi* phi = MPhi::New(alloc()); - if (!phi->reserveLength(returns.length())) { - return nullptr; - } - - for (size_t i = 0; i < returns.length(); i++) { - MDefinition* rdef = - patchInlinedReturn(target, callInfo, returns[i], bottom); - if (!rdef) { - return nullptr; - } - phi->addInput(rdef); - } - - bottom->addPhi(phi); - return phi; -} - -IonBuilder::InliningDecision IonBuilder::makeInliningDecision( - JSObject* targetArg, CallInfo& callInfo) { - // When there is no target, inlining is impossible. - if (targetArg == nullptr) { - return InliningDecision_DontInline; - } - - // Inlining non-function targets is handled by inlineNonFunctionCall(). - if (!targetArg->is()) { - return InliningDecision_Inline; - } - - JSFunction* target = &targetArg->as(); - - // Never inline during the arguments usage analysis. - if (info().analysisMode() == Analysis_ArgumentsUsage) { - return InliningDecision_DontInline; - } - - // Native functions provide their own detection in inlineNativeCall(). - if (target->isNative()) { - return InliningDecision_Inline; - } - - // Determine whether inlining is possible at callee site - InliningDecision decision = canInlineTarget(target, callInfo); - if (decision != InliningDecision_Inline) { - return decision; - } - - // Heuristics! - JSScript* targetScript = target->nonLazyScript(); - - // Callee must not be excessively large. - // This heuristic also applies to the callsite as a whole. - bool offThread = mirGen_.options.offThreadCompilationAvailable(); - if (targetScript->length() > - optimizationInfo().inlineMaxBytecodePerCallSite(offThread)) { - return DontInline(targetScript, "Vetoed: callee excessively large"); - } - - // Callee must have been called a few times to have somewhat stable - // type information, except for definite properties analysis, - // as the caller has not run yet. - if (targetScript->getWarmUpCount() < - optimizationInfo().inliningWarmUpThreshold() && - !targetScript->jitScript()->ionCompiledOrInlined() && - info().analysisMode() != Analysis_DefiniteProperties) { - JitSpew(JitSpew_Inlining, - "Cannot inline %s:%u:%u: callee is insufficiently hot.", - targetScript->filename(), targetScript->lineno(), - targetScript->column()); - return InliningDecision_WarmUpCountTooLow; - } - - // Don't inline if the callee is known to inline a lot of code, to avoid - // huge MIR graphs. - uint32_t inlinedBytecodeLength = - targetScript->jitScript()->inlinedBytecodeLength(); - if (inlinedBytecodeLength > - optimizationInfo().inlineMaxCalleeInlinedBytecodeLength()) { - return DontInline(targetScript, - "Vetoed: callee inlinedBytecodeLength is too big"); - } - - IonBuilder* outerBuilder = outermostBuilder(); - - // Cap the total bytecode length we inline under a single script, to avoid - // excessive inlining in pathological cases. - size_t totalBytecodeLength = - outerBuilder->inlinedBytecodeLength_ + targetScript->length(); - if (totalBytecodeLength > optimizationInfo().inlineMaxTotalBytecodeLength()) { - return DontInline(targetScript, - "Vetoed: exceeding max total bytecode length"); - } - - // Cap the inlining depth. - - uint32_t maxInlineDepth; - if (JitOptions.isSmallFunction(targetScript)) { - maxInlineDepth = optimizationInfo().smallFunctionMaxInlineDepth(); - } else { - maxInlineDepth = optimizationInfo().maxInlineDepth(); - - // Caller must not be excessively large. - if (script()->length() >= - optimizationInfo().inliningMaxCallerBytecodeLength()) { - return DontInline(targetScript, "Vetoed: caller excessively large"); - } - } - - JitScript* outerJitScript = outermostBuilder()->script()->jitScript(); - if (inliningDepth_ >= maxInlineDepth) { - // We hit the depth limit and won't inline this function. Give the - // outermost script a max inlining depth of 0, so that it won't be - // inlined in other scripts. This heuristic is currently only used - // when we're inlining scripts with loops, see the comment below. - // These heuristics only apply to the highest optimization level. - if (isHighestOptimizationLevel()) { - outerJitScript->setMaxInliningDepth(0); - } - - return DontInline(targetScript, "Vetoed: exceeding allowed inline depth"); - } - - // Inlining functions with loops can be complicated. For instance, if we're - // close to the inlining depth limit and we inline the function f below, we - // can no longer inline the call to g: - // - // function f() { - // while (cond) { - // g(); - // } - // } - // - // If the loop has many iterations, it's more efficient to call f and inline - // g in f. - // - // To avoid this problem, we record a separate max inlining depth for each - // script, indicating at which depth we won't be able to inline all functions - // we inlined this time. This solves the issue above, because we will only - // inline f if it means we can also inline g. - // - // These heuristics only apply to the highest optimization level: other tiers - // do very little inlining and performance is not as much of a concern there. - if (isHighestOptimizationLevel() && targetScript->hasLoops() && - inliningDepth_ >= targetScript->jitScript()->maxInliningDepth()) { - return DontInline(targetScript, - "Vetoed: exceeding allowed script inline depth"); - } - - // Update the max depth at which we can inline the outer script. - MOZ_ASSERT(maxInlineDepth > inliningDepth_); - uint32_t scriptInlineDepth = maxInlineDepth - inliningDepth_ - 1; - if (scriptInlineDepth < outerJitScript->maxInliningDepth() && - isHighestOptimizationLevel()) { - outerJitScript->setMaxInliningDepth(scriptInlineDepth); - } - - // End of heuristics, we will inline this function. - - outerBuilder->inlinedBytecodeLength_ += targetScript->length(); - - return InliningDecision_Inline; -} - -AbortReasonOr IonBuilder::selectInliningTargets( - const InliningTargets& targets, CallInfo& callInfo, BoolVector& choiceSet, - uint32_t* numInlineable) { - *numInlineable = 0; - uint32_t totalSize = 0; - - // For each target, ask whether it may be inlined. - if (!choiceSet.reserve(targets.length())) { - return abort(AbortReason::Alloc); - } - - // Don't inline polymorphic sites during the definite properties analysis. - // AddClearDefiniteFunctionUsesInScript depends on this for correctness. - if (info().analysisMode() == Analysis_DefiniteProperties && - targets.length() > 1) { - return Ok(); - } - - for (size_t i = 0; i < targets.length(); i++) { - JSObject* target = targets[i].target; - - bool inlineable; - InliningDecision decision = makeInliningDecision(target, callInfo); - switch (decision) { - case InliningDecision_Error: - return abort(AbortReason::Error); - case InliningDecision_DontInline: - case InliningDecision_WarmUpCountTooLow: - inlineable = false; - break; - case InliningDecision_Inline: - inlineable = true; - break; - default: - MOZ_CRASH("Unhandled InliningDecision value!"); - } - - if (target->is()) { - // Enforce a maximum inlined bytecode limit at the callsite. - if (inlineable && target->as().isInterpreted()) { - totalSize += target->as().nonLazyScript()->length(); - bool offThread = mirGen_.options.offThreadCompilationAvailable(); - if (totalSize > - optimizationInfo().inlineMaxBytecodePerCallSite(offThread)) { - inlineable = false; - } - } - } else { - // Non-function targets are not supported by polymorphic inlining. - inlineable = false; - } - - // Only use a group guard and inline the target if we will recompile when - // the target function gets a new group. - if (inlineable && targets[i].group) { - ObjectGroup* group = targets[i].group; - TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(group); - if (!key->hasStableClassAndProto(constraints())) { - inlineable = false; - } - } - - choiceSet.infallibleAppend(inlineable); - if (inlineable) { - *numInlineable += 1; - } - } - - MOZ_ASSERT(choiceSet.length() == targets.length()); - return Ok(); -} - -static bool CanInlineGetPropertyCache(MGetPropertyCache* cache, - MDefinition* thisDef) { - if (cache->value()->type() != MIRType::Object) { - return false; - } - - if (cache->value() != thisDef) { - return false; - } - - InlinePropertyTable* table = cache->propTable(); - if (!table) { - return false; - } - if (table->numEntries() == 0) { - return false; - } - return true; -} - -class WrapMGetPropertyCache { - MGetPropertyCache* cache_; - - private: - void discardPriorResumePoint() { - if (!cache_) { - return; - } - - InlinePropertyTable* propTable = cache_->propTable(); - if (!propTable) { - return; - } - MResumePoint* rp = propTable->takePriorResumePoint(); - if (!rp) { - return; - } - cache_->block()->discardPreAllocatedResumePoint(rp); - } - - public: - explicit WrapMGetPropertyCache(MGetPropertyCache* cache) : cache_(cache) {} - - ~WrapMGetPropertyCache() { discardPriorResumePoint(); } - - MGetPropertyCache* get() { return cache_; } - MGetPropertyCache* operator->() { return get(); } - - // This function returns the cache given to the constructor if the - // GetPropertyCache can be moved into the ObjectGroup fallback path. - MGetPropertyCache* moveableCache(bool hasTypeBarrier, MDefinition* thisDef) { - // If we have unhandled uses of the MGetPropertyCache, then we cannot - // move it to the ObjectGroup fallback path. - if (!hasTypeBarrier) { - if (cache_->hasUses()) { - return nullptr; - } - } else { - // There is the TypeBarrier consumer, so we check that this is the - // only consumer. - MOZ_ASSERT(cache_->hasUses()); - if (!cache_->hasOneUse()) { - return nullptr; - } - } - - // If the this-object is not identical to the object of the - // MGetPropertyCache, then we cannot use the InlinePropertyTable, or if - // we do not yet have enough information from the ObjectGroup. - if (!CanInlineGetPropertyCache(cache_, thisDef)) { - return nullptr; - } - - MGetPropertyCache* ret = cache_; - cache_ = nullptr; - return ret; - } -}; - -MGetPropertyCache* IonBuilder::getInlineableGetPropertyCache( - CallInfo& callInfo) { - if (callInfo.constructing()) { - return nullptr; - } - - MDefinition* thisDef = callInfo.thisArg(); - if (thisDef->type() != MIRType::Object) { - return nullptr; - } - - MDefinition* funcDef = callInfo.callee(); - if (funcDef->type() != MIRType::Object) { - return nullptr; - } - - // MGetPropertyCache with no uses may be optimized away. - if (funcDef->isGetPropertyCache()) { - WrapMGetPropertyCache cache(funcDef->toGetPropertyCache()); - return cache.moveableCache(/* hasTypeBarrier = */ false, thisDef); - } - - // Optimize away the following common pattern: - // MTypeBarrier[MIRType::Object] <- MGetPropertyCache - if (funcDef->isTypeBarrier()) { - MTypeBarrier* barrier = funcDef->toTypeBarrier(); - if (barrier->hasUses()) { - return nullptr; - } - if (barrier->type() != MIRType::Object) { - return nullptr; - } - if (!barrier->input()->isGetPropertyCache()) { - return nullptr; - } - - WrapMGetPropertyCache cache(barrier->input()->toGetPropertyCache()); - return cache.moveableCache(/* hasTypeBarrier = */ true, thisDef); - } - - return nullptr; -} - -IonBuilder::InliningResult IonBuilder::inlineSingleCall(CallInfo& callInfo, - JSObject* targetArg) { - InliningStatus status; - if (!targetArg->is()) { - return InliningStatus_NotInlined; - } - - JSFunction* target = &targetArg->as(); - if (target->isNative()) { - MOZ_TRY_VAR(status, inlineNativeCall(callInfo, target)); - return status; - } - - return inlineScriptedCall(callInfo, target); -} - -IonBuilder::InliningResult IonBuilder::inlineCallsite( - const InliningTargets& targets, CallInfo& callInfo) { - if (targets.empty()) { - return InliningStatus_NotInlined; - } - - // Is the function provided by an MGetPropertyCache? - // If so, the cache may be movable to a fallback path, with a dispatch - // instruction guarding on the incoming ObjectGroup. - WrapMGetPropertyCache propCache(getInlineableGetPropertyCache(callInfo)); - keepFallbackFunctionGetter(propCache.get()); - - // Inline single targets -- unless they derive from a cache, in which case - // avoiding the cache and guarding is still faster. - if (!propCache.get() && targets.length() == 1) { - JSObject* target = targets[0].target; - - InliningDecision decision = makeInliningDecision(target, callInfo); - switch (decision) { - case InliningDecision_Error: - return abort(AbortReason::Error); - case InliningDecision_DontInline: - return InliningStatus_NotInlined; - case InliningDecision_WarmUpCountTooLow: - return InliningStatus_WarmUpCountTooLow; - case InliningDecision_Inline: - break; - } - - // Inlining will elminate uses of the original callee, but it needs to - // be preserved in phis if we bail out. Mark the old callee definition as - // implicitly used to ensure this happens. - callInfo.callee()->setImplicitlyUsedUnchecked(); - - // If the callee is not going to be a lambda (which may vary across - // different invocations), then the callee definition can be replaced by a - // constant. - if (target->isSingleton()) { - // Replace the function with an MConstant. - MConstant* constFun = constant(ObjectValue(*target)); - if (callInfo.constructing() && - callInfo.getNewTarget() == callInfo.callee()) { - callInfo.setNewTarget(constFun); - } - callInfo.setCallee(constFun); - } - - return inlineSingleCall(callInfo, target); - } - - // Choose a subset of the targets for polymorphic inlining. - BoolVector choiceSet(alloc()); - uint32_t numInlined; - MOZ_TRY(selectInliningTargets(targets, callInfo, choiceSet, &numInlined)); - if (numInlined == 0) { - return InliningStatus_NotInlined; - } - - // Perform a polymorphic dispatch. - MOZ_TRY(inlineCalls(callInfo, targets, choiceSet, propCache.get())); - - return InliningStatus_Inlined; -} - -AbortReasonOr IonBuilder::inlineGenericFallback( - const Maybe& targets, CallInfo& callInfo, - MBasicBlock* dispatchBlock) { - // Generate a new block with all arguments on-stack. - MBasicBlock* fallbackBlock; - MOZ_TRY_VAR(fallbackBlock, newBlock(dispatchBlock, pc)); - graph().addBlock(fallbackBlock); - - // Create a new CallInfo to track modified state within this block. - CallInfo fallbackInfo(alloc(), pc, callInfo.constructing(), - callInfo.ignoresReturnValue()); - if (!fallbackInfo.init(callInfo)) { - return abort(AbortReason::Alloc); - } - fallbackInfo.popCallStack(fallbackBlock); - - // Generate an MCall, which uses stateful |current|. - MOZ_TRY(setCurrentAndSpecializePhis(fallbackBlock)); - MOZ_TRY(makeCall(targets, fallbackInfo)); - - // Pass return block to caller as |current|. - return Ok(); -} - -AbortReasonOr IonBuilder::inlineObjectGroupFallback( - const Maybe& targets, CallInfo& callInfo, - MBasicBlock* dispatchBlock, MObjectGroupDispatch* dispatch, - MGetPropertyCache* cache, MBasicBlock** fallbackTarget) { - // Getting here implies the following: - // 1. The callee is an MGetPropertyCache, or an MGetPropertyCache - // followed by an MTypeBarrier. - MOZ_ASSERT(callInfo.callee()->isGetPropertyCache() || - callInfo.callee()->isTypeBarrier()); - - // 2. The MGetPropertyCache has inlineable cases by guarding on the - // ObjectGroup. - MOZ_ASSERT(dispatch->numCases() > 0); - - // 3. The MGetPropertyCache (and, if applicable, MTypeBarrier) only - // have at most a single use. - MOZ_ASSERT_IF(callInfo.callee()->isGetPropertyCache(), !cache->hasUses()); - MOZ_ASSERT_IF(callInfo.callee()->isTypeBarrier(), cache->hasOneUse()); - - // This means that no resume points yet capture the MGetPropertyCache, - // so everything from the MGetPropertyCache up until the call is movable. - // We now move the MGetPropertyCache and friends into a fallback path. - MOZ_ASSERT(cache->idempotent()); - - // Create a new CallInfo to track modified state within the fallback path. - CallInfo fallbackInfo(alloc(), pc, callInfo.constructing(), - callInfo.ignoresReturnValue()); - if (!fallbackInfo.init(callInfo)) { - return abort(AbortReason::Alloc); - } - - // Capture stack prior to the call operation. This captures the function. - MResumePoint* preCallResumePoint = - MResumePoint::New(alloc(), dispatchBlock, pc, MResumePoint::ResumeAt); - if (!preCallResumePoint) { - return abort(AbortReason::Alloc); - } - - DebugOnly preCallFuncIndex = - preCallResumePoint->stackDepth() - callInfo.numFormals(); - MOZ_ASSERT(preCallResumePoint->getOperand(preCallFuncIndex) == - fallbackInfo.callee()); - - // In the dispatch block, replace the function's slot entry with Undefined. - MConstant* undefined = MConstant::New(alloc(), UndefinedValue()); - dispatchBlock->add(undefined); - dispatchBlock->rewriteAtDepth(-int(callInfo.numFormals()), undefined); - - // Construct a block that does nothing but remove formals from the stack. - // This is effectively changing the entry resume point of the later fallback - // block. - MBasicBlock* prepBlock; - MOZ_TRY_VAR(prepBlock, newBlock(dispatchBlock, pc)); - graph().addBlock(prepBlock); - fallbackInfo.popCallStack(prepBlock); - - // Construct a block into which the MGetPropertyCache can be moved. - // This is subtle: the pc and resume point are those of the MGetPropertyCache! - InlinePropertyTable* propTable = cache->propTable(); - MResumePoint* priorResumePoint = propTable->takePriorResumePoint(); - MOZ_ASSERT(propTable->pc() != nullptr); - MOZ_ASSERT(priorResumePoint != nullptr); - MBasicBlock* getPropBlock; - MOZ_TRY_VAR(getPropBlock, - newBlock(prepBlock, propTable->pc(), priorResumePoint)); - graph().addBlock(getPropBlock); - - prepBlock->end(MGoto::New(alloc(), getPropBlock)); - - // Since the getPropBlock inherited the stack from right before the - // MGetPropertyCache, the target of the MGetPropertyCache is still on the - // stack. - DebugOnly checkObject = getPropBlock->pop(); - MOZ_ASSERT(checkObject == cache->value()); - - // Move the MGetPropertyCache and friends into the getPropBlock. - if (fallbackInfo.callee()->isGetPropertyCache()) { - MOZ_ASSERT(fallbackInfo.callee()->toGetPropertyCache() == cache); - getPropBlock->addFromElsewhere(cache); - getPropBlock->push(cache); - } else { - MTypeBarrier* barrier = callInfo.callee()->toTypeBarrier(); - MOZ_ASSERT(barrier->type() == MIRType::Object); - MOZ_ASSERT(barrier->input()->isGetPropertyCache()); - MOZ_ASSERT(barrier->input()->toGetPropertyCache() == cache); - - getPropBlock->addFromElsewhere(cache); - getPropBlock->addFromElsewhere(barrier); - getPropBlock->push(barrier); - } - - // Construct an end block with the correct resume point. - MBasicBlock* preCallBlock; - MOZ_TRY_VAR(preCallBlock, newBlock(getPropBlock, pc, preCallResumePoint)); - graph().addBlock(preCallBlock); - getPropBlock->end(MGoto::New(alloc(), preCallBlock)); - - // Now inline the MCallGeneric, using preCallBlock as the dispatch point. - MOZ_TRY(inlineGenericFallback(targets, fallbackInfo, preCallBlock)); - - // inlineGenericFallback() set the return block as |current|. - preCallBlock->end(MGoto::New(alloc(), current)); - *fallbackTarget = prepBlock; - return Ok(); -} - -AbortReasonOr IonBuilder::inlineCalls(CallInfo& callInfo, - const InliningTargets& targets, - BoolVector& choiceSet, - MGetPropertyCache* maybeCache) { - // Only handle polymorphic inlining. - MOZ_ASSERT(IsIonInlinableOp(JSOp(*pc))); - MOZ_ASSERT(choiceSet.length() == targets.length()); - MOZ_ASSERT_IF(!maybeCache, targets.length() >= 2); - MOZ_ASSERT_IF(maybeCache, targets.length() >= 1); - MOZ_ASSERT_IF(maybeCache, maybeCache->value()->type() == MIRType::Object); - - MBasicBlock* dispatchBlock = current; - callInfo.setImplicitlyUsedUnchecked(); - if (!callInfo.pushCallStack(dispatchBlock)) { - return abort(AbortReason::Alloc); - } - - // Patch any InlinePropertyTable to only contain functions that are - // inlineable. The InlinePropertyTable will also be patched at the end to - // exclude native functions that vetoed inlining. - if (maybeCache) { - InlinePropertyTable* propTable = maybeCache->propTable(); - propTable->trimToTargets(targets); - if (propTable->numEntries() == 0) { - maybeCache = nullptr; - } - } - - // Generate a dispatch based on guard kind. - MDispatchInstruction* dispatch; - if (maybeCache) { - dispatch = MObjectGroupDispatch::New(alloc(), maybeCache->value(), - maybeCache->propTable()); - callInfo.callee()->setImplicitlyUsedUnchecked(); - } else { - dispatch = MFunctionDispatch::New(alloc(), callInfo.callee()); - } - - MOZ_ASSERT(dispatchBlock->stackDepth() >= callInfo.numFormals()); - uint32_t stackDepth = dispatchBlock->stackDepth() - callInfo.numFormals() + 1; - - // Generate a return block to host the rval-collecting MPhi. - jsbytecode* postCall = GetNextPc(pc); - MBasicBlock* returnBlock; - MOZ_TRY_VAR(returnBlock, newBlock(stackDepth, postCall)); - graph().addBlock(returnBlock); - returnBlock->setCallerResumePoint(callerResumePoint_); - - // Set up stack, used to manually create a post-call resume point. - returnBlock->inheritSlots(dispatchBlock); - callInfo.popCallStack(returnBlock); - - MPhi* retPhi = MPhi::New(alloc()); - returnBlock->addPhi(retPhi); - returnBlock->push(retPhi); - - // Create a resume point from current stack state. - if (!returnBlock->initEntrySlots(alloc())) { - return abort(AbortReason::Alloc); - } - - // Reserve the capacity for the phi. - // Note: this is an upperbound. Unreachable targets and uninlineable natives - // are also counted. - uint32_t count = 1; // Possible fallback block. - for (uint32_t i = 0; i < targets.length(); i++) { - if (choiceSet[i]) { - count++; - } - } - if (!retPhi->reserveLength(count)) { - return abort(AbortReason::Alloc); - } - - // Inline each of the inlineable targets. - for (uint32_t i = 0; i < targets.length(); i++) { - // Target must be inlineable. - if (!choiceSet[i]) { - continue; - } - - // Target must be reachable by the MDispatchInstruction. - JSFunction* target = &targets[i].target->as(); - if (maybeCache && !maybeCache->propTable()->hasFunction(target)) { - choiceSet[i] = false; - continue; - } - - MBasicBlock* inlineBlock; - MOZ_TRY_VAR(inlineBlock, newBlock(dispatchBlock, pc)); - graph().addBlock(inlineBlock); - - // Create a function MConstant to use in the entry ResumePoint. If we - // can't use a constant, add a no-op MPolyInlineGuard, to prevent - // hoisting env chain gets above the dispatch instruction. - MInstruction* funcDef; - if (target->isSingleton()) { - funcDef = MConstant::New(alloc(), ObjectValue(*target), constraints()); - } else { - funcDef = MPolyInlineGuard::New(alloc(), callInfo.callee()); - } - - funcDef->setImplicitlyUsedUnchecked(); - dispatchBlock->add(funcDef); - - // Use the inlined callee in the inline resume point and on stack. - int funIndex = - inlineBlock->entryResumePoint()->stackDepth() - callInfo.numFormals(); - inlineBlock->entryResumePoint()->replaceOperand(funIndex, funcDef); - inlineBlock->rewriteSlot(funIndex, funcDef); - - // Create a new CallInfo to track modified state within the inline block. - CallInfo inlineInfo(alloc(), pc, callInfo.constructing(), - callInfo.ignoresReturnValue()); - if (!inlineInfo.init(callInfo)) { - return abort(AbortReason::Alloc); - } - inlineInfo.popCallStack(inlineBlock); - inlineInfo.setCallee(funcDef); - - if (callInfo.constructing() && - callInfo.getNewTarget() == callInfo.callee()) { - inlineInfo.setNewTarget(funcDef); - } - - if (maybeCache) { - // Assign the 'this' value a TypeSet specialized to the groups that - // can generate this inlining target. - MOZ_ASSERT(callInfo.thisArg() == maybeCache->value()); - TemporaryTypeSet* thisTypes = - maybeCache->propTable()->buildTypeSetForFunction(alloc(), target); - if (!thisTypes) { - return abort(AbortReason::Alloc); - } - - MFilterTypeSet* filter = - MFilterTypeSet::New(alloc(), inlineInfo.thisArg(), thisTypes); - inlineBlock->add(filter); - inlineInfo.setThis(filter); - } - - // Inline the call into the inlineBlock. - MOZ_TRY(setCurrentAndSpecializePhis(inlineBlock)); - InliningStatus status; - MOZ_TRY_VAR(status, inlineSingleCall(inlineInfo, target)); - - // Natives may veto inlining. - if (status == InliningStatus_NotInlined) { - MOZ_ASSERT(current == inlineBlock); - graph().removeBlock(inlineBlock); - choiceSet[i] = false; - continue; - } - - // inlineSingleCall() changed |current| to the inline return block. - MBasicBlock* inlineReturnBlock = current; - setCurrent(dispatchBlock); - - // Connect the inline path to the returnBlock. - if (!dispatch->addCase(target, targets[i].group, inlineBlock)) { - return abort(AbortReason::Alloc); - } - - MDefinition* retVal = inlineReturnBlock->peek(-1); - retPhi->addInput(retVal); - inlineReturnBlock->end(MGoto::New(alloc(), returnBlock)); - if (!returnBlock->addPredecessorWithoutPhis(inlineReturnBlock)) { - return abort(AbortReason::Alloc); - } - } - - // Patch the InlinePropertyTable to not dispatch to vetoed paths. - bool useFallback; - if (maybeCache) { - InlinePropertyTable* propTable = maybeCache->propTable(); - propTable->trimTo(targets, choiceSet); - - if (propTable->numEntries() == 0 || !propTable->hasPriorResumePoint()) { - // Output a generic fallback path. - MOZ_ASSERT_IF(propTable->numEntries() == 0, dispatch->numCases() == 0); - maybeCache = nullptr; - useFallback = true; - } else { - // We need a fallback path if the ObjectGroup dispatch does not - // handle all incoming objects. - useFallback = false; - TemporaryTypeSet* objectTypes = maybeCache->value()->resultTypeSet(); - for (uint32_t i = 0; i < objectTypes->getObjectCount(); i++) { - TypeSet::ObjectKey* obj = objectTypes->getObject(i); - if (!obj) { - continue; - } - - if (!obj->isGroup()) { - useFallback = true; - break; - } - - if (!propTable->hasObjectGroup(obj->group())) { - useFallback = true; - break; - } - } - - if (!useFallback) { - // The object group dispatch handles all possible incoming - // objects, so the cache and barrier will not be reached and - // can be eliminated. - if (callInfo.callee()->isGetPropertyCache()) { - MOZ_ASSERT(callInfo.callee() == maybeCache); - } else { - MTypeBarrier* barrier = callInfo.callee()->toTypeBarrier(); - MOZ_ASSERT(!barrier->hasUses()); - MOZ_ASSERT(barrier->type() == MIRType::Object); - MOZ_ASSERT(barrier->input()->isGetPropertyCache()); - MOZ_ASSERT(barrier->input()->toGetPropertyCache() == maybeCache); - barrier->block()->discard(barrier); - } - - MOZ_ASSERT(!maybeCache->hasUses()); - maybeCache->block()->discard(maybeCache); - } - } - } else { - useFallback = dispatch->numCases() < targets.length(); - } - - // If necessary, generate a fallback path. - if (useFallback) { - // Annotate the fallback call with the target information. - Maybe remainingTargets; - remainingTargets.emplace(alloc()); - for (uint32_t i = 0; i < targets.length(); i++) { - if (!maybeCache && choiceSet[i]) { - continue; - } - - JSObject* target = targets[i].target; - if (!target->is()) { - remainingTargets = Nothing(); - break; - } - if (!remainingTargets->append(&target->as())) { - return abort(AbortReason::Alloc); - } - } - - // Generate fallback blocks, and set |current| to the fallback return block. - if (maybeCache) { - MBasicBlock* fallbackTarget; - MOZ_TRY(inlineObjectGroupFallback( - remainingTargets, callInfo, dispatchBlock, - dispatch->toObjectGroupDispatch(), maybeCache, &fallbackTarget)); - dispatch->addFallback(fallbackTarget); - } else { - MOZ_TRY(inlineGenericFallback(remainingTargets, callInfo, dispatchBlock)); - dispatch->addFallback(current); - } - - MBasicBlock* fallbackReturnBlock = current; - - // Connect fallback case to return infrastructure. - MDefinition* retVal = fallbackReturnBlock->peek(-1); - retPhi->addInput(retVal); - fallbackReturnBlock->end(MGoto::New(alloc(), returnBlock)); - if (!returnBlock->addPredecessorWithoutPhis(fallbackReturnBlock)) { - return abort(AbortReason::Alloc); - } - } - - // Finally add the dispatch instruction. - // This must be done at the end so that add() may be called above. - dispatchBlock->end(dispatch); - - // Check the depth change: +1 for retval - MOZ_ASSERT(returnBlock->stackDepth() == - dispatchBlock->stackDepth() - callInfo.numFormals() + 1); - - graph().moveBlockToEnd(returnBlock); - return setCurrentAndSpecializePhis(returnBlock); -} - -MInstruction* IonBuilder::createNamedLambdaObject(MDefinition* callee, - MDefinition* env) { - // Get a template CallObject that we'll use to generate inline object - // creation. - LexicalEnvironmentObject* templateObj = - inspector->templateNamedLambdaObject(); - - // One field is added to the function to handle its name. This cannot be a - // dynamic slot because there is still plenty of room on the NamedLambda - // object. - MOZ_ASSERT(!templateObj->hasDynamicSlots()); - - // Allocate the actual object. It is important that no intervening - // instructions could potentially bailout, thus leaking the dynamic slots - // pointer. - MInstruction* declEnvObj = MNewNamedLambdaObject::New(alloc(), templateObj); - current->add(declEnvObj); - - // Initialize the object's reserved slots. No post barrier is needed here: - // the object will be allocated in the nursery if possible, and if the - // tenured heap is used instead, a minor collection will have been performed - // that moved env/callee to the tenured heap. - current->add(MStoreFixedSlot::New( - alloc(), declEnvObj, NamedLambdaObject::enclosingEnvironmentSlot(), env)); - current->add(MStoreFixedSlot::New(alloc(), declEnvObj, - NamedLambdaObject::lambdaSlot(), callee)); - - return declEnvObj; -} - -AbortReasonOr IonBuilder::createCallObject(MDefinition* callee, - MDefinition* env) { - // Get a template CallObject that we'll use to generate inline object - // creation. - CallObject* templateObj = inspector->templateCallObject(); - MConstant* templateCst = - MConstant::NewConstraintlessObject(alloc(), templateObj); - current->add(templateCst); - - // Allocate the object. - MNewCallObject* callObj = MNewCallObject::New(alloc(), templateCst); - current->add(callObj); - - // Initialize the object's reserved slots. No post barrier is needed here, - // for the same reason as in createNamedLambdaObject. - current->add(MStoreFixedSlot::New( - alloc(), callObj, CallObject::enclosingEnvironmentSlot(), env)); - current->add( - MStoreFixedSlot::New(alloc(), callObj, CallObject::calleeSlot(), callee)); - - // Copy closed-over argument slots if there aren't parameter expressions. - MSlots* slots = nullptr; - for (PositionalFormalParameterIter fi(script()); fi; fi++) { - if (!fi.closedOver()) { - continue; - } - - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - unsigned slot = fi.location().slot(); - unsigned formal = fi.argumentSlot(); - unsigned numFixedSlots = templateObj->numFixedSlots(); - MDefinition* param; - if (script()->functionHasParameterExprs()) { - param = constant(MagicValue(JS_UNINITIALIZED_LEXICAL)); - } else { - param = current->getSlot(info().argSlotUnchecked(formal)); - } - if (slot >= numFixedSlots) { - if (!slots) { - slots = MSlots::New(alloc(), callObj); - current->add(slots); - } - current->add( - MStoreDynamicSlot::New(alloc(), slots, slot - numFixedSlots, param)); - } else { - current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param)); - } - } - - return AbortReasonOr(callObj); -} - -MDefinition* IonBuilder::createThisScripted(MDefinition* callee, - MDefinition* newTarget) { - // Get callee.prototype. - // - // This instruction MUST be idempotent: since it does not correspond to an - // explicit operation in the bytecode, we cannot use resumeAfter(). - // Getters may not override |prototype| fetching, so this operation is - // indeed idempotent. - // - // Note: GetPropertyCache can trigger a GC, and thus invalidation. - MConstant* id = constant(StringValue(names().prototype)); - MGetPropertyCache* getPropCache = - MGetPropertyCache::New(alloc(), newTarget, id, - /* monitored = */ false); - getPropCache->setIdempotent(); - current->add(getPropCache); - - // Create this from prototype - MCreateThisWithProto* createThis = - MCreateThisWithProto::New(alloc(), callee, newTarget, getPropCache); - current->add(createThis); - - return createThis; -} - -JSObject* IonBuilder::getSingletonPrototype(JSFunction* target) { - TypeSet::ObjectKey* targetKey = TypeSet::ObjectKey::get(target); - if (targetKey->unknownProperties()) { - return nullptr; - } - - jsid protoid = NameToId(names().prototype); - HeapTypeSetKey protoProperty = targetKey->property(protoid); - - return protoProperty.singleton(constraints()); -} - -MDefinition* IonBuilder::createThisScriptedSingleton(JSFunction* target) { - if (!target->hasBytecode()) { - return nullptr; - } - - // Get the singleton prototype (if exists) - JSObject* proto = getSingletonPrototype(target); - if (!proto) { - return nullptr; - } - - JSObject* templateObject = inspector->getTemplateObject(pc); - if (!templateObject) { - return nullptr; - } - if (!templateObject->is()) { - return nullptr; - } - if (templateObject->staticPrototype() != proto) { - return nullptr; - } - if (templateObject->nonCCWRealm() != target->realm()) { - return nullptr; - } - - TypeSet::ObjectKey* templateObjectKey = - TypeSet::ObjectKey::get(templateObject->group()); - if (templateObjectKey->hasFlags(constraints(), - OBJECT_FLAG_NEW_SCRIPT_CLEARED)) { - return nullptr; - } - - JSScript* targetScript = target->nonLazyScript(); - JitScript* jitScript = targetScript->maybeJitScript(); - if (!jitScript) { - return nullptr; - } - - AutoSweepJitScript sweep(targetScript); - StackTypeSet* thisTypes = jitScript->thisTypes(sweep, targetScript); - if (!thisTypes->hasType(TypeSet::ObjectType(templateObject))) { - return nullptr; - } - - // Generate an inline path to create a new |this| object with - // the given singleton prototype. - MConstant* templateConst = - MConstant::NewConstraintlessObject(alloc(), templateObject); - MCreateThisWithTemplate* createThis = MCreateThisWithTemplate::New( - alloc(), constraints(), templateConst, - templateObject->group()->initialHeap(constraints())); - current->add(templateConst); - current->add(createThis); - - return createThis; -} - -MDefinition* IonBuilder::createThisScriptedBaseline(MDefinition* callee) { - // Try to inline |this| creation based on Baseline feedback. - - JSFunction* target = inspector->getSingleCallee(pc); - if (!target || !target->hasBytecode()) { - return nullptr; - } - - if (target->constructorNeedsUninitializedThis()) { - return nullptr; - } - - JSObject* templateObject = inspector->getTemplateObject(pc); - if (!templateObject) { - return nullptr; - } - if (!templateObject->is()) { - return nullptr; - } - if (templateObject->nonCCWRealm() != target->realm()) { - return nullptr; - } - - Shape* shape = target->lookupPure(realm->runtime()->names().prototype); - if (!shape || !shape->isDataProperty()) { - return nullptr; - } - - Value protov = target->getSlot(shape->slot()); - if (!protov.isObject()) { - return nullptr; - } - - JSObject* proto = checkNurseryObject(&protov.toObject()); - if (proto != templateObject->staticPrototype()) { - return nullptr; - } - - TypeSet::ObjectKey* templateObjectKey = - TypeSet::ObjectKey::get(templateObject->group()); - if (templateObjectKey->hasFlags(constraints(), - OBJECT_FLAG_NEW_SCRIPT_CLEARED)) { - return nullptr; - } - - JSScript* targetScript = target->nonLazyScript(); - JitScript* jitScript = targetScript->maybeJitScript(); - if (!jitScript) { - return nullptr; - } - - AutoSweepJitScript sweep(targetScript); - StackTypeSet* thisTypes = jitScript->thisTypes(sweep, targetScript); - if (!thisTypes->hasType(TypeSet::ObjectType(templateObject))) { - return nullptr; - } - - // Shape guard. - callee = addShapeGuard(callee, target->lastProperty()); - - // Guard callee.prototype == proto. - MOZ_ASSERT(shape->numFixedSlots() == 0, "Must be a dynamic slot"); - MSlots* slots = MSlots::New(alloc(), callee); - current->add(slots); - MLoadDynamicSlot* prototype = - MLoadDynamicSlot::New(alloc(), slots, shape->slot()); - current->add(prototype); - MDefinition* protoConst = constant(ObjectValue(*proto)); - MGuardObjectIdentity* guard = - MGuardObjectIdentity::New(alloc(), prototype, protoConst, - /* bailOnEquality = */ false); - current->add(guard); - - // Generate an inline path to create a new |this| object with - // the given prototype. - MConstant* templateConst = - MConstant::NewConstraintlessObject(alloc(), templateObject); - MCreateThisWithTemplate* createThis = MCreateThisWithTemplate::New( - alloc(), constraints(), templateConst, - templateObject->group()->initialHeap(constraints())); - current->add(templateConst); - current->add(createThis); - - return createThis; -} - -MDefinition* IonBuilder::createThisSlow(MDefinition* callee, - MDefinition* newTarget, bool inlining) { - // Call jit::CreateThisFromIon. This may return a NullValue for |this| that - // LCallGeneric has to check for if we can't create |this| inline. - MOZ_ASSERT(!inlining); - MCreateThis* createThis = MCreateThis::New(alloc(), callee, newTarget); - current->add(createThis); - return createThis; -} - -MDefinition* IonBuilder::createThis(JSFunction* target, MDefinition* callee, - MDefinition* newTarget, bool inlining) { - // getPolyCallTargets ensures |target| is a constructor. - MOZ_ASSERT_IF(target, target->isConstructor()); - - // Can't inline without a known target function. - MOZ_ASSERT_IF(inlining, target); - - // Create |this| for unknown target. - if (!target) { - if (callee == newTarget) { - if (MDefinition* createThis = createThisScriptedBaseline(callee)) { - return createThis; - } - } - return createThisSlow(callee, newTarget, inlining); - } - - // Handle known native functions, bound functions and derived class - // constructors. Note: proxies are already excluded since target has type - // JSFunction. - if (target->isNative()) { - MOZ_ASSERT(target->isNativeWithoutJitEntry(), - "Natives with JitEntry are not supported for constructor calls"); - return constant(MagicValue(JS_IS_CONSTRUCTING)); - } - if (target->constructorNeedsUninitializedThis()) { - return constant(MagicValue(JS_UNINITIALIZED_LEXICAL)); - } - - if (callee == newTarget) { - // We must not have an effectful .prototype lookup when inlining. - MOZ_ASSERT_IF(inlining, target->hasNonConfigurablePrototypeDataProperty()); - - // Try baking in the prototype. - if (MDefinition* createThis = createThisScriptedSingleton(target)) { - return createThis; - } - if (MDefinition* createThis = createThisScriptedBaseline(callee)) { - return createThis; - } - } - - // We can use createThisScripted if newTarget is known to be a function with a - // (builtin, getter-free) .prototype property and the callee is not one of the - // isNative/constructorNeedsUninitializedThis cases handled above. - JSFunction* newTargetFun = - callee == newTarget ? target - : getSingleCallTarget(newTarget->resultTypeSet()); - if (newTargetFun && newTargetFun->hasNonConfigurablePrototypeDataProperty()) { - return createThisScripted(callee, newTarget); - } - - // The .prototype lookup may be effectful, so we can't inline the call. - MOZ_ASSERT(!inlining); - return createThisSlow(callee, newTarget, inlining); -} - -AbortReasonOr IonBuilder::jsop_funcall(uint32_t argc) { - // Stack for JSOp::FunCall: - // 1: arg0 - // ... - // argc: argN - // argc+1: JSFunction*, the 'f' in |f.call()|, in |this| position. - // argc+2: The native 'call' function. - - int calleeDepth = -((int)argc + 2); - int funcDepth = -((int)argc + 1); - - // If |Function.prototype.call| may be overridden, don't optimize callsite. - TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet(); - JSFunction* native = getSingleCallTarget(calleeTypes); - if (!native || !native->isNative() || native->native() != &fun_call) { - CallInfo callInfo(alloc(), pc, /* constructing = */ false, - /* ignoresReturnValue = */ BytecodeIsPopped(pc)); - if (!callInfo.init(current, argc)) { - return abort(AbortReason::Alloc); - } - return makeCall(native, callInfo); - } - current->peek(calleeDepth)->setImplicitlyUsedUnchecked(); - - // Extract call target. - TemporaryTypeSet* funTypes = current->peek(funcDepth)->resultTypeSet(); - JSFunction* target = getSingleCallTarget(funTypes); - - CallInfo callInfo(alloc(), pc, /* constructing = */ false, - /* ignoresReturnValue = */ BytecodeIsPopped(pc)); - - // Save prior call stack in case we need to resolve during bailout - // recovery of inner inlined function. This includes the JSFunction and the - // 'call' native function. - if (!callInfo.savePriorCallStack(current, argc + 2)) { - return abort(AbortReason::Alloc); - } - - // Shimmy the slots down to remove the native 'call' function. - current->shimmySlots(funcDepth - 1); - - bool zeroArguments = (argc == 0); - - // If no |this| argument was provided, explicitly pass Undefined. - // Pushing is safe here, since one stack slot has been removed. - if (zeroArguments) { - pushConstant(UndefinedValue()); - } else { - // |this| becomes implicit in the call. - argc -= 1; - } - - if (!callInfo.init(current, argc)) { - return abort(AbortReason::Alloc); - } - - // Try to inline the call. - if (!zeroArguments) { - InliningDecision decision = makeInliningDecision(target, callInfo); - switch (decision) { - case InliningDecision_Error: - return abort(AbortReason::Error); - case InliningDecision_DontInline: - case InliningDecision_WarmUpCountTooLow: - break; - case InliningDecision_Inline: { - InliningStatus status; - MOZ_TRY_VAR(status, inlineSingleCall(callInfo, target)); - if (status == InliningStatus_Inlined) { - return Ok(); - } - break; - } - } - } - - // Call without inlining. - return makeCall(target, callInfo); -} - -AbortReasonOr IonBuilder::jsop_funapply(uint32_t argc) { - int calleeDepth = -((int)argc + 2); - - TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet(); - JSFunction* native = getSingleCallTarget(calleeTypes); - if (argc != 2 || info().analysisMode() == Analysis_ArgumentsUsage) { - CallInfo callInfo(alloc(), pc, /* constructing = */ false, - /* ignoresReturnValue = */ BytecodeIsPopped(pc)); - if (!callInfo.init(current, argc)) { - return abort(AbortReason::Alloc); - } - return makeCall(native, callInfo); - } - - // Disable compilation if the second argument to |apply| cannot be guaranteed - // to be either definitely |arguments| or definitely not |arguments|. - MDefinition* argument = current->peek(-1); - if (script()->argumentsHasVarBinding() && - argument->mightBeType(MIRType::MagicOptimizedArguments) && - argument->type() != MIRType::MagicOptimizedArguments) { - return abort(AbortReason::Disable, "fun.apply with MaybeArguments"); - } - - // Fallback to regular call if arg 2 is not definitely |arguments|. - if (argument->type() != MIRType::MagicOptimizedArguments) { - // Optimize fun.apply(self, array) if the length is sane and there are no - // holes. - TemporaryTypeSet* objTypes = argument->resultTypeSet(); - if (native && native->isNative() && native->native() == fun_apply && - objTypes && - objTypes->getKnownClass(constraints()) == &ArrayObject::class_ && - !objTypes->hasObjectFlags(constraints(), OBJECT_FLAG_LENGTH_OVERFLOW) && - ElementAccessIsPacked(constraints(), argument)) { - return jsop_funapplyarray(argc); - } - - CallInfo callInfo(alloc(), pc, /* constructing = */ false, - /* ignoresReturnValue = */ BytecodeIsPopped(pc)); - if (!callInfo.init(current, argc)) { - return abort(AbortReason::Alloc); - } - return makeCall(native, callInfo); - } - - if ((!native || !native->isNative() || native->native() != fun_apply) && - info().analysisMode() != Analysis_DefiniteProperties) { - return abort(AbortReason::Disable, "fun.apply speculation failed"); - } - - // Use funapply that definitely uses |arguments| - return jsop_funapplyarguments(argc); -} - -static void AssertSpreadArgIsArray(MDefinition* argument, - CompilerConstraintList* constraints) { -#ifdef DEBUG - // If we know class, ensure it is what we expected - if (TemporaryTypeSet* objTypes = argument->resultTypeSet()) { - if (const JSClass* clasp = objTypes->getKnownClass(constraints)) { - MOZ_ASSERT(clasp == &ArrayObject::class_); - } - } -#endif -} - -AbortReasonOr IonBuilder::jsop_spreadcall() { - MDefinition* argArr = current->pop(); - MDefinition* argThis = current->pop(); - MDefinition* argFunc = current->pop(); - - // The arguments array is constructed by a JSOp::NewArray and not - // leaked to user. The complications of spread call iterator behaviour are - // handled when the user objects are expanded and copied into this hidden - // array. - AssertSpreadArgIsArray(argArr, constraints()); - - // Extract call target. - TemporaryTypeSet* funTypes = argFunc->resultTypeSet(); - JSFunction* target = getSingleCallTarget(funTypes); - WrappedFunction* wrappedTarget = - target ? new (alloc()) WrappedFunction(target) : nullptr; - - // Dense elements of argument array - MElements* elements = MElements::New(alloc(), argArr); - current->add(elements); - - MApplyArray* apply = - MApplyArray::New(alloc(), wrappedTarget, argFunc, elements, argThis); - current->add(apply); - current->push(apply); - MOZ_TRY(resumeAfter(apply)); - - if (target && target->realm() == script()->realm()) { - apply->setNotCrossRealm(); - } - if (BytecodeIsPopped(pc)) { - apply->setIgnoresReturnValue(); - } - - // TypeBarrier the call result - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(apply, types, BarrierKind::TypeSet); -} - -AbortReasonOr IonBuilder::jsop_spreadnew() { - MDefinition* newTarget = current->pop(); - MDefinition* argArr = current->pop(); - MDefinition* thisValue = current->pop(); - MDefinition* callee = current->pop(); - - // The arguments array is constructed by JSOp::NewArray and not leaked to the - // user. The complications of spread call iterator behaviour are handled when - // the user objects are expanded and copied into this hidden array. - AssertSpreadArgIsArray(argArr, constraints()); - - // Extract call target. - TemporaryTypeSet* funTypes = callee->resultTypeSet(); - JSFunction* target = getSingleCallTarget(funTypes); - if (target && !target->isConstructor()) { - // Don't optimize when the target doesn't support construct calls. - target = nullptr; - } - WrappedFunction* wrappedTarget = - target ? new (alloc()) WrappedFunction(target) : nullptr; - - // Inline the constructor on the caller-side. - MDefinition* create = createThis(target, callee, newTarget, false); - thisValue->setImplicitlyUsedUnchecked(); - - // Dense elements of the argument array. - MElements* elements = MElements::New(alloc(), argArr); - current->add(elements); - - auto* apply = MConstructArray::New(alloc(), wrappedTarget, callee, elements, - create, newTarget); - current->add(apply); - current->push(apply); - MOZ_TRY(resumeAfter(apply)); - - if (target && target->realm() == script()->realm()) { - apply->setNotCrossRealm(); - } - - // TypeBarrier the call result. - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(apply, types, BarrierKind::TypeSet); -} - -bool IonBuilder::propertyIsConstantFunction(NativeObject* nobj, jsid id, - bool (*test)(IonBuilder* builder, - JSFunction* fun)) { - if (!nobj->isSingleton()) { - return false; - } - - TypeSet::ObjectKey* objKey = TypeSet::ObjectKey::get(nobj); - if (analysisContext) { - objKey->ensureTrackedProperty(analysisContext, id); - } - - if (objKey->unknownProperties()) { - return false; - } - - HeapTypeSetKey property = objKey->property(id); - Value value = UndefinedValue(); - if (!property.constant(constraints(), &value)) { - return false; - } - return value.isObject() && value.toObject().is() && - test(this, &value.toObject().as()); -} - -bool IonBuilder::ensureArrayPrototypeIteratorNotModified() { - NativeObject* obj = script()->global().maybeGetArrayPrototype(); - if (!obj) { - return false; - } - - jsid id = SYMBOL_TO_JSID(realm->runtime()->wellKnownSymbols().iterator); - return propertyIsConstantFunction(obj, id, [](auto* builder, auto* fun) { - CompileRuntime* runtime = builder->mirGen().runtime; - return IsSelfHostedFunctionWithName(fun, runtime->names().ArrayValues); - }); -} - -bool IonBuilder::ensureArrayIteratorPrototypeNextNotModified() { - NativeObject* obj = script()->global().maybeGetArrayIteratorPrototype(); - if (!obj) { - return false; - } - - jsid id = NameToId(mirGen_.runtime->names().next); - return propertyIsConstantFunction(obj, id, [](auto* builder, auto* fun) { - return IsSelfHostedFunctionWithName( - fun, builder->mirGen().runtime->names().ArrayIteratorNext); - }); -} - -AbortReasonOr IonBuilder::jsop_optimize_spreadcall() { - MDefinition* arr = current->peek(-1); - - bool result = false; - do { - // Inline with MIsPackedArray if the conditions described in - // js::OptimizeSpreadCall() are all met or can be expressed through - // compiler constraints. - - // The argument is an array. - TemporaryTypeSet* types = arr->resultTypeSet(); - if (!types || types->getKnownClass(constraints()) != &ArrayObject::class_) { - break; - } - - // The array's prototype is Array.prototype. - JSObject* proto; - if (!types->getCommonPrototype(constraints(), &proto)) { - break; - } - NativeObject* arrayProto = script()->global().maybeGetArrayPrototype(); - if (!arrayProto || arrayProto != proto) { - break; - } - - // The array doesn't define an own @@iterator property. - jsid id = SYMBOL_TO_JSID(realm->runtime()->wellKnownSymbols().iterator); - bool res; - MOZ_TRY_VAR(res, testNotDefinedProperty(arr, id, true)); - if (!res) { - break; - } - - // Array.prototype[@@iterator] is not modified. - if (!ensureArrayPrototypeIteratorNotModified()) { - break; - } - - // %ArrayIteratorPrototype%.next is not modified. - if (!ensureArrayIteratorPrototypeNextNotModified()) { - break; - } - - result = true; - } while (false); - - if (result) { - auto* ins = MIsPackedArray::New(alloc(), arr); - current->add(ins); - current->push(ins); - return Ok(); - } - - auto* ins = MOptimizeSpreadCallCache::New(alloc(), arr); - current->add(ins); - current->push(ins); - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_funapplyarray(uint32_t argc) { - MOZ_ASSERT(argc == 2); - - int funcDepth = -((int)argc + 1); - - // Extract call target. - TemporaryTypeSet* funTypes = current->peek(funcDepth)->resultTypeSet(); - JSFunction* target = getSingleCallTarget(funTypes); - - // Pop the array agument - MDefinition* argObj = current->pop(); - - MElements* elements = MElements::New(alloc(), argObj); - current->add(elements); - - // Pop the |this| argument. - MDefinition* argThis = current->pop(); - - // Unwrap the (JSFunction *) parameter. - MDefinition* argFunc = current->pop(); - - // Pop apply function. - MDefinition* nativeFunc = current->pop(); - nativeFunc->setImplicitlyUsedUnchecked(); - - WrappedFunction* wrappedTarget = - target ? new (alloc()) WrappedFunction(target) : nullptr; - MApplyArray* apply = - MApplyArray::New(alloc(), wrappedTarget, argFunc, elements, argThis); - current->add(apply); - current->push(apply); - MOZ_TRY(resumeAfter(apply)); - - if (target && target->realm() == script()->realm()) { - apply->setNotCrossRealm(); - } - if (BytecodeIsPopped(pc)) { - apply->setIgnoresReturnValue(); - } - - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(apply, types, BarrierKind::TypeSet); -} - -bool CallInfo::savePriorCallStack(MBasicBlock* current, size_t peekDepth) { - MOZ_ASSERT(priorArgs_.empty()); - if (!priorArgs_.reserve(peekDepth)) { - return false; - } - while (peekDepth) { - priorArgs_.infallibleAppend(current->peek(0 - int32_t(peekDepth))); - peekDepth--; - } - return true; -} - -AbortReasonOr IonBuilder::jsop_funapplyarguments(uint32_t argc) { - // Stack for JSOp::FunApply: - // 1: Vp - // 2: This - // argc+1: JSFunction*, the 'f' in |f.call()|, in |this| position. - // argc+2: The native 'apply' function. - - int funcDepth = -((int)argc + 1); - - // Extract call target. - TemporaryTypeSet* funTypes = current->peek(funcDepth)->resultTypeSet(); - JSFunction* target = getSingleCallTarget(funTypes); - - // When this script isn't inlined, use MApplyArgs, - // to copy the arguments from the stack and call the function - if (inliningDepth_ == 0 && - info().analysisMode() != Analysis_DefiniteProperties) { - // The array argument corresponds to the arguments object. As the JIT - // is implicitly reading the arguments object in the next instruction, - // we need to prevent the deletion of the arguments object from resume - // points, so that Baseline will behave correctly after a bailout. - MDefinition* vp = current->pop(); - vp->setImplicitlyUsedUnchecked(); - - MDefinition* argThis = current->pop(); - - // Unwrap the (JSFunction*) parameter. - MDefinition* argFunc = current->pop(); - - // Pop apply function. - MDefinition* nativeFunc = current->pop(); - nativeFunc->setImplicitlyUsedUnchecked(); - - MArgumentsLength* numArgs = MArgumentsLength::New(alloc()); - current->add(numArgs); - - WrappedFunction* wrappedTarget = - target ? new (alloc()) WrappedFunction(target) : nullptr; - MApplyArgs* apply = - MApplyArgs::New(alloc(), wrappedTarget, argFunc, numArgs, argThis); - current->add(apply); - current->push(apply); - MOZ_TRY(resumeAfter(apply)); - - if (target && target->realm() == script()->realm()) { - apply->setNotCrossRealm(); - } - if (BytecodeIsPopped(pc)) { - apply->setIgnoresReturnValue(); - } - - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(apply, types, BarrierKind::TypeSet); - } - - // When inlining we have the arguments the function gets called with - // and can optimize even more, by just calling the functions with the args. - // We also try this path when doing the definite properties analysis, as we - // can inline the apply() target and don't care about the actual arguments - // that were passed in. - - CallInfo callInfo(alloc(), pc, /* constructing = */ false, - /* ignoresReturnValue = */ BytecodeIsPopped(pc)); - if (!callInfo.savePriorCallStack(current, 4)) { - return abort(AbortReason::Alloc); - } - - // Vp - MDefinition* vp = current->pop(); - vp->setImplicitlyUsedUnchecked(); - - // Arguments - if (inliningDepth_) { - if (!callInfo.setArgs(inlineCallInfo_->argv())) { - return abort(AbortReason::Alloc); - } - } - - // Pop this. - MDefinition* argThis = current->pop(); - callInfo.setThis(argThis); - - // Pop callee. - MDefinition* argFunc = current->pop(); - callInfo.setCallee(argFunc); - - // Pop apply function. - MDefinition* nativeFunc = current->pop(); - nativeFunc->setImplicitlyUsedUnchecked(); - - // Try to inline the call. - InliningDecision decision = makeInliningDecision(target, callInfo); - switch (decision) { - case InliningDecision_Error: - return abort(AbortReason::Error); - case InliningDecision_DontInline: - case InliningDecision_WarmUpCountTooLow: - break; - case InliningDecision_Inline: { - InliningStatus status; - MOZ_TRY_VAR(status, inlineSingleCall(callInfo, target)); - if (status == InliningStatus_Inlined) { - return Ok(); - } - } - } - - return makeCall(target, callInfo); -} - -AbortReasonOr IonBuilder::jsop_call(uint32_t argc, bool constructing, - bool ignoresReturnValue) { - // If this call has never executed, try to seed the observed type set - // based on how the call result is used. - TemporaryTypeSet* observed = bytecodeTypes(pc); - if (observed->empty()) { - if (BytecodeFlowsToBitop(pc)) { - observed->addType(TypeSet::Int32Type(), alloc_->lifoAlloc()); - } else if (JSOp(*GetNextPc(pc)) == JSOp::Pos) { - // Note: this is lame, overspecialized on the code patterns used - // by asm.js and should be replaced by a more general mechanism. - // See bug 870847. - observed->addType(TypeSet::DoubleType(), alloc_->lifoAlloc()); - } - } - - int calleeDepth = -((int)argc + 2 + constructing); - - // Acquire known call target if existent. - InliningTargets targets(alloc()); - TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet(); - if (calleeTypes) { - MOZ_TRY(getPolyCallTargets(calleeTypes, constructing, targets, 4)); - } - - CallInfo callInfo(alloc(), pc, constructing, ignoresReturnValue); - if (!callInfo.init(current, argc)) { - return abort(AbortReason::Alloc); - } - - // Try inlining - InliningStatus status; - MOZ_TRY_VAR(status, inlineCallsite(targets, callInfo)); - if (status == InliningStatus_Inlined) { - return Ok(); - } - - // Discard unreferenced & pre-allocated resume points. - replaceMaybeFallbackFunctionGetter(nullptr); - - // No inline, just make the call. - Maybe callTargets; - if (!targets.empty()) { - callTargets.emplace(alloc()); - for (const InliningTarget& target : targets) { - if (!target.target->is()) { - callTargets = Nothing(); - break; - } - if (!callTargets->append(&target.target->as())) { - return abort(AbortReason::Alloc); - } - } - } - - if (status == InliningStatus_WarmUpCountTooLow && callTargets && - callTargets->length() == 1 && isHighestOptimizationLevel()) { - JSFunction* target = callTargets.ref()[0]; - MRecompileCheck* check = - MRecompileCheck::New(alloc(), target->nonLazyScript(), - optimizationInfo().inliningRecompileThreshold(), - MRecompileCheck::RecompileCheckType::Inlining); - current->add(check); - } - - return makeCall(callTargets, callInfo); -} - -AbortReasonOr IonBuilder::testShouldDOMCall(TypeSet* inTypes, - JSFunction* func, - JSJitInfo::OpType opType) { - if (!func->isNative() || !func->hasJitInfo()) { - return false; - } - - // If all the DOM objects flowing through are legal with this - // property, we can bake in a call to the bottom half of the DOM - // accessor - DOMInstanceClassHasProtoAtDepth instanceChecker = - realm->runtime()->DOMcallbacks()->instanceClassMatchesProto; - - const JSJitInfo* jinfo = func->jitInfo(); - if (jinfo->type() != opType) { - return false; - } - - for (unsigned i = 0; i < inTypes->getObjectCount(); i++) { - TypeSet::ObjectKey* key = inTypes->getObject(i); - if (!key) { - continue; - } - - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - if (!key->hasStableClassAndProto(constraints())) { - return false; - } - - if (!instanceChecker(key->clasp(), jinfo->protoID, jinfo->depth)) { - return false; - } - } - - return true; -} - -static bool ArgumentTypesMatch(MDefinition* def, StackTypeSet* calleeTypes) { - MOZ_ASSERT(calleeTypes); - - if (calleeTypes->unknown()) { - return true; - } - - if (TypeSet::IsUntrackedMIRType(def->type())) { - // The TypeSet has to be marked as unknown. See JitScript::MonitorThisType. - return false; - } - - if (def->resultTypeSet()) { - MOZ_ASSERT(def->type() == MIRType::Value || def->mightBeType(def->type())); - return def->resultTypeSet()->isSubset(calleeTypes); - } - - if (def->type() == MIRType::Value) { - return false; - } - - if (def->type() == MIRType::Object) { - return calleeTypes->unknownObject(); - } - - return calleeTypes->mightBeMIRType(def->type()); -} - -bool IonBuilder::testNeedsArgumentCheck(JSFunction* target, - CallInfo& callInfo) { - // If we have a known target, check if the caller arg types are a subset of - // callee. Since typeset accumulates and can't decrease that means we don't - // need to check the arguments anymore. - - if (!target->hasBytecode()) { - return true; - } - - JSScript* targetScript = target->nonLazyScript(); - JitScript* jitScript = targetScript->maybeJitScript(); - if (!jitScript) { - return true; - } - - AutoSweepJitScript sweep(targetScript); - if (!ArgumentTypesMatch(callInfo.thisArg(), - jitScript->thisTypes(sweep, targetScript))) { - return true; - } - uint32_t expected_args = std::min(callInfo.argc(), target->nargs()); - for (size_t i = 0; i < expected_args; i++) { - if (!ArgumentTypesMatch(callInfo.getArg(i), - jitScript->argTypes(sweep, targetScript, i))) { - return true; - } - } - for (size_t i = callInfo.argc(); i < target->nargs(); i++) { - StackTypeSet* types = jitScript->argTypes(sweep, targetScript, i); - if (!types->mightBeMIRType(MIRType::Undefined)) { - return true; - } - } - - return false; -} - -AbortReasonOr IonBuilder::makeCallHelper( - const Maybe& targets, CallInfo& callInfo) { - // This function may be called with mutated stack. - // Querying TI for popped types is invalid. - - MOZ_ASSERT_IF(targets, !targets->empty()); - - JSFunction* target = nullptr; - if (targets && targets->length() == 1) { - target = targets.ref()[0]; - } - - bool isDOMCall = false; - DOMObjectKind objKind = DOMObjectKind::Unknown; - if (target && !callInfo.constructing()) { - // We know we have a single call target. Check whether the "this" types - // are DOM types and our function a DOM function, and if so flag the - // MCall accordingly. - TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet(); - if (thisTypes && thisTypes->getKnownMIRType() == MIRType::Object && - thisTypes->isDOMClass(constraints(), &objKind)) { - MOZ_TRY_VAR(isDOMCall, - testShouldDOMCall(thisTypes, target, JSJitInfo::Method)); - } - } - - bool needsThisCheck = false; - if (callInfo.constructing()) { - // Inline the this-object allocation on the caller-side. - MDefinition* create = - createThis(target, callInfo.callee(), callInfo.getNewTarget(), - /* inlining = */ false); - callInfo.thisArg()->setImplicitlyUsedUnchecked(); - callInfo.setThis(create); - needsThisCheck = create->isCreateThis(); - if (needsThisCheck) { - // We have to use the LCallGeneric path. - target = nullptr; - } - } - - uint32_t targetArgs = callInfo.argc(); - - // Collect number of missing arguments provided that the target is - // scripted. Native functions are passed an explicit 'argc' parameter. - if (target && target->hasJitEntry()) { - targetArgs = std::max(target->nargs(), callInfo.argc()); - } - - WrappedFunction* wrappedTarget = - target ? new (alloc()) WrappedFunction(target) : nullptr; - - MCall* call = MCall::New(alloc(), wrappedTarget, - targetArgs + 1 + callInfo.constructing(), - callInfo.argc(), callInfo.constructing(), - callInfo.ignoresReturnValue(), isDOMCall, objKind); - if (!call) { - return abort(AbortReason::Alloc); - } - - if (callInfo.constructing()) { - if (needsThisCheck) { - call->setNeedsThisCheck(); - } - call->addArg(targetArgs + 1, callInfo.getNewTarget()); - } - - // Explicitly pad any missing arguments with |undefined|. - // This permits skipping the argumentsRectifier. - MOZ_ASSERT_IF(target && targetArgs > callInfo.argc(), target->hasJitEntry()); - for (int i = targetArgs; i > (int)callInfo.argc(); i--) { - MConstant* undef = constant(UndefinedValue()); - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - call->addArg(i, undef); - } - - // Add explicit arguments. - // Skip addArg(0) because it is reserved for this - for (int32_t i = callInfo.argc() - 1; i >= 0; i--) { - call->addArg(i + 1, callInfo.getArg(i)); - } - - // Now that we've told it about all the args, compute whether it's movable - call->computeMovable(); - - // Pass |this| and function. - MDefinition* thisArg = callInfo.thisArg(); - call->addArg(0, thisArg); - - if (targets) { - // The callee must be one of the target JSFunctions, so we don't need a - // Class check. - call->disableClassCheck(); - - // Determine whether we can skip the callee's prologue type checks and - // whether we have to switch realms. - bool needArgCheck = false; - bool maybeCrossRealm = false; - for (JSFunction* target : targets.ref()) { - if (testNeedsArgumentCheck(target, callInfo)) { - needArgCheck = true; - } - if (target->realm() != script()->realm()) { - maybeCrossRealm = true; - } - } - if (!needArgCheck) { - call->disableArgCheck(); - } - if (!maybeCrossRealm) { - call->setNotCrossRealm(); - } - } - - call->initCallee(callInfo.callee()); - - current->add(call); - return call; -} - -static bool DOMCallNeedsBarrier(const JSJitInfo* jitinfo, - TemporaryTypeSet* types) { - MOZ_ASSERT(jitinfo->type() != JSJitInfo::InlinableNative); - - // If the return type of our DOM native is in "types" already, we don't - // actually need a barrier. - if (jitinfo->returnType() == JSVAL_TYPE_UNKNOWN) { - return true; - } - - // JSVAL_TYPE_OBJECT doesn't tell us much; we still have to barrier on the - // actual type of the object. - if (jitinfo->returnType() == JSVAL_TYPE_OBJECT) { - return true; - } - - // No need for a barrier if we're already expecting the type we'll produce. - return MIRTypeFromValueType(jitinfo->returnType()) != - types->getKnownMIRType(); -} - -AbortReasonOr IonBuilder::makeCall(const Maybe& targets, - CallInfo& callInfo) { -#ifdef DEBUG - // Constructor calls to non-constructors should throw. We don't want to use - // CallKnown in this case. - if (callInfo.constructing() && targets) { - for (JSFunction* target : targets.ref()) { - MOZ_ASSERT(target->isConstructor()); - } - } -#endif - - MCall* call; - MOZ_TRY_VAR(call, makeCallHelper(targets, callInfo)); - - current->push(call); - if (call->isEffectful()) { - MOZ_TRY(resumeAfter(call)); - } - - TemporaryTypeSet* types = bytecodeTypes(pc); - - if (call->isCallDOMNative()) { - return pushDOMTypeBarrier(call, types, - call->getSingleTarget()->rawNativeJSFunction()); - } - - return pushTypeBarrier(call, types, BarrierKind::TypeSet); -} - -AbortReasonOr IonBuilder::makeCall(JSFunction* target, CallInfo& callInfo) { - Maybe targets; - if (target) { - targets.emplace(alloc()); - if (!targets->append(target)) { - return abort(AbortReason::Alloc); - } - } - return makeCall(targets, callInfo); -} - -AbortReasonOr IonBuilder::jsop_eval(uint32_t argc) { - int calleeDepth = -((int)argc + 2); - TemporaryTypeSet* calleeTypes = current->peek(calleeDepth)->resultTypeSet(); - - // Emit a normal call if the eval has never executed. This keeps us from - // disabling compilation for the script when testing with --ion-eager. - if (calleeTypes && calleeTypes->empty()) { - return jsop_call(argc, /* constructing = */ false, false); - } - - JSFunction* target = getSingleCallTarget(calleeTypes); - if (!target) { - return abort(AbortReason::Disable, "No single callee for eval()"); - } - - if (script()->global().valueIsEval(ObjectValue(*target))) { - if (argc != 1) { - return abort(AbortReason::Disable, - "Direct eval with more than one argument"); - } - - if (!info().funMaybeLazy()) { - return abort(AbortReason::Disable, "Direct eval in global code"); - } - - if (info().funMaybeLazy()->isArrow()) { - return abort(AbortReason::Disable, "Direct eval from arrow function"); - } - - CallInfo callInfo(alloc(), pc, /* constructing = */ false, - /* ignoresReturnValue = */ BytecodeIsPopped(pc)); - if (!callInfo.init(current, argc)) { - return abort(AbortReason::Alloc); - } - callInfo.setImplicitlyUsedUnchecked(); - - callInfo.callee()->setImplicitlyUsedUnchecked(); - - MDefinition* envChain = current->environmentChain(); - MDefinition* string = callInfo.getArg(0); - - // Direct eval acts as identity on non-string types according to - // ES5 15.1.2.1 step 1. - if (!string->mightBeType(MIRType::String)) { - current->push(string); - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(string, types, BarrierKind::TypeSet); - } - - MOZ_TRY(jsop_newtarget()); - MDefinition* newTargetValue = current->pop(); - - // Try to pattern match 'eval(v + "()")'. In this case v is likely a - // name on the env chain and the eval is performing a call on that - // value. Use an env chain lookup rather than a full eval. - if (string->isConcat() && - string->getOperand(1)->type() == MIRType::String && - string->getOperand(1)->maybeConstantValue()) { - JSAtom* atom = - &string->getOperand(1)->maybeConstantValue()->toString()->asAtom(); - - if (StringEqualsLiteral(atom, "()")) { - MDefinition* name = string->getOperand(0); - MInstruction* dynamicName = - MGetDynamicName::New(alloc(), envChain, name); - current->add(dynamicName); - - current->push(dynamicName); - current->push(constant(UndefinedValue())); // thisv - - CallInfo evalCallInfo(alloc(), pc, /* constructing = */ false, - /* ignoresReturnValue = */ BytecodeIsPopped(pc)); - if (!evalCallInfo.init(current, /* argc = */ 0)) { - return abort(AbortReason::Alloc); - } - - return makeCall(nullptr, evalCallInfo); - } - } - - MInstruction* ins = - MCallDirectEval::New(alloc(), envChain, string, newTargetValue, pc); - current->add(ins); - current->push(ins); - - TemporaryTypeSet* types = bytecodeTypes(pc); - MOZ_TRY(resumeAfter(ins)); - return pushTypeBarrier(ins, types, BarrierKind::TypeSet); - } - - return jsop_call(argc, /* constructing = */ false, false); -} - -AbortReasonOr IonBuilder::jsop_compare(JSOp op) { - MDefinition* right = current->pop(); - MDefinition* left = current->pop(); - - return jsop_compare(op, left, right); -} - -AbortReasonOr IonBuilder::jsop_compare(JSOp op, MDefinition* left, - MDefinition* right) { - bool emitted = false; - - if (!forceInlineCaches()) { - MOZ_TRY(compareTrySpecialized(&emitted, op, left, right)); - if (emitted) { - return Ok(); - } - MOZ_TRY(compareTryBitwise(&emitted, op, left, right)); - if (emitted) { - return Ok(); - } - MOZ_TRY( - compareTrySpecializedOnBaselineInspector(&emitted, op, left, right)); - if (emitted) { - return Ok(); - } - } - - MOZ_TRY(compareTryBinaryStub(&emitted, left, right)); - if (emitted) { - return Ok(); - } - - // Not possible to optimize. Do a slow vm call. - MCompare* ins = MCompare::New(alloc(), left, right, op); - ins->cacheOperandMightEmulateUndefined(constraints()); - - current->add(ins); - current->push(ins); - if (ins->isEffectful()) { - MOZ_TRY(resumeAfter(ins)); - } - - return Ok(); -} - -static bool ObjectOrSimplePrimitive(MDefinition* op) { - // Return true if op is either undefined/null/boolean/int32/symbol or an - // object. - return op->definitelyType({MIRType::Undefined, MIRType::Null, - MIRType::Boolean, MIRType::Int32, MIRType::Symbol, - MIRType::Object}); -} - -AbortReasonOr IonBuilder::compareTrySpecialized(bool* emitted, JSOp op, - MDefinition* left, - MDefinition* right) { - MOZ_ASSERT(*emitted == false); - - // Try to emit an compare based on the input types. - - MCompare::CompareType type = MCompare::determineCompareType(op, left, right); - if (type == MCompare::Compare_Unknown) { - return Ok(); - } - - MCompare* ins = MCompare::New(alloc(), left, right, op); - ins->setCompareType(type); - ins->cacheOperandMightEmulateUndefined(constraints()); - - // Some compare types need to have the specific type in the rhs. - // Swap operands if that is not the case. - if (type == MCompare::Compare_StrictString && - right->type() != MIRType::String) { - ins->swapOperands(); - } else if (type == MCompare::Compare_Null && right->type() != MIRType::Null) { - ins->swapOperands(); - } else if (type == MCompare::Compare_Undefined && - right->type() != MIRType::Undefined) { - ins->swapOperands(); - } else if (type == MCompare::Compare_Boolean && - right->type() != MIRType::Boolean) { - ins->swapOperands(); - } - - // Replace inputs with unsigned variants if needed. - if (type == MCompare::Compare_UInt32) { - ins->replaceWithUnsignedOperands(); - } - - current->add(ins); - current->push(ins); - - MOZ_ASSERT(!ins->isEffectful()); - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::compareTryBitwise(bool* emitted, JSOp op, - MDefinition* left, - MDefinition* right) { - MOZ_ASSERT(*emitted == false); - - // Try to emit a bitwise compare. Check if a bitwise compare equals the wanted - // result for all observed operand types. - - // Only allow loose and strict equality. - if (op != JSOp::Eq && op != JSOp::Ne && op != JSOp::StrictEq && - op != JSOp::StrictNe) { - return Ok(); - } - - // Only primitive (not double/string) or objects are supported. - // I.e. Undefined/Null/Boolean/Int32/Symbol and Object - if (!ObjectOrSimplePrimitive(left) || !ObjectOrSimplePrimitive(right)) { - return Ok(); - } - - // In the loose comparison more values could be the same, - // but value comparison reporting otherwise. - if (op == JSOp::Eq || op == JSOp::Ne) { - // Objects that emulate undefined are not supported. - if (left->maybeEmulatesUndefined(constraints()) || - right->maybeEmulatesUndefined(constraints())) { - return Ok(); - } - - // Undefined compared loosy to Null is not supported, - // because tag is different, but value can be the same (undefined == null). - if ((left->mightBeType(MIRType::Undefined) && - right->mightBeType(MIRType::Null)) || - (left->mightBeType(MIRType::Null) && - right->mightBeType(MIRType::Undefined))) { - return Ok(); - } - - // Int32 compared loosy to Boolean is not supported, - // because tag is different, but value can be the same (1 == true). - if ((left->mightBeType(MIRType::Int32) && - right->mightBeType(MIRType::Boolean)) || - (left->mightBeType(MIRType::Boolean) && - right->mightBeType(MIRType::Int32))) { - return Ok(); - } - - // For loosy comparison of an object with a Boolean/Number/String/Symbol - // the valueOf the object is taken. Therefore not supported. - bool simpleLHS = left->mightBeType(MIRType::Boolean) || - left->mightBeType(MIRType::Int32) || - left->mightBeType(MIRType::Symbol); - bool simpleRHS = right->mightBeType(MIRType::Boolean) || - right->mightBeType(MIRType::Int32) || - right->mightBeType(MIRType::Symbol); - if ((left->mightBeType(MIRType::Object) && simpleRHS) || - (right->mightBeType(MIRType::Object) && simpleLHS)) { - return Ok(); - } - } - - MCompare* ins = MCompare::New(alloc(), left, right, op); - ins->setCompareType(MCompare::Compare_Bitwise); - ins->cacheOperandMightEmulateUndefined(constraints()); - - current->add(ins); - current->push(ins); - - MOZ_ASSERT(!ins->isEffectful()); - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::compareTrySpecializedOnBaselineInspector( - bool* emitted, JSOp op, MDefinition* left, MDefinition* right) { - MOZ_ASSERT(*emitted == false); - - // Not supported for call expressions. - if (IsInvokePC(pc)) { - return Ok(); - } - - // Try to specialize based on any baseline caches that have been generated - // for the opcode. These will cause the instruction's type policy to insert - // fallible unboxes to the appropriate input types. - - // Strict equality isn't supported. - if (op == JSOp::StrictEq || op == JSOp::StrictNe) { - return Ok(); - } - - MCompare::CompareType type = inspector->expectedCompareType(pc); - if (type == MCompare::Compare_Unknown) { - return Ok(); - } - - MCompare* ins = MCompare::New(alloc(), left, right, op); - ins->setCompareType(type); - ins->cacheOperandMightEmulateUndefined(constraints()); - - current->add(ins); - current->push(ins); - - MOZ_ASSERT(!ins->isEffectful()); - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::compareTryBinaryStub(bool* emitted, - MDefinition* left, - MDefinition* right) { - MOZ_ASSERT(*emitted == false); - - // Try to emit a CacheIR Stub. - if (JitOptions.disableCacheIR) { - return Ok(); - } - - if (IsInvokePC(pc)) { - return Ok(); - } - - MBinaryCache* stub = - MBinaryCache::New(alloc(), left, right, MIRType::Boolean); - current->add(stub); - current->push(stub); - MOZ_TRY(resumeAfter(stub)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::newArrayTryTemplateObject( - bool* emitted, JSObject* templateObject, uint32_t length) { - MOZ_ASSERT(*emitted == false); - - if (!templateObject) { - return Ok(); - } - - MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT); - - size_t arraySlots = - gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()) - - ObjectElements::VALUES_PER_HEADER; - - if (length > arraySlots) { - return Ok(); - } - - // Emit fastpath. - - gc::InitialHeap heap = templateObject->group()->initialHeap(constraints()); - MConstant* templateConst = - MConstant::NewConstraintlessObject(alloc(), templateObject); - current->add(templateConst); - - MNewArray* ins = - MNewArray::New(alloc(), constraints(), length, templateConst, heap, pc); - current->add(ins); - current->push(ins); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::newArrayTryVM(bool* emitted, - JSObject* templateObject, - uint32_t length) { - MOZ_ASSERT(*emitted == false); - - gc::InitialHeap heap = gc::DefaultHeap; - MConstant* templateConst = MConstant::New(alloc(), NullValue()); - - if (templateObject) { - heap = templateObject->group()->initialHeap(constraints()); - templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject); - } - - current->add(templateConst); - - MNewArray* ins = - MNewArray::NewVM(alloc(), constraints(), length, templateConst, heap, pc); - current->add(ins); - current->push(ins); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_newarray(uint32_t length) { - JSObject* templateObject = inspector->getTemplateObject(pc); - MOZ_TRY(jsop_newarray(templateObject, length)); - - // Improve resulting typeset. - ObjectGroup* templateGroup = inspector->getTemplateObjectGroup(pc); - if (templateGroup) { - TemporaryTypeSet* types = - MakeSingletonTypeSet(alloc(), constraints(), templateGroup); - current->peek(-1)->setResultTypeSet(types); - } - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_newarray(JSObject* templateObject, - uint32_t length) { - bool emitted = false; - - MOZ_TRY(newArrayTryTemplateObject(&emitted, templateObject, length)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(newArrayTryVM(&emitted, templateObject, length)); - if (emitted) { - return Ok(); - } - - MOZ_CRASH("newarray should have been emited"); -} - -AbortReasonOr IonBuilder::jsop_newarray_copyonwrite() { - ArrayObject* templateObject = ObjectGroup::getCopyOnWriteObject(script(), pc); - - // The baseline compiler should have ensured the template object has a type - // with the copy on write flag set already. During the arguments usage - // analysis the baseline compiler hasn't run yet, however, though in this - // case the template object's type doesn't matter. - ObjectGroup* group = templateObject->group(); - MOZ_ASSERT_IF( - info().analysisMode() != Analysis_ArgumentsUsage, - group->hasAllFlagsDontCheckGeneration(OBJECT_FLAG_COPY_ON_WRITE)); - - MConstant* templateConst = - MConstant::NewConstraintlessObject(alloc(), templateObject); - current->add(templateConst); - - MNewArrayCopyOnWrite* ins = MNewArrayCopyOnWrite::New( - alloc(), constraints(), templateConst, group->initialHeap(constraints())); - - current->add(ins); - current->push(ins); - - return Ok(); -} - -AbortReasonOr IonBuilder::newObjectTryTemplateObject( - bool* emitted, JSObject* templateObject) { - MOZ_ASSERT(*emitted == false); - - if (!templateObject) { - return Ok(); - } - - // Emit fastpath. - - MNewObject::Mode mode; - if (JSOp(*pc) == JSOp::NewObject || JSOp(*pc) == JSOp::NewObjectWithGroup || - JSOp(*pc) == JSOp::NewInit) { - mode = MNewObject::ObjectLiteral; - } else { - mode = MNewObject::ObjectCreate; - } - - gc::InitialHeap heap = templateObject->group()->initialHeap(constraints()); - MConstant* templateConst = - MConstant::NewConstraintlessObject(alloc(), templateObject); - current->add(templateConst); - - MNewObject* ins = - MNewObject::New(alloc(), constraints(), templateConst, heap, mode); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::newObjectTryVM(bool* emitted, - JSObject* templateObject) { - // Emit a VM call. - MOZ_ASSERT(JSOp(*pc) == JSOp::NewObject || - JSOp(*pc) == JSOp::NewObjectWithGroup || - JSOp(*pc) == JSOp::NewInit); - - gc::InitialHeap heap = gc::DefaultHeap; - MConstant* templateConst = MConstant::New(alloc(), NullValue()); - - if (templateObject) { - heap = templateObject->group()->initialHeap(constraints()); - templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject); - } - - current->add(templateConst); - - MNewObject* ins = MNewObject::NewVM(alloc(), constraints(), templateConst, - heap, MNewObject::ObjectLiteral); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_newobject() { - bool emitted = false; - - JSObject* templateObject = inspector->getTemplateObject(pc); - - MOZ_TRY(newObjectTryTemplateObject(&emitted, templateObject)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(newObjectTryVM(&emitted, templateObject)); - if (emitted) { - return Ok(); - } - - MOZ_CRASH("newobject should have been emited"); -} - -AbortReasonOr IonBuilder::jsop_initelem() { - MOZ_ASSERT(JSOp(*pc) == JSOp::InitElem || JSOp(*pc) == JSOp::InitHiddenElem || - JSOp(*pc) == JSOp::InitLockedElem); - - MDefinition* value = current->pop(); - MDefinition* id = current->pop(); - MDefinition* obj = current->peek(-1); - - bool emitted = false; - - if (!forceInlineCaches() && JSOp(*pc) == JSOp::InitElem) { - MOZ_TRY(initOrSetElemTryDense(&emitted, obj, id, value, - /* writeHole = */ true)); - if (emitted) { - return Ok(); - } - } - - MOZ_TRY(initOrSetElemTryCache(&emitted, obj, id, value)); - if (emitted) { - return Ok(); - } - - MInitElem* initElem = MInitElem::New(alloc(), obj, id, value); - current->add(initElem); - - return resumeAfter(initElem); -} - -AbortReasonOr IonBuilder::jsop_initelem_inc() { - MDefinition* value = current->pop(); - MDefinition* id = current->pop(); - MDefinition* obj = current->peek(-1); - - MAdd* nextId = MAdd::New(alloc(), id, constantInt(1), MDefinition::Truncate); - current->add(nextId); - current->push(nextId); - - return initArrayElement(obj, id, value); -} - -AbortReasonOr IonBuilder::initArrayElement(MDefinition* obj, - MDefinition* id, - MDefinition* value) { - MOZ_ASSERT(JSOp(*pc) == JSOp::InitElemArray || - JSOp(*pc) == JSOp::InitElemInc); - - bool emitted = false; - - if (!forceInlineCaches()) { - MOZ_TRY(initArrayElemTryFastPath(&emitted, obj, id, value)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(initOrSetElemTryDense(&emitted, obj, id, value, - /* writeHole = */ true)); - if (emitted) { - return Ok(); - } - } - - MOZ_TRY(initOrSetElemTryCache(&emitted, obj, id, value)); - if (emitted) { - return Ok(); - } - - MCallInitElementArray* initElem = - MCallInitElementArray::New(alloc(), obj, id, value); - current->add(initElem); - - return resumeAfter(initElem); -} - -AbortReasonOr IonBuilder::initArrayElemTryFastPath(bool* emitted, - MDefinition* obj, - MDefinition* id, - MDefinition* value) { - MOZ_ASSERT(*emitted == false); - MOZ_ASSERT(JSOp(*pc) == JSOp::InitElemArray || - JSOp(*pc) == JSOp::InitElemInc); - - // Make sure that arrays have the type being written to them by the - // intializer, and that arrays are marked as non-packed when writing holes - // to them during initialization. - - if (!obj->isNewArray()) { - return Ok(); - } - - if (shouldAbortOnPreliminaryGroups(obj)) { - return Ok(); - } - - if (!obj->resultTypeSet() || obj->resultTypeSet()->unknownObject() || - obj->resultTypeSet()->getObjectCount() != 1) { - return Ok(); - } - - TypeSet::ObjectKey* initializer = obj->resultTypeSet()->getObject(0); - if (value->type() == MIRType::MagicHole) { - if (!initializer->hasFlags(constraints(), OBJECT_FLAG_NON_PACKED)) { - return Ok(); - } - } else if (!initializer->unknownProperties()) { - HeapTypeSetKey elemTypes = initializer->property(JSID_VOID); - if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), - value->resultTypeSet())) { - elemTypes.freeze(constraints()); - return Ok(); - } - } - - MOZ_TRY(initArrayElementFastPath(obj->toNewArray(), id, value, - /* addResumePoint = */ true)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_initelem_array() { - MDefinition* value = current->pop(); - MDefinition* obj = current->peek(-1); - - uint32_t index = GET_UINT32(pc); - MOZ_ASSERT(index <= INT32_MAX, - "the bytecode emitter must fail to compile code that would " - "produce JSOp::InitElemArray with an index exceeding " - "int32_t range"); - - MConstant* id = MConstant::New(alloc(), Int32Value(index)); - current->add(id); - - return initArrayElement(obj, id, value); -} - -AbortReasonOr IonBuilder::initArrayElementFastPath( - MNewArray* obj, MDefinition* id, MDefinition* value, - bool addResumePointAndIncrementInitializedLength) { - // Get the elements vector. - MElements* elements = MElements::New(alloc(), obj); - current->add(elements); - - if (needsPostBarrier(value)) { - current->add(MPostWriteBarrier::New(alloc(), obj, value)); - } - - if (obj->convertDoubleElements()) { - MInstruction* valueDouble = MToDouble::New(alloc(), value); - current->add(valueDouble); - value = valueDouble; - } - - // Store the value. - if (value->type() == MIRType::MagicHole) { - value->setImplicitlyUsedUnchecked(); - auto* store = MStoreHoleValueElement::New(alloc(), elements, id); - current->add(store); - } else { - auto* store = MStoreElement::New(alloc(), elements, id, value, - /* needsHoleCheck = */ false); - current->add(store); - } - - if (addResumePointAndIncrementInitializedLength) { - // Update the initialized length. (The template object for this - // array has the array's ultimate length, so the length field is - // already correct: no updating needed.) - MSetInitializedLength* initLength = - MSetInitializedLength::New(alloc(), elements, id); - current->add(initLength); - - MOZ_TRY(resumeAfter(initLength)); - } - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_mutateproto() { - MDefinition* value = current->pop(); - MDefinition* obj = current->peek(-1); - - MMutateProto* mutate = MMutateProto::New(alloc(), obj, value); - current->add(mutate); - return resumeAfter(mutate); -} - -AbortReasonOr IonBuilder::jsop_initprop(PropertyName* name) { - bool useFastPath = false; - - MDefinition* obj = current->peek(-2); - if (obj->isNewObject()) { - if (JSObject* templateObject = obj->toNewObject()->templateObject()) { - if (templateObject->is()) { - if (templateObject->as().containsPure(name)) { - useFastPath = true; - } - } - } - } - MInstructionReverseIterator last = current->rbegin(); - - if (useFastPath && !forceInlineCaches()) { - // This is definitely initializing an 'own' property of the object, treat - // it as an assignment. - MOZ_TRY(jsop_setprop(name)); - } else { - MDefinition* value = current->pop(); - MDefinition* obj = current->pop(); - - bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), - current, &obj, name, &value, - /* canModify = */ true); - - bool emitted = false; - MOZ_TRY(setPropTryCache(&emitted, obj, name, value, barrier)); - MOZ_ASSERT(emitted == true); - } - - // SetProp pushed the value, instead of the object. Fix this on the stack, - // and check the most recent resume point to see if it needs updating too. - current->pop(); - current->push(obj); - for (MInstructionReverseIterator riter = current->rbegin(); riter != last; - riter++) { - if (MResumePoint* resumePoint = riter->resumePoint()) { - MOZ_ASSERT(resumePoint->pc() == pc); - if (resumePoint->mode() == MResumePoint::ResumeAfter) { - size_t index = resumePoint->numOperands() - 1; - resumePoint->replaceOperand(index, obj); - } - break; - } - } - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_initprop_getter_setter(PropertyName* name) { - MDefinition* value = current->pop(); - MDefinition* obj = current->peek(-1); - - MInitPropGetterSetter* init = - MInitPropGetterSetter::New(alloc(), obj, name, value); - current->add(init); - return resumeAfter(init); -} - -AbortReasonOr IonBuilder::jsop_initelem_getter_setter() { - MDefinition* value = current->pop(); - MDefinition* id = current->pop(); - MDefinition* obj = current->peek(-1); - - MInitElemGetterSetter* init = - MInitElemGetterSetter::New(alloc(), obj, id, value); - current->add(init); - return resumeAfter(init); -} - -AbortReasonOr IonBuilder::newBlock( - size_t stackDepth, jsbytecode* pc, MBasicBlock* maybePredecessor) { - MOZ_ASSERT_IF(maybePredecessor, maybePredecessor->stackDepth() == stackDepth); - - MBasicBlock* block = - MBasicBlock::New(graph(), stackDepth, info(), maybePredecessor, - bytecodeSite(pc), MBasicBlock::NORMAL); - if (!block) { - return abort(AbortReason::Alloc); - } - - block->setLoopDepth(loopDepth_); - return block; -} - -AbortReasonOr IonBuilder::newBlock( - MBasicBlock* predecessor, jsbytecode* pc, MResumePoint* priorResumePoint) { - MBasicBlock* block = MBasicBlock::NewWithResumePoint( - graph(), info(), predecessor, bytecodeSite(pc), priorResumePoint); - if (!block) { - return abort(AbortReason::Alloc); - } - - block->setLoopDepth(loopDepth_); - return block; -} - -AbortReasonOr IonBuilder::newBlockPopN(MBasicBlock* predecessor, - jsbytecode* pc, - uint32_t popped) { - MBasicBlock* block = - MBasicBlock::NewPopN(graph(), info(), predecessor, bytecodeSite(pc), - MBasicBlock::NORMAL, popped); - if (!block) { - return abort(AbortReason::Alloc); - } - - block->setLoopDepth(loopDepth_); - return block; -} - -AbortReasonOr IonBuilder::newBlockAfter( - MBasicBlock* at, size_t stackDepth, jsbytecode* pc, - MBasicBlock* maybePredecessor) { - MOZ_ASSERT_IF(maybePredecessor, maybePredecessor->stackDepth() == stackDepth); - - MBasicBlock* block = - MBasicBlock::New(graph(), stackDepth, info(), maybePredecessor, - bytecodeSite(pc), MBasicBlock::NORMAL); - if (!block) { - return abort(AbortReason::Alloc); - } - - block->setLoopDepth(loopDepth_); - block->setHitCount(0); // osr block - graph().insertBlockAfter(at, block); - return block; -} - -AbortReasonOr IonBuilder::newOsrPreheader( - MBasicBlock* predecessor, jsbytecode* loopHead) { - MOZ_ASSERT(JSOp(*loopHead) == JSOp::LoopHead); - MOZ_ASSERT(loopHead == info().osrPc()); - - // Create two blocks: one for the OSR entry with no predecessors, one for - // the preheader, which has the OSR entry block as a predecessor. The - // OSR block is always the second block (with id 1). - MBasicBlock* osrBlock; - MOZ_TRY_VAR(osrBlock, newBlockAfter(*graph().begin(), - predecessor->stackDepth(), loopHead)); - MBasicBlock* preheader; - MOZ_TRY_VAR(preheader, newBlock(predecessor, loopHead)); - - graph().addBlock(preheader); - - // Give the pre-header the same hit count as the code before the loop. - if (predecessor->getHitState() == MBasicBlock::HitState::Count) { - preheader->setHitCount(predecessor->getHitCount()); - } - - MOsrEntry* entry = MOsrEntry::New(alloc()); - osrBlock->add(entry); - - // Initialize |envChain|. - { - uint32_t slot = info().environmentChainSlot(); - - MInstruction* envv; - if (usesEnvironmentChain()) { - envv = MOsrEnvironmentChain::New(alloc(), entry); - } else { - // Use an undefined value if the script does not need its env - // chain, to match the type that is already being tracked for the - // slot. - envv = MConstant::New(alloc(), UndefinedValue()); - } - - osrBlock->add(envv); - osrBlock->initSlot(slot, envv); - } - // Initialize |return value| - { - MInstruction* returnValue; - if (!script()->noScriptRval()) { - returnValue = MOsrReturnValue::New(alloc(), entry); - } else { - returnValue = MConstant::New(alloc(), UndefinedValue()); - } - osrBlock->add(returnValue); - osrBlock->initSlot(info().returnValueSlot(), returnValue); - } - - // Initialize arguments object. - bool needsArgsObj = info().needsArgsObj(); - MInstruction* argsObj = nullptr; - if (info().hasArguments()) { - if (needsArgsObj) { - argsObj = MOsrArgumentsObject::New(alloc(), entry); - } else { - argsObj = MConstant::New(alloc(), UndefinedValue()); - } - osrBlock->add(argsObj); - osrBlock->initSlot(info().argsObjSlot(), argsObj); - } - - if (info().funMaybeLazy()) { - // Initialize |this| parameter. - MParameter* thisv = - MParameter::New(alloc(), MParameter::THIS_SLOT, nullptr); - osrBlock->add(thisv); - osrBlock->initSlot(info().thisSlot(), thisv); - - // Initialize arguments. - for (uint32_t i = 0; i < info().nargs(); i++) { - uint32_t slot = - needsArgsObj ? info().argSlotUnchecked(i) : info().argSlot(i); - - // Only grab arguments from the arguments object if the arguments object - // aliases formals. If the argsobj does not alias formals, then the - // formals may have been assigned to during interpretation, and that - // change will not be reflected in the argsobj. - if (needsArgsObj && info().argsObjAliasesFormals()) { - MOZ_ASSERT(argsObj && argsObj->isOsrArgumentsObject()); - // If this is an aliased formal, then the arguments object - // contains a hole at this index. Any references to this - // variable in the jitcode will come from JSOp::*AliasedVar - // opcodes, so the slot itself can be set to undefined. If - // it's not aliased, it must be retrieved from the arguments - // object. - MInstruction* osrv; - if (script()->formalIsAliased(i)) { - osrv = MConstant::New(alloc(), UndefinedValue()); - } else { - osrv = MGetArgumentsObjectArg::New(alloc(), argsObj, i); - } - - osrBlock->add(osrv); - osrBlock->initSlot(slot, osrv); - } else { - MParameter* arg = MParameter::New(alloc(), i, nullptr); - osrBlock->add(arg); - osrBlock->initSlot(slot, arg); - } - } - } - - // Initialize locals. - for (uint32_t i = 0; i < info().nlocals(); i++) { - uint32_t slot = info().localSlot(i); - ptrdiff_t offset = BaselineFrame::reverseOffsetOfLocal(i); - - MOsrValue* osrv = MOsrValue::New(alloc().fallible(), entry, offset); - if (!osrv) { - return abort(AbortReason::Alloc); - } - osrBlock->add(osrv); - osrBlock->initSlot(slot, osrv); - } - - // Initialize stack. - uint32_t numStackSlots = preheader->stackDepth() - info().firstStackSlot(); - for (uint32_t i = 0; i < numStackSlots; i++) { - uint32_t slot = info().stackSlot(i); - ptrdiff_t offset = - BaselineFrame::reverseOffsetOfLocal(info().nlocals() + i); - - MOsrValue* osrv = MOsrValue::New(alloc().fallible(), entry, offset); - if (!osrv) { - return abort(AbortReason::Alloc); - } - osrBlock->add(osrv); - osrBlock->initSlot(slot, osrv); - } - - // Create an MStart to hold the first valid MResumePoint. - MStart* start = MStart::New(alloc()); - osrBlock->add(start); - - // MOsrValue instructions are infallible, so the first MResumePoint must - // occur after they execute, at the point of the MStart. - MOZ_TRY(resumeAt(start, loopHead)); - - // Link the same MResumePoint from the MStart to each MOsrValue. - // This causes logic in ShouldSpecializeInput() to not replace Uses with - // Unboxes in the MResumePiont, so that the MStart always sees Values. - if (!osrBlock->linkOsrValues(start)) { - return abort(AbortReason::Alloc); - } - - // Clone types of the other predecessor of the pre-header to the osr block, - // such as pre-header phi's won't discard specialized type of the - // predecessor. - MOZ_ASSERT(predecessor->stackDepth() == osrBlock->stackDepth()); - MOZ_ASSERT(info().environmentChainSlot() == 0); - - // Treat the OSR values as having the same type as the existing values - // coming in to the loop. These will be fixed up with appropriate - // unboxing and type barriers in finishLoop, once the possible types - // at the loop header are known. - for (uint32_t i = info().startArgSlot(); i < osrBlock->stackDepth(); i++) { - MDefinition* existing = current->getSlot(i); - MDefinition* def = osrBlock->getSlot(i); - MOZ_ASSERT_IF(!needsArgsObj || !info().isSlotAliased(i), - def->type() == MIRType::Value); - - // Aliased slots are never accessed, since they need to go through - // the callobject. No need to type them here. - if (info().isSlotAliased(i)) { - continue; - } - - def->setResultType(existing->type()); - def->setResultTypeSet(existing->resultTypeSet()); - } - - // Finish the osrBlock. - osrBlock->end(MGoto::New(alloc(), preheader)); - if (!preheader->addPredecessor(alloc(), osrBlock)) { - return abort(AbortReason::Alloc); - } - graph().setOsrBlock(osrBlock); - - return preheader; -} - -AbortReasonOr IonBuilder::newPendingLoopHeader( - MBasicBlock* predecessor, jsbytecode* pc, bool osr) { - MBasicBlock* block = MBasicBlock::NewPendingLoopHeader( - graph(), info(), predecessor, bytecodeSite(pc)); - if (!block) { - return abort(AbortReason::Alloc); - } - - if (osr) { - // Incorporate type information from the OSR frame into the loop - // header. The OSR frame may have unexpected types due to type changes - // within the loop body or due to incomplete profiling information, - // in which case this may avoid restarts of loop analysis or bailouts - // during the OSR itself. - - MOZ_ASSERT(info().firstLocalSlot() - info().firstArgSlot() == - baselineFrame_->argTypes.length()); - MOZ_ASSERT(block->stackDepth() - info().firstLocalSlot() == - baselineFrame_->varTypes.length()); - - // Unbox the MOsrValue if it is known to be unboxable. - for (uint32_t i = info().startArgSlot(); i < block->stackDepth(); i++) { - // The value of aliased args and slots are in the callobject. So we can't - // the value from the baseline frame. - if (info().isSlotAliased(i)) { - continue; - } - - MPhi* phi = block->getSlot(i)->toPhi(); - - // Get the type from the baseline frame. - TypeSet::Type existingType = TypeSet::UndefinedType(); - uint32_t arg = i - info().firstArgSlot(); - uint32_t var = i - info().firstLocalSlot(); - if (info().funMaybeLazy() && i == info().thisSlot()) { - existingType = baselineFrame_->thisType; - } else if (arg < info().nargs()) { - existingType = baselineFrame_->argTypes[arg]; - } else { - existingType = baselineFrame_->varTypes[var]; - } - - if (existingType.isSingletonUnchecked()) { - checkNurseryObject(existingType.singleton()); - } - - // Extract typeset from value. - LifoAlloc* lifoAlloc = alloc().lifoAlloc(); - LifoAlloc::AutoFallibleScope fallibleAllocator(lifoAlloc); - TemporaryTypeSet* typeSet = - lifoAlloc->new_(lifoAlloc, existingType); - if (!typeSet) { - return abort(AbortReason::Alloc); - } - MIRType type = typeSet->getKnownMIRType(); - if (!phi->addBackedgeType(alloc(), type, typeSet)) { - return abort(AbortReason::Alloc); - } - } - } - - // The exception handler has code to close iterators for certain loops. We - // need to mark the phis (and phis these iterators flow into) as having - // implicit uses so that Ion does not optimize them away (replace with the - // JS_OPTIMIZED_OUT MagicValue). - // See ProcessTryNotes in vm/Interpreter.cpp. - MOZ_ASSERT(block->stackDepth() >= info().firstStackSlot()); - bool emptyStack = block->stackDepth() == info().firstStackSlot(); - if (!emptyStack) { - for (TryNoteIterAllNoGC tni(script(), pc); !tni.done(); ++tni) { - const TryNote& tn = **tni; - - // Stop if we reach an outer loop because outer loops were already - // processed when we visited their loop headers. - if (tn.isLoop()) { - BytecodeLocation tnStart = script()->offsetToLocation(tn.start); - if (tnStart.toRawBytecode() != pc) { - MOZ_ASSERT(tnStart.is(JSOp::LoopHead)); - MOZ_ASSERT(tnStart.toRawBytecode() < pc); - break; - } - } - - switch (tn.kind()) { - case TryNoteKind::Destructuring: - case TryNoteKind::ForIn: { - // For for-in loops we add the iterator object to iterators_. For - // destructuring loops we add the "done" value that's on top of the - // stack and used in the exception handler. - MOZ_ASSERT(tn.stackDepth >= 1); - uint32_t slot = info().stackSlot(tn.stackDepth - 1); - MPhi* phi = block->getSlot(slot)->toPhi(); - if (!outermostBuilder()->iterators_.append(phi)) { - return abort(AbortReason::Alloc); - } - break; - } - default: - break; - } - } - } - - return block; -} - -MTest* IonBuilder::newTest(MDefinition* ins, MBasicBlock* ifTrue, - MBasicBlock* ifFalse) { - MTest* test = MTest::New(alloc(), ins, ifTrue, ifFalse); - test->cacheOperandMightEmulateUndefined(constraints()); - return test; -} - -// A resume point is a mapping of stack slots to MDefinitions. It is used to -// capture the environment such that if a guard fails, and IonMonkey needs -// to exit back to the interpreter, the interpreter state can be -// reconstructed. -// -// We capture stack state at critical points: -// * (1) At the beginning of every basic block. -// * (2) After every effectful operation. -// -// As long as these two properties are maintained, instructions can -// be moved, hoisted, or, eliminated without problems, and ops without side -// effects do not need to worry about capturing state at precisely the -// right point in time. -// -// Effectful instructions, of course, need to capture state after completion, -// where the interpreter will not attempt to repeat the operation. For this, -// ResumeAfter must be used. The state is attached directly to the effectful -// instruction to ensure that no intermediate instructions could be injected -// in between by a future analysis pass. -// -// During LIR construction, if an instruction can bail back to the interpreter, -// we create an LSnapshot, which uses the last known resume point to request -// register/stack assignments for every live value. -AbortReasonOr IonBuilder::resume(MInstruction* ins, jsbytecode* pc, - MResumePoint::Mode mode) { - MOZ_ASSERT(ins->isEffectful() || !ins->isMovable()); - - MResumePoint* resumePoint = - MResumePoint::New(alloc(), ins->block(), pc, mode); - if (!resumePoint) { - return abort(AbortReason::Alloc); - } - ins->setResumePoint(resumePoint); - return Ok(); -} - -AbortReasonOr IonBuilder::resumeAt(MInstruction* ins, jsbytecode* pc) { - return resume(ins, pc, MResumePoint::ResumeAt); -} - -AbortReasonOr IonBuilder::resumeAfter(MInstruction* ins) { - return resume(ins, pc, MResumePoint::ResumeAfter); -} - -AbortReasonOr IonBuilder::maybeInsertResume() { - // Create a resume point at the current position, without an existing - // effectful instruction. This resume point is not necessary for correct - // behavior (see above), but is added to avoid holding any values from the - // previous resume point which are now dead. This shortens the live ranges - // of such values and improves register allocation. - // - // This optimization is not performed outside of loop bodies, where good - // register allocation is not as critical, in order to avoid creating - // excessive resume points. - - if (loopDepth_ == 0) { - return Ok(); - } - - MNop* ins = MNop::New(alloc()); - current->add(ins); - - return resumeAfter(ins); -} - -void IonBuilder::maybeMarkEmpty(MDefinition* ins) { - MOZ_ASSERT(ins->type() == MIRType::Value); - - // When one of the operands has no type information, mark the output - // as having no possible types too. This is to avoid degrading - // subsequent analysis. - for (size_t i = 0; i < ins->numOperands(); i++) { - if (!ins->getOperand(i)->emptyResultTypeSet()) { - continue; - } - - TemporaryTypeSet* types = alloc().lifoAlloc()->new_(); - if (types) { - ins->setResultTypeSet(types); - return; - } - } -} - -// Return whether property lookups can be performed effectlessly on clasp. -static bool ClassHasEffectlessLookup(const JSClass* clasp) { - return IsTypedObjectClass(clasp) || - (clasp->isNative() && !clasp->getOpsLookupProperty()); -} - -// Return whether an object might have a property for name which is not -// accounted for by type information. -static bool ObjectHasExtraOwnProperty(CompileRealm* realm, - TypeSet::ObjectKey* object, jsid id) { - // Some typed object properties are not reflected in type information. - if (object->isGroup() && object->group()->maybeTypeDescr()) { - return object->group()->typeDescr().hasProperty(realm->runtime()->names(), - id); - } - - const JSClass* clasp = object->clasp(); - - // Array |length| properties are not reflected in type information. - if (clasp == &ArrayObject::class_) { - return JSID_IS_ATOM(id, realm->runtime()->names().length); - } - - // Resolve hooks can install new properties on objects on demand. - JSObject* singleton = object->isSingleton() ? object->singleton() : nullptr; - return ClassMayResolveId(realm->runtime()->names(), clasp, id, singleton); -} - -void IonBuilder::insertRecompileCheck(jsbytecode* pc) { - MOZ_ASSERT(pc == script()->code() || JSOp(*pc) == JSOp::LoopHead); - - // No need for recompile checks if this is the highest optimization level or - // if we're performing an analysis instead of compilation. - OptimizationLevel curLevel = optimizationLevel(); - if (IonOptimizations.isLastLevel(curLevel) || info().isAnalysis()) { - return; - } - - MOZ_ASSERT(!JitOptions.disableOptimizationLevels); - - // Add recompile check. See MRecompileCheck::RecompileCheckType for how this - // works. - - MRecompileCheck::RecompileCheckType type; - if (JSOp(*pc) == JSOp::LoopHead) { - type = MRecompileCheck::RecompileCheckType::OptimizationLevelOSR; - } else if (this != outermostBuilder()) { - type = MRecompileCheck::RecompileCheckType::OptimizationLevelInlined; - } else { - type = MRecompileCheck::RecompileCheckType::OptimizationLevel; - } - - // Add recompile check to recompile when the warm-up count reaches the - // threshold of the next optimization level. - OptimizationLevel nextLevel = IonOptimizations.nextLevel(curLevel); - const OptimizationInfo* info = IonOptimizations.get(nextLevel); - uint32_t warmUpThreshold = info->recompileWarmUpThreshold(script(), pc); - MRecompileCheck* check = - MRecompileCheck::New(alloc(), script(), warmUpThreshold, type); - current->add(check); -} - -JSObject* IonBuilder::testSingletonProperty(JSObject* obj, jsid id) { - // We would like to completely no-op property/global accesses which can - // produce only a particular JSObject. When indicating the access result is - // definitely an object, type inference does not account for the - // possibility that the property is entirely missing from the input object - // and its prototypes (if this happens, a semantic trigger would be hit and - // the pushed types updated, even if there is no type barrier). - // - // If the access definitely goes through obj, either directly or on the - // prototype chain, and the object has singleton type, then the type - // information for that property reflects the value that will definitely be - // read on accesses to the object. If the property is later deleted or - // reconfigured as a getter/setter then the type information for the - // property will change and trigger invalidation. - - while (obj) { - if (!alloc().ensureBallast()) { - return nullptr; - } - - if (!ClassHasEffectlessLookup(obj->getClass())) { - return nullptr; - } - - TypeSet::ObjectKey* objKey = TypeSet::ObjectKey::get(obj); - if (analysisContext) { - objKey->ensureTrackedProperty(analysisContext, id); - } - - if (objKey->unknownProperties()) { - return nullptr; - } - - HeapTypeSetKey property = objKey->property(id); - if (property.isOwnProperty(constraints())) { - if (obj->isSingleton()) { - return property.singleton(constraints()); - } - return nullptr; - } - - if (ObjectHasExtraOwnProperty(realm, objKey, id)) { - return nullptr; - } - - obj = checkNurseryObject(obj->staticPrototype()); - } - - return nullptr; -} - -JSObject* IonBuilder::testSingletonPropertyTypes(MDefinition* obj, jsid id) { - // As for TestSingletonProperty, but the input is any value in a type set - // rather than a specific object. - - TemporaryTypeSet* types = obj->resultTypeSet(); - if (types && types->unknownObject()) { - return nullptr; - } - - JSObject* objectSingleton = types ? types->maybeSingleton() : nullptr; - if (objectSingleton) { - return testSingletonProperty(objectSingleton, id); - } - - MIRType objType = obj->type(); - if (objType == MIRType::Value && types) { - objType = types->getKnownMIRType(); - } - - JSProtoKey key; - switch (objType) { - case MIRType::String: - key = JSProto_String; - break; - - case MIRType::Symbol: - key = JSProto_Symbol; - break; - - case MIRType::BigInt: - key = JSProto_BigInt; - break; - - case MIRType::Int32: - case MIRType::Double: - key = JSProto_Number; - break; - - case MIRType::Boolean: - key = JSProto_Boolean; - break; - - case MIRType::Object: { - if (!types) { - return nullptr; - } - - // For property accesses which may be on many objects, we just need to - // find a prototype common to all the objects; if that prototype - // has the singleton property, the access will not be on a missing - // property. - JSObject* singleton = nullptr; - for (unsigned i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - - if (!alloc().ensureBallast()) { - return nullptr; - } - - if (analysisContext) { - key->ensureTrackedProperty(analysisContext, id); - } - - const JSClass* clasp = key->clasp(); - if (!ClassHasEffectlessLookup(clasp) || - ObjectHasExtraOwnProperty(realm, key, id)) { - return nullptr; - } - if (key->unknownProperties()) { - return nullptr; - } - HeapTypeSetKey property = key->property(id); - if (property.isOwnProperty(constraints())) { - return nullptr; - } - - if (JSObject* proto = - checkNurseryObject(key->proto().toObjectOrNull())) { - // Test this type. - JSObject* thisSingleton = testSingletonProperty(proto, id); - if (!thisSingleton) { - return nullptr; - } - if (singleton) { - if (thisSingleton != singleton) { - return nullptr; - } - } else { - singleton = thisSingleton; - } - } else { - // Can't be on the prototype chain with no prototypes... - return nullptr; - } - } - return singleton; - } - default: - return nullptr; - } - - if (JSObject* proto = script()->global().maybeGetPrototype(key)) { - return testSingletonProperty(proto, id); - } - - return nullptr; -} - -AbortReasonOr IonBuilder::testNotDefinedProperty( - MDefinition* obj, jsid id, bool ownProperty /* = false */) { - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject() || - types->getKnownMIRType() != MIRType::Object) { - return false; - } - - for (unsigned i = 0, count = types->getObjectCount(); i < count; i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - - while (true) { - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - if (!key->hasStableClassAndProto(constraints()) || - key->unknownProperties()) { - return false; - } - - const JSClass* clasp = key->clasp(); - if (!ClassHasEffectlessLookup(clasp) || - ObjectHasExtraOwnProperty(realm, key, id)) { - return false; - } - - // If the object is a singleton, we can do a lookup now to avoid - // unnecessary invalidations later on, in case the property types - // have not yet been instantiated. - if (key->isSingleton() && key->singleton()->is() && - key->singleton()->as().lookupPure(id)) { - return false; - } - - HeapTypeSetKey property = key->property(id); - if (property.isOwnProperty(constraints())) { - return false; - } - - // If we only care about own properties don't check the proto. - if (ownProperty) { - break; - } - - JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull()); - if (!proto) { - break; - } - key = TypeSet::ObjectKey::get(proto); - } - } - - return true; -} - -AbortReasonOr IonBuilder::pushTypeBarrier(MDefinition* def, - TemporaryTypeSet* observed, - BarrierKind kind) { - MOZ_ASSERT(def == current->peek(-1)); - - MDefinition* replace = addTypeBarrier(current->pop(), observed, kind); - if (!replace) { - return abort(AbortReason::Alloc); - } - - current->push(replace); - return Ok(); -} - -// Given an observed type set, annotates the IR as much as possible: -// (1) If no type information is provided, the given value is returned. -// (2) If a single type definitely exists, and no type barrier is needed, -// then an infallible unbox instruction is returned. -// (3) If a type barrier is needed, but has an unknown type set, the given -// value is returned. -// (4) Lastly, a type barrier instruction is added and returned. -MDefinition* IonBuilder::addTypeBarrier(MDefinition* def, - TemporaryTypeSet* observed, - BarrierKind kind, - MTypeBarrier** pbarrier) { - // Barriers are never needed for instructions whose result will not be used. - if (BytecodeIsPopped(pc)) { - return def; - } - - // If the instruction has no side effects, we'll resume the entire operation. - // The actual type barrier will occur in the interpreter. If the - // instruction is effectful, even if it has a singleton type, there - // must be a resume point capturing the original def, and resuming - // to that point will explicitly monitor the new type. - if (kind == BarrierKind::NoBarrier) { - MDefinition* replace = ensureDefiniteType(def, observed->getKnownMIRType()); - replace->setResultTypeSet(observed); - return replace; - } - - if (observed->unknown()) { - return def; - } - - MTypeBarrier* barrier = MTypeBarrier::New(alloc(), def, observed, kind); - current->add(barrier); - - if (pbarrier) { - *pbarrier = barrier; - } - - if (barrier->type() == MIRType::Undefined) { - return constant(UndefinedValue()); - } - if (barrier->type() == MIRType::Null) { - return constant(NullValue()); - } - - return barrier; -} - -AbortReasonOr IonBuilder::pushDOMTypeBarrier(MInstruction* ins, - TemporaryTypeSet* observed, - JSFunction* func) { - MOZ_ASSERT(func && func->isNative() && func->hasJitInfo()); - - const JSJitInfo* jitinfo = func->jitInfo(); - bool barrier = DOMCallNeedsBarrier(jitinfo, observed); - // Need to be a bit careful: if jitinfo->returnType is JSVAL_TYPE_DOUBLE but - // types->getKnownMIRType() is MIRType::Int32, then don't unconditionally - // unbox as a double. Instead, go ahead and barrier on having an int type, - // since we know we need a barrier anyway due to the type mismatch. This is - // the only situation in which TI actually has more information about the - // JSValueType than codegen can, short of jitinfo->returnType just being - // JSVAL_TYPE_UNKNOWN. - MDefinition* replace = ins; - if (jitinfo->returnType() != JSVAL_TYPE_DOUBLE || - observed->getKnownMIRType() != MIRType::Int32) { - replace = - ensureDefiniteType(ins, MIRTypeFromValueType(jitinfo->returnType())); - if (replace != ins) { - current->pop(); - current->push(replace); - } - } else { - MOZ_ASSERT(barrier); - } - - return pushTypeBarrier( - replace, observed, - barrier ? BarrierKind::TypeSet : BarrierKind::NoBarrier); -} - -MDefinition* IonBuilder::ensureDefiniteType(MDefinition* def, - MIRType definiteType) { - MInstruction* replace; - switch (definiteType) { - case MIRType::Undefined: - def->setImplicitlyUsedUnchecked(); - replace = MConstant::New(alloc(), UndefinedValue()); - break; - - case MIRType::Null: - def->setImplicitlyUsedUnchecked(); - replace = MConstant::New(alloc(), NullValue()); - break; - - case MIRType::Value: - return def; - - default: { - if (def->type() != MIRType::Value) { - if (def->type() == MIRType::Int32 && definiteType == MIRType::Double) { - replace = MToDouble::New(alloc(), def); - break; - } - return def; - } - replace = MUnbox::New(alloc(), def, definiteType, MUnbox::Infallible); - break; - } - } - - current->add(replace); - return replace; -} - -static size_t NumFixedSlots(JSObject* object) { - // Note: we can't use object->numFixedSlots() here, as this will read the - // shape and can race with the main thread if we are building off thread. - // The allocation kind and object class (which goes through the type) can - // be read freely, however. - gc::AllocKind kind = object->asTenured().getAllocKind(); - return gc::GetGCKindSlots(kind, object->getClass()); -} - -static bool IsUninitializedGlobalLexicalSlot(JSObject* obj, - PropertyName* name) { - LexicalEnvironmentObject& globalLexical = obj->as(); - MOZ_ASSERT(globalLexical.isGlobal()); - Shape* shape = globalLexical.lookupPure(name); - if (!shape) { - return false; - } - return globalLexical.getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL); -} - -AbortReasonOr IonBuilder::getStaticName(bool* emitted, - JSObject* staticObject, - PropertyName* name, - MDefinition* lexicalCheck) { - MOZ_ASSERT(*emitted == false); - - jsid id = NameToId(name); - - bool isGlobalLexical = - staticObject->is() && - staticObject->as().isGlobal(); - MOZ_ASSERT(isGlobalLexical || staticObject->is()); - MOZ_ASSERT(staticObject->isSingleton()); - - // Always emit the lexical check. This could be optimized, but is - // currently not for simplicity's sake. - if (lexicalCheck) { - return Ok(); - } - - TypeSet::ObjectKey* staticKey = TypeSet::ObjectKey::get(staticObject); - if (analysisContext) { - staticKey->ensureTrackedProperty(analysisContext, NameToId(name)); - } - - if (staticKey->unknownProperties()) { - return Ok(); - } - - HeapTypeSetKey property = staticKey->property(id); - if (!property.maybeTypes() || !property.maybeTypes()->definiteProperty() || - property.nonData(constraints())) { - // The property has been reconfigured as non-configurable, non-enumerable - // or non-writable. - return Ok(); - } - - // Don't optimize global lexical bindings if they aren't initialized at - // compile time. - if (isGlobalLexical && IsUninitializedGlobalLexicalSlot(staticObject, name)) { - return Ok(); - } - - *emitted = true; - - TemporaryTypeSet* types = bytecodeTypes(pc); - BarrierKind barrier = PropertyReadNeedsTypeBarrier( - analysisContext, alloc(), constraints(), staticKey, name, types, - /* updateObserved = */ true); - - if (barrier == BarrierKind::NoBarrier) { - // Try to inline properties holding a known constant object. - JSObject* singleton = types->maybeSingleton(); - if (singleton) { - if (testSingletonProperty(staticObject, id) == singleton) { - pushConstant(ObjectValue(*singleton)); - return Ok(); - } - } - - // Try to inline properties that have never been overwritten. - Value constantValue; - if (property.constant(constraints(), &constantValue)) { - pushConstant(constantValue); - return Ok(); - } - } - - MOZ_TRY(loadStaticSlot(staticObject, barrier, types, - property.maybeTypes()->definiteSlot())); - - return Ok(); -} - -AbortReasonOr IonBuilder::loadStaticSlot(JSObject* staticObject, - BarrierKind barrier, - TemporaryTypeSet* types, - uint32_t slot) { - if (barrier == BarrierKind::NoBarrier) { - // Try to inline properties that can only have one value. - MIRType knownType = types->getKnownMIRType(); - if (knownType == MIRType::Undefined) { - pushConstant(UndefinedValue()); - return Ok(); - } - if (knownType == MIRType::Null) { - pushConstant(NullValue()); - return Ok(); - } - } - - MInstruction* obj = constant(ObjectValue(*staticObject)); - - MIRType rvalType = types->getKnownMIRType(); - if (barrier != BarrierKind::NoBarrier) { - rvalType = MIRType::Value; - } - - return loadSlot(obj, slot, NumFixedSlots(staticObject), rvalType, barrier, - types); -} - -// Whether a write of the given value may need a post-write barrier for GC -// purposes. -bool IonBuilder::needsPostBarrier(MDefinition* value) { - CompileZone* zone = realm->zone(); - if (value->mightBeType(MIRType::Object)) { - return true; - } - if (value->mightBeType(MIRType::String) && - zone->canNurseryAllocateStrings()) { - return true; - } - if (value->mightBeType(MIRType::BigInt) && - zone->canNurseryAllocateBigInts()) { - return true; - } - return false; -} - -AbortReasonOr IonBuilder::setStaticName(JSObject* staticObject, - PropertyName* name) { - jsid id = NameToId(name); - - bool isGlobalLexical = - staticObject->is() && - staticObject->as().isGlobal(); - MOZ_ASSERT(isGlobalLexical || staticObject->is()); - - MDefinition* value = current->peek(-1); - - TypeSet::ObjectKey* staticKey = TypeSet::ObjectKey::get(staticObject); - if (staticKey->unknownProperties()) { - return jsop_setprop(name); - } - - HeapTypeSetKey property = staticKey->property(id); - if (!property.maybeTypes() || !property.maybeTypes()->definiteProperty() || - property.nonData(constraints()) || property.nonWritable(constraints())) { - // The property has been reconfigured as non-configurable, non-enumerable - // or non-writable. - return jsop_setprop(name); - } - - if (!CanWriteProperty(alloc(), constraints(), property, value)) { - return jsop_setprop(name); - } - - // Don't optimize global lexical bindings if they aren't initialized at - // compile time. - if (isGlobalLexical && IsUninitializedGlobalLexicalSlot(staticObject, name)) { - return jsop_setprop(name); - } - - current->pop(); - - // Pop the bound object on the stack. This is usually a constant but it can - // be a phi if loops are involved, for example: x = [...arr]; - MDefinition* obj = current->pop(); - MOZ_ASSERT(obj->isConstant() || obj->isPhi()); - MOZ_ASSERT_IF(obj->isConstant(), - &obj->toConstant()->toObject() == staticObject); - - if (needsPostBarrier(value)) { - current->add(MPostWriteBarrier::New(alloc(), obj, value)); - } - - // If the property has a known type, we may be able to optimize typed stores - // by not storing the type tag. - MIRType slotType = MIRType::None; - MIRType knownType = property.knownMIRType(constraints()); - if (knownType != MIRType::Value) { - slotType = knownType; - } - - bool needsPreBarrier = property.needsBarrier(constraints()); - return storeSlot(obj, property.maybeTypes()->definiteSlot(), - NumFixedSlots(staticObject), value, needsPreBarrier, - slotType); -} - -JSObject* IonBuilder::testGlobalLexicalBinding(PropertyName* name) { - MOZ_ASSERT(JSOp(*pc) == JSOp::BindGName || JSOp(*pc) == JSOp::GetGName || - JSOp(*pc) == JSOp::SetGName || JSOp(*pc) == JSOp::StrictSetGName); - - // The global isn't the global lexical env's prototype, but its enclosing - // env. Test for the existence of |name| manually on the global lexical - // env. If it is not found, look for it on the global itself. - - NativeObject* obj = &script()->global().lexicalEnvironment(); - TypeSet::ObjectKey* lexicalKey = TypeSet::ObjectKey::get(obj); - jsid id = NameToId(name); - if (analysisContext) { - lexicalKey->ensureTrackedProperty(analysisContext, id); - } - - // If the property is not found on the global lexical env but it is found - // on the global and is configurable, try to freeze the typeset for its - // non-existence. If we don't have type information then fail. - // - // In the case that it is found on the global but is non-configurable, - // the binding cannot be shadowed by a global lexical binding. - Maybe lexicalProperty; - if (!lexicalKey->unknownProperties()) { - lexicalProperty.emplace(lexicalKey->property(id)); - } - Shape* shape = obj->lookupPure(name); - if (shape) { - if ((JSOp(*pc) != JSOp::GetGName && !shape->writable()) || - obj->getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL)) { - return nullptr; - } - } else { - shape = script()->global().lookupPure(name); - if (!shape || shape->configurable()) { - if (lexicalProperty.isSome()) { - MOZ_ALWAYS_FALSE(lexicalProperty->isOwnProperty(constraints())); - } else { - return nullptr; - } - } - obj = &script()->global(); - } - - return obj; -} - -AbortReasonOr IonBuilder::jsop_getgname(PropertyName* name) { - // Optimize undefined/NaN/Infinity first. - if (name == names().undefined) { - pushConstant(UndefinedValue()); - return Ok(); - } - if (name == names().NaN) { - pushConstant(JS::NaNValue()); - return Ok(); - } - if (name == names().Infinity) { - pushConstant(JS::InfinityValue()); - return Ok(); - } - - if (JSObject* obj = testGlobalLexicalBinding(name)) { - bool emitted = false; - MOZ_TRY(getStaticName(&emitted, obj, name)); - if (emitted) { - return Ok(); - } - - if (!forceInlineCaches() && obj->is()) { - TemporaryTypeSet* types = bytecodeTypes(pc); - MDefinition* globalObj = constant(ObjectValue(*obj)); - MOZ_TRY( - getPropTryCommonGetter(&emitted, globalObj, NameToId(name), types)); - if (emitted) { - return Ok(); - } - } - } - - return jsop_getname(name); -} - -AbortReasonOr IonBuilder::jsop_getname(PropertyName* name) { - MDefinition* object; - if (IsGlobalOp(JSOp(*pc)) && !script()->hasNonSyntacticScope()) { - object = constant(ObjectValue(script()->global().lexicalEnvironment())); - } else { - object = current->environmentChain(); - } - - MGetNameCache* ins = MGetNameCache::New(alloc(), object); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(ins, types, BarrierKind::TypeSet); -} - -AbortReasonOr IonBuilder::jsop_intrinsic(PropertyName* name) { - TemporaryTypeSet* types = bytecodeTypes(pc); - - Value vp = UndefinedValue(); - // If the intrinsic value doesn't yet exist, we generate code to get - // it and monitor the result. - if (!script()->global().maybeExistingIntrinsicValue(name, &vp)) { - MCallGetIntrinsicValue* ins = MCallGetIntrinsicValue::New(alloc(), name); - - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - - return pushTypeBarrier(ins, types, BarrierKind::TypeSet); - } - - // Otherwise, we can bake in the intrinsic. - pushConstant(vp); - - // Make sure that TI agrees with us on the type. - if (!types->hasType(TypeSet::GetValueType(vp))) { - types->addType(TypeSet::GetValueType(vp), alloc().lifoAlloc()); - } - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_getimport(PropertyName* name) { - ModuleEnvironmentObject* env = GetModuleEnvironmentForScript(script()); - MOZ_ASSERT(env); - - Shape* shape; - ModuleEnvironmentObject* targetEnv; - MOZ_ALWAYS_TRUE(env->lookupImport(NameToId(name), &targetEnv, &shape)); - - // We always use a type barrier because the slot's value can be modified by - // JSOP_SETALIASEDVAR without triggering type updates. This matches - // JSOP_GETALIASEDVAR. - TemporaryTypeSet* types = bytecodeTypes(pc); - BarrierKind barrier = BarrierKind::TypeSet; - MOZ_TRY(loadStaticSlot(targetEnv, barrier, types, shape->slot())); - - // In the rare case where this import hasn't been initialized already (we - // have an import cycle where modules reference each other's imports), emit - // a check. - if (targetEnv->getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL)) { - MDefinition* checked; - MOZ_TRY_VAR(checked, addLexicalCheck(current->pop())); - current->push(checked); - } - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_bindname(PropertyName* name) { - MDefinition* envChain; - if (IsGlobalOp(JSOp(*pc)) && !script()->hasNonSyntacticScope()) { - envChain = constant(ObjectValue(script()->global().lexicalEnvironment())); - } else { - envChain = current->environmentChain(); - } - - MBindNameCache* ins = MBindNameCache::New(alloc(), envChain); - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_bindvar() { - MOZ_ASSERT(usesEnvironmentChain()); - MCallBindVar* ins = MCallBindVar::New(alloc(), current->environmentChain()); - current->add(ins); - current->push(ins); - return Ok(); -} - -static MIRType GetElemKnownType(bool needsHoleCheck, TemporaryTypeSet* types) { - MIRType knownType = types->getKnownMIRType(); - - // Null and undefined have no payload so they can't be specialized. - // Since folding null/undefined while building SSA is not safe (see the - // comment in IsPhiObservable), we just add an untyped load instruction - // and rely on pushTypeBarrier and DCE to replace it with a null/undefined - // constant. - if (knownType == MIRType::Undefined || knownType == MIRType::Null) { - knownType = MIRType::Value; - } - - // Different architectures may want typed element reads which require - // hole checks to be done as either value or typed reads. - if (needsHoleCheck && !LIRGenerator::allowTypedElementHoleCheck()) { - knownType = MIRType::Value; - } - - return knownType; -} - -AbortReasonOr IonBuilder::jsop_getelem() { - MDefinition* index = current->pop(); - MDefinition* obj = current->pop(); - - // Always use a call if we are performing analysis and not actually - // emitting code, to simplify later analysis. - if (info().isAnalysis() || shouldAbortOnPreliminaryGroups(obj)) { - MInstruction* ins = MCallGetElement::New(alloc(), obj, index); - - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(ins, types, BarrierKind::TypeSet); - } - - bool emitted = false; - - // Handle lazy-arguments first. We have to do this even if forceInlineCaches - // is true (lazy arguments cannot escape to the IC). Like the code in - // IonBuilder::jsop_getprop, we only do this if we're not in analysis mode, - // to avoid unnecessary analysis aborts. - if (obj->mightBeType(MIRType::MagicOptimizedArguments) && - !info().isAnalysis()) { - MOZ_TRY(getElemTryArguments(&emitted, obj, index)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(getElemTryArgumentsInlinedConstant(&emitted, obj, index)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(getElemTryArgumentsInlinedIndex(&emitted, obj, index)); - if (emitted) { - return Ok(); - } - - if (script()->argumentsHasVarBinding()) { - return abort(AbortReason::Disable, - "Type is not definitely lazy arguments."); - } - } - - obj = maybeUnboxForPropertyAccess(obj); - - if (!forceInlineCaches()) { - // Note: no trackOptimizationAttempt call is needed, getElemTryGetProp - // will call it. - MOZ_TRY(getElemTryGetProp(&emitted, obj, index)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(getElemTryCallSiteObject(&emitted, obj, index)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(getElemTryDense(&emitted, obj, index)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(getElemTryTypedArray(&emitted, obj, index)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(getElemTryString(&emitted, obj, index)); - if (emitted) { - return Ok(); - } - } - - return getElemAddCache(obj, index); -} - -AbortReasonOr IonBuilder::getElemTryGetProp(bool* emitted, MDefinition* obj, - MDefinition* index) { - // If index is a constant string or symbol, try to optimize this GetElem - // as a GetProp. - - MOZ_ASSERT(*emitted == false); - - MConstant* indexConst = index->maybeConstantValue(); - jsid id; - if (!indexConst || !ValueToIdPure(indexConst->toJSValue(), &id)) { - return Ok(); - } - - if (id != IdToTypeId(id)) { - return Ok(); - } - - TemporaryTypeSet* types = bytecodeTypes(pc); - - MOZ_TRY(getPropTryConstant(emitted, obj, id, types)); - if (*emitted) { - index->setImplicitlyUsedUnchecked(); - return Ok(); - } - - MOZ_TRY(getPropTryNotDefined(emitted, obj, id, types)); - if (*emitted) { - index->setImplicitlyUsedUnchecked(); - return Ok(); - } - - MOZ_TRY(getPropTryCommonGetter(emitted, obj, id, types)); - if (*emitted) { - index->setImplicitlyUsedUnchecked(); - return Ok(); - } - - return Ok(); -} - -AbortReasonOr IonBuilder::getElemTryDense(bool* emitted, MDefinition* obj, - MDefinition* index) { - MOZ_ASSERT(*emitted == false); - - if (!ElementAccessIsDenseNative(constraints(), obj, index)) { - return Ok(); - } - - // Don't generate a fast path if there have been bounds check failures - // and this access might be on a sparse property. - bool hasExtraIndexedProperty; - MOZ_TRY_VAR(hasExtraIndexedProperty, - ElementAccessHasExtraIndexedProperty(this, obj)); - if (hasExtraIndexedProperty && failedBoundsCheck_) { - return Ok(); - } - - // Don't generate a fast path if this pc has seen negative - // or floating-point indexes accessed which will not appear - // to be extra indexed properties. - if (inspector->hasSeenNonIntegerIndex(pc)) { - return Ok(); - } - if (inspector->hasSeenNegativeIndexGetElement(pc)) { - return Ok(); - } - - MOZ_TRY(jsop_getelem_dense(obj, index)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getElemTryTypedArray(bool* emitted, - MDefinition* obj, - MDefinition* index) { - MOZ_ASSERT(*emitted == false); - - Scalar::Type arrayType; - if (!ElementAccessIsTypedArray(constraints(), obj, index, &arrayType)) { - return Ok(); - } - - // Emit typed getelem variant. - MOZ_TRY(jsop_getelem_typed(obj, index, arrayType)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getElemTryCallSiteObject(bool* emitted, - MDefinition* obj, - MDefinition* index) { - MOZ_ASSERT(*emitted == false); - - if (!obj->isConstant() || obj->type() != MIRType::Object) { - return Ok(); - } - - if (!index->isConstant() || index->type() != MIRType::Int32) { - return Ok(); - } - - JSObject* cst = &obj->toConstant()->toObject(); - if (!cst->is()) { - return Ok(); - } - - // Technically this code would work with any kind of frozen array, - // in pratice it is usually a CallSiteObject. - - ArrayObject* array = &cst->as(); - if (array->lengthIsWritable() || array->hasEmptyElements() || - !array->denseElementsAreFrozen()) { - return Ok(); - } - - int32_t idx = index->toConstant()->toInt32(); - if (idx < 0 || !array->containsDenseElement(uint32_t(idx))) { - return Ok(); - } - - const Value& v = array->getDenseElement(uint32_t(idx)); - // Strings should have been atomized by the parser. - if (!v.isString() || !v.toString()->isAtom()) { - return Ok(); - } - - obj->setImplicitlyUsedUnchecked(); - index->setImplicitlyUsedUnchecked(); - - pushConstant(v); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getElemTryString(bool* emitted, MDefinition* obj, - MDefinition* index) { - MOZ_ASSERT(*emitted == false); - - if (obj->type() != MIRType::String || !IsNumberType(index->type())) { - return Ok(); - } - - // If the index is expected to be out-of-bounds, don't optimize to avoid - // frequent bailouts. - if (bytecodeTypes(pc)->hasType(TypeSet::UndefinedType())) { - return Ok(); - } - - // Emit fast path for string[index]. - MInstruction* idInt32 = MToNumberInt32::New(alloc(), index); - current->add(idInt32); - index = idInt32; - - MStringLength* length = MStringLength::New(alloc(), obj); - current->add(length); - - index = addBoundsCheck(index, length); - - MCharCodeAt* charCode = MCharCodeAt::New(alloc(), obj, index); - current->add(charCode); - - MFromCharCode* result = MFromCharCode::New(alloc(), charCode); - current->add(result); - current->push(result); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getElemTryArguments(bool* emitted, - MDefinition* obj, - MDefinition* index) { - MOZ_ASSERT(*emitted == false); - - if (inliningDepth_ > 0) { - return Ok(); - } - - if (obj->type() != MIRType::MagicOptimizedArguments) { - return Ok(); - } - - // Emit GetFrameArgument. - - MOZ_ASSERT(!info().argsObjAliasesFormals()); - - // Type Inference has guaranteed this is an optimized arguments object. - obj->setImplicitlyUsedUnchecked(); - - // To ensure that we are not looking above the number of actual arguments. - MArgumentsLength* length = MArgumentsLength::New(alloc()); - current->add(length); - - // Ensure index is an integer. - MInstruction* idInt32 = MToNumberInt32::New(alloc(), index); - current->add(idInt32); - index = idInt32; - - // Bailouts if we read more than the number of actual arguments. - index = addBoundsCheck(index, length); - - // Load the argument from the actual arguments. - auto* load = MGetFrameArgument::New(alloc(), index); - current->add(load); - current->push(load); - - TemporaryTypeSet* types = bytecodeTypes(pc); - MOZ_TRY(pushTypeBarrier(load, types, BarrierKind::TypeSet)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getElemTryArgumentsInlinedConstant( - bool* emitted, MDefinition* obj, MDefinition* index) { - MOZ_ASSERT(*emitted == false); - - if (inliningDepth_ == 0) { - return Ok(); - } - - if (obj->type() != MIRType::MagicOptimizedArguments) { - return Ok(); - } - - MConstant* indexConst = index->maybeConstantValue(); - if (!indexConst || indexConst->type() != MIRType::Int32) { - return Ok(); - } - - // Emit inlined arguments. - obj->setImplicitlyUsedUnchecked(); - - MOZ_ASSERT(!info().argsObjAliasesFormals()); - - // When the id is constant, we can just return the corresponding inlined - // argument - MOZ_ASSERT(inliningDepth_ > 0); - - int32_t id = indexConst->toInt32(); - index->setImplicitlyUsedUnchecked(); - - if (id < (int32_t)inlineCallInfo_->argc() && id >= 0) { - current->push(inlineCallInfo_->getArg(id)); - } else { - pushConstant(UndefinedValue()); - } - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getElemTryArgumentsInlinedIndex( - bool* emitted, MDefinition* obj, MDefinition* index) { - MOZ_ASSERT(*emitted == false); - - if (inliningDepth_ == 0) { - return Ok(); - } - - if (obj->type() != MIRType::MagicOptimizedArguments) { - return Ok(); - } - - if (!IsNumberType(index->type())) { - return Ok(); - } - - // Currently, we do not support any arguments vector larger than 10, as this - // is being translated into code at the call site, and it would be better to - // store the arguments contiguously on the stack. - if (inlineCallInfo_->argc() > 10) { - return abort(AbortReason::Disable, - "NYI get argument element with too many arguments"); - } - - // Emit inlined arguments. - obj->setImplicitlyUsedUnchecked(); - - MOZ_ASSERT(!info().argsObjAliasesFormals()); - - // Ensure index is an integer. - MInstruction* idInt32 = MToNumberInt32::New(alloc(), index); - current->add(idInt32); - index = idInt32; - - // Bailout if we read more than the number of actual arguments. This bailout - // cannot re-enter because reading out of bounds arguments will disable the - // lazy arguments optimization for this script, when this code would be - // executed in Baseline. (see GetElemOptimizedArguments) - index = addBoundsCheck(index, constantInt(inlineCallInfo_->argc())); - - // Get an instruction to represent the state of the argument vector. - MInstruction* args = - MArgumentState::New(alloc().fallible(), inlineCallInfo_->argv()); - if (!args) { - return abort(AbortReason::Alloc); - } - current->add(args); - - // Select a value to pick from a vector. - MInstruction* load = MLoadElementFromState::New(alloc(), args, index); - current->add(load); - current->push(load); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getElemAddCache(MDefinition* obj, - MDefinition* index) { - // Emit GetPropertyCache. - - MGetPropertyCache* ins = MGetPropertyCache::New(alloc(), obj, index, - /* monitoredResult = */ true); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - - // We always barrier getElem to handle missing elements, as type inference - // doesn't handle missing properties (see Bug 1488786) - TemporaryTypeSet* types = bytecodeTypes(pc); - MOZ_TRY(pushTypeBarrier(ins, types, BarrierKind::TypeSet)); - - return Ok(); -} - -TemporaryTypeSet* IonBuilder::computeHeapType(const TemporaryTypeSet* objTypes, - const jsid id) { - if (objTypes->unknownObject() || objTypes->getObjectCount() == 0) { - return nullptr; - } - - TemporaryTypeSet* acc = nullptr; - LifoAlloc* lifoAlloc = alloc().lifoAlloc(); - - Vector properties; - if (!properties.reserve(objTypes->getObjectCount())) { - return nullptr; - } - - for (unsigned i = 0; i < objTypes->getObjectCount(); i++) { - TypeSet::ObjectKey* key = objTypes->getObject(i); - if (!key) { - continue; - } - - if (key->unknownProperties()) { - return nullptr; - } - - HeapTypeSetKey property = key->property(id); - HeapTypeSet* currentSet = property.maybeTypes(); - - if (!currentSet || currentSet->unknown()) { - return nullptr; - } - - properties.infallibleAppend(property); - - if (acc) { - acc = TypeSet::unionSets(acc, currentSet, lifoAlloc); - } else { - TemporaryTypeSet empty; - acc = TypeSet::unionSets(&empty, currentSet, lifoAlloc); - } - - if (!acc) { - return nullptr; - } - } - - // Freeze all the properties associated with the refined type set. - for (HeapTypeSetKey* i = properties.begin(); i != properties.end(); i++) { - i->freeze(constraints()); - } - - return acc; -} - -AbortReasonOr IonBuilder::jsop_getelem_dense(MDefinition* obj, - MDefinition* index) { - TemporaryTypeSet* types = bytecodeTypes(pc); - - MOZ_ASSERT(index->type() == MIRType::Int32 || - index->type() == MIRType::Double); - - BarrierKind barrier = PropertyReadNeedsTypeBarrier( - analysisContext, alloc(), constraints(), obj, nullptr, types); - bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj); - - // Reads which are on holes in the object do not have to bail out if - // 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 = false; - if (types->hasType(TypeSet::UndefinedType())) { - bool hasExtraIndexedProperty; - MOZ_TRY_VAR(hasExtraIndexedProperty, - ElementAccessHasExtraIndexedProperty(this, obj)); - readOutOfBounds = !hasExtraIndexedProperty; - } - - MIRType knownType = MIRType::Value; - if (barrier == BarrierKind::NoBarrier) { - knownType = GetElemKnownType(needsHoleCheck, types); - } - - // Ensure index is an integer. - MInstruction* idInt32 = MToNumberInt32::New(alloc(), index); - current->add(idInt32); - index = idInt32; - - // Get the elements vector. - MInstruction* elements = MElements::New(alloc(), obj); - current->add(elements); - - // Note: to help GVN, use the original MElements instruction and not - // MConvertElementsToDoubles as operand. This is fine because converting - // elements to double does not change the initialized length. - MInstruction* initLength = initializedLength(elements); - - // If we can load the element as a definite double, make sure to check that - // the array has been converted to homogenous doubles first. - TemporaryTypeSet* objTypes = obj->resultTypeSet(); - bool inBounds = !readOutOfBounds && !needsHoleCheck; - - if (inBounds) { - TemporaryTypeSet* heapTypes = computeHeapType(objTypes, JSID_VOID); - if (heapTypes && heapTypes->isSubset(types)) { - knownType = heapTypes->getKnownMIRType(); - types = heapTypes; - } - } - - bool loadDouble = barrier == BarrierKind::NoBarrier && loopDepth_ && - inBounds && knownType == MIRType::Double && objTypes && - objTypes->convertDoubleElements(constraints()) == - TemporaryTypeSet::AlwaysConvertToDoubles; - if (loadDouble) { - elements = addConvertElementsToDoubles(elements); - } - - MInstruction* load; - - if (!readOutOfBounds) { - // This load should not return undefined, so likely we're reading - // 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. - index = addBoundsCheck(index, initLength); - - load = - MLoadElement::New(alloc(), elements, index, needsHoleCheck, loadDouble); - 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. - load = MLoadElementHole::New(alloc(), elements, index, initLength, - needsHoleCheck); - current->add(load); - - // If maybeUndefined was true, the typeset must have undefined, and - // then either additional types or a barrier. This means we should - // never have a typed version of LoadElementHole. - MOZ_ASSERT(knownType == MIRType::Value); - } - - if (knownType != MIRType::Value) { - load->setResultType(knownType); - load->setResultTypeSet(types); - } - - current->push(load); - return pushTypeBarrier(load, types, barrier); -} - -MInstruction* IonBuilder::addArrayBufferByteLength(MDefinition* obj) { - auto* ins = MArrayBufferByteLengthInt32::New(alloc(), obj); - current->add(ins); - return ins; -} - -TypedArrayObject* IonBuilder::tryTypedArrayEmbedConstantElements( - MDefinition* obj) { - JSObject* object = nullptr; - if (MConstant* objConst = obj->maybeConstantValue()) { - if (objConst->type() == MIRType::Object) { - object = &objConst->toObject(); - } - } else if (TemporaryTypeSet* types = obj->resultTypeSet()) { - object = types->maybeSingleton(); - } - if (!object || !object->isSingleton()) { - return nullptr; - } - - TypedArrayObject* tarr = &object->as(); - - // TypedArrays are only singletons when created with a (Shared)ArrayBuffer - // and a length greater or equal to |SINGLETON_BYTE_LENGTH|. - MOZ_ASSERT(tarr->hasBuffer()); - MOZ_ASSERT(tarr->byteLength().get() >= - TypedArrayObject::SINGLETON_BYTE_LENGTH || - tarr->hasDetachedBuffer()); - - // TypedArrays using an ArrayBuffer don't have nursery-allocated data, see - // |ArrayBufferViewObject::init(...)|. - MOZ_ASSERT(!tarr->runtimeFromMainThread()->gc.nursery().isInside( - tarr->dataPointerEither())); - - // The 'data' pointer of TypedArrayObject can change in rare circumstances - // (ArrayBufferObject::setNewData). - TypeSet::ObjectKey* tarrKey = TypeSet::ObjectKey::get(tarr); - if (tarrKey->unknownProperties()) { - return nullptr; - } - if (!tarr->isSharedMemory()) { - tarrKey->watchStateChangeForTypedArrayData(constraints()); - } - return tarr; -} - -void IonBuilder::addTypedArrayLengthAndData(MDefinition* obj, - BoundsChecking checking, - MDefinition** index, - MInstruction** length, - MInstruction** elements) { - MOZ_ASSERT((index != nullptr) == (elements != nullptr)); - - if (TypedArrayObject* tarr = tryTypedArrayEmbedConstantElements(obj)) { - // Bug 979449 - Optimistically embed the elements and use TI to - // invalidate if we move them. - - obj->setImplicitlyUsedUnchecked(); - - int32_t len = AssertedCast(tarr->length().deprecatedGetUint32()); - *length = MConstant::New(alloc(), Int32Value(len)); - current->add(*length); - - if (index) { - if (checking == DoBoundsCheck) { - *index = addBoundsCheck(*index, *length); - } - - *elements = MConstantElements::New(alloc(), tarr->dataPointerEither()); - current->add(*elements); - } - return; - } - - *length = MArrayBufferViewLength::New(alloc(), obj); - current->add(*length); - - if (index) { - if (checking == DoBoundsCheck) { - *index = addBoundsCheck(*index, *length); - } - - *elements = MArrayBufferViewElements::New(alloc(), obj); - current->add(*elements); - } -} - -void IonBuilder::addDataViewData(MDefinition* obj, Scalar::Type type, - MDefinition** index, MInstruction** elements) { - MInstruction* length = MArrayBufferViewLength::New(alloc(), obj); - current->add(length); - - // Adjust the length to account for accesses near the end of the dataview. - if (size_t byteSize = Scalar::byteSize(type); byteSize > 1) { - // To ensure |0 <= index && index + byteSize <= length|, we can either emit - // |BoundsCheck(index, length)| followed by - // |BoundsCheck(index + (byteSize - 1), length)|, or alternatively emit - // |BoundsCheck(index, Max(length - (byteSize - 1), 0))|. The latter should - // result in faster code when LICM moves the length adjustment and also - // ensures Spectre index masking occurs after all bounds checks. - - auto* byteSizeMinusOne = MConstant::New(alloc(), Int32Value(byteSize - 1)); - current->add(byteSizeMinusOne); - - length = MSub::New(alloc(), length, byteSizeMinusOne, MIRType::Int32); - length->toSub()->setTruncateKind(MDefinition::Truncate); - current->add(length); - - // |length| mustn't be negative for MBoundsCheck. - auto* zero = MConstant::New(alloc(), Int32Value(0)); - current->add(zero); - - length = MMinMax::New(alloc(), length, zero, MIRType::Int32, true); - current->add(length); - } - - *index = addBoundsCheck(*index, length); - - *elements = MArrayBufferViewElements::New(alloc(), obj); - current->add(*elements); -} - -MInstruction* IonBuilder::addTypedArrayByteOffset(MDefinition* obj) { - MInstruction* byteOffset; - if (TypedArrayObject* tarr = tryTypedArrayEmbedConstantElements(obj)) { - obj->setImplicitlyUsedUnchecked(); - - int32_t offset = - AssertedCast(tarr->byteOffset().deprecatedGetUint32()); - byteOffset = MConstant::New(alloc(), Int32Value(offset)); - } else { - byteOffset = MArrayBufferViewByteOffset::New(alloc(), obj); - } - - current->add(byteOffset); - return byteOffset; -} - -AbortReasonOr IonBuilder::jsop_getelem_typed(MDefinition* obj, - MDefinition* index, - Scalar::Type arrayType) { - TemporaryTypeSet* types = bytecodeTypes(pc); - - bool maybeUndefined = types->hasType(TypeSet::UndefinedType()); - - // Reading from an Uint32Array will result in a double for values - // that don't fit in an int32. We have to bailout if this happens - // and the instruction is not known to return a double. - bool allowDouble = types->hasType(TypeSet::DoubleType()); - - if (!maybeUndefined) { - // Assume the index is in range, so that we can hoist the length, - // elements vector and bounds check. - - // Ensure the index is an integer. This is a stricter requirement than - // enforcing that it is a TypedArray index via MTypedArrayIndexToInt32, - // because any double which isn't exactly representable as an int32 will - // lead to a bailout. But it's okay to have this stricter requirement here, - // since any non-int32 index is equivalent to an out-of-bounds access, which - // will lead to a bailout anyway. - MInstruction* indexInt32 = MToNumberInt32::New(alloc(), index); - current->add(indexInt32); - index = indexInt32; - - // If we are reading in-bounds elements, we can use knowledge about - // the array type to determine the result type, even if the opcode has - // never executed. The known pushed type is only used to distinguish - // uint32 reads that may produce either doubles or integers. - MIRType knownType = MIRTypeForArrayBufferViewRead(arrayType, allowDouble); - - // Get length, bounds-check, then get elements, and add all instructions. - MInstruction* length; - MInstruction* elements; - addTypedArrayLengthAndData(obj, DoBoundsCheck, &index, &length, &elements); - - // Load the element. - MLoadUnboxedScalar* load = - MLoadUnboxedScalar::New(alloc(), elements, index, arrayType); - current->add(load); - current->push(load); - - // Note: we can ignore the type barrier here, we know the type must - // be valid and unbarriered. - load->setResultType(knownType); - return Ok(); - } else { - // Ensure the index is a TypedArray index. - auto* indexInt32 = MTypedArrayIndexToInt32::New(alloc(), index); - current->add(indexInt32); - index = indexInt32; - - // We need a type barrier if the array's element type has never been - // observed (we've only read out-of-bounds values). Note that for - // Uint32Array, we only check for int32: if allowDouble is false we - // will bailout when we read a double. - BarrierKind barrier = BarrierKind::TypeSet; - switch (arrayType) { - case Scalar::Int8: - case Scalar::Uint8: - case Scalar::Uint8Clamped: - case Scalar::Int16: - case Scalar::Uint16: - case Scalar::Int32: - case Scalar::Uint32: - if (types->hasType(TypeSet::Int32Type())) { - barrier = BarrierKind::NoBarrier; - } - break; - case Scalar::Float32: - case Scalar::Float64: - if (allowDouble) { - barrier = BarrierKind::NoBarrier; - } - break; - case Scalar::BigInt64: - case Scalar::BigUint64: - if (types->hasType(TypeSet::BigIntType())) { - barrier = BarrierKind::NoBarrier; - } - break; - default: - MOZ_CRASH("Unknown typed array type"); - } - - // Assume we will read out-of-bound values. In this case the - // bounds check will be part of the instruction, and the instruction - // will always return a Value. - MLoadTypedArrayElementHole* load = MLoadTypedArrayElementHole::New( - alloc(), obj, index, arrayType, allowDouble); - current->add(load); - current->push(load); - - return pushTypeBarrier(load, types, barrier); - } -} - -AbortReasonOr IonBuilder::jsop_setelem() { - bool emitted = false; - - MDefinition* value = current->pop(); - MDefinition* index = current->pop(); - MDefinition* object = current->pop(); - - if (shouldAbortOnPreliminaryGroups(object)) { - MInstruction* ins = - MCallSetElement::New(alloc(), object, index, value, IsStrictSetPC(pc)); - current->add(ins); - current->push(value); - return resumeAfter(ins); - } - - if (!forceInlineCaches()) { - MOZ_TRY(setElemTryTypedArray(&emitted, object, index, value)); - if (emitted) { - return Ok(); - } - - SetElemICInspector icInspect(inspector->setElemICInspector(pc)); - bool writeHole = icInspect.sawOOBDenseWrite(); - MOZ_TRY(initOrSetElemTryDense(&emitted, object, index, value, writeHole)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(setElemTryArguments(&emitted, object)); - if (emitted) { - return Ok(); - } - } - - if (script()->argumentsHasVarBinding() && - object->mightBeType(MIRType::MagicOptimizedArguments) && - info().analysisMode() != Analysis_ArgumentsUsage) { - return abort(AbortReason::Disable, - "Type is not definitely lazy arguments."); - } - - MOZ_TRY(initOrSetElemTryCache(&emitted, object, index, value)); - if (emitted) { - return Ok(); - } - - // Emit call. - MInstruction* ins = - MCallSetElement::New(alloc(), object, index, value, IsStrictSetPC(pc)); - current->add(ins); - current->push(value); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::setElemTryTypedArray(bool* emitted, - MDefinition* object, - MDefinition* index, - MDefinition* value) { - MOZ_ASSERT(*emitted == false); - - Scalar::Type arrayType; - if (!ElementAccessIsTypedArray(constraints(), object, index, &arrayType)) { - return Ok(); - } - - // Emit typed setelem variant. - MOZ_TRY(jsop_setelem_typed(arrayType, object, index, value)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::initOrSetElemTryDense(bool* emitted, - MDefinition* object, - MDefinition* index, - MDefinition* value, - bool writeHole) { - MOZ_ASSERT(*emitted == false); - - if (value->type() == MIRType::MagicHole) { - return Ok(); - } - - if (!ElementAccessIsDenseNative(constraints(), object, index)) { - return Ok(); - } - - if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &object, - nullptr, &value, /* canModify = */ true)) { - return Ok(); - } - - if (!object->resultTypeSet()) { - return Ok(); - } - - TemporaryTypeSet::DoubleConversion conversion = - object->resultTypeSet()->convertDoubleElements(constraints()); - - // If AmbiguousDoubleConversion, only handle int32 values for now. - if (conversion == TemporaryTypeSet::AmbiguousDoubleConversion && - value->type() != MIRType::Int32) { - return Ok(); - } - - // Don't generate a fast path if there have been bounds check failures - // and this access might be on a sparse property. - bool hasExtraIndexedProperty; - MOZ_TRY_VAR(hasExtraIndexedProperty, - ElementAccessHasExtraIndexedProperty(this, object)); - if (hasExtraIndexedProperty && failedBoundsCheck_) { - return Ok(); - } - - // Emit dense setelem variant. - return initOrSetElemDense(conversion, object, index, value, writeHole, - emitted); -} - -AbortReasonOr IonBuilder::setElemTryArguments(bool* emitted, - MDefinition* object) { - MOZ_ASSERT(*emitted == false); - - if (object->type() != MIRType::MagicOptimizedArguments) { - return Ok(); - } - - // Arguments are not supported yet. - return abort(AbortReason::Disable, "NYI arguments[]="); -} - -AbortReasonOr IonBuilder::initOrSetElemTryCache(bool* emitted, - MDefinition* object, - MDefinition* index, - MDefinition* value) { - MOZ_ASSERT(*emitted == false); - - if (!object->mightBeType(MIRType::Object)) { - return Ok(); - } - - if (value->type() == MIRType::MagicHole) { - return Ok(); - } - - bool barrier = true; - if (index->type() == MIRType::Int32 && - !PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &object, - nullptr, &value, /* canModify = */ true)) { - barrier = false; - } - - // We can avoid worrying about holes in the IC if we know a priori we are safe - // from them. If TI can guard that there are no indexed properties on the - // prototype chain, we know that we aren't missing any setters by overwriting - // the hole with another value. - bool guardHoles; - MOZ_TRY_VAR(guardHoles, ElementAccessHasExtraIndexedProperty(this, object)); - - // Make sure the object being written to doesn't have copy on write elements. - const JSClass* clasp = - object->resultTypeSet() - ? object->resultTypeSet()->getKnownClass(constraints()) - : nullptr; - bool checkNative = !clasp || !clasp->isNative(); - object = addMaybeCopyElementsForWrite(object, checkNative); - - // Emit SetPropertyCache. - bool strict = JSOp(*pc) == JSOp::StrictSetElem; - MSetPropertyCache* ins = - MSetPropertyCache::New(alloc(), object, index, value, strict, - needsPostBarrier(value), barrier, guardHoles); - current->add(ins); - - // Push value back onto stack. Init ops keep their object on stack. - if (!IsPropertyInitOp(JSOp(*pc))) { - current->push(value); - } - - MOZ_TRY(resumeAfter(ins)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::initOrSetElemDense( - TemporaryTypeSet::DoubleConversion conversion, MDefinition* obj, - MDefinition* id, MDefinition* value, bool writeHole, bool* emitted) { - MOZ_ASSERT(*emitted == false); - - MIRType elementType = DenseNativeElementType(constraints(), obj); - bool packed = ElementAccessIsPacked(constraints(), obj); - - // Writes which are on holes in the object do not have to bail out if they - // cannot hit another indexed property on the object or its prototypes. - bool hasExtraIndexedProperty; - MOZ_TRY_VAR(hasExtraIndexedProperty, - ElementAccessHasExtraIndexedProperty(this, obj)); - - bool mayBeNonExtensible = - ElementAccessMightBeNonExtensible(constraints(), obj); - - if (mayBeNonExtensible) { - // FallibleStoreElement does not know how to deal with extra indexed - // properties on the prototype. This case should be rare so we fall back - // to an IC. - if (hasExtraIndexedProperty) { - return Ok(); - } - - // Don't optimize InitElem (DefineProperty) on potentially non-extensible - // objects: when the array is sealed, we have to throw an exception. - if (IsPropertyInitOp(JSOp(*pc))) { - return Ok(); - } - } - - *emitted = true; - - // Ensure id is an integer. - MInstruction* idInt32 = MToNumberInt32::New(alloc(), id); - current->add(idInt32); - id = idInt32; - - if (needsPostBarrier(value)) { - current->add(MPostWriteElementBarrier::New(alloc(), obj, value, id)); - } - - // Copy the elements vector if necessary. - obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); - - // Get the elements vector. - MElements* elements = MElements::New(alloc(), obj); - current->add(elements); - - // Ensure the value is a double, if double conversion might be needed. - MDefinition* newValue = value; - switch (conversion) { - case TemporaryTypeSet::AlwaysConvertToDoubles: - case TemporaryTypeSet::MaybeConvertToDoubles: { - MInstruction* valueDouble = MToDouble::New(alloc(), value); - current->add(valueDouble); - newValue = valueDouble; - break; - } - - case TemporaryTypeSet::AmbiguousDoubleConversion: { - MOZ_ASSERT(value->type() == MIRType::Int32); - MInstruction* maybeDouble = - MMaybeToDoubleElement::New(alloc(), elements, value); - current->add(maybeDouble); - newValue = maybeDouble; - break; - } - - case TemporaryTypeSet::DontConvertToDoubles: - break; - - default: - MOZ_CRASH("Unknown double conversion"); - } - - // Use MStoreElementHole if this SetElem has written to out-of-bounds - // indexes in the past. Otherwise, use MStoreElement so that we can hoist - // the initialized length and bounds check. - // If an object may have been made non-extensible, no previous expectations - // hold and we fallback to MFallibleStoreElement. - MInstruction* store; - MStoreElementCommon* common = nullptr; - if (writeHole && !hasExtraIndexedProperty && !mayBeNonExtensible) { - MStoreElementHole* ins = - MStoreElementHole::New(alloc(), obj, elements, id, newValue); - store = ins; - common = ins; - - current->add(ins); - } else if (mayBeNonExtensible) { - MOZ_ASSERT( - !hasExtraIndexedProperty, - "FallibleStoreElement codegen assumes no extra indexed properties"); - - bool needsHoleCheck = !packed; - MFallibleStoreElement* ins = MFallibleStoreElement::New( - alloc(), obj, elements, id, newValue, needsHoleCheck); - store = ins; - common = ins; - - current->add(ins); - } else { - MInstruction* initLength = initializedLength(elements); - - id = addBoundsCheck(id, initLength); - bool needsHoleCheck = !packed && hasExtraIndexedProperty; - - MStoreElement* ins = - MStoreElement::New(alloc(), elements, id, newValue, needsHoleCheck); - store = ins; - common = ins; - - current->add(store); - } - - // Push value back onto stack. Init ops keep their object on stack. - if (!IsPropertyInitOp(JSOp(*pc))) { - current->push(value); - } - - MOZ_TRY(resumeAfter(store)); - - if (common) { - // Determine whether a write barrier is required. - if (obj->resultTypeSet()->propertyNeedsBarrier(constraints(), JSID_VOID)) { - common->setNeedsBarrier(); - } - - if (elementType != MIRType::None && packed) { - common->setElementType(elementType); - } - } - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_setelem_typed(Scalar::Type arrayType, - MDefinition* obj, - MDefinition* id, - MDefinition* value) { - SetElemICInspector icInspect(inspector->setElemICInspector(pc)); - bool expectOOB = icInspect.sawOOBTypedArrayWrite(); - - if (expectOOB) { - spew("Emitting OOB TypedArray SetElem"); - } - - // Ensure id is an integer. Just as in |jsop_getelem_typed|, use either - // MTypedArrayIndexToInt32 or MToNumberInt32 depending on whether or not - // out-of-bounds accesses are to be expected. - MInstruction* idInt32; - if (expectOOB) { - idInt32 = MTypedArrayIndexToInt32::New(alloc(), id); - } else { - idInt32 = MToNumberInt32::New(alloc(), id); - } - current->add(idInt32); - id = idInt32; - - // Get length, bounds-check, then get elements, and add all instructions. - MInstruction* length; - MInstruction* elements; - BoundsChecking checking = expectOOB ? SkipBoundsCheck : DoBoundsCheck; - addTypedArrayLengthAndData(obj, checking, &id, &length, &elements); - - // Clamp value to [0, 255] for Uint8ClampedArray. - MDefinition* toWrite = value; - if (arrayType == Scalar::Uint8Clamped) { - toWrite = MClampToUint8::New(alloc(), value); - current->add(toWrite->toInstruction()); - } - - // Store the value. - MInstruction* ins; - if (expectOOB) { - ins = MStoreTypedArrayElementHole::New(alloc(), elements, length, id, - toWrite, arrayType); - } else { - ins = MStoreUnboxedScalar::New(alloc(), elements, id, toWrite, arrayType); - } - - current->add(ins); - current->push(value); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_length() { - if (jsop_length_fastPath()) { - return Ok(); - } - - PropertyName* name = info().getAtom(pc)->asPropertyName(); - return jsop_getprop(name); -} - -bool IonBuilder::jsop_length_fastPath() { - TemporaryTypeSet* types = bytecodeTypes(pc); - - if (types->getKnownMIRType() != MIRType::Int32) { - return false; - } - - MDefinition* obj = current->peek(-1); - - if (shouldAbortOnPreliminaryGroups(obj)) { - return false; - } - - if (obj->mightBeType(MIRType::String)) { - if (obj->mightBeType(MIRType::Object)) { - return false; - } - current->pop(); - MStringLength* ins = MStringLength::New(alloc(), obj); - current->add(ins); - current->push(ins); - return true; - } - - if (obj->mightBeType(MIRType::Object)) { - TemporaryTypeSet* objTypes = obj->resultTypeSet(); - - // Compute the length for array objects. - if (objTypes && - objTypes->getKnownClass(constraints()) == &ArrayObject::class_ && - !objTypes->hasObjectFlags(constraints(), OBJECT_FLAG_LENGTH_OVERFLOW)) { - current->pop(); - MElements* elements = MElements::New(alloc(), obj); - current->add(elements); - - // Read length. - MArrayLength* length = MArrayLength::New(alloc(), elements); - current->add(length); - current->push(length); - return true; - } - } - - return false; -} - -AbortReasonOr IonBuilder::jsop_arguments() { - if (info().needsArgsObj()) { - current->push(current->argumentsObject()); - return Ok(); - } - - MOZ_ASSERT(hasLazyArguments_); - MConstant* lazyArg = - MConstant::New(alloc(), MagicValue(JS_OPTIMIZED_ARGUMENTS)); - current->add(lazyArg); - current->push(lazyArg); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_newtarget() { - MOZ_ASSERT(info().funMaybeLazy()); - - if (info().funMaybeLazy()->isArrow()) { - MArrowNewTarget* arrowNewTarget = - MArrowNewTarget::New(alloc(), getCallee()); - current->add(arrowNewTarget); - current->push(arrowNewTarget); - return Ok(); - } - - if (inliningDepth_ == 0) { - MNewTarget* newTarget = MNewTarget::New(alloc()); - current->add(newTarget); - current->push(newTarget); - return Ok(); - } - - if (!inlineCallInfo_->constructing()) { - pushConstant(UndefinedValue()); - return Ok(); - } - - current->push(inlineCallInfo_->getNewTarget()); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_rest() { - if (info().analysisMode() == Analysis_ArgumentsUsage) { - // There's no BaselineScript with the template object. Just push a - // dummy value, it does not affect the arguments analysis. - MUnknownValue* unknown = MUnknownValue::New(alloc()); - current->add(unknown); - current->push(unknown); - return Ok(); - } - - ArrayObject* templateObject = - &inspector->getTemplateObject(pc)->as(); - - if (inliningDepth_ == 0) { - // We don't know anything about the callee. - MArgumentsLength* numActuals = MArgumentsLength::New(alloc()); - current->add(numActuals); - - // Pass in the number of actual arguments, the number of formals (not - // including the rest parameter slot itself), and the template object. - MRest* rest = MRest::New(alloc(), constraints(), numActuals, - info().nargs() - 1, templateObject); - current->add(rest); - current->push(rest); - return Ok(); - } - - // We know the exact number of arguments the callee pushed. - unsigned numActuals = inlineCallInfo_->argc(); - unsigned numFormals = info().nargs() - 1; - unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0; - - MOZ_TRY(jsop_newarray(numRest)); - - if (numRest == 0) { - // No more updating to do. (Note that in this one case the length from - // the template object is already correct.) - return Ok(); - } - - MDefinition* array = current->peek(-1); - MElements* elements = MElements::New(alloc(), array); - current->add(elements); - - // Unroll the argument copy loop. We don't need to do any bounds or hole - // checking here. - MConstant* index = nullptr; - for (unsigned i = numFormals; i < numActuals; i++) { - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - index = MConstant::New(alloc(), Int32Value(i - numFormals)); - current->add(index); - - MDefinition* arg = inlineCallInfo_->argv()[i]; - MStoreElement* store = MStoreElement::New(alloc(), elements, index, arg, - /* needsHoleCheck = */ false); - current->add(store); - - if (needsPostBarrier(arg)) { - current->add(MPostWriteBarrier::New(alloc(), array, arg)); - } - } - - // The array's length is incorrectly 0 now, from the template object created - // by BaselineCompiler::emit_Rest() before the actual argument count was - // known. Set the correct length now that we know that count. - MSetArrayLength* length = MSetArrayLength::New(alloc(), elements, index); - current->add(length); - - // Update the initialized length for all the (necessarily non-hole) - // elements added. - MSetInitializedLength* initLength = - MSetInitializedLength::New(alloc(), elements, index); - current->add(initLength); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_checkisobj(uint8_t kind) { - MDefinition* toCheck = current->peek(-1); - - if (toCheck->type() == MIRType::Object) { - toCheck->setImplicitlyUsedUnchecked(); - return Ok(); - } - - MCheckIsObj* check = MCheckIsObj::New(alloc(), current->pop(), kind); - current->add(check); - current->push(check); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_checkobjcoercible() { - MDefinition* toCheck = current->peek(-1); - - if (!toCheck->mightBeType(MIRType::Undefined) && - !toCheck->mightBeType(MIRType::Null)) { - toCheck->setImplicitlyUsedUnchecked(); - return Ok(); - } - - MOZ_ASSERT(toCheck->type() == MIRType::Value || - toCheck->type() == MIRType::Null || - toCheck->type() == MIRType::Undefined); - - // If we want to squeeze more perf here, we can throw without checking, - // if IsNullOrUndefined(toCheck->type()). Since this is a failure case, - // it should be OK. - MCheckObjCoercible* check = MCheckObjCoercible::New(alloc(), current->pop()); - current->add(check); - current->push(check); - return resumeAfter(check); -} - -AbortReasonOr IonBuilder::jsop_checkclassheritage() { - auto* ins = MCheckClassHeritage::New(alloc(), current->pop()); - current->add(ins); - current->push(ins); - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_checkthis() { - auto* ins = MCheckThis::New(alloc(), current->pop()); - current->add(ins); - current->push(ins); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_checkthisreinit() { - auto* ins = MCheckThisReinit::New(alloc(), current->pop()); - current->add(ins); - current->push(ins); - return Ok(); -} - -uint32_t IonBuilder::getDefiniteSlot(TemporaryTypeSet* types, jsid id, - uint32_t* pnfixed) { - if (!types || types->unknownObject() || !types->objectOrSentinel()) { - return UINT32_MAX; - } - - uint32_t slot = UINT32_MAX; - - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - - if (key->unknownProperties()) { - return UINT32_MAX; - } - - if (key->isSingleton()) { - return UINT32_MAX; - } - - HeapTypeSetKey property = key->property(id); - if (!property.maybeTypes() || !property.maybeTypes()->definiteProperty() || - property.nonData(constraints())) { - return UINT32_MAX; - } - - // Definite slots will always be fixed slots when they are in the - // allowable range for fixed slots. - size_t nfixed = NativeObject::MAX_FIXED_SLOTS; - - uint32_t propertySlot = property.maybeTypes()->definiteSlot(); - if (slot == UINT32_MAX) { - slot = propertySlot; - *pnfixed = nfixed; - } else if (slot != propertySlot || nfixed != *pnfixed) { - return UINT32_MAX; - } - } - - return slot; -} - -AbortReasonOr IonBuilder::jsop_not() { - MDefinition* value = current->pop(); - - MNot* ins = MNot::New(alloc(), value, constraints()); - current->add(ins); - current->push(ins); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_envcallee() { - uint8_t numHops = GET_UINT8(pc); - MDefinition* env = walkEnvironmentChain(numHops); - MInstruction* callee = - MLoadFixedSlot::New(alloc(), env, CallObject::calleeSlot()); - current->add(callee); - current->push(callee); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_superbase() { - MDefinition* callee = current->pop(); - - auto* homeObject = MHomeObject::New(alloc(), callee); - current->add(homeObject); - - auto* superBase = MHomeObjectSuperBase::New(alloc(), homeObject); - current->add(superBase); - current->push(superBase); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_getprop_super(PropertyName* name) { - MDefinition* obj = current->pop(); - MDefinition* receiver = current->pop(); - - MConstant* id = constant(StringValue(name)); - auto* ins = MGetPropSuperCache::New(alloc(), obj, receiver, id); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(ins, types, BarrierKind::TypeSet); -} - -AbortReasonOr IonBuilder::jsop_getelem_super() { - MDefinition* obj = current->pop(); - MDefinition* id = current->pop(); - MDefinition* receiver = current->pop(); - -#if defined(JS_CODEGEN_X86) - if (mirGen_.instrumentedProfiling()) { - return abort(AbortReason::Disable, - "profiling functions with GETELEM_SUPER is disabled on x86"); - } -#endif - - auto* ins = MGetPropSuperCache::New(alloc(), obj, receiver, id); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(ins, types, BarrierKind::TypeSet); -} - -NativeObject* IonBuilder::commonPrototypeWithGetterSetter( - TemporaryTypeSet* types, jsid id, bool isGetter, JSFunction* getterOrSetter, - bool* guardGlobal) { - // If there's a single object on the proto chain of all objects in |types| - // that contains a property |id| with |getterOrSetter| getter or setter - // function, return that object. - - // No sense looking if we don't know what's going on. - if (!types || types->unknownObject()) { - return nullptr; - } - *guardGlobal = false; - - NativeObject* foundProto = nullptr; - for (unsigned i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - - while (key) { - if (key->unknownProperties()) { - return nullptr; - } - - const JSClass* clasp = key->clasp(); - if (!ClassHasEffectlessLookup(clasp)) { - return nullptr; - } - JSObject* singleton = key->isSingleton() ? key->singleton() : nullptr; - if (ObjectHasExtraOwnProperty(realm, key, id)) { - if (!singleton || !singleton->is()) { - return nullptr; - } - *guardGlobal = true; - } - - // Look for a getter/setter on the class itself which may need - // to be called. - if (isGetter && clasp->getOpsGetProperty()) { - return nullptr; - } - if (!isGetter && clasp->getOpsSetProperty()) { - return nullptr; - } - - // If we have a singleton, check if it contains the getter or - // setter we're looking for. Note that we don't need to add any - // type constraints as the caller will add a Shape guard for the - // holder and type constraints for other objects on the proto - // chain. - // - // If the object is not a singleton, we fall back to the code below - // and check whether the property is missing. That's fine because - // we're looking for a getter or setter on the proto chain and - // these objects are singletons. - if (singleton) { - if (!singleton->is()) { - return nullptr; - } - - NativeObject* singletonNative = &singleton->as(); - if (Shape* propShape = singletonNative->lookupPure(id)) { - // We found a property. Check if it's the getter or setter - // we're looking for. - Value getterSetterVal = ObjectValue(*getterOrSetter); - if (isGetter) { - if (propShape->getterOrUndefined() != getterSetterVal) { - return nullptr; - } - } else { - if (propShape->setterOrUndefined() != getterSetterVal) { - return nullptr; - } - } - - if (!foundProto) { - foundProto = singletonNative; - } else if (foundProto != singletonNative) { - return nullptr; - } - break; - } - } - - // Test for isOwnProperty() without freezing. If we end up - // optimizing, freezePropertiesForCommonPropFunc will freeze the - // property type sets later on. - HeapTypeSetKey property = key->property(id); - if (TypeSet* types = property.maybeTypes()) { - if (!types->empty() || types->nonDataProperty()) { - return nullptr; - } - } - if (singleton) { - if (CanHaveEmptyPropertyTypesForOwnProperty(singleton)) { - MOZ_ASSERT(singleton->is()); - *guardGlobal = true; - } - } - - JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull()); - if (foundProto && proto == foundProto) { - // We found an object on the proto chain that's known to have - // the getter or setter property, so we can stop looking. - break; - } - - if (!proto) { - // The getter or setter being searched for did not show up on - // the object's prototype chain. - return nullptr; - } - key = TypeSet::ObjectKey::get(proto); - } - } - - return foundProto; -} - -AbortReasonOr IonBuilder::freezePropertiesForCommonPrototype( - TemporaryTypeSet* types, jsid id, JSObject* foundProto, - bool allowEmptyTypesforGlobal) { - for (unsigned i = 0; i < types->getObjectCount(); i++) { - // If we found a Singleton object's own-property, there's nothing to - // freeze. - if (types->getSingleton(i) == foundProto) { - continue; - } - - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - - while (true) { - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - HeapTypeSetKey property = key->property(id); - MOZ_ALWAYS_TRUE( - !property.isOwnProperty(constraints(), allowEmptyTypesforGlobal)); - - // Don't mark the proto. It will be held down by the shape - // guard. This allows us to use properties found on prototypes - // with properties unknown to TI. - if (key->proto() == TaggedProto(foundProto)) { - break; - } - key = TypeSet::ObjectKey::get(key->proto().toObjectOrNull()); - } - } - return Ok(); -} - -AbortReasonOr IonBuilder::testCommonGetterSetter( - TemporaryTypeSet* types, jsid id, bool isGetter, JSFunction* getterOrSetter, - MDefinition** guard, Shape* globalShape /* = nullptr*/, - MDefinition** globalGuard /* = nullptr */) { - MOZ_ASSERT(getterOrSetter); - MOZ_ASSERT_IF(globalShape, globalGuard); - bool guardGlobal; - - // Check if all objects being accessed will lookup the name through - // foundProto. - NativeObject* foundProto = commonPrototypeWithGetterSetter( - types, id, isGetter, getterOrSetter, &guardGlobal); - if (!foundProto || (guardGlobal && !globalShape)) { - return false; - } - - // We can optimize the getter/setter, so freeze all involved properties to - // ensure there isn't a lower shadowing getter or setter installed in the - // future. - MOZ_TRY( - freezePropertiesForCommonPrototype(types, id, foundProto, guardGlobal)); - - // Add a shape guard on the prototype we found the property on. The rest of - // the prototype chain is guarded by TI freezes, except when name is a global - // name. In this case, we also have to guard on the globals shape to be able - // to optimize, because the way global property sets are handled means - // freezing doesn't work for what we want here. Note that a shape guard is - // good enough here, even in the proxy case, because we have ensured there - // are no lookup hooks for this property. - if (guardGlobal) { - JSObject* obj = &script()->global(); - MDefinition* globalObj = constant(ObjectValue(*obj)); - *globalGuard = addShapeGuard(globalObj, globalShape); - } - - // If the getter/setter is not configurable we don't have to guard on the - // proto's shape. - Shape* propShape = foundProto->lookupPure(id); - MOZ_ASSERT_IF(isGetter, propShape->getterObject() == getterOrSetter); - MOZ_ASSERT_IF(!isGetter, propShape->setterObject() == getterOrSetter); - if (propShape && !propShape->configurable()) { - return true; - } - - MInstruction* wrapper = constant(ObjectValue(*foundProto)); - *guard = addShapeGuard(wrapper, foundProto->lastProperty()); - return true; -} - -void IonBuilder::replaceMaybeFallbackFunctionGetter(MGetPropertyCache* cache) { - // Discard the last prior resume point of the previous MGetPropertyCache. - WrapMGetPropertyCache rai(maybeFallbackFunctionGetter_); - maybeFallbackFunctionGetter_ = cache; -} - -AbortReasonOr IonBuilder::annotateGetPropertyCache( - MDefinition* obj, PropertyName* name, MGetPropertyCache* getPropCache, - TemporaryTypeSet* objTypes, TemporaryTypeSet* pushedTypes) { - // Ensure every pushed value is a singleton. - if (pushedTypes->unknownObject() || pushedTypes->baseFlags() != 0) { - return Ok(); - } - - for (unsigned i = 0; i < pushedTypes->getObjectCount(); i++) { - if (pushedTypes->getGroup(i) != nullptr) { - return Ok(); - } - } - - // Object's typeset should be a proper object - if (!objTypes || objTypes->baseFlags() || objTypes->unknownObject()) { - return Ok(); - } - - unsigned int objCount = objTypes->getObjectCount(); - if (objCount == 0) { - return Ok(); - } - - InlinePropertyTable* inlinePropTable = - getPropCache->initInlinePropertyTable(alloc(), pc); - if (!inlinePropTable) { - return abort(AbortReason::Alloc); - } - - // Ensure that the relevant property typeset for each group is - // is a single-object typeset containing a JSFunction - for (unsigned int i = 0; i < objCount; i++) { - ObjectGroup* group = objTypes->getGroup(i); - if (!group) { - continue; - } - TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(group); - if (key->unknownProperties() || !key->proto().isObject()) { - continue; - } - JSObject* proto = checkNurseryObject(key->proto().toObject()); - - const JSClass* clasp = key->clasp(); - if (!ClassHasEffectlessLookup(clasp) || - ObjectHasExtraOwnProperty(realm, key, NameToId(name))) { - continue; - } - - HeapTypeSetKey ownTypes = key->property(NameToId(name)); - if (ownTypes.isOwnProperty(constraints())) { - continue; - } - - JSObject* singleton = testSingletonProperty(proto, NameToId(name)); - if (!singleton || !singleton->is()) { - continue; - } - - // Don't add cases corresponding to non-observed pushes - if (!pushedTypes->hasType(TypeSet::ObjectType(singleton))) { - continue; - } - - if (!inlinePropTable->addEntry(alloc(), group, - &singleton->as())) { - return abort(AbortReason::Alloc); - } - } - - if (inlinePropTable->numEntries() == 0) { - getPropCache->clearInlinePropertyTable(); - return Ok(); - } - -#ifdef JS_JITSPEW - if (inlinePropTable->numEntries() > 0) { - JitSpew(JitSpew_Inlining, - "Annotated GetPropertyCache with %d/%d inline cases", - (int)inlinePropTable->numEntries(), (int)objCount); - } -#endif - - // If we successfully annotated the GetPropertyCache and there are inline - // cases, then keep a resume point of the state right before this instruction - // for use later when we have to bail out to this point in the fallback case - // of a PolyInlineDispatch. - if (inlinePropTable->numEntries() > 0) { - // Push the object back onto the stack temporarily to capture the resume - // point. - current->push(obj); - MResumePoint* resumePoint = - MResumePoint::New(alloc(), current, pc, MResumePoint::ResumeAt); - if (!resumePoint) { - return abort(AbortReason::Alloc); - } - inlinePropTable->setPriorResumePoint(resumePoint); - replaceMaybeFallbackFunctionGetter(getPropCache); - current->pop(); - } - return Ok(); -} - -// Returns true if an idempotent cache has ever invalidated this script -// or an outer script. -bool IonBuilder::invalidatedIdempotentCache() { - IonBuilder* builder = this; - do { - if (builder->script()->invalidatedIdempotentCache()) { - return true; - } - builder = builder->callerBuilder_; - } while (builder); - - return false; -} - -AbortReasonOr IonBuilder::loadSlot(MDefinition* obj, size_t slot, - size_t nfixed, MIRType rvalType, - BarrierKind barrier, - TemporaryTypeSet* types) { - if (slot < nfixed) { - MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), obj, slot); - current->add(load); - current->push(load); - - load->setResultType(rvalType); - return pushTypeBarrier(load, types, barrier); - } - - MSlots* slots = MSlots::New(alloc(), obj); - current->add(slots); - - MLoadDynamicSlot* load = MLoadDynamicSlot::New(alloc(), slots, slot - nfixed); - current->add(load); - current->push(load); - - load->setResultType(rvalType); - return pushTypeBarrier(load, types, barrier); -} - -AbortReasonOr IonBuilder::loadSlot(MDefinition* obj, Shape* shape, - MIRType rvalType, BarrierKind barrier, - TemporaryTypeSet* types) { - return loadSlot(obj, shape->slot(), shape->numFixedSlots(), rvalType, barrier, - types); -} - -AbortReasonOr IonBuilder::storeSlot( - MDefinition* obj, size_t slot, size_t nfixed, MDefinition* value, - bool needsBarrier, MIRType slotType /* = MIRType::None */) { - if (slot < nfixed) { - MStoreFixedSlot* store = MStoreFixedSlot::New(alloc(), obj, slot, value); - current->add(store); - current->push(value); - if (needsBarrier) { - store->setNeedsBarrier(); - } - return resumeAfter(store); - } - - MSlots* slots = MSlots::New(alloc(), obj); - current->add(slots); - - MStoreDynamicSlot* store = - MStoreDynamicSlot::New(alloc(), slots, slot - nfixed, value); - current->add(store); - current->push(value); - if (needsBarrier) { - store->setNeedsBarrier(); - } - if (slotType != MIRType::None) { - store->setSlotType(slotType); - } - return resumeAfter(store); -} - -AbortReasonOr IonBuilder::storeSlot( - MDefinition* obj, Shape* shape, MDefinition* value, bool needsBarrier, - MIRType slotType /* = MIRType::None */) { - MOZ_ASSERT(shape->writable()); - return storeSlot(obj, shape->slot(), shape->numFixedSlots(), value, - needsBarrier, slotType); -} - -bool IonBuilder::shouldAbortOnPreliminaryGroups(MDefinition* obj) { - // Watch for groups which still have preliminary object information and - // have not had the new script properties or unboxed layout analyses - // performed. Normally this is done after a small number of the objects - // have been created, but if only a few have been created we can still - // perform the analysis with a smaller object population. The analysis can - // have side effects so we will end up aborting compilation after building - // finishes and retrying later. - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject()) { - return false; - } - - bool preliminary = false; - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - - if (ObjectGroup* group = key->maybeGroup()) { - if (group->hasUnanalyzedPreliminaryObjects()) { - addAbortedPreliminaryGroup(group); - preliminary = true; - } - } - } - - return preliminary; -} - -MDefinition* IonBuilder::maybeUnboxForPropertyAccess(MDefinition* def) { - if (def->type() != MIRType::Value) { - return def; - } - - MIRType type = inspector->expectedPropertyAccessInputType(pc); - if (type == MIRType::Value || !def->mightBeType(type)) { - return def; - } - - MUnbox* unbox = MUnbox::New(alloc(), def, type, MUnbox::Fallible); - current->add(unbox); - - // Fixup type information for a common case where a property call - // is converted to the following bytecodes - // - // a.foo() - // ================= Compiles to ================ - // GetLocal "a" (or similar) - // Dup - // CallProp "foo" - // Swap - // Call 0 - // - // If we have better type information to unbox the first copy going into - // the CallProp operation, we can replace the duplicated copy on the - // stack as well. - if (JSOp(*pc) == JSOp::CallProp || JSOp(*pc) == JSOp::CallElem) { - uint32_t idx = current->stackDepth() - 1; - MOZ_ASSERT(current->getSlot(idx) == def); - current->setSlot(idx, unbox); - } - - return unbox; -} - -AbortReasonOr IonBuilder::jsop_getprop(PropertyName* name) { - bool emitted = false; - - MDefinition* obj = current->pop(); - TemporaryTypeSet* types = bytecodeTypes(pc); - - if (!info().isAnalysis()) { - // The calls below can abort compilation, so we only try this if we're - // not analyzing. - // Try to optimize arguments.length. - MOZ_TRY(getPropTryArgumentsLength(&emitted, obj)); - if (emitted) { - return Ok(); - } - - // Try to optimize arguments.callee. - MOZ_TRY(getPropTryArgumentsCallee(&emitted, obj, name)); - if (emitted) { - return Ok(); - } - } - - obj = maybeUnboxForPropertyAccess(obj); - - BarrierKind barrier = PropertyReadNeedsTypeBarrier( - analysisContext, alloc(), constraints(), obj, name, types); - - // Try to optimize to a specific constant. - if (barrier == BarrierKind::NoBarrier) { - MOZ_TRY(getPropTryInferredConstant(&emitted, obj, name, types)); - if (emitted) { - return Ok(); - } - } - - // Always use a call if we are performing analysis and - // not actually emitting code, to simplify later analysis. Also skip deeper - // analysis if there are no known types for this operation, as it will - // always invalidate when executing. - if (info().isAnalysis() || types->empty() || - shouldAbortOnPreliminaryGroups(obj)) { - MCallGetProperty* call = MCallGetProperty::New(alloc(), obj, name); - current->add(call); - - // During the definite properties analysis we can still try to bake in - // constants read off the prototype chain, to allow inlining later on. - // In this case we still need the getprop call so that the later - // analysis knows when the |this| value has been read from. - if (info().isAnalysis()) { - MOZ_TRY(getPropTryConstant(&emitted, obj, NameToId(name), types)); - if (emitted) { - return Ok(); - } - } - - current->push(call); - MOZ_TRY(resumeAfter(call)); - return pushTypeBarrier(call, types, BarrierKind::TypeSet); - } - - // Try to optimize accesses on outer window proxies, for example window.foo. - // This needs to come before the various strategies getPropTryInnerize tries - // internally, since some of those strategies will "succeed" in silly ways - // even for an outer object. - MOZ_TRY(getPropTryInnerize(&emitted, obj, name, types)); - if (emitted) { - return Ok(); - } - - if (!forceInlineCaches()) { - // Try to hardcode known constants. - MOZ_TRY(getPropTryConstant(&emitted, obj, NameToId(name), types)); - if (emitted) { - return Ok(); - } - - // Try to hardcode known not-defined - MOZ_TRY(getPropTryNotDefined(&emitted, obj, NameToId(name), types)); - if (emitted) { - return Ok(); - } - - // Try to emit loads from definite slots. - MOZ_TRY(getPropTryDefiniteSlot(&emitted, obj, name, barrier, types)); - if (emitted) { - return Ok(); - } - - // Try to inline a common property getter, or make a call. - MOZ_TRY(getPropTryCommonGetter(&emitted, obj, NameToId(name), types)); - if (emitted) { - return Ok(); - } - - // Try to emit a monomorphic/polymorphic access based on baseline caches. - MOZ_TRY(getPropTryInlineAccess(&emitted, obj, name, barrier, types)); - if (emitted) { - return Ok(); - } - - // Try to emit a property access on the prototype based on baseline - // caches. - MOZ_TRY(getPropTryInlineProtoAccess(&emitted, obj, name, types)); - if (emitted) { - return Ok(); - } - - // Try to emit loads from a module namespace. - MOZ_TRY(getPropTryModuleNamespace(&emitted, obj, name, barrier, types)); - if (emitted) { - return Ok(); - } - } - - // Emit a polymorphic cache. - return getPropAddCache(obj, name, barrier, types); -} - -AbortReasonOr IonBuilder::improveThisTypesForCall() { - // After a CallProp (or CallElem) for obj.prop(), the this-value and callee - // for the call are on top of the stack: - // - // ... [this: obj], [callee: obj.prop] - // - // If obj is null or undefined, obj.prop would have thrown an exception so - // at this point we can remove null and undefined from obj's TypeSet, to - // improve type information for the call that will follow. - - MOZ_ASSERT(JSOp(*pc) == JSOp::CallProp || JSOp(*pc) == JSOp::CallElem); - - // Ensure |this| has types {object, null/undefined}. For simplicity don't - // optimize if the callee is a Phi (this can happen in rare cases after - // inlining a scripted getter). - MDefinition* thisDef = current->peek(-2); - MDefinition* calleeDef = current->peek(-1); - if (thisDef->type() != MIRType::Value || - !thisDef->mightBeType(MIRType::Object) || !thisDef->resultTypeSet() || - !thisDef->resultTypeSet()->objectOrSentinel() || calleeDef->isPhi()) { - return Ok(); - } - - // Remove null/undefined from the TypeSet. - TemporaryTypeSet* types = - thisDef->resultTypeSet()->cloneObjectsOnly(alloc_->lifoAlloc()); - if (!types) { - return abort(AbortReason::Alloc); - } - - MFilterTypeSet* filter = MFilterTypeSet::New(alloc(), thisDef, types); - current->add(filter); - current->rewriteAtDepth(-2, filter); - - // FilterTypeSetPolicy::adjustInputs will insert an infallible Unbox(Object) - // for the input. Don't hoist this unbox above the getprop or getelem - // operation. - filter->setDependency(calleeDef); - return Ok(); -} - -AbortReasonOr IonBuilder::checkIsDefinitelyOptimizedArguments( - MDefinition* obj, bool* isOptimizedArgs) { - if (obj->type() != MIRType::MagicOptimizedArguments) { - if (script()->argumentsHasVarBinding() && - obj->mightBeType(MIRType::MagicOptimizedArguments)) { - return abort(AbortReason::Disable, - "Type is not definitely lazy arguments."); - } - - *isOptimizedArgs = false; - return Ok(); - } - - *isOptimizedArgs = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getPropTryInferredConstant( - bool* emitted, MDefinition* obj, PropertyName* name, - TemporaryTypeSet* types) { - MOZ_ASSERT(*emitted == false); - - // Need a result typeset to optimize. - TemporaryTypeSet* objTypes = obj->resultTypeSet(); - if (!objTypes) { - return Ok(); - } - - JSObject* singleton = objTypes->maybeSingleton(); - if (!singleton) { - return Ok(); - } - - TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(singleton); - if (key->unknownProperties()) { - return Ok(); - } - - HeapTypeSetKey property = key->property(NameToId(name)); - - Value constantValue = UndefinedValue(); - if (property.constant(constraints(), &constantValue)) { - spew("Optimized constant property"); - obj->setImplicitlyUsedUnchecked(); - pushConstant(constantValue); - types->addType(TypeSet::GetValueType(constantValue), alloc_->lifoAlloc()); - *emitted = true; - } - - return Ok(); -} - -AbortReasonOr IonBuilder::getPropTryArgumentsLength(bool* emitted, - MDefinition* obj) { - MOZ_ASSERT(*emitted == false); - - if (JSOp(*pc) != JSOp::Length) { - return Ok(); - } - - bool isOptimizedArgs = false; - MOZ_TRY(checkIsDefinitelyOptimizedArguments(obj, &isOptimizedArgs)); - if (!isOptimizedArgs) { - return Ok(); - } - - *emitted = true; - - obj->setImplicitlyUsedUnchecked(); - - // We don't know anything from the callee - if (inliningDepth_ == 0) { - MInstruction* ins = MArgumentsLength::New(alloc()); - current->add(ins); - current->push(ins); - return Ok(); - } - - // We are inlining and know the number of arguments the callee pushed - pushConstant(Int32Value(inlineCallInfo_->argv().length())); - return Ok(); -} - -AbortReasonOr IonBuilder::getPropTryArgumentsCallee(bool* emitted, - MDefinition* obj, - PropertyName* name) { - MOZ_ASSERT(*emitted == false); - - if (name != names().callee) { - return Ok(); - } - - bool isOptimizedArgs = false; - MOZ_TRY(checkIsDefinitelyOptimizedArguments(obj, &isOptimizedArgs)); - if (!isOptimizedArgs) { - return Ok(); - } - - MOZ_ASSERT(script()->hasMappedArgsObj()); - - obj->setImplicitlyUsedUnchecked(); - current->push(getCallee()); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getPropTryConstant(bool* emitted, - MDefinition* obj, jsid id, - TemporaryTypeSet* types) { - MOZ_ASSERT(*emitted == false); - - if (!types->mightBeMIRType(MIRType::Object)) { - // If we have not observed an object result here, don't look for a - // singleton constant. - return Ok(); - } - - JSObject* singleton = testSingletonPropertyTypes(obj, id); - if (!singleton) { - return Ok(); - } - - // Property access is a known constant -- safe to emit. - obj->setImplicitlyUsedUnchecked(); - - pushConstant(ObjectValue(*singleton)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getPropTryNotDefined(bool* emitted, - MDefinition* obj, jsid id, - TemporaryTypeSet* types) { - MOZ_ASSERT(*emitted == false); - - if (!types->mightBeMIRType(MIRType::Undefined)) { - // Only optimize if we expect this property access to return undefined. - return Ok(); - } - - bool res; - MOZ_TRY_VAR(res, testNotDefinedProperty(obj, id)); - if (!res) { - return Ok(); - } - - obj->setImplicitlyUsedUnchecked(); - pushConstant(UndefinedValue()); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getPropTryDefiniteSlot(bool* emitted, - MDefinition* obj, - PropertyName* name, - BarrierKind barrier, - TemporaryTypeSet* types) { - MOZ_ASSERT(*emitted == false); - - uint32_t nfixed; - uint32_t slot = - getDefiniteSlot(obj->resultTypeSet(), NameToId(name), &nfixed); - if (slot == UINT32_MAX) { - return Ok(); - } - - if (obj->type() != MIRType::Object) { - MGuardObject* guard = MGuardObject::New(alloc(), obj); - current->add(guard); - obj = guard; - } - - MInstruction* load; - if (slot < nfixed) { - load = MLoadFixedSlot::New(alloc(), obj, slot); - } else { - MInstruction* slots = MSlots::New(alloc(), obj); - current->add(slots); - - load = MLoadDynamicSlot::New(alloc(), slots, slot - nfixed); - } - - if (barrier == BarrierKind::NoBarrier) { - load->setResultType(types->getKnownMIRType()); - } - - current->add(load); - current->push(load); - - MOZ_TRY(pushTypeBarrier(load, types, barrier)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getPropTryModuleNamespace( - bool* emitted, MDefinition* obj, PropertyName* name, BarrierKind barrier, - TemporaryTypeSet* types) { - MOZ_ASSERT(*emitted == false); - - TemporaryTypeSet* objTypes = obj->resultTypeSet(); - if (!objTypes) { - return Ok(); - } - - JSObject* singleton = objTypes->maybeSingleton(); - if (!singleton) { - return Ok(); - } - - if (!singleton->is()) { - return Ok(); - } - - ModuleNamespaceObject* ns = &singleton->as(); - ModuleEnvironmentObject* env; - Shape* shape; - if (!ns->bindings().lookup(NameToId(name), &env, &shape)) { - return Ok(); - } - - obj->setImplicitlyUsedUnchecked(); - MConstant* envConst = constant(ObjectValue(*env)); - uint32_t slot = shape->slot(); - uint32_t nfixed = env->numFixedSlots(); - - MIRType rvalType = types->getKnownMIRType(); - if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) { - rvalType = MIRType::Value; - } - - MOZ_TRY(loadSlot(envConst, slot, nfixed, rvalType, barrier, types)); - - *emitted = true; - return Ok(); -} - -MDefinition* IonBuilder::addShapeGuardsForGetterSetter( - MDefinition* obj, JSObject* holder, Shape* holderShape, - const BaselineInspector::ReceiverVector& receivers, bool isOwnProperty) { - MOZ_ASSERT(isOwnProperty == !holder); - MOZ_ASSERT(holderShape); - - if (isOwnProperty) { - MOZ_ASSERT(receivers.empty()); - return addShapeGuard(obj, holderShape); - } - - MDefinition* holderDef = constant(ObjectValue(*holder)); - addShapeGuard(holderDef, holderShape); - - return addGuardReceiverPolymorphic(obj, receivers); -} - -AbortReasonOr IonBuilder::getPropTryCommonGetter(bool* emitted, - MDefinition* obj, jsid id, - TemporaryTypeSet* types, - bool innerized) { - MOZ_ASSERT(*emitted == false); - - TemporaryTypeSet* objTypes = obj->resultTypeSet(); - - JSFunction* commonGetter = nullptr; - MDefinition* guard = nullptr; - MDefinition* globalGuard = nullptr; - - { - Shape* lastProperty = nullptr; - Shape* globalShape = nullptr; - JSObject* foundProto = nullptr; - bool isOwnProperty = false; - BaselineInspector::ReceiverVector receivers(alloc()); - if (inspector->commonGetPropFunction( - pc, id, innerized, &foundProto, &lastProperty, &commonGetter, - &globalShape, &isOwnProperty, receivers)) { - bool canUseTIForGetter = false; - if (!isOwnProperty) { - // If it's not an own property, try to use TI to avoid shape guards. - // For own properties we use the path below. - MOZ_TRY_VAR(canUseTIForGetter, - testCommonGetterSetter(objTypes, id, - /* isGetter = */ true, commonGetter, - &guard, globalShape, &globalGuard)); - } - if (!canUseTIForGetter) { - // If it's an own property or type information is bad, we can still - // optimize the getter if we shape guard. - obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty, - receivers, isOwnProperty); - if (!obj) { - return abort(AbortReason::Alloc); - } - } - } else if (inspector->megamorphicGetterSetterFunction( - pc, id, /* isGetter = */ true, &commonGetter)) { - // Try to use TI to guard on this getter. - bool canUseTIForGetter = false; - MOZ_TRY_VAR(canUseTIForGetter, - testCommonGetterSetter(objTypes, id, /* isGetter = */ true, - commonGetter, &guard)); - if (!canUseTIForGetter) { - return Ok(); - } - } else { - // The Baseline IC didn't have any information we can use. - return Ok(); - } - } - - DOMObjectKind objKind = DOMObjectKind::Unknown; - bool isDOM = objTypes && objTypes->isDOMClass(constraints(), &objKind); - if (isDOM) { - MOZ_TRY_VAR(isDOM, - testShouldDOMCall(objTypes, commonGetter, JSJitInfo::Getter)); - } - - if (isDOM) { - const JSJitInfo* jitinfo = commonGetter->jitInfo(); - // We don't support MGetDOMProperty/MGetDOMMember on things that might - // be proxies when the value might be in a slot, because the - // CodeGenerator code for LGetDOMProperty/LGetDOMMember doesn't handle - // that case correctly. - if (objKind == DOMObjectKind::Native || - (!jitinfo->isAlwaysInSlot && !jitinfo->isLazilyCachedInSlot)) { - MInstruction* get; - if (jitinfo->isAlwaysInSlot) { - // If our object is a singleton and we know the property is - // constant (which is true if and only if the get doesn't alias - // anything), we can just read the slot here and use that - // constant. - JSObject* singleton = objTypes->maybeSingleton(); - if (singleton && jitinfo->aliasSet() == JSJitInfo::AliasNone) { - size_t slot = jitinfo->slotIndex; - *emitted = true; - pushConstant(JS::GetReservedSlot(singleton, slot)); - return Ok(); - } - - // We can't use MLoadFixedSlot here because it might not have - // the right aliasing behavior; we want to alias DOM setters as - // needed. - get = MGetDOMMember::New(alloc(), jitinfo, obj, guard, globalGuard); - } else { - get = MGetDOMProperty::New(alloc(), jitinfo, objKind, - commonGetter->realm(), obj, guard, - globalGuard); - } - if (!get) { - return abort(AbortReason::Alloc); - } - current->add(get); - current->push(get); - - if (get->isEffectful()) { - MOZ_TRY(resumeAfter(get)); - } - - MOZ_TRY(pushDOMTypeBarrier(get, types, commonGetter)); - - *emitted = true; - return Ok(); - } - } - - // Don't call the getter with a primitive value. - if (obj->type() != MIRType::Object) { - MGuardObject* guardObj = MGuardObject::New(alloc(), obj); - current->add(guardObj); - obj = guardObj; - } - - // Spoof stack to expected state for call. - - // Make sure there's enough room - if (!current->ensureHasSlots(2)) { - return abort(AbortReason::Alloc); - } - current->push(constant(ObjectValue(*commonGetter))); - - current->push(obj); - - CallInfo callInfo(alloc(), pc, /* constructing = */ false, - /* ignoresReturnValue = */ BytecodeIsPopped(pc)); - if (!callInfo.init(current, 0)) { - return abort(AbortReason::Alloc); - } - - if (commonGetter->isNative()) { - InliningStatus status; - MOZ_TRY_VAR(status, inlineNativeGetter(callInfo, commonGetter)); - switch (status) { - case InliningStatus_WarmUpCountTooLow: - case InliningStatus_NotInlined: - break; - case InliningStatus_Inlined: - *emitted = true; - return Ok(); - } - } - - // Inline if we can, otherwise, forget it and just generate a call. - if (commonGetter->isInterpreted()) { - InliningDecision decision = makeInliningDecision(commonGetter, callInfo); - switch (decision) { - case InliningDecision_Error: - return abort(AbortReason::Error); - case InliningDecision_DontInline: - case InliningDecision_WarmUpCountTooLow: - break; - case InliningDecision_Inline: { - InliningStatus status; - MOZ_TRY_VAR(status, inlineScriptedCall(callInfo, commonGetter)); - if (status == InliningStatus_Inlined) { - *emitted = true; - return Ok(); - } - break; - } - } - } - - MOZ_TRY(makeCall(commonGetter, callInfo)); - - *emitted = true; - return Ok(); -} - -bool IonBuilder::canInlinePropertyOpShapes( - const BaselineInspector::ReceiverVector& receivers) { - if (receivers.empty()) { - return false; - } - - for (size_t i = 0; i < receivers.length(); i++) { - // We inline the property access as long as the shape is not in - // dictionary mode. We cannot be sure that the shape is still a - // lastProperty, and calling Shape::search() on dictionary mode - // shapes that aren't lastProperty is invalid. - if (receivers[i].getShape() && receivers[i].getShape()->inDictionary()) { - return false; - } - } - - return true; -} - -static Shape* PropertyShapesHaveSameSlot( - const BaselineInspector::ReceiverVector& receivers, jsid id) { - Shape* firstShape = nullptr; - for (size_t i = 0; i < receivers.length(); i++) { - if (receivers[i].getGroup()) { - return nullptr; - } - - Shape* shape = receivers[i].getShape()->searchLinear(id); - MOZ_ASSERT(shape); - - if (i == 0) { - firstShape = shape; - } else if (shape->slot() != firstShape->slot() || - shape->numFixedSlots() != firstShape->numFixedSlots()) { - return nullptr; - } - } - - return firstShape; -} - -AbortReasonOr IonBuilder::getPropTryInlineAccess(bool* emitted, - MDefinition* obj, - PropertyName* name, - BarrierKind barrier, - TemporaryTypeSet* types) { - MOZ_ASSERT(*emitted == false); - - BaselineInspector::ReceiverVector receivers(alloc()); - if (!inspector->maybeInfoForPropertyOp(pc, receivers)) { - return abort(AbortReason::Alloc); - } - - if (!canInlinePropertyOpShapes(receivers)) { - return Ok(); - } - - MIRType rvalType = types->getKnownMIRType(); - if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) { - rvalType = MIRType::Value; - } - - if (receivers.length() == 1) { - if (!receivers[0].getGroup()) { - // Monomorphic load from a native object. - spew("Inlining monomorphic native GETPROP"); - - obj = addShapeGuard(obj, receivers[0].getShape()); - - Shape* shape = receivers[0].getShape()->searchLinear(NameToId(name)); - MOZ_ASSERT(shape); - - MOZ_TRY(loadSlot(obj, shape, rvalType, barrier, types)); - - *emitted = true; - return Ok(); - } - - return Ok(); - } - - MOZ_ASSERT(receivers.length() > 1); - spew("Inlining polymorphic GETPROP"); - - if (Shape* propShape = - PropertyShapesHaveSameSlot(receivers, NameToId(name))) { - obj = addGuardReceiverPolymorphic(obj, receivers); - if (!obj) { - return abort(AbortReason::Alloc); - } - - MOZ_TRY(loadSlot(obj, propShape, rvalType, barrier, types)); - - *emitted = true; - return Ok(); - } - - MGetPropertyPolymorphic* load = - MGetPropertyPolymorphic::New(alloc(), obj, name); - current->add(load); - current->push(load); - - for (size_t i = 0; i < receivers.length(); i++) { - Shape* propShape = nullptr; - if (receivers[i].getShape()) { - propShape = receivers[i].getShape()->searchLinear(NameToId(name)); - MOZ_ASSERT(propShape); - } - if (!load->addReceiver(receivers[i], propShape)) { - return abort(AbortReason::Alloc); - } - } - - if (failedShapeGuard_) { - load->setNotMovable(); - } - - load->setResultType(rvalType); - MOZ_TRY(pushTypeBarrier(load, types, barrier)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getPropTryInlineProtoAccess( - bool* emitted, MDefinition* obj, PropertyName* name, - TemporaryTypeSet* types) { - MOZ_ASSERT(*emitted == false); - - BaselineInspector::ReceiverVector receivers(alloc()); - JSObject* holder = nullptr; - if (!inspector->maybeInfoForProtoReadSlot(pc, receivers, &holder)) { - return abort(AbortReason::Alloc); - } - - if (!canInlinePropertyOpShapes(receivers)) { - return Ok(); - } - - MOZ_ASSERT(holder); - holder = checkNurseryObject(holder); - - BarrierKind barrier; - MOZ_TRY_VAR(barrier, - PropertyReadOnPrototypeNeedsTypeBarrier(this, obj, name, types)); - - MIRType rvalType = types->getKnownMIRType(); - if (barrier != BarrierKind::NoBarrier || IsNullOrUndefined(rvalType)) { - rvalType = MIRType::Value; - } - - // Guard on the receiver shapes/groups. - obj = addGuardReceiverPolymorphic(obj, receivers); - if (!obj) { - return abort(AbortReason::Alloc); - } - - // Guard on the holder's shape. - MInstruction* holderDef = constant(ObjectValue(*holder)); - Shape* holderShape = holder->as().shape(); - holderDef = addShapeGuard(holderDef, holderShape); - - Shape* propShape = holderShape->searchLinear(NameToId(name)); - MOZ_ASSERT(propShape); - - MOZ_TRY(loadSlot(holderDef, propShape, rvalType, barrier, types)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::getPropAddCache(MDefinition* obj, - PropertyName* name, - BarrierKind barrier, - TemporaryTypeSet* types) { - // PropertyReadNeedsTypeBarrier only accounts for object types, so for now - // always insert a barrier if the input is not known to be an object. - if (obj->type() != MIRType::Object) { - barrier = BarrierKind::TypeSet; - } - - // Since getters have no guaranteed return values, we must barrier in order to - // be able to attach stubs for them. - if (inspector->hasSeenAccessedGetter(pc)) { - barrier = BarrierKind::TypeSet; - } - - // Caches can read values from prototypes, so update the barrier to - // reflect such possible values. - if (barrier != BarrierKind::TypeSet) { - BarrierKind protoBarrier; - MOZ_TRY_VAR(protoBarrier, PropertyReadOnPrototypeNeedsTypeBarrier( - this, obj, name, types)); - if (protoBarrier != BarrierKind::NoBarrier) { - MOZ_ASSERT(barrier <= protoBarrier); - barrier = protoBarrier; - } - } - - // Ensure we insert a type barrier for reads from typed objects, as type - // information does not account for the initial undefined/null types. - if (barrier != BarrierKind::TypeSet && !types->unknown()) { - MOZ_ASSERT(obj->resultTypeSet()); - switch (obj->resultTypeSet()->forAllClasses(constraints(), - IsTypedObjectClass)) { - case TemporaryTypeSet::ForAllResult::ALL_FALSE: - case TemporaryTypeSet::ForAllResult::EMPTY: - break; - case TemporaryTypeSet::ForAllResult::ALL_TRUE: - case TemporaryTypeSet::ForAllResult::MIXED: - barrier = BarrierKind::TypeSet; - break; - } - } - - MConstant* id = constant(StringValue(name)); - MGetPropertyCache* load = - MGetPropertyCache::New(alloc(), obj, id, barrier == BarrierKind::TypeSet); - - // Try to mark the cache as idempotent. - if (obj->type() == MIRType::Object && !invalidatedIdempotentCache()) { - if (PropertyReadIsIdempotent(constraints(), obj, name)) { - load->setIdempotent(); - } - } - - // When we are in the context of making a call from the value returned from - // a property, we query the typeObject for the given property name to fill - // the InlinePropertyTable of the GetPropertyCache. This information is - // then used in inlineCallsite and inlineCalls, if the "this" definition is - // matching the "object" definition of the GetPropertyCache (see - // CanInlineGetPropertyCache). - // - // If this GetPropertyCache is idempotent, then we can dispatch to the right - // function only by checking the typed object, instead of querying the value - // of the property. Thus this GetPropertyCache can be moved into the - // fallback path (see inlineObjectGroupFallback). Otherwise, we always have - // to do the GetPropertyCache, and we can dispatch based on the JSFunction - // value. - if (JSOp(*pc) == JSOp::CallProp && load->idempotent()) { - MOZ_TRY( - annotateGetPropertyCache(obj, name, load, obj->resultTypeSet(), types)); - } - - current->add(load); - current->push(load); - - if (load->isEffectful()) { - MOZ_TRY(resumeAfter(load)); - } - - MIRType rvalType = types->getKnownMIRType(); - if (barrier != BarrierKind::NoBarrier) { - rvalType = MIRType::Value; - } else { - load->setResultTypeSet(types); - if (IsNullOrUndefined(rvalType)) { - rvalType = MIRType::Value; - } - } - load->setResultType(rvalType); - - if (JSOp(*pc) != JSOp::CallProp || !IsNullOrUndefined(obj->type())) { - // Due to inlining, it's possible the observed TypeSet is non-empty, - // even though we know |obj| is null/undefined and the MCallGetProperty - // will throw. Don't push a TypeBarrier in this case, to avoid - // inlining the following (unreachable) JSOp::Call. - MOZ_TRY(pushTypeBarrier(load, types, barrier)); - } - - return Ok(); -} - -MDefinition* IonBuilder::tryInnerizeWindow(MDefinition* obj) { - // Try to optimize accesses on outer window proxies (window.foo, for - // example) to go directly to the inner window, the global. - // - // Callers should be careful not to pass the global object to getters or - // setters that require the WindowProxy. - - if (obj->type() != MIRType::Object) { - return obj; - } - - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types) { - return obj; - } - - JSObject* singleton = types->maybeSingleton(); - if (!singleton) { - return obj; - } - - if (!IsWindowProxyForScriptGlobal(script(), singleton)) { - return obj; - } - - // When we navigate, the WindowProxy is brain transplanted and we'll mark - // its ObjectGroup as having unknown properties. The type constraint we add - // here will invalidate JIT code when this happens. - TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(singleton); - if (key->hasFlags(constraints(), OBJECT_FLAG_UNKNOWN_PROPERTIES)) { - return obj; - } - - obj->setImplicitlyUsedUnchecked(); - return constant(ObjectValue(script()->global())); -} - -AbortReasonOr IonBuilder::getPropTryInnerize(bool* emitted, - MDefinition* obj, - PropertyName* name, - TemporaryTypeSet* types) { - // See the comment in tryInnerizeWindow for how this works. - - // Note that it's important that we do this _before_ we'd try to - // do the optimizations below on obj normally, since some of those - // optimizations have fallback paths that are slower than the path - // we'd produce here. - - MOZ_ASSERT(*emitted == false); - - MDefinition* inner = tryInnerizeWindow(obj); - if (inner == obj) { - return Ok(); - } - - if (!forceInlineCaches()) { - MOZ_TRY(getPropTryConstant(emitted, inner, NameToId(name), types)); - if (*emitted) { - return Ok(); - } - MOZ_TRY(getStaticName(emitted, &script()->global(), name)); - if (*emitted) { - return Ok(); - } - MOZ_TRY(getPropTryCommonGetter(emitted, inner, NameToId(name), types, - /* innerized = */ true)); - if (*emitted) { - return Ok(); - } - } - - // Passing the inner object to GetProperty IC is safe, see the - // needsOuterizedThisObject check in IsCacheableGetPropCallNative. - BarrierKind barrier = PropertyReadNeedsTypeBarrier( - analysisContext, alloc(), constraints(), inner, name, types); - MOZ_TRY(getPropAddCache(inner, name, barrier, types)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_setprop(PropertyName* name) { - MDefinition* value = current->pop(); - MDefinition* obj = current->pop(); - - bool emitted = false; - - // Always use a call if we are doing the definite properties analysis and - // not actually emitting code, to simplify later analysis. - if (info().isAnalysis() || shouldAbortOnPreliminaryGroups(obj)) { - bool strict = IsStrictSetPC(pc); - MInstruction* ins = - MCallSetProperty::New(alloc(), obj, value, name, strict); - current->add(ins); - current->push(value); - return resumeAfter(ins); - } - - if (!forceInlineCaches()) { - // Try to inline a common property setter, or make a call. - MOZ_TRY(setPropTryCommonSetter(&emitted, obj, name, value)); - if (emitted) { - return Ok(); - } - } - - TemporaryTypeSet* objTypes = obj->resultTypeSet(); - bool barrier = PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, - &obj, name, &value, - /* canModify = */ true); - - if (!forceInlineCaches()) { - // Try to emit store from definite slots. - MOZ_TRY(setPropTryDefiniteSlot(&emitted, obj, name, value, barrier)); - if (emitted) { - return Ok(); - } - - // Try to emit a monomorphic/polymorphic store based on baseline caches. - MOZ_TRY( - setPropTryInlineAccess(&emitted, obj, name, value, barrier, objTypes)); - if (emitted) { - return Ok(); - } - } - - // Emit a polymorphic cache. - MOZ_TRY(setPropTryCache(&emitted, obj, name, value, barrier)); - MOZ_ASSERT(emitted == true); - return Ok(); -} - -AbortReasonOr IonBuilder::setPropTryCommonSetter(bool* emitted, - MDefinition* obj, - PropertyName* name, - MDefinition* value) { - MOZ_ASSERT(*emitted == false); - - TemporaryTypeSet* objTypes = obj->resultTypeSet(); - JSFunction* commonSetter = nullptr; - MDefinition* guard = nullptr; - - { - Shape* lastProperty = nullptr; - JSObject* foundProto = nullptr; - bool isOwnProperty; - BaselineInspector::ReceiverVector receivers(alloc()); - if (inspector->commonSetPropFunction(pc, &foundProto, &lastProperty, - &commonSetter, &isOwnProperty, - receivers)) { - bool canUseTIForSetter = false; - if (!isOwnProperty) { - // If it's not an own property, try to use TI to avoid shape guards. - // For own properties we use the path below. - MOZ_TRY_VAR(canUseTIForSetter, - testCommonGetterSetter(objTypes, NameToId(name), - /* isGetter = */ false, commonSetter, - &guard)); - } - if (!canUseTIForSetter) { - // If it's an own property or type information is bad, we can still - // optimize the setter if we shape guard. - obj = addShapeGuardsForGetterSetter(obj, foundProto, lastProperty, - receivers, isOwnProperty); - if (!obj) { - return abort(AbortReason::Alloc); - } - } - } else if (inspector->megamorphicGetterSetterFunction( - pc, NameToId(name), /* isGetter = */ false, &commonSetter)) { - // Try to use TI to guard on this setter. - bool canUseTIForSetter = false; - MOZ_TRY_VAR( - canUseTIForSetter, - testCommonGetterSetter(objTypes, NameToId(name), - /* isGetter = */ false, commonSetter, &guard)); - if (!canUseTIForSetter) { - return Ok(); - } - } else { - // The Baseline IC didn't have any information we can use. - return Ok(); - } - } - - // Emit common setter. - - // Setters can be called even if the property write needs a type - // barrier, as calling the setter does not actually write any data - // properties. - - // Try emitting dom call. - MOZ_TRY( - setPropTryCommonDOMSetter(emitted, obj, value, commonSetter, objTypes)); - if (*emitted) { - return Ok(); - } - - // Don't call the setter with a primitive value. - if (obj->type() != MIRType::Object) { - MGuardObject* guardObj = MGuardObject::New(alloc(), obj); - current->add(guardObj); - obj = guardObj; - } - - // Dummy up the stack, as in getprop. We are pushing an extra value, so - // ensure there is enough space. - if (!current->ensureHasSlots(3)) { - return abort(AbortReason::Alloc); - } - - current->push(constant(ObjectValue(*commonSetter))); - current->push(obj); - current->push(value); - - // Call the setter. Note that we have to push the original value, not - // the setter's return value. - CallInfo callInfo(alloc(), pc, /* constructing = */ false, - /* ignoresReturnValue = */ BytecodeIsPopped(pc)); - if (!callInfo.init(current, 1)) { - return abort(AbortReason::Alloc); - } - - // Ensure that we know we are calling a setter in case we inline it. - callInfo.markAsSetter(); - - // Inline the setter if we can. - if (commonSetter->isInterpreted()) { - InliningDecision decision = makeInliningDecision(commonSetter, callInfo); - switch (decision) { - case InliningDecision_Error: - return abort(AbortReason::Error); - case InliningDecision_DontInline: - case InliningDecision_WarmUpCountTooLow: - break; - case InliningDecision_Inline: { - InliningStatus status; - MOZ_TRY_VAR(status, inlineScriptedCall(callInfo, commonSetter)); - if (status == InliningStatus_Inlined) { - *emitted = true; - return Ok(); - } - } - } - } - - Maybe targets; - targets.emplace(alloc()); - if (!targets->append(commonSetter)) { - return abort(AbortReason::Alloc); - } - MCall* call; - MOZ_TRY_VAR(call, makeCallHelper(targets, callInfo)); - - current->push(value); - MOZ_TRY(resumeAfter(call)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::setPropTryCommonDOMSetter( - bool* emitted, MDefinition* obj, MDefinition* value, JSFunction* setter, - TemporaryTypeSet* objTypes) { - MOZ_ASSERT(*emitted == false); - - DOMObjectKind objKind = DOMObjectKind::Unknown; - if (!objTypes || !objTypes->isDOMClass(constraints(), &objKind)) { - return Ok(); - } - - bool isDOM = false; - MOZ_TRY_VAR(isDOM, testShouldDOMCall(objTypes, setter, JSJitInfo::Setter)); - if (!isDOM) { - return Ok(); - } - - // Emit SetDOMProperty. - MOZ_ASSERT(setter->jitInfo()->type() == JSJitInfo::Setter); - MSetDOMProperty* set = MSetDOMProperty::New( - alloc(), setter->jitInfo()->setter, objKind, setter->realm(), obj, value); - - current->add(set); - current->push(value); - - MOZ_TRY(resumeAfter(set)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::setPropTryDefiniteSlot(bool* emitted, - MDefinition* obj, - PropertyName* name, - MDefinition* value, - bool barrier) { - MOZ_ASSERT(*emitted == false); - - if (barrier) { - return Ok(); - } - - uint32_t nfixed; - uint32_t slot = - getDefiniteSlot(obj->resultTypeSet(), NameToId(name), &nfixed); - if (slot == UINT32_MAX) { - return Ok(); - } - - bool writeBarrier = false; - for (size_t i = 0; i < obj->resultTypeSet()->getObjectCount(); i++) { - TypeSet::ObjectKey* key = obj->resultTypeSet()->getObject(i); - if (!key) { - continue; - } - - HeapTypeSetKey property = key->property(NameToId(name)); - if (property.nonWritable(constraints())) { - return Ok(); - } - writeBarrier |= property.needsBarrier(constraints()); - } - - if (needsPostBarrier(value)) { - current->add(MPostWriteBarrier::New(alloc(), obj, value)); - } - - MInstruction* store; - if (slot < nfixed) { - store = MStoreFixedSlot::New(alloc(), obj, slot, value); - if (writeBarrier) { - store->toStoreFixedSlot()->setNeedsBarrier(); - } - } else { - MInstruction* slots = MSlots::New(alloc(), obj); - current->add(slots); - - store = MStoreDynamicSlot::New(alloc(), slots, slot - nfixed, value); - if (writeBarrier) { - store->toStoreDynamicSlot()->setNeedsBarrier(); - } - } - - current->add(store); - current->push(value); - - MOZ_TRY(resumeAfter(store)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::setPropTryInlineAccess( - bool* emitted, MDefinition* obj, PropertyName* name, MDefinition* value, - bool barrier, TemporaryTypeSet* objTypes) { - MOZ_ASSERT(*emitted == false); - - if (barrier) { - return Ok(); - } - - BaselineInspector::ReceiverVector receivers(alloc()); - if (!inspector->maybeInfoForPropertyOp(pc, receivers)) { - return abort(AbortReason::Alloc); - } - - if (!canInlinePropertyOpShapes(receivers)) { - return Ok(); - } - - if (receivers.length() == 1) { - if (!receivers[0].getGroup()) { - // Monomorphic store to a native object. - spew("Inlining monomorphic native SETPROP"); - - obj = addShapeGuard(obj, receivers[0].getShape()); - - Shape* shape = receivers[0].getShape()->searchLinear(NameToId(name)); - MOZ_ASSERT(shape); - - if (needsPostBarrier(value)) { - current->add(MPostWriteBarrier::New(alloc(), obj, value)); - } - - bool needsPreBarrier = - objTypes->propertyNeedsBarrier(constraints(), NameToId(name)); - MOZ_TRY(storeSlot(obj, shape, value, needsPreBarrier)); - - *emitted = true; - return Ok(); - } - } - - MOZ_ASSERT(receivers.length() > 1); - spew("Inlining polymorphic SETPROP"); - - if (Shape* propShape = - PropertyShapesHaveSameSlot(receivers, NameToId(name))) { - obj = addGuardReceiverPolymorphic(obj, receivers); - if (!obj) { - return abort(AbortReason::Alloc); - } - - if (needsPostBarrier(value)) { - current->add(MPostWriteBarrier::New(alloc(), obj, value)); - } - - bool needsPreBarrier = - objTypes->propertyNeedsBarrier(constraints(), NameToId(name)); - MOZ_TRY(storeSlot(obj, propShape, value, needsPreBarrier)); - - *emitted = true; - return Ok(); - } - - if (needsPostBarrier(value)) { - current->add(MPostWriteBarrier::New(alloc(), obj, value)); - } - - MSetPropertyPolymorphic* ins = - MSetPropertyPolymorphic::New(alloc(), obj, value, name); - current->add(ins); - current->push(value); - - for (size_t i = 0; i < receivers.length(); i++) { - Shape* propShape = nullptr; - if (receivers[i].getShape()) { - propShape = receivers[i].getShape()->searchLinear(NameToId(name)); - MOZ_ASSERT(propShape); - } - if (!ins->addReceiver(receivers[i], propShape)) { - return abort(AbortReason::Alloc); - } - } - - if (objTypes->propertyNeedsBarrier(constraints(), NameToId(name))) { - ins->setNeedsBarrier(); - } - - MOZ_TRY(resumeAfter(ins)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::setPropTryCache(bool* emitted, MDefinition* obj, - PropertyName* name, - MDefinition* value, - bool barrier) { - MOZ_ASSERT(*emitted == false); - - bool strict = IsStrictSetPC(pc); - - MConstant* id = constant(StringValue(name)); - MSetPropertyCache* ins = MSetPropertyCache::New( - alloc(), obj, id, value, strict, needsPostBarrier(value), barrier, - /* guardHoles = */ false); - current->add(ins); - current->push(value); - - MOZ_TRY(resumeAfter(ins)); - - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_delprop(PropertyName* name) { - MDefinition* obj = current->pop(); - - bool strict = JSOp(*pc) == JSOp::StrictDelProp; - MInstruction* ins = MDeleteProperty::New(alloc(), obj, name, strict); - - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_delelem() { - MDefinition* index = current->pop(); - MDefinition* obj = current->pop(); - - bool strict = JSOp(*pc) == JSOp::StrictDelElem; - MDeleteElement* ins = MDeleteElement::New(alloc(), obj, index, strict); - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_regexp(RegExpObject* reobj) { - MOZ_ASSERT(!IsInsideNursery(reobj)); - - // Determine this while we're still on the main thread to avoid races. - bool hasShared = reobj->hasShared(); - - MRegExp* regexp = MRegExp::New(alloc(), constraints(), reobj, hasShared); - current->add(regexp); - current->push(regexp); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_object(JSObject* obj) { - pushConstant(ObjectValue(*obj)); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_classconstructor() { - MClassConstructor* constructor = MClassConstructor::New(alloc(), pc); - current->add(constructor); - current->push(constructor); - return resumeAfter(constructor); -} - -AbortReasonOr IonBuilder::jsop_derivedclassconstructor() { - MDefinition* prototype = current->pop(); - - auto* constructor = MDerivedClassConstructor::New(alloc(), prototype, pc); - current->add(constructor); - current->push(constructor); - return resumeAfter(constructor); -} - -static LambdaFunctionInfo LambdaInfoFromFunction(JSFunction* fun) { - return LambdaFunctionInfo(fun, fun->baseScript(), fun->flags(), fun->nargs(), - fun->isSingleton(), - ObjectGroup::useSingletonForClone(fun)); -} - -AbortReasonOr IonBuilder::jsop_lambda(JSFunction* fun) { - MOZ_ASSERT(usesEnvironmentChain()); - MOZ_ASSERT(!fun->isArrow()); - - if (IsAsmJSModule(fun)) { - return abort(AbortReason::Disable, "Lambda is an asm.js module function"); - } - - MConstant* cst = MConstant::NewConstraintlessObject(alloc(), fun); - current->add(cst); - auto* ins = MLambda::New(alloc(), constraints(), current->environmentChain(), - cst, LambdaInfoFromFunction(fun)); - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_lambda_arrow(JSFunction* fun) { - MOZ_ASSERT(usesEnvironmentChain()); - MOZ_ASSERT(fun->isArrow()); - MOZ_ASSERT(!fun->isNative()); - - MDefinition* newTargetDef = current->pop(); - MConstant* cst = MConstant::NewConstraintlessObject(alloc(), fun); - current->add(cst); - auto* ins = - MLambdaArrow::New(alloc(), constraints(), current->environmentChain(), - newTargetDef, cst, LambdaInfoFromFunction(fun)); - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_funwithproto(JSFunction* fun) { - MOZ_ASSERT(usesEnvironmentChain()); - MOZ_ASSERT(!fun->isArrow()); - MOZ_ASSERT(!fun->isNative()); - - MDefinition* proto = current->pop(); - MConstant* cst = MConstant::NewConstraintlessObject(alloc(), fun); - current->add(cst); - auto* ins = - MFunctionWithProto::New(alloc(), current->environmentChain(), proto, cst); - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_setfunname(uint8_t prefixKind) { - MDefinition* name = current->pop(); - MDefinition* fun = current->pop(); - MOZ_ASSERT(fun->type() == MIRType::Object); - - MSetFunName* ins = MSetFunName::New(alloc(), fun, name, prefixKind); - - current->add(ins); - current->push(fun); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_pushlexicalenv(GCThingIndex index) { - MOZ_ASSERT(usesEnvironmentChain()); - - LexicalScope* scope = &script()->getScope(index)->as(); - MNewLexicalEnvironmentObject* ins = MNewLexicalEnvironmentObject::New( - alloc(), current->environmentChain(), scope); - - current->add(ins); - current->setEnvironmentChain(ins); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_copylexicalenv(bool copySlots) { - MOZ_ASSERT(usesEnvironmentChain()); - - MCopyLexicalEnvironmentObject* ins = MCopyLexicalEnvironmentObject::New( - alloc(), current->environmentChain(), copySlots); - - current->add(ins); - current->setEnvironmentChain(ins); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_getarg(uint32_t arg) { - if (info().argsObjAliasesFormals()) { - auto* getArg = - MGetArgumentsObjectArg::New(alloc(), current->argumentsObject(), arg); - current->add(getArg); - current->push(getArg); - } else { - current->pushArg(arg); - } - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_setarg(uint32_t arg) { - MOZ_ASSERT(script()->jitScript()->modifiesArguments()); - MDefinition* val = current->peek(-1); - - if (!info().argumentsAliasesFormals()) { - MOZ_ASSERT(!info().argsObjAliasesFormals()); - - // |arguments| is never referenced within this function. No arguments object - // is created in this case, so we don't need to worry about synchronizing - // the argument values when writing to them. - MOZ_ASSERT_IF(!info().hasArguments(), !info().needsArgsObj()); - - // The arguments object doesn't map to the actual argument values, so we - // also don't need to worry about synchronizing them. - // Directly writing to a positional formal parameter is only possible when - // the |arguments| contents are never observed, otherwise we can't - // reconstruct the original parameter values when we access them through - // |arguments[i]|. AnalyzeArgumentsUsage ensures this is handled correctly. - MOZ_ASSERT_IF(info().hasArguments(), !info().hasMappedArgsObj()); - - current->setArg(arg); - return Ok(); - } - - MOZ_ASSERT(info().hasArguments() && info().hasMappedArgsObj(), - "arguments aliases formals when an arguments binding is present " - "and the arguments object is mapped"); - - // |needsArgsObj()| is true when analyzing arguments usage, so the - // JSOp::SetArg bytecode will always emit a |MSetArgumentsObjectArg| node. - MOZ_ASSERT_IF(info().analysisMode() == Analysis_ArgumentsUsage, - info().needsArgsObj()); - - // When |ArgumentsUseCanBeLazy()| in IonAnalysis then inspects all |arguments| - // uses, the |MSetArgumentsObjectArg| usage will prevent the script from using - // lazy arguments and an actual arguments object is created. - MOZ_ASSERT(info().needsArgsObj(), - "unexpected JSOp::SetArg with lazy arguments"); - - MOZ_ASSERT( - info().argsObjAliasesFormals(), - "argsObjAliasesFormals() is true iff a mapped arguments object is used"); - - // If an arguments object is in use, and it aliases formals, then all SETARGs - // must go through the arguments object. - if (needsPostBarrier(val)) { - current->add( - MPostWriteBarrier::New(alloc(), current->argumentsObject(), val)); - } - auto* ins = MSetArgumentsObjectArg::New(alloc(), current->argumentsObject(), - arg, val); - current->add(ins); - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_defvar() { - MOZ_ASSERT(JSOp(*pc) == JSOp::DefVar); - - // Pass the EnvironmentChain. - MOZ_ASSERT(usesEnvironmentChain()); - - MDefVar* defvar = MDefVar::New(alloc(), current->environmentChain()); - current->add(defvar); - - return resumeAfter(defvar); -} - -AbortReasonOr IonBuilder::jsop_deflexical() { - MOZ_ASSERT(JSOp(*pc) == JSOp::DefLet || JSOp(*pc) == JSOp::DefConst); - MOZ_ASSERT(usesEnvironmentChain()); - - MDefinition* env = current->environmentChain(); - MDefLexical* defLexical = MDefLexical::New(alloc(), env); - current->add(defLexical); - - return resumeAfter(defLexical); -} - -AbortReasonOr IonBuilder::jsop_deffun() { - MOZ_ASSERT(usesEnvironmentChain()); - - MDefFun* deffun = - MDefFun::New(alloc(), current->pop(), current->environmentChain()); - current->add(deffun); - - return resumeAfter(deffun); -} - -AbortReasonOr IonBuilder::jsop_checkGlobalOrEvalDecl() { - MOZ_ASSERT(!script()->isForEval(), "Eval scripts not supported"); - auto* redeclCheck = MGlobalNameConflictsCheck::New(alloc()); - current->add(redeclCheck); - return resumeAfter(redeclCheck); -} - -AbortReasonOr IonBuilder::jsop_throwsetconst() { - MInstruction* lexicalError = - MThrowRuntimeLexicalError::New(alloc(), JSMSG_BAD_CONST_ASSIGN); - current->add(lexicalError); - MOZ_TRY(resumeAfter(lexicalError)); - - // Terminate the block. - current->end(MUnreachable::New(alloc())); - setTerminatedBlock(); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_checklexical() { - JSOp op = JSOp(*pc); - MOZ_ASSERT(op == JSOp::CheckLexical || op == JSOp::CheckAliasedLexical); - - MDefinition* val = current->peek(-1); - MDefinition* lexical; - MOZ_TRY_VAR(lexical, addLexicalCheck(val)); - current->pop(); - current->push(lexical); - - if (op == JSOp::CheckLexical) { - // Set the local slot so that a subsequent GetLocal without a CheckLexical - // (the frontend can elide lexical checks) doesn't let a definition with - // MIRType::MagicUninitializedLexical escape to arbitrary MIR instructions. - // Note that in this case the GetLocal would be unreachable because we throw - // an exception here, but we still generate MIR instructions for it. - uint32_t slot = info().localSlot(GET_LOCALNO(pc)); - current->setSlot(slot, lexical); - } - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_functionthis() { - MOZ_ASSERT(info().funMaybeLazy()); - MOZ_ASSERT(!info().funMaybeLazy()->isArrow()); - - if (script()->strict()) { - // No need to wrap primitive |this| in strict mode. - current->pushSlot(info().thisSlot()); - return Ok(); - } - - if (thisTypes && (thisTypes->getKnownMIRType() == MIRType::Object || - (thisTypes->empty() && baselineFrame_ && - baselineFrame_->thisType.isSomeObject()))) { - // This is safe, because if the entry type of |this| is an object, it - // will necessarily be an object throughout the entire function. OSR - // can introduce a phi, but this phi will be specialized. - current->pushSlot(info().thisSlot()); - return Ok(); - } - - // If we are doing an analysis, we might not yet know the type of |this|. - // Instead of bailing out just push the |this| slot, as this code won't - // actually execute and it does not matter whether |this| is primitive. - if (info().isAnalysis()) { - current->pushSlot(info().thisSlot()); - return Ok(); - } - - // Hard case: |this| may be a primitive we have to wrap. - MDefinition* def = current->getSlot(info().thisSlot()); - - if (def->type() == MIRType::Object) { - current->push(def); - return Ok(); - } - - // Beyond this point we may need to access non-syntactic global. Ion doesn't - // currently support this so just abort. - if (script()->hasNonSyntacticScope()) { - return abort(AbortReason::Disable, - "JSOp::FunctionThis would need non-syntactic global"); - } - - LexicalEnvironmentObject* globalLexical = - &script()->global().lexicalEnvironment(); - JSObject* globalThis = globalLexical->thisObject(); - - if (IsNullOrUndefined(def->type())) { - pushConstant(ObjectValue(*globalThis)); - return Ok(); - } - - MBoxNonStrictThis* thisObj = MBoxNonStrictThis::New(alloc(), def, globalThis); - current->add(thisObj); - current->push(thisObj); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_globalthis() { - if (script()->hasNonSyntacticScope()) { - // Ion does not compile global scripts with a non-syntactic scope, but - // we can end up here when we're compiling an arrow function. - return abort(AbortReason::Disable, - "JSOp::GlobalThis in script with non-syntactic scope"); - } - - LexicalEnvironmentObject* globalLexical = - &script()->global().lexicalEnvironment(); - pushConstant(ObjectValue(*globalLexical->thisObject())); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_typeof() { - MDefinition* input = current->pop(); - MTypeOf* ins = MTypeOf::New(alloc(), input); - - ins->cacheInputMaybeCallableOrEmulatesUndefined(constraints()); - - current->add(ins); - current->push(ins); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_toasynciter() { - MDefinition* nextMethod = current->pop(); - MDefinition* iterator = current->pop(); - MOZ_ASSERT(iterator->type() == MIRType::Object); - - MToAsyncIter* ins = MToAsyncIter::New(alloc(), iterator, nextMethod); - - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_topropertykey() { - // No-op if the index is trivally convertable to a PropertyKey. - MIRType type = current->peek(-1)->type(); - if (type == MIRType::Int32 || type == MIRType::String || - type == MIRType::Symbol) { - return Ok(); - } - - MDefinition* index = current->pop(); - auto* ins = MToPropertyKeyCache::New(alloc(), index); - - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_iter() { - MDefinition* obj = current->pop(); - MInstruction* ins = MGetIteratorCache::New(alloc(), obj); - - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_itermore() { - MDefinition* iter = current->peek(-1); - MInstruction* ins = MIteratorMore::New(alloc(), iter); - - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_isnoiter() { - MDefinition* def = current->peek(-1); - MOZ_ASSERT(def->isIteratorMore()); - - MInstruction* ins = MIsNoIter::New(alloc(), def); - current->add(ins); - current->push(ins); - - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_iterend() { - current->pop(); // Iterator value is not used. - MDefinition* iter = current->pop(); - - MInstruction* ins = MIteratorEnd::New(alloc(), iter); - current->add(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_iternext() { - MDefinition* def = current->pop(); - MOZ_ASSERT(def->type() == MIRType::Value); - - // The value must be a string. - MInstruction* unbox = - MUnbox::New(alloc(), def, MIRType::String, MUnbox::Infallible); - current->add(unbox); - current->push(unbox); - - return Ok(); -} - -MDefinition* IonBuilder::walkEnvironmentChain(unsigned hops) { - MDefinition* env = current->getSlot(info().environmentChainSlot()); - - for (unsigned i = 0; i < hops; i++) { - MInstruction* ins = MEnclosingEnvironment::New(alloc(), env); - current->add(ins); - env = ins; - } - - return env; -} - -MDefinition* IonBuilder::getAliasedVar(EnvironmentCoordinate ec) { - MDefinition* obj = walkEnvironmentChain(ec.hops()); - - MInstruction* load; - if (EnvironmentObject::nonExtensibleIsFixedSlot(ec)) { - load = MLoadFixedSlot::New(alloc(), obj, ec.slot()); - } else { - MInstruction* slots = MSlots::New(alloc(), obj); - current->add(slots); - - uint32_t slot = EnvironmentObject::nonExtensibleDynamicSlotIndex(ec); - load = MLoadDynamicSlot::New(alloc(), slots, slot); - } - - current->add(load); - return load; -} - -AbortReasonOr IonBuilder::jsop_getaliasedvar(EnvironmentCoordinate ec) { - MDefinition* load = getAliasedVar(ec); - current->push(load); - - TemporaryTypeSet* types = bytecodeTypes(pc); - return pushTypeBarrier(load, types, BarrierKind::TypeSet); -} - -AbortReasonOr IonBuilder::jsop_setaliasedvar(EnvironmentCoordinate ec) { - MDefinition* rval = current->peek(-1); - MDefinition* obj = walkEnvironmentChain(ec.hops()); - - if (needsPostBarrier(rval)) { - current->add(MPostWriteBarrier::New(alloc(), obj, rval)); - } - - MInstruction* store; - if (EnvironmentObject::nonExtensibleIsFixedSlot(ec)) { - store = MStoreFixedSlot::NewBarriered(alloc(), obj, ec.slot(), rval); - } else { - MInstruction* slots = MSlots::New(alloc(), obj); - current->add(slots); - - uint32_t slot = EnvironmentObject::nonExtensibleDynamicSlotIndex(ec); - store = MStoreDynamicSlot::NewBarriered(alloc(), slots, slot, rval); - } - - current->add(store); - return resumeAfter(store); -} - -AbortReasonOr IonBuilder::jsop_in() { - MDefinition* obj = current->pop(); - MDefinition* id = current->pop(); - - if (!forceInlineCaches()) { - bool emitted = false; - - MOZ_TRY(inTryDense(&emitted, obj, id)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(hasTryNotDefined(&emitted, obj, id, /* ownProperty = */ false)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(hasTryDefiniteSlotOrUnboxed(&emitted, obj, id)); - if (emitted) { - return Ok(); - } - } - - MInCache* ins = MInCache::New(alloc(), id, obj); - - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::inTryDense(bool* emitted, MDefinition* obj, - MDefinition* id) { - MOZ_ASSERT(!*emitted); - - if (shouldAbortOnPreliminaryGroups(obj)) { - return Ok(); - } - - if (!ElementAccessIsDenseNative(constraints(), obj, id)) { - return Ok(); - } - - bool hasExtraIndexedProperty; - MOZ_TRY_VAR(hasExtraIndexedProperty, - ElementAccessHasExtraIndexedProperty(this, obj)); - if (hasExtraIndexedProperty) { - return Ok(); - } - - *emitted = true; - - bool needsHoleCheck = !ElementAccessIsPacked(constraints(), obj); - - // Ensure id is an integer. - MInstruction* idInt32 = MToNumberInt32::New(alloc(), id); - current->add(idInt32); - id = idInt32; - - // Get the elements vector. - MElements* elements = MElements::New(alloc(), obj); - current->add(elements); - - MInstruction* initLength = initializedLength(elements); - - // If there are no holes, speculate the InArray check will not fail. - if (!needsHoleCheck && !failedBoundsCheck_) { - addBoundsCheck(idInt32, initLength); - pushConstant(BooleanValue(true)); - return Ok(); - } - - // Check if id < initLength and elem[id] not a hole. - MInArray* ins = - MInArray::New(alloc(), elements, id, initLength, obj, needsHoleCheck); - - current->add(ins); - current->push(ins); - - return Ok(); -} - -AbortReasonOr IonBuilder::hasTryNotDefined(bool* emitted, MDefinition* obj, - MDefinition* id, - bool ownProperty) { - // Fold |id in obj| to |false|, if we know the object (or an object on its - // prototype chain) does not have this property. - - MOZ_ASSERT(!*emitted); - - MConstant* idConst = id->maybeConstantValue(); - jsid propId; - if (!idConst || !ValueToIdPure(idConst->toJSValue(), &propId)) { - return Ok(); - } - - if (propId != IdToTypeId(propId)) { - return Ok(); - } - - bool res; - MOZ_TRY_VAR(res, testNotDefinedProperty(obj, propId, ownProperty)); - if (!res) { - return Ok(); - } - - *emitted = true; - - pushConstant(BooleanValue(false)); - obj->setImplicitlyUsedUnchecked(); - id->setImplicitlyUsedUnchecked(); - return Ok(); -} - -AbortReasonOr IonBuilder::hasTryDefiniteSlotOrUnboxed(bool* emitted, - MDefinition* obj, - MDefinition* id) { - // Fold |id in obj| to |true|, when obj definitely contains a property with - // that name. - MOZ_ASSERT(!*emitted); - - if (obj->type() != MIRType::Object) { - return Ok(); - } - - MConstant* idConst = id->maybeConstantValue(); - jsid propId; - if (!idConst || !ValueToIdPure(idConst->toJSValue(), &propId)) { - return Ok(); - } - - if (propId != IdToTypeId(propId)) { - return Ok(); - } - - // Try finding a native definite slot first. - uint32_t nfixed; - uint32_t slot = getDefiniteSlot(obj->resultTypeSet(), propId, &nfixed); - if (slot == UINT32_MAX) { - return Ok(); - } - - *emitted = true; - - pushConstant(BooleanValue(true)); - obj->setImplicitlyUsedUnchecked(); - id->setImplicitlyUsedUnchecked(); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_hasown() { - MDefinition* obj = current->pop(); - MDefinition* id = current->pop(); - - if (!forceInlineCaches()) { - bool emitted = false; - - MOZ_TRY(hasTryNotDefined(&emitted, obj, id, /* ownProperty = */ true)); - if (emitted) { - return Ok(); - } - - MOZ_TRY(hasTryDefiniteSlotOrUnboxed(&emitted, obj, id)); - if (emitted) { - return Ok(); - } - } - - MHasOwnCache* ins = MHasOwnCache::New(alloc(), obj, id); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_checkprivatefield() { - MDefinition* id = current->peek(-1); - MDefinition* obj = current->peek(-2); - - MCheckPrivateFieldCache* ins = MCheckPrivateFieldCache::New(alloc(), obj, id); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - return Ok(); -} - -AbortReasonOr IonBuilder::hasOnProtoChain(TypeSet::ObjectKey* key, - JSObject* protoObject, - bool* onProto) { - MOZ_ASSERT(protoObject); - - while (true) { - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - if (!key->hasStableClassAndProto(constraints()) || - !key->clasp()->isNative()) { - return false; - } - - JSObject* proto = checkNurseryObject(key->proto().toObjectOrNull()); - if (!proto) { - *onProto = false; - return true; - } - - if (proto == protoObject) { - *onProto = true; - return true; - } - - key = TypeSet::ObjectKey::get(proto); - } - - MOZ_CRASH("Unreachable"); -} - -AbortReasonOr IonBuilder::tryFoldInstanceOf(bool* emitted, MDefinition* lhs, - JSObject* protoObject) { - // Try to fold the js::IsPrototypeOf part of the instanceof operation. - MOZ_ASSERT(*emitted == false); - - if (!lhs->mightBeType(MIRType::Object)) { - // If the lhs is a primitive, the result is false. - lhs->setImplicitlyUsedUnchecked(); - pushConstant(BooleanValue(false)); - *emitted = true; - return Ok(); - } - - TemporaryTypeSet* lhsTypes = lhs->resultTypeSet(); - if (!lhsTypes || lhsTypes->unknownObject()) { - return Ok(); - } - - // We can fold if either all objects have protoObject on their proto chain - // or none have. - bool isFirst = true; - bool knownIsInstance = false; - - for (unsigned i = 0; i < lhsTypes->getObjectCount(); i++) { - TypeSet::ObjectKey* key = lhsTypes->getObject(i); - if (!key) { - continue; - } - - bool checkSucceeded; - bool isInstance; - MOZ_TRY_VAR(checkSucceeded, hasOnProtoChain(key, protoObject, &isInstance)); - if (!checkSucceeded) { - return Ok(); - } - - if (isFirst) { - knownIsInstance = isInstance; - isFirst = false; - } else if (knownIsInstance != isInstance) { - // Some of the objects have protoObject on their proto chain and - // others don't, so we can't optimize this. - return Ok(); - } - } - - if (knownIsInstance && lhsTypes->getKnownMIRType() != MIRType::Object) { - // The result is true for all objects, but the lhs might be a primitive. - // We can't fold this completely but we can use a much faster IsObject - // test. - MIsObject* isObject = MIsObject::New(alloc(), lhs); - current->add(isObject); - current->push(isObject); - *emitted = true; - return Ok(); - } - - lhs->setImplicitlyUsedUnchecked(); - pushConstant(BooleanValue(knownIsInstance)); - *emitted = true; - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_instanceof() { - MDefinition* rhs = current->pop(); - MDefinition* obj = current->pop(); - bool emitted = false; - - // If this is an 'x instanceof function' operation and we can determine the - // exact function and prototype object being tested for, use a typed path. - do { - TemporaryTypeSet* rhsTypes = rhs->resultTypeSet(); - JSObject* rhsObject = rhsTypes ? rhsTypes->maybeSingleton() : nullptr; - if (!rhsObject || !rhsObject->is() || - rhsObject->isBoundFunction()) { - break; - } - - // Refuse to optimize anything whose [[Prototype]] isn't Function.prototype - // since we can't guarantee that it uses the default @@hasInstance method. - if (rhsObject->hasUncacheableProto() || !rhsObject->hasStaticPrototype()) { - break; - } - - Value funProto = script()->global().getPrototype(JSProto_Function); - if (!funProto.isObject() || - rhsObject->staticPrototype() != &funProto.toObject()) { - break; - } - - // If the user has supplied their own @@hasInstance method we shouldn't - // clobber it. - JSFunction* fun = &rhsObject->as(); - const WellKnownSymbols* symbols = &realm->runtime()->wellKnownSymbols(); - if (!js::FunctionHasDefaultHasInstance(fun, *symbols)) { - break; - } - - // Ensure that we will bail if the @@hasInstance property or [[Prototype]] - // change. - TypeSet::ObjectKey* rhsKey = TypeSet::ObjectKey::get(rhsObject); - if (!rhsKey->hasStableClassAndProto(constraints())) { - break; - } - - if (rhsKey->unknownProperties()) { - break; - } - - HeapTypeSetKey hasInstanceObject = - rhsKey->property(SYMBOL_TO_JSID(symbols->hasInstance)); - if (hasInstanceObject.isOwnProperty(constraints())) { - break; - } - - HeapTypeSetKey protoProperty = - rhsKey->property(NameToId(names().prototype)); - JSObject* protoObject = protoProperty.singleton(constraints()); - if (!protoObject) { - break; - } - - rhs->setImplicitlyUsedUnchecked(); - - MOZ_TRY(tryFoldInstanceOf(&emitted, obj, protoObject)); - if (emitted) { - return Ok(); - } - - MConstant* protoConst = constant(ObjectValue(*protoObject)); - MInstanceOf* ins = MInstanceOf::New(alloc(), obj, protoConst); - - current->add(ins); - current->push(ins); - - return resumeAfter(ins); - } while (false); - - // Try to inline a fast path based on Baseline ICs. - do { - Shape* shape; - uint32_t slot; - JSObject* protoObject; - if (!inspector->instanceOfData(pc, &shape, &slot, &protoObject)) { - break; - } - - // Shape guard. - rhs = addShapeGuard(rhs, shape); - - // Guard .prototype == protoObject. - MOZ_ASSERT(shape->numFixedSlots() == 0, "Must be a dynamic slot"); - MSlots* slots = MSlots::New(alloc(), rhs); - current->add(slots); - MLoadDynamicSlot* prototype = MLoadDynamicSlot::New(alloc(), slots, slot); - current->add(prototype); - MConstant* protoConst = - MConstant::NewConstraintlessObject(alloc(), protoObject); - current->add(protoConst); - MGuardObjectIdentity* guard = - MGuardObjectIdentity::New(alloc(), prototype, protoConst, - /* bailOnEquality = */ false); - current->add(guard); - - MOZ_TRY(tryFoldInstanceOf(&emitted, obj, protoObject)); - if (emitted) { - return Ok(); - } - - MInstanceOf* ins = MInstanceOf::New(alloc(), obj, protoConst); - current->add(ins); - current->push(ins); - return resumeAfter(ins); - } while (false); - - MInstanceOfCache* ins = MInstanceOfCache::New(alloc(), obj, rhs); - - current->add(ins); - current->push(ins); - - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_debugger() { - // The |debugger;| statement will bail out to Baseline if the realm is a - // debuggee realm with an onDebuggerStatement hook. - MDebugger* debugger = MDebugger::New(alloc()); - current->add(debugger); - return resumeAfter(debugger); -} - -AbortReasonOr IonBuilder::jsop_implicitthis(PropertyName* name) { - MOZ_ASSERT(usesEnvironmentChain()); - - MImplicitThis* implicitThis = - MImplicitThis::New(alloc(), current->environmentChain(), name); - current->add(implicitThis); - current->push(implicitThis); - - return resumeAfter(implicitThis); -} - -AbortReasonOr IonBuilder::jsop_importmeta() { - if (info().analysisMode() == Analysis_ArgumentsUsage) { - // The meta object may not have been created yet. Just push a dummy - // value, it does not affect the arguments analysis. - MUnknownValue* unknown = MUnknownValue::New(alloc()); - current->add(unknown); - current->push(unknown); - return Ok(); - } - - ModuleObject* module = GetModuleObjectForScript(script()); - MOZ_ASSERT(module); - - MModuleMetadata* meta = MModuleMetadata::New(alloc(), module); - current->add(meta); - current->push(meta); - return resumeAfter(meta); -} - -AbortReasonOr IonBuilder::jsop_dynamic_import() { - MDefinition* specifier = current->pop(); - - MDynamicImport* ins = MDynamicImport::New(alloc(), specifier); - current->add(ins); - current->push(ins); - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_instrumentation_active() { - // All IonScripts in the realm are discarded when instrumentation activity - // changes, so we can treat the value we get as a constant. - bool active = RealmInstrumentation::isActive(&script()->global()); - pushConstant(BooleanValue(active)); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_instrumentation_callback() { - JSObject* obj = RealmInstrumentation::getCallback(&script()->global()); - MOZ_ASSERT(obj); - pushConstant(ObjectValue(*obj)); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_instrumentation_scriptid() { - // Getting the script ID requires interacting with the Debugger used for - // instrumentation, but cannot run script. - JSContext* cx = TlsContext.get(); - - int32_t scriptId; - RootedScript script(cx, this->script()); - if (!RealmInstrumentation::getScriptId(cx, cx->global(), script, &scriptId)) { - return abort(AbortReason::Error); - } - pushConstant(Int32Value(scriptId)); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_objwithproto() { - auto* ins = MObjectWithProto::New(alloc(), current->pop()); - current->add(ins); - current->push(ins); - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_builtinobject() { - auto kind = BuiltinObjectKind(GET_UINT8(pc)); - - // Bake in the built-in if it exists. - if (JSObject* builtin = MaybeGetBuiltinObject(&script()->global(), kind)) { - pushConstant(ObjectValue(*builtin)); - return Ok(); - } - - // Otherwise emit code to generate it. - auto* ins = MBuiltinObject::New(alloc(), kind); - current->add(ins); - current->push(ins); - return resumeAfter(ins); -} - -AbortReasonOr IonBuilder::jsop_checkreturn() { - MOZ_ASSERT(!script()->noScriptRval()); - - MDefinition* returnValue = current->getSlot(info().returnValueSlot()); - MDefinition* thisValue = current->pop(); - - if (returnValue->type() == MIRType::Object) { - thisValue->setImplicitlyUsedUnchecked(); - return Ok(); - } - - if (returnValue->type() == MIRType::Undefined && - !thisValue->mightBeMagicType()) { - // The return value mustn't be optimized out, otherwise baseline may see the - // optimized-out magic value when it re-executes this op after a bailout. - returnValue->setImplicitlyUsedUnchecked(); - thisValue->setImplicitlyUsedUnchecked(); - current->setSlot(info().returnValueSlot(), thisValue); - return Ok(); - } - - auto* ins = MCheckReturn::New(alloc(), returnValue, thisValue); - current->add(ins); - current->setSlot(info().returnValueSlot(), ins); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_superfun() { - MDefinition* callee = current->pop(); - - do { - TemporaryTypeSet* calleeTypes = callee->resultTypeSet(); - if (!calleeTypes) { - break; - } - - TemporaryTypeSet::ObjectKey* calleeKey = calleeTypes->maybeSingleObject(); - if (!calleeKey) { - break; - } - - JSObject* calleeObj; - if (calleeKey->isSingleton()) { - calleeObj = calleeKey->singleton(); - } else { - calleeObj = calleeKey->group()->maybeInterpretedFunction(); - } - if (!calleeObj) { - break; - } - - // Refuse to optimize if the prototype is uncacheable. - if (calleeObj->hasUncacheableProto() || !calleeObj->hasStaticPrototype()) { - break; - } - - // The prototype must be a constructor. - JSObject* proto = calleeObj->staticPrototype(); - if (!proto || !proto->isConstructor()) { - break; - } - - // Add a constraint to ensure we're notified when the prototype changes. - if (!calleeKey->hasStableClassAndProto(constraints())) { - break; - } - - callee->setImplicitlyUsedUnchecked(); - - pushConstant(ObjectValue(*proto)); - - return Ok(); - } while (false); - - auto* ins = MSuperFunction::New(alloc(), callee); - current->add(ins); - current->push(ins); - return Ok(); -} - -AbortReasonOr IonBuilder::jsop_inithomeobject() { - MDefinition* homeObject = current->pop(); - MDefinition* function = current->pop(); - - if (needsPostBarrier(homeObject)) { - current->add(MPostWriteBarrier::New(alloc(), function, homeObject)); - } - - auto* ins = MInitHomeObject::New(alloc(), function, homeObject); - current->add(ins); - current->push(ins); - return Ok(); -} - -MInstruction* IonBuilder::addConvertElementsToDoubles(MDefinition* elements) { - MInstruction* convert = MConvertElementsToDoubles::New(alloc(), elements); - current->add(convert); - return convert; -} - -MDefinition* IonBuilder::addMaybeCopyElementsForWrite(MDefinition* object, - bool checkNative) { - if (!ElementAccessMightBeCopyOnWrite(constraints(), object)) { - return object; - } - MInstruction* copy = - MMaybeCopyElementsForWrite::New(alloc(), object, checkNative); - current->add(copy); - return copy; -} - -MInstruction* IonBuilder::addBoundsCheck(MDefinition* index, - MDefinition* length) { - MInstruction* check = MBoundsCheck::New(alloc(), index, length); - current->add(check); - - // If a bounds check failed in the past, don't optimize bounds checks. - if (failedBoundsCheck_) { - check->setNotMovable(); - } - - if (JitOptions.spectreIndexMasking) { - // Use a separate MIR instruction for the index masking. Doing this as - // part of MBoundsCheck would be unsound because bounds checks can be - // optimized or eliminated completely. Consider this: - // - // for (var i = 0; i < x; i++) - // res = arr[i]; - // - // If we can prove |x < arr.length|, we are able to eliminate the bounds - // check, but we should not get rid of the index masking because the - // |i < x| branch could still be mispredicted. - // - // Using a separate instruction lets us eliminate the bounds check - // without affecting the index masking. - check = MSpectreMaskIndex::New(alloc(), check, length); - current->add(check); - } - - return check; -} - -MInstruction* IonBuilder::addShapeGuard(MDefinition* obj, Shape* const shape) { - MGuardShape* guard = MGuardShape::New(alloc(), obj, shape); - current->add(guard); - - // If a shape guard failed in the past, don't optimize shape guard. - if (failedShapeGuard_) { - guard->setNotMovable(); - } - - return guard; -} - -MInstruction* IonBuilder::addGuardReceiverPolymorphic( - MDefinition* obj, const BaselineInspector::ReceiverVector& receivers) { - if (receivers.length() == 1) { - if (!receivers[0].getGroup()) { - // Monomorphic guard on a native object. - return addShapeGuard(obj, receivers[0].getShape()); - } - } - - MGuardReceiverPolymorphic* guard = - MGuardReceiverPolymorphic::New(alloc(), obj); - current->add(guard); - - if (failedShapeGuard_) { - guard->setNotMovable(); - } - - for (size_t i = 0; i < receivers.length(); i++) { - if (!guard->addReceiver(receivers[i])) { - return nullptr; - } - } - - return guard; -} - -TemporaryTypeSet* IonBuilder::bytecodeTypes(jsbytecode* pc) { - return JitScript::BytecodeTypes(script(), pc, bytecodeTypeMap, &typeArrayHint, - typeArray); -} - -void IonBuilder::checkNurseryCell(gc::Cell* cell) { - // If we try to use any nursery pointers during compilation, make sure that - // the main thread will cancel this compilation before performing a minor - // GC. All constants used during compilation should either go through this - // function or should come from a type set (which has a similar barrier). - if (cell && IsInsideNursery(cell)) { - realm->zone()->setMinorGCShouldCancelIonCompilations(); - mirGen().setNotSafeForMinorGC(); - } -} - -JSObject* IonBuilder::checkNurseryObject(JSObject* obj) { - checkNurseryCell(obj); - return obj; -} - -MConstant* IonBuilder::constant(const Value& v) { - MOZ_ASSERT(!v.isString() || v.toString()->isAtom(), - "Handle non-atomized strings outside IonBuilder."); - - if (v.isGCThing()) { - checkNurseryCell(v.toGCThing()); - } - - MConstant* c = MConstant::New(alloc(), v, constraints()); - current->add(c); - return c; -} - -MConstant* IonBuilder::constantInt(int32_t i) { - return constant(Int32Value(i)); -} - -MInstruction* IonBuilder::initializedLength(MDefinition* elements) { - MInstruction* res = MInitializedLength::New(alloc(), elements); - current->add(res); - return res; -} - -MInstruction* IonBuilder::setInitializedLength(MDefinition* obj, size_t count) { - MOZ_ASSERT(count); - - // MSetInitializedLength takes the index of the last element, rather - // than the count itself. - MInstruction* elements = MElements::New(alloc(), obj); - current->add(elements); - MInstruction* res = MSetInitializedLength::New( - alloc(), elements, constant(Int32Value(count - 1))); - current->add(res); - return res; -} - -MDefinition* IonBuilder::getCallee() { - if (inliningDepth_ == 0) { - MInstruction* callee = MCallee::New(alloc()); - current->add(callee); - return callee; - } - - return inlineCallInfo_->callee(); -} - -void IonBuilder::addAbortedPreliminaryGroup(ObjectGroup* group) { - for (size_t i = 0; i < abortedPreliminaryGroups_.length(); i++) { - if (group == abortedPreliminaryGroups_[i]) { - return; - } - } - AutoEnterOOMUnsafeRegion oomUnsafe; - if (!abortedPreliminaryGroups_.append(group)) { - oomUnsafe.crash("addAbortedPreliminaryGroup"); - } -} - -AbortReasonOr IonBuilder::addLexicalCheck(MDefinition* input) { - MOZ_ASSERT(JSOp(*pc) == JSOp::CheckLexical || - JSOp(*pc) == JSOp::CheckAliasedLexical || - JSOp(*pc) == JSOp::GetImport); - - // If we're guaranteed to not be JS_UNINITIALIZED_LEXICAL, no need to check. - if (input->type() == MIRType::MagicUninitializedLexical) { - // Mark the input as implicitly used so the JS_UNINITIALIZED_LEXICAL - // magic value will be preserved on bailout. - input->setImplicitlyUsedUnchecked(); - MInstruction* lexicalCheck = - MThrowRuntimeLexicalError::New(alloc(), JSMSG_UNINITIALIZED_LEXICAL); - current->add(lexicalCheck); - MOZ_TRY(resumeAfter(lexicalCheck)); - return constant(UndefinedValue()); - } - - if (input->type() == MIRType::Value) { - MInstruction* lexicalCheck = MLexicalCheck::New(alloc(), input); - current->add(lexicalCheck); - if (failedLexicalCheck_) { - lexicalCheck->setNotMovableUnchecked(); - } - return lexicalCheck; - } - - input->setImplicitlyUsedUnchecked(); - return input; -} - -MDefinition* IonBuilder::convertToBoolean(MDefinition* input) { - // Convert to bool with the '!!' idiom - MNot* resultInverted = MNot::New(alloc(), input, constraints()); - current->add(resultInverted); - MNot* result = MNot::New(alloc(), resultInverted, constraints()); - current->add(result); - - return result; -} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/IonBuilder.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/IonBuilder.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/IonBuilder.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/IonBuilder.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1176 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef jit_IonBuilder_h -#define jit_IonBuilder_h - -// This file declares the data structures for building a MIRGraph from a -// JSScript. - -#include "mozilla/Maybe.h" - -#include "jsfriendapi.h" - -#include "jit/BaselineInspector.h" -#include "jit/CompileInfo.h" -#include "jit/InlineScriptTree.h" -#include "jit/IonAnalysis.h" -#include "jit/IonOptimizationLevels.h" -#include "jit/MIR.h" -#include "jit/MIRBuilderShared.h" -#include "jit/MIRGenerator.h" -#include "jit/MIRGraph.h" -#include "jit/TIOracle.h" -#include "js/experimental/JitInfo.h" // JSJitInfo -#include "js/ScalarType.h" // js::Scalar::Type -#include "vm/SharedStencil.h" // GCThingIndex - -namespace js { - -class TypedArrayObject; - -namespace jit { - -class CodeGenerator; -class CallInfo; -class BaselineFrameInspector; - -enum class InlinableNative : uint16_t; - -// Records information about a baseline frame for compilation that is stable -// when later used off thread. -BaselineFrameInspector* NewBaselineFrameInspector(TempAllocator* temp, - BaselineFrame* frame, - uint32_t frameSize); - -using CallTargets = Vector; - -// [SMDOC] Control Flow handling in IonBuilder -// -// IonBuilder traverses the script's bytecode and compiles each instruction to -// corresponding MIR instructions. Handling control flow bytecode ops requires -// some special machinery: -// -// Forward branches -// ---------------- -// Most branches in the bytecode are forward branches to a JSOp::JumpTarget -// instruction that we have not inspected yet. We compile them in two phases: -// -// 1) When compiling the source instruction: the MBasicBlock is terminated -// with a control instruction that has a nullptr successor block. We also add -// a PendingEdge instance to the PendingEdges list for the target bytecode -// location. -// -// 2) When finally compiling the JSOp::JumpTarget: IonBuilder::visitJumpTarget -// creates the target block and uses the list of PendingEdges to 'link' the -// blocks. -// -// Loops -// ----- -// Loops complicate this a bit: -// -// * Because of IonBuilder's single pass design, we sometimes have to 'restart' -// a loop when we find new types for locals, arguments, or stack slots while -// compiling the loop body. When this happens the loop has to be recompiled -// from the beginning. -// -// * Loops may be nested within other loops, so we track loop states in a stack -// per IonBuilder. -// -// Unreachable/dead code -// --------------------- -// Some bytecode instructions never fall through to the next instruction, for -// example JSOp::Return, JSOp::Goto, or JSOp::Throw. Code after such -// instructions is guaranteed to be dead so IonBuilder skips it until it gets to -// a jump target instruction with pending edges. -// -// Note: The frontend may generate unnecessary JSOp::JumpTarget instructions we -// can ignore when they have no incoming pending edges. -// -// Try-catch -// --------- -// IonBuilder supports scripts with try-catch by only compiling the try-block -// and bailing out (to the Baseline Interpreter) from the exception handler -// whenever we need to execute the catch-block. -// -// Because we don't compile the catch-block and the code after the try-catch may -// only be reachable via the catch-block, Baseline's BytecodeAnalysis ensures -// Baseline does not attempt OSR into Ion/Warp when loops are only reachable via -// catch/finally blocks. -// -// Finally-blocks are currently not supported by Ion. - -class MOZ_STACK_CLASS IonBuilder { - public: - IonBuilder(JSContext* analysisContext, MIRGenerator& mirGen, - CompileInfo* info, CompilerConstraintList* constraints, - BaselineInspector* inspector, - BaselineFrameInspector* baselineFrame, size_t inliningDepth = 0, - uint32_t loopDepth = 0); - - // Callers of build() and buildInline() should always check whether the - // call overrecursed, if false is returned. Overrecursion is not - // signaled as OOM and will not in general be caught by OOM paths. - AbortReasonOr build(); - AbortReasonOr buildInline(IonBuilder* callerBuilder, - MResumePoint* callerResumePoint, - CallInfo& callInfo); - - mozilla::GenericErrorResult abort(AbortReason r); - mozilla::GenericErrorResult abort(AbortReason r, - const char* message, ...) - MOZ_FORMAT_PRINTF(3, 4); - - private: - AbortReasonOr traverseBytecode(); - AbortReasonOr startTraversingBlock(MBasicBlock* block); - AbortReasonOr processIterators(); - AbortReasonOr inspectOpcode(JSOp op, bool* restarted); - uint32_t readIndex(jsbytecode* pc); - JSAtom* readAtom(jsbytecode* pc); - - void spew(const char* message); - - JSFunction* getSingleCallTarget(TemporaryTypeSet* calleeTypes); - AbortReasonOr getPolyCallTargets(TemporaryTypeSet* calleeTypes, - bool constructing, - InliningTargets& targets, - uint32_t maxTargets); - - AbortReasonOr analyzeNewLoopTypes(MBasicBlock* entry); - AbortReasonOr analyzeNewLoopTypesForLocation( - MBasicBlock* entry, const BytecodeLocation loc, - const mozilla::Maybe& last_, - const mozilla::Maybe& earlier); - - AbortReasonOr newBlock(size_t stackDepth, jsbytecode* pc, - MBasicBlock* maybePredecessor = nullptr); - AbortReasonOr newBlock(MBasicBlock* predecessor, jsbytecode* pc, - MResumePoint* priorResumePoint); - AbortReasonOr newBlockPopN(MBasicBlock* predecessor, - jsbytecode* pc, uint32_t popped); - AbortReasonOr newBlockAfter( - MBasicBlock* at, size_t stackDepth, jsbytecode* pc, - MBasicBlock* maybePredecessor = nullptr); - AbortReasonOr newOsrPreheader(MBasicBlock* header, - jsbytecode* loopHead); - AbortReasonOr newPendingLoopHeader(MBasicBlock* predecessor, - jsbytecode* pc, bool osr); - - AbortReasonOr newBlock(MBasicBlock* predecessor, - jsbytecode* pc) { - return newBlock(predecessor->stackDepth(), pc, predecessor); - } - - AbortReasonOr addPendingEdge(const PendingEdge& edge, jsbytecode* target); - - AbortReasonOr jsop_loophead(); - - AbortReasonOr visitJumpTarget(JSOp op); - AbortReasonOr visitTest(JSOp op, bool* restarted); - AbortReasonOr visitTestBackedge(JSOp op, bool* restarted); - AbortReasonOr visitReturn(JSOp op); - AbortReasonOr visitGoto(jsbytecode* target); - AbortReasonOr visitBackEdge(bool* restarted); - AbortReasonOr visitTry(); - AbortReasonOr visitThrow(); - AbortReasonOr visitTableSwitch(); - - // We want to make sure that our MTest instructions all check whether the - // thing being tested might emulate undefined. So we funnel their creation - // through this method, to make sure that happens. We don't want to just do - // the check in MTest::New, because that can run on background compilation - // threads, and we're not sure it's safe to touch that part of the typeset - // from a background thread. - MTest* newTest(MDefinition* ins, MBasicBlock* ifTrue, MBasicBlock* ifFalse); - - // Incorporates a type/typeSet into an OSR value for a loop, after the loop - // body has been processed. - AbortReasonOr addOsrValueTypeBarrier(uint32_t slot, MInstruction** def, - MIRType type, - TemporaryTypeSet* typeSet); - AbortReasonOr maybeAddOsrTypeBarriers(); - - AbortReasonOr emitLoopHeadInstructions(jsbytecode* pc); - - // Restarts processing of a loop if the type information at its header was - // incomplete. - AbortReasonOr restartLoop(MBasicBlock* header); - - // Please see the Big Honkin' Comment about how resume points work in - // IonBuilder.cpp, near the definition for this function. - AbortReasonOr resume(MInstruction* ins, jsbytecode* pc, - MResumePoint::Mode mode); - AbortReasonOr resumeAt(MInstruction* ins, jsbytecode* pc); - AbortReasonOr resumeAfter(MInstruction* ins); - AbortReasonOr maybeInsertResume(); - - void insertRecompileCheck(jsbytecode* pc); - - bool usesEnvironmentChain(); - - AbortReasonOr initParameters(); - void initLocals(); - void rewriteParameter(uint32_t slotIdx, MDefinition* param); - AbortReasonOr rewriteParameters(); - AbortReasonOr initEnvironmentChain(MDefinition* callee = nullptr); - void initArgumentsObject(); - void pushConstant(const Value& v); - - MConstant* constant(const Value& v); - MConstant* constantInt(int32_t i); - MInstruction* initializedLength(MDefinition* elements); - MInstruction* setInitializedLength(MDefinition* obj, size_t count); - - // Improve the type information at tests - AbortReasonOr improveTypesAtTest(MDefinition* ins, bool trueBranch, - MTest* test); - AbortReasonOr improveTypesAtTestSuccessor(MTest* test, - MBasicBlock* successor); - AbortReasonOr improveTypesAtCompare(MCompare* ins, bool trueBranch, - MTest* test); - AbortReasonOr improveTypesAtNullOrUndefinedCompare(MCompare* ins, - bool trueBranch, - MTest* test); - AbortReasonOr improveTypesAtTypeOfCompare(MCompare* ins, bool trueBranch, - MTest* test); - - AbortReasonOr replaceTypeSet(MDefinition* subject, TemporaryTypeSet* type, - MTest* test); - - // Add a guard which ensure that the set of type which goes through this - // generated code correspond to the observed types for the bytecode. - MDefinition* addTypeBarrier(MDefinition* def, TemporaryTypeSet* observed, - BarrierKind kind, - MTypeBarrier** pbarrier = nullptr); - AbortReasonOr pushTypeBarrier(MDefinition* def, - TemporaryTypeSet* observed, - BarrierKind kind); - - // As pushTypeBarrier, but will compute the needBarrier boolean itself based - // on observed and the JSFunction that we're planning to call. The - // JSFunction must be a DOM method or getter. - AbortReasonOr pushDOMTypeBarrier(MInstruction* ins, - TemporaryTypeSet* observed, - JSFunction* func); - - // If definiteType is not known or def already has the right type, just - // returns def. Otherwise, returns an MInstruction that has that definite - // type, infallibly unboxing ins as needed. The new instruction will be - // added to |current| in this case. - MDefinition* ensureDefiniteType(MDefinition* def, MIRType definiteType); - - void maybeMarkEmpty(MDefinition* ins); - - JSObject* getSingletonPrototype(JSFunction* target); - - MDefinition* createThisScripted(MDefinition* callee, MDefinition* newTarget); - MDefinition* createThisScriptedSingleton(JSFunction* target); - MDefinition* createThisScriptedBaseline(MDefinition* callee); - MDefinition* createThisSlow(MDefinition* callee, MDefinition* newTarget, - bool inlining); - MDefinition* createThis(JSFunction* target, MDefinition* callee, - MDefinition* newTarget, bool inlining); - MInstruction* createNamedLambdaObject(MDefinition* callee, - MDefinition* envObj); - AbortReasonOr createCallObject(MDefinition* callee, - MDefinition* envObj); - - // Returns true if a property hasn't been overwritten and matches the given - // predicate. Adds type constraints to ensure recompilation happens if the - // property value ever changes. - bool propertyIsConstantFunction(NativeObject* nobj, jsid id, - bool (*test)(IonBuilder* builder, - JSFunction* fun)); - - bool ensureArrayPrototypeIteratorNotModified(); - bool ensureArrayIteratorPrototypeNextNotModified(); - - MDefinition* walkEnvironmentChain(unsigned hops); - - MInstruction* addConvertElementsToDoubles(MDefinition* elements); - MDefinition* addMaybeCopyElementsForWrite(MDefinition* object, - bool checkNative); - - MInstruction* addBoundsCheck(MDefinition* index, MDefinition* length); - - MInstruction* addShapeGuard(MDefinition* obj, Shape* const shape); - - MInstruction* addGuardReceiverPolymorphic( - MDefinition* obj, const BaselineInspector::ReceiverVector& receivers); - - bool invalidatedIdempotentCache(); - - AbortReasonOr loadSlot(MDefinition* obj, size_t slot, size_t nfixed, - MIRType rvalType, BarrierKind barrier, - TemporaryTypeSet* types); - AbortReasonOr loadSlot(MDefinition* obj, Shape* shape, MIRType rvalType, - BarrierKind barrier, TemporaryTypeSet* types); - AbortReasonOr storeSlot(MDefinition* obj, size_t slot, size_t nfixed, - MDefinition* value, bool needsBarrier, - MIRType slotType = MIRType::None); - AbortReasonOr storeSlot(MDefinition* obj, Shape* shape, - MDefinition* value, bool needsBarrier, - MIRType slotType = MIRType::None); - bool shouldAbortOnPreliminaryGroups(MDefinition* obj); - - MDefinition* tryInnerizeWindow(MDefinition* obj); - MDefinition* maybeUnboxForPropertyAccess(MDefinition* def); - - // jsop_getprop() helpers. - AbortReasonOr checkIsDefinitelyOptimizedArguments(MDefinition* obj, - bool* isOptimizedArgs); - AbortReasonOr getPropTryInferredConstant(bool* emitted, MDefinition* obj, - PropertyName* name, - TemporaryTypeSet* types); - AbortReasonOr getPropTryArgumentsLength(bool* emitted, MDefinition* obj); - AbortReasonOr getPropTryArgumentsCallee(bool* emitted, MDefinition* obj, - PropertyName* name); - AbortReasonOr getPropTryConstant(bool* emitted, MDefinition* obj, jsid id, - TemporaryTypeSet* types); - AbortReasonOr getPropTryNotDefined(bool* emitted, MDefinition* obj, - jsid id, TemporaryTypeSet* types); - AbortReasonOr getPropTryDefiniteSlot(bool* emitted, MDefinition* obj, - PropertyName* name, - BarrierKind barrier, - TemporaryTypeSet* types); - AbortReasonOr getPropTryModuleNamespace(bool* emitted, MDefinition* obj, - PropertyName* name, - BarrierKind barrier, - TemporaryTypeSet* types); - AbortReasonOr getPropTryCommonGetter(bool* emitted, MDefinition* obj, - jsid id, TemporaryTypeSet* types, - bool innerized = false); - AbortReasonOr getPropTryInlineAccess(bool* emitted, MDefinition* obj, - PropertyName* name, - BarrierKind barrier, - TemporaryTypeSet* types); - AbortReasonOr getPropTryInlineProtoAccess(bool* emitted, MDefinition* obj, - PropertyName* name, - TemporaryTypeSet* types); - AbortReasonOr getPropTryInnerize(bool* emitted, MDefinition* obj, - PropertyName* name, - TemporaryTypeSet* types); - AbortReasonOr getPropAddCache(MDefinition* obj, PropertyName* name, - BarrierKind barrier, - TemporaryTypeSet* types); - - // jsop_setprop() helpers. - AbortReasonOr setPropTryCommonSetter(bool* emitted, MDefinition* obj, - PropertyName* name, - MDefinition* value); - AbortReasonOr setPropTryCommonDOMSetter(bool* emitted, MDefinition* obj, - MDefinition* value, - JSFunction* setter, - TemporaryTypeSet* objTypes); - AbortReasonOr setPropTryDefiniteSlot(bool* emitted, MDefinition* obj, - PropertyName* name, - MDefinition* value, bool barrier); - AbortReasonOr setPropTryInlineAccess(bool* emitted, MDefinition* obj, - PropertyName* name, - MDefinition* value, bool barrier, - TemporaryTypeSet* objTypes); - AbortReasonOr setPropTryCache(bool* emitted, MDefinition* obj, - PropertyName* name, MDefinition* value, - bool barrier); - - AbortReasonOr arithUnaryBinaryCache(JSOp op, MDefinition* left, - MDefinition* right); - - // jsop_binary_arith helpers. - MBinaryArithInstruction* binaryArithInstruction(JSOp op, MDefinition* left, - MDefinition* right); - MIRType binaryArithNumberSpecialization(MDefinition* left, - MDefinition* right); - AbortReasonOr binaryArithTryConcat(bool* emitted, JSOp op, - MDefinition* left, MDefinition* right); - AbortReasonOr binaryArithEmitSpecialized( - MDefinition::Opcode op, MIRType specialization, MDefinition* left, - MDefinition* right); - AbortReasonOr binaryArithTrySpecialized(bool* emitted, JSOp op, - MDefinition* left, - MDefinition* right); - AbortReasonOr binaryArithTrySpecializedOnBaselineInspector( - bool* emitted, JSOp op, MDefinition* left, MDefinition* right); - MDefinition* maybeConvertToNumber(MDefinition* def); - - // jsop_bitop helpers. - AbortReasonOr binaryBitOpTrySpecialized(bool* emitted, JSOp op, - MDefinition* left, - MDefinition* right); - - // jsop_bitnot helpers. - AbortReasonOr bitnotTrySpecialized(bool* emitted, MDefinition* input); - - // jsop_inc_or_dec helpers. - MDefinition* unaryArithConvertToBinary(JSOp op, MDefinition::Opcode* defOp); - AbortReasonOr unaryArithTrySpecialized(bool* emitted, JSOp op, - MDefinition* value); - AbortReasonOr unaryArithTrySpecializedOnBaselineInspector( - bool* emitted, JSOp op, MDefinition* value); - - // jsop_pow helpers. - AbortReasonOr powTrySpecialized(bool* emitted, MDefinition* base, - MDefinition* power, MIRType outputType); - - // jsop_compare helpers. - AbortReasonOr compareTrySpecialized(bool* emitted, JSOp op, - MDefinition* left, - MDefinition* right); - AbortReasonOr compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, - MDefinition* right); - AbortReasonOr compareTrySpecializedOnBaselineInspector( - bool* emitted, JSOp op, MDefinition* left, MDefinition* right); - AbortReasonOr compareTryBinaryStub(bool* emitted, MDefinition* left, - MDefinition* right); - - // jsop_newarray helpers. - AbortReasonOr newArrayTryTemplateObject(bool* emitted, - JSObject* templateObject, - uint32_t length); - AbortReasonOr newArrayTryVM(bool* emitted, JSObject* templateObject, - uint32_t length); - - // jsop_newobject helpers. - AbortReasonOr newObjectTryTemplateObject(bool* emitted, - JSObject* templateObject); - AbortReasonOr newObjectTryVM(bool* emitted, JSObject* templateObject); - - // jsop_in/jsop_hasown helpers. - AbortReasonOr inTryDense(bool* emitted, MDefinition* obj, - MDefinition* id); - AbortReasonOr hasTryNotDefined(bool* emitted, MDefinition* obj, - MDefinition* id, bool ownProperty); - AbortReasonOr hasTryDefiniteSlotOrUnboxed(bool* emitted, MDefinition* obj, - MDefinition* id); - - // jsop_setelem() helpers. - AbortReasonOr setElemTryTypedArray(bool* emitted, MDefinition* object, - MDefinition* index, - MDefinition* value); - AbortReasonOr initOrSetElemTryDense(bool* emitted, MDefinition* object, - MDefinition* index, - MDefinition* value, bool writeHole); - AbortReasonOr setElemTryArguments(bool* emitted, MDefinition* object); - AbortReasonOr initOrSetElemTryCache(bool* emitted, MDefinition* object, - MDefinition* index, - MDefinition* value); - - AbortReasonOr initArrayElemTryFastPath(bool* emitted, MDefinition* obj, - MDefinition* id, - MDefinition* value); - - AbortReasonOr initArrayElementFastPath( - MNewArray* obj, MDefinition* id, MDefinition* value, - bool addResumePointAndIncrementInitializedLength); - - AbortReasonOr initArrayElement(MDefinition* obj, MDefinition* id, - MDefinition* value); - - // jsop_getelem() helpers. - AbortReasonOr getElemTryDense(bool* emitted, MDefinition* obj, - MDefinition* index); - AbortReasonOr getElemTryGetProp(bool* emitted, MDefinition* obj, - MDefinition* index); - AbortReasonOr getElemTryTypedArray(bool* emitted, MDefinition* obj, - MDefinition* index); - AbortReasonOr getElemTryCallSiteObject(bool* emitted, MDefinition* obj, - MDefinition* index); - AbortReasonOr getElemTryString(bool* emitted, MDefinition* obj, - MDefinition* index); - AbortReasonOr getElemTryArguments(bool* emitted, MDefinition* obj, - MDefinition* index); - AbortReasonOr getElemTryArgumentsInlinedConstant(bool* emitted, - MDefinition* obj, - MDefinition* index); - AbortReasonOr getElemTryArgumentsInlinedIndex(bool* emitted, - MDefinition* obj, - MDefinition* index); - AbortReasonOr getElemAddCache(MDefinition* obj, MDefinition* index); - - TemporaryTypeSet* computeHeapType(const TemporaryTypeSet* objTypes, - const jsid id); - - enum BoundsChecking { DoBoundsCheck, SkipBoundsCheck }; - - MInstruction* addArrayBufferByteLength(MDefinition* obj); - - TypedArrayObject* tryTypedArrayEmbedConstantElements(MDefinition* obj); - - // Add instructions to compute a typed array's length and data. Also - // optionally convert |*index| into a bounds-checked definition, if - // requested. - // - // If you only need the array's length, use addTypedArrayLength below. - void addTypedArrayLengthAndData(MDefinition* obj, BoundsChecking checking, - MDefinition** index, MInstruction** length, - MInstruction** elements); - - // Add an instruction to compute a typed array's length to the current - // block. If you also need the typed array's data, use the above method - // instead. - MInstruction* addTypedArrayLength(MDefinition* obj) { - MInstruction* length; - addTypedArrayLengthAndData(obj, SkipBoundsCheck, nullptr, &length, nullptr); - return length; - } - - // Add instructions to compute a data view's data and convert |*index| into a - // bounds-checked definition. - void addDataViewData(MDefinition* obj, Scalar::Type type, MDefinition** index, - MInstruction** elements); - - // Add an instruction to compute a typed array's byte offset to the current - // block. - MInstruction* addTypedArrayByteOffset(MDefinition* obj); - - AbortReasonOr improveThisTypesForCall(); - - MDefinition* getCallee(); - MDefinition* getAliasedVar(EnvironmentCoordinate ec); - AbortReasonOr addLexicalCheck(MDefinition* input); - - MDefinition* convertToBoolean(MDefinition* input); - - AbortReasonOr tryFoldInstanceOf(bool* emitted, MDefinition* lhs, - JSObject* protoObject); - AbortReasonOr hasOnProtoChain(TypeSet::ObjectKey* key, - JSObject* protoObject, bool* onProto); - - AbortReasonOr jsop_add(MDefinition* left, MDefinition* right); - AbortReasonOr jsop_bitnot(); - AbortReasonOr jsop_bitop(JSOp op); - AbortReasonOr jsop_binary_arith(JSOp op); - AbortReasonOr jsop_binary_arith(JSOp op, MDefinition* left, - MDefinition* right); - AbortReasonOr jsop_pow(); - AbortReasonOr jsop_pos(); - AbortReasonOr jsop_neg(); - AbortReasonOr jsop_tonumeric(); - AbortReasonOr jsop_inc_or_dec(JSOp op); - AbortReasonOr jsop_tostring(); - AbortReasonOr jsop_getarg(uint32_t arg); - AbortReasonOr jsop_setarg(uint32_t arg); - AbortReasonOr jsop_defvar(); - AbortReasonOr jsop_deflexical(); - AbortReasonOr jsop_deffun(); - AbortReasonOr jsop_checkGlobalOrEvalDecl(); - AbortReasonOr jsop_notearg(); - AbortReasonOr jsop_throwsetconst(); - AbortReasonOr jsop_checklexical(); - AbortReasonOr jsop_checkaliasedlexical(EnvironmentCoordinate ec); - AbortReasonOr jsop_funcall(uint32_t argc); - AbortReasonOr jsop_funapply(uint32_t argc); - AbortReasonOr jsop_funapplyarguments(uint32_t argc); - AbortReasonOr jsop_funapplyarray(uint32_t argc); - AbortReasonOr jsop_spreadcall(); - AbortReasonOr jsop_spreadnew(); - AbortReasonOr jsop_optimize_spreadcall(); - AbortReasonOr jsop_call(uint32_t argc, bool constructing, - bool ignoresReturnValue); - AbortReasonOr jsop_eval(uint32_t argc); - AbortReasonOr jsop_label(); - AbortReasonOr jsop_andor(JSOp op); - AbortReasonOr jsop_dup2(); - AbortReasonOr jsop_goto(bool* restarted); - AbortReasonOr jsop_loophead(jsbytecode* pc); - AbortReasonOr jsop_compare(JSOp op); - AbortReasonOr jsop_compare(JSOp op, MDefinition* left, - MDefinition* right); - AbortReasonOr getStaticName(bool* emitted, JSObject* staticObject, - PropertyName* name, - MDefinition* lexicalCheck = nullptr); - AbortReasonOr loadStaticSlot(JSObject* staticObject, BarrierKind barrier, - TemporaryTypeSet* types, uint32_t slot); - AbortReasonOr setStaticName(JSObject* staticObject, PropertyName* name); - AbortReasonOr jsop_getgname(PropertyName* name); - AbortReasonOr jsop_getname(PropertyName* name); - AbortReasonOr jsop_intrinsic(PropertyName* name); - AbortReasonOr jsop_getimport(PropertyName* name); - AbortReasonOr jsop_bindname(PropertyName* name); - AbortReasonOr jsop_bindvar(); - AbortReasonOr jsop_getelem(); - AbortReasonOr jsop_getelem_dense(MDefinition* obj, MDefinition* index); - AbortReasonOr jsop_getelem_typed(MDefinition* obj, MDefinition* index, - Scalar::Type arrayType); - AbortReasonOr jsop_setelem(); - AbortReasonOr initOrSetElemDense( - TemporaryTypeSet::DoubleConversion conversion, MDefinition* object, - MDefinition* index, MDefinition* value, bool writeHole, bool* emitted); - AbortReasonOr jsop_setelem_typed(Scalar::Type arrayType, - MDefinition* object, MDefinition* index, - MDefinition* value); - AbortReasonOr jsop_length(); - bool jsop_length_fastPath(); - AbortReasonOr jsop_arguments(); - AbortReasonOr jsop_arguments_getelem(); - AbortReasonOr jsop_rest(); - AbortReasonOr jsop_not(); - AbortReasonOr jsop_envcallee(); - AbortReasonOr jsop_superbase(); - AbortReasonOr jsop_getprop_super(PropertyName* name); - AbortReasonOr jsop_getelem_super(); - AbortReasonOr jsop_getprop(PropertyName* name); - AbortReasonOr jsop_setprop(PropertyName* name); - AbortReasonOr jsop_delprop(PropertyName* name); - AbortReasonOr jsop_delelem(); - AbortReasonOr jsop_newarray(uint32_t length); - AbortReasonOr jsop_newarray(JSObject* templateObject, uint32_t length); - AbortReasonOr jsop_newarray_copyonwrite(); - AbortReasonOr jsop_newobject(); - AbortReasonOr jsop_initelem(); - AbortReasonOr jsop_initelem_inc(); - AbortReasonOr jsop_initelem_array(); - AbortReasonOr jsop_initelem_getter_setter(); - AbortReasonOr jsop_mutateproto(); - AbortReasonOr jsop_initprop(PropertyName* name); - AbortReasonOr jsop_initprop_getter_setter(PropertyName* name); - AbortReasonOr jsop_regexp(RegExpObject* reobj); - AbortReasonOr jsop_object(JSObject* obj); - AbortReasonOr jsop_classconstructor(); - AbortReasonOr jsop_derivedclassconstructor(); - AbortReasonOr jsop_lambda(JSFunction* fun); - AbortReasonOr jsop_lambda_arrow(JSFunction* fun); - AbortReasonOr jsop_funwithproto(JSFunction* fun); - AbortReasonOr jsop_setfunname(uint8_t prefixKind); - AbortReasonOr jsop_pushlexicalenv(GCThingIndex index); - AbortReasonOr jsop_copylexicalenv(bool copySlots); - AbortReasonOr jsop_functionthis(); - AbortReasonOr jsop_globalthis(); - AbortReasonOr jsop_typeof(); - AbortReasonOr jsop_toasync(); - AbortReasonOr jsop_toasynciter(); - AbortReasonOr jsop_topropertykey(); - AbortReasonOr jsop_iter(); - AbortReasonOr jsop_itermore(); - AbortReasonOr jsop_isnoiter(); - AbortReasonOr jsop_iterend(); - AbortReasonOr jsop_iternext(); - AbortReasonOr jsop_in(); - AbortReasonOr jsop_hasown(); - AbortReasonOr jsop_checkprivatefield(); - AbortReasonOr jsop_instanceof(); - AbortReasonOr jsop_getaliasedvar(EnvironmentCoordinate ec); - AbortReasonOr jsop_setaliasedvar(EnvironmentCoordinate ec); - AbortReasonOr jsop_debugger(); - AbortReasonOr jsop_newtarget(); - AbortReasonOr jsop_checkisobj(uint8_t kind); - AbortReasonOr jsop_checkiscallable(uint8_t kind); - AbortReasonOr jsop_checkobjcoercible(); - AbortReasonOr jsop_checkclassheritage(); - AbortReasonOr jsop_pushcallobj(); - AbortReasonOr jsop_implicitthis(PropertyName* name); - AbortReasonOr jsop_importmeta(); - AbortReasonOr jsop_dynamic_import(); - AbortReasonOr jsop_instrumentation_active(); - AbortReasonOr jsop_instrumentation_callback(); - AbortReasonOr jsop_instrumentation_scriptid(); - AbortReasonOr jsop_coalesce(); - AbortReasonOr jsop_objwithproto(); - AbortReasonOr jsop_builtinobject(); - AbortReasonOr jsop_checkreturn(); - AbortReasonOr jsop_checkthis(); - AbortReasonOr jsop_checkthisreinit(); - AbortReasonOr jsop_superfun(); - AbortReasonOr jsop_inithomeobject(); - - /* Inlining. */ - - enum InliningStatus { - InliningStatus_NotInlined, - InliningStatus_WarmUpCountTooLow, - InliningStatus_Inlined - }; - using InliningResult = AbortReasonOr; - - enum InliningDecision { - InliningDecision_Error, - InliningDecision_Inline, - InliningDecision_DontInline, - InliningDecision_WarmUpCountTooLow - }; - - static InliningDecision DontInline(JSScript* targetScript, - const char* reason); - - // Helper function for canInlineTarget - bool hasCommonInliningPath(const JSScript* scriptToInline); - - // Oracles. - InliningDecision canInlineTarget(JSFunction* target, CallInfo& callInfo); - InliningDecision makeInliningDecision(JSObject* target, CallInfo& callInfo); - AbortReasonOr selectInliningTargets(const InliningTargets& targets, - CallInfo& callInfo, - BoolVector& choiceSet, - uint32_t* numInlineable); - - OptimizationLevel optimizationLevel() const { - return optimizationInfo().level(); - } - bool isHighestOptimizationLevel() const { - return IonOptimizations.isLastLevel(optimizationLevel()); - } - - // Native inlining helpers. - // The typeset for the return value of our function. These are - // the types it's been observed returning in the past. - TemporaryTypeSet* getInlineReturnTypeSet(); - // The known MIR type of getInlineReturnTypeSet. - MIRType getInlineReturnType(); - - // Array natives. - InliningResult inlineArray(CallInfo& callInfo, Realm* targetRealm); - InliningResult inlineArrayIsArray(CallInfo& callInfo); - InliningResult inlineArrayPopShift(CallInfo& callInfo, - MArrayPopShift::Mode mode); - InliningResult inlineArrayPush(CallInfo& callInfo); - InliningResult inlineArraySlice(CallInfo& callInfo); - InliningResult inlineArrayJoin(CallInfo& callInfo); - - // Boolean natives. - InliningResult inlineBoolean(CallInfo& callInfo); - - // DataView natives. - InliningResult inlineDataViewGet(CallInfo& callInfo, Scalar::Type type); - InliningResult inlineDataViewSet(CallInfo& callInfo, Scalar::Type type); - - // Iterator intrinsics. - InliningResult inlineNewIterator(CallInfo& callInfo, MNewIterator::Type type); - InliningResult inlineArrayIteratorPrototypeOptimizable(CallInfo& callInfo); - - // Math natives. - InliningResult inlineMathAbs(CallInfo& callInfo); - InliningResult inlineMathFloor(CallInfo& callInfo); - InliningResult inlineMathCeil(CallInfo& callInfo); - InliningResult inlineMathClz32(CallInfo& callInfo); - InliningResult inlineMathRound(CallInfo& callInfo); - InliningResult inlineMathSqrt(CallInfo& callInfo); - InliningResult inlineMathAtan2(CallInfo& callInfo); - InliningResult inlineMathHypot(CallInfo& callInfo); - InliningResult inlineMathMinMax(CallInfo& callInfo, bool max); - InliningResult inlineMathPow(CallInfo& callInfo); - InliningResult inlineMathRandom(CallInfo& callInfo); - InliningResult inlineMathImul(CallInfo& callInfo); - InliningResult inlineMathFRound(CallInfo& callInfo); - InliningResult inlineMathTrunc(CallInfo& callInfo); - InliningResult inlineMathSign(CallInfo& callInfo); - InliningResult inlineMathFunction(CallInfo& callInfo, - UnaryMathFunction function); - - // String natives. - InliningResult inlineStringObject(CallInfo& callInfo); - InliningResult inlineStrCharCodeAt(CallInfo& callInfo); - InliningResult inlineStrFromCharCode(CallInfo& callInfo); - InliningResult inlineStrFromCodePoint(CallInfo& callInfo); - InliningResult inlineStrCharAt(CallInfo& callInfo); - InliningResult inlineStringConvertCase(CallInfo& callInfo, - MStringConvertCase::Mode mode); - - // String intrinsics. - InliningResult inlineStringReplaceString(CallInfo& callInfo); - InliningResult inlineConstantStringSplitString(CallInfo& callInfo); - InliningResult inlineStringSplitString(CallInfo& callInfo); - - // Reflect natives. - InliningResult inlineReflectGetPrototypeOf(CallInfo& callInfo); - - // RegExp intrinsics. - InliningResult inlineRegExpMatcher(CallInfo& callInfo); - InliningResult inlineRegExpSearcher(CallInfo& callInfo); - InliningResult inlineRegExpTester(CallInfo& callInfo); - InliningResult inlineIsRegExpObject(CallInfo& callInfo); - InliningResult inlineIsPossiblyWrappedRegExpObject(CallInfo& callInfo); - InliningResult inlineRegExpPrototypeOptimizable(CallInfo& callInfo); - InliningResult inlineRegExpInstanceOptimizable(CallInfo& callInfo); - InliningResult inlineGetFirstDollarIndex(CallInfo& callInfo); - - // Object natives and intrinsics. - InliningResult inlineObject(CallInfo& callInfo); - InliningResult inlineObjectCreate(CallInfo& callInfo); - InliningResult inlineObjectIs(CallInfo& callInfo); - InliningResult inlineObjectIsPrototypeOf(CallInfo& callInfo); - InliningResult inlineObjectToString(CallInfo& callInfo); - InliningResult inlineDefineDataProperty(CallInfo& callInfo); - - // Atomics natives. - InliningResult inlineAtomicsCompareExchange(CallInfo& callInfo); - InliningResult inlineAtomicsExchange(CallInfo& callInfo); - InliningResult inlineAtomicsLoad(CallInfo& callInfo); - InliningResult inlineAtomicsStore(CallInfo& callInfo); - InliningResult inlineAtomicsBinop(CallInfo& callInfo, InlinableNative target); - InliningResult inlineAtomicsIsLockFree(CallInfo& callInfo); - - // Slot intrinsics. - InliningResult inlineUnsafeSetReservedSlot(CallInfo& callInfo); - InliningResult inlineUnsafeGetReservedSlot(CallInfo& callInfo, - MIRType knownValueType); - - // Map and Set intrinsics. - InliningResult inlineGetNextEntryForIterator( - CallInfo& callInfo, MGetNextEntryForIterator::Mode mode); - - // ArrayBuffer intrinsics. - InliningResult inlineArrayBufferByteLength(CallInfo& callInfo); - InliningResult inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo); - - // TypedArray intrinsics. - enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays }; - InliningResult inlineTypedArray(CallInfo& callInfo, Native native); - InliningResult inlineIsTypedArrayConstructor(CallInfo& callInfo); - InliningResult inlineIsTypedArrayHelper(CallInfo& callInfo, - WrappingBehavior wrappingBehavior); - InliningResult inlineIsTypedArray(CallInfo& callInfo); - InliningResult inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo); - InliningResult inlineTypedArrayLength(CallInfo& callInfo); - InliningResult inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo); - InliningResult inlineTypedArrayByteOffset(CallInfo& callInfo); - InliningResult inlineTypedArrayElementShift(CallInfo& callInfo); - - // Utility intrinsics. - InliningResult inlineIsCallable(CallInfo& callInfo); - InliningResult inlineIsConstructor(CallInfo& callInfo); - InliningResult inlineIsObject(CallInfo& callInfo); - InliningResult inlineToObject(CallInfo& callInfo); - InliningResult inlineIsCrossRealmArrayConstructor(CallInfo& callInfo); - InliningResult inlineToInteger(CallInfo& callInfo); - InliningResult inlineToLength(CallInfo& callInfo); - InliningResult inlineDump(CallInfo& callInfo); - InliningResult inlineGuardToClass(CallInfo& callInfo, InlinableNative native); - InliningResult inlineIsConstructing(CallInfo& callInfo); - InliningResult inlineSubstringKernel(CallInfo& callInfo); - InliningResult inlineObjectHasPrototype(CallInfo& callInfo); - InliningResult inlineFinishBoundFunctionInit(CallInfo& callInfo); - InliningResult inlineIsPackedArray(CallInfo& callInfo); - InliningResult inlineWasmCall(CallInfo& callInfo, JSFunction* target); - - // Testing functions. - InliningResult inlineBailout(CallInfo& callInfo); - InliningResult inlineAssertFloat32(CallInfo& callInfo); - InliningResult inlineAssertRecoveredOnBailout(CallInfo& callInfo); - - // Bind function. - InliningResult inlineBoundFunction(CallInfo& callInfo, JSFunction* target); - - // Main inlining functions - InliningResult inlineNativeCall(CallInfo& callInfo, JSFunction* target); - InliningResult inlineNativeGetter(CallInfo& callInfo, JSFunction* target); - InliningResult inlineScriptedCall(CallInfo& callInfo, JSFunction* target); - InliningResult inlineSingleCall(CallInfo& callInfo, JSObject* target); - - // Call functions - InliningResult inlineCallsite(const InliningTargets& targets, - CallInfo& callInfo); - AbortReasonOr inlineCalls(CallInfo& callInfo, - const InliningTargets& targets, - BoolVector& choiceSet, - MGetPropertyCache* maybeCache); - - // Inlining helpers. - AbortReasonOr inlineGenericFallback( - const mozilla::Maybe& targets, CallInfo& callInfo, - MBasicBlock* dispatchBlock); - AbortReasonOr inlineObjectGroupFallback( - const mozilla::Maybe& targets, CallInfo& callInfo, - MBasicBlock* dispatchBlock, MObjectGroupDispatch* dispatch, - MGetPropertyCache* cache, MBasicBlock** fallbackTarget); - - enum AtomicCheckResult { DontCheckAtomicResult, DoCheckAtomicResult }; - - bool atomicsMeetsPreconditions( - CallInfo& callInfo, Scalar::Type* arrayElementType, - TemporaryTypeSet::TypedArraySharedness* sharedness, - AtomicCheckResult checkResult = DoCheckAtomicResult); - void atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, - MDefinition** index); - - bool testNeedsArgumentCheck(JSFunction* target, CallInfo& callInfo); - - AbortReasonOr makeCallHelper( - const mozilla::Maybe& targets, CallInfo& callInfo); - AbortReasonOr makeCall(const mozilla::Maybe& targets, - CallInfo& callInfo); - AbortReasonOr makeCall(JSFunction* target, CallInfo& callInfo); - - MDefinition* patchInlinedReturn(JSFunction* target, CallInfo& callInfo, - MBasicBlock* exit, MBasicBlock* bottom); - MDefinition* patchInlinedReturns(JSFunction* target, CallInfo& callInfo, - MIRGraphReturns& returns, - MBasicBlock* bottom); - MDefinition* specializeInlinedReturn(MDefinition* rdef, MBasicBlock* exit); - - NativeObject* commonPrototypeWithGetterSetter(TemporaryTypeSet* types, - jsid id, bool isGetter, - JSFunction* getterOrSetter, - bool* guardGlobal); - AbortReasonOr freezePropertiesForCommonPrototype( - TemporaryTypeSet* types, jsid id, JSObject* foundProto, - bool allowEmptyTypesForGlobal); - /* - * Callers must pass a non-null globalGuard if they pass a non-null - * globalShape. - */ - AbortReasonOr testCommonGetterSetter( - TemporaryTypeSet* types, jsid id, bool isGetter, - JSFunction* getterOrSetter, MDefinition** guard, - Shape* globalShape = nullptr, MDefinition** globalGuard = nullptr); - AbortReasonOr testShouldDOMCall(TypeSet* inTypes, JSFunction* func, - JSJitInfo::OpType opType); - - MDefinition* addShapeGuardsForGetterSetter( - MDefinition* obj, JSObject* holder, Shape* holderShape, - const BaselineInspector::ReceiverVector& receivers, bool isOwnProperty); - - AbortReasonOr annotateGetPropertyCache(MDefinition* obj, - PropertyName* name, - MGetPropertyCache* getPropCache, - TemporaryTypeSet* objTypes, - TemporaryTypeSet* pushedTypes); - - MGetPropertyCache* getInlineableGetPropertyCache(CallInfo& callInfo); - - JSObject* testGlobalLexicalBinding(PropertyName* name); - - JSObject* testSingletonProperty(JSObject* obj, jsid id); - JSObject* testSingletonPropertyTypes(MDefinition* obj, jsid id); - - AbortReasonOr testNotDefinedProperty(MDefinition* obj, jsid id, - bool ownProperty = false); - - uint32_t getDefiniteSlot(TemporaryTypeSet* types, jsid id, uint32_t* pnfixed); - - AbortReasonOr checkPreliminaryGroups(MDefinition* obj); - AbortReasonOr freezePropTypeSets(TemporaryTypeSet* types, - JSObject* foundProto, - PropertyName* name); - bool canInlinePropertyOpShapes( - const BaselineInspector::ReceiverVector& receivers); - - TemporaryTypeSet* bytecodeTypes(jsbytecode* pc); - - // Use one of the below methods for updating the current block, rather than - // updating |current| directly. setCurrent() should only be used in cases - // where the block cannot have phis whose type needs to be computed. - - AbortReasonOr setCurrentAndSpecializePhis(MBasicBlock* block) { - MOZ_ASSERT(block); - if (!block->specializePhis(alloc())) { - return abort(AbortReason::Alloc); - } - setCurrent(block); - return Ok(); - } - - void setCurrent(MBasicBlock* block) { - MOZ_ASSERT(block); - current = block; - } - - bool hasTerminatedBlock() const { return current == nullptr; } - void setTerminatedBlock() { current = nullptr; } - - // A builder is inextricably tied to a particular script. - JSScript* script_; - - // Some aborts are actionable (e.g., using an unsupported bytecode). When - // optimization tracking is enabled, the location and message of the abort - // are recorded here so they may be propagated to the script's - // corresponding JitcodeGlobalEntry::BaselineEntry. - JSScript* actionableAbortScript_; - jsbytecode* actionableAbortPc_; - const char* actionableAbortMessage_; - - public: - using ObjectGroupVector = Vector; - - void checkNurseryCell(gc::Cell* cell); - JSObject* checkNurseryObject(JSObject* obj); - - JSScript* script() const { return script_; } - - TIOracle& tiOracle() { return tiOracle_; } - - CompilerConstraintList* constraints() { return constraints_; } - - bool isInlineBuilder() const { return callerBuilder_ != nullptr; } - - const JSAtomState& names() { return realm->runtime()->names(); } - - bool hadActionableAbort() const { - MOZ_ASSERT(!actionableAbortScript_ || - (actionableAbortPc_ && actionableAbortMessage_)); - return actionableAbortScript_ != nullptr; - } - - void actionableAbortLocationAndMessage(JSScript** abortScript, - jsbytecode** abortPc, - const char** abortMessage) { - MOZ_ASSERT(hadActionableAbort()); - *abortScript = actionableAbortScript_; - *abortPc = actionableAbortPc_; - *abortMessage = actionableAbortMessage_; - } - - private: - AbortReasonOr init(); - - JSContext* analysisContext; - BaselineFrameInspector* baselineFrame_; - - // Constraints for recording dependencies on type information. - CompilerConstraintList* constraints_; - - MIRGenerator& mirGen_; - TIOracle tiOracle_; - - CompileRealm* realm; - const CompileInfo* info_; - const OptimizationInfo* optimizationInfo_; - TempAllocator* alloc_; - MIRGraph* graph_; - - TemporaryTypeSet* thisTypes; - TemporaryTypeSet* argTypes; - TemporaryTypeSet* typeArray; - uint32_t typeArrayHint; - uint32_t* bytecodeTypeMap; - - jsbytecode* pc; - jsbytecode* nextpc = nullptr; - - // The current MIR block. This can be nullptr after a block has been - // terminated, for example right after a 'return' or 'break' statement. - MBasicBlock* current = nullptr; - - uint32_t loopDepth_; - - PendingEdgesMap pendingEdges_; - LoopStateStack loopStack_; - - Vector trackedOptimizationSites_; - - ObjectGroupVector abortedPreliminaryGroups_; - - BytecodeSite* bytecodeSite(jsbytecode* pc) { - MOZ_ASSERT(info().inlineScriptTree()->script()->containsPC(pc)); - return new (alloc()) BytecodeSite(info().inlineScriptTree(), pc); - } - - /* Information used for inline-call builders. */ - MResumePoint* callerResumePoint_; - jsbytecode* callerPC() { - return callerResumePoint_ ? callerResumePoint_->pc() : nullptr; - } - IonBuilder* callerBuilder_; - - IonBuilder* outermostBuilder(); - - struct LoopHeader { - jsbytecode* pc; - MBasicBlock* header; - - LoopHeader(jsbytecode* pc, MBasicBlock* header) : pc(pc), header(header) {} - }; - - PhiVector iterators_; - Vector loopHeaders_; - - BaselineInspector* inspector; - - size_t inliningDepth_; - - // Total bytecode length of all inlined scripts. Only tracked for the - // outermost builder. - size_t inlinedBytecodeLength_; - - // Cutoff to disable compilation if excessive time is spent reanalyzing - // loop bodies to compute a fixpoint of the types for loop variables. - static const size_t MAX_LOOP_RESTARTS = 40; - size_t numLoopRestarts_; - - // True if script->failedBoundsCheck is set for the current script or - // an outer script. - bool failedBoundsCheck_; - - // True if script->failedShapeGuard is set for the current script or - // an outer script. - bool failedShapeGuard_; - - // True if script->failedLexicalCheck_ is set for the current script or - // an outer script. - bool failedLexicalCheck_; - -#ifdef DEBUG - // If this script uses the lazy arguments object. - bool hasLazyArguments_; -#endif - - // If this is an inline builder, the call info for the builder. - const CallInfo* inlineCallInfo_; - - // When compiling a call with multiple targets, we are first creating a - // MGetPropertyCache. This MGetPropertyCache is following the bytecode, and - // is used to recover the JSFunction. In some cases, the Type of the object - // which own the property is enough for dispatching to the right function. - // In such cases we do not have read the property, except when the type - // object is unknown. - // - // As an optimization, we can dispatch a call based on the object group, - // without doing the MGetPropertyCache. This is what is achieved by - // |IonBuilder::inlineCalls|. As we might not know all the functions, we - // are adding a fallback path, where this MGetPropertyCache would be moved - // into. - // - // In order to build the fallback path, we have to capture a resume point - // ahead, for the potential fallback path. This resume point is captured - // while building MGetPropertyCache. It is capturing the state of Baseline - // before the execution of the MGetPropertyCache, such as we can safely do - // it in the fallback path. - // - // This field is used to discard the resume point if it is not used for - // building a fallback path. - - // Discard the prior resume point while setting a new MGetPropertyCache. - void replaceMaybeFallbackFunctionGetter(MGetPropertyCache* cache); - - // Discard the MGetPropertyCache if it is handled by WrapMGetPropertyCache. - void keepFallbackFunctionGetter(MGetPropertyCache* cache) { - if (cache == maybeFallbackFunctionGetter_) { - maybeFallbackFunctionGetter_ = nullptr; - } - } - - MGetPropertyCache* maybeFallbackFunctionGetter_; - - bool needsPostBarrier(MDefinition* value); - - void addAbortedPreliminaryGroup(ObjectGroup* group); - - MIRGraph& graph() { return *graph_; } - const CompileInfo& info() const { return *info_; } - - const OptimizationInfo& optimizationInfo() const { - return *optimizationInfo_; - } - - bool forceInlineCaches() { - return MOZ_UNLIKELY(JitOptions.forceInlineCaches); - } - - public: - MIRGenerator& mirGen() { return mirGen_; } - TempAllocator& alloc() { return *alloc_; } - - // When aborting with AbortReason::PreliminaryObjects, all groups with - // preliminary objects which haven't been analyzed yet. - const ObjectGroupVector& abortedPreliminaryGroups() const { - return abortedPreliminaryGroups_; - } -}; - -} // namespace jit -} // namespace js - -#endif /* jit_IonBuilder_h */ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/Ion.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/Ion.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/Ion.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/Ion.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -21,7 +21,6 @@ #include "jit/AutoWritableJitCode.h" #include "jit/BacktrackingAllocator.h" #include "jit/BaselineFrame.h" -#include "jit/BaselineInspector.h" #include "jit/BaselineJIT.h" #include "jit/CacheIRSpewer.h" #include "jit/CodeGenerator.h" @@ -33,7 +32,6 @@ #include "jit/InlineScriptTree.h" #include "jit/InstructionReordering.h" #include "jit/IonAnalysis.h" -#include "jit/IonBuilder.h" #include "jit/IonCompileTask.h" #include "jit/IonIC.h" #include "jit/IonOptimizationLevels.h" @@ -71,6 +69,7 @@ #include "debugger/DebugAPI-inl.h" #include "gc/GC-inl.h" +#include "jit/InlineScriptTree-inl.h" #include "jit/MacroAssembler-inl.h" #include "jit/SafepointIndex-inl.h" #include "jit/shared/Lowering-shared-inl.h" @@ -1528,79 +1527,6 @@ TrackIonAbort(cx, script, script->code(), message); } -static AbortReason BuildMIR(JSContext* cx, MIRGenerator* mirGen, - CompileInfo* info, - CompilerConstraintList* constraints, - BaselineFrame* baselineFrame, - uint32_t baselineFrameSize) { - BaselineFrameInspector* baselineFrameInspector = nullptr; - if (baselineFrame) { - baselineFrameInspector = NewBaselineFrameInspector( - &mirGen->alloc(), baselineFrame, baselineFrameSize); - if (!baselineFrameInspector) { - return AbortReason::Alloc; - } - } - - SpewBeginFunction(mirGen, info->script()); - - BaselineInspector inspector(info->script()); - IonBuilder builder((JSContext*)nullptr, *mirGen, info, constraints, - &inspector, baselineFrameInspector); - - AbortReasonOr buildResult = Ok(); - { - AutoEnterAnalysis enter(cx); - buildResult = builder.build(); - } - - if (buildResult.isErr()) { - AbortReason reason = buildResult.unwrapErr(); - mirGen->graphSpewer().endFunction(); - if (reason == AbortReason::PreliminaryObjects) { - // Some group was accessed which has associated preliminary objects - // to analyze. Do this now and we will try to build again shortly. - const IonBuilder::ObjectGroupVector& groups = - builder.abortedPreliminaryGroups(); - for (size_t i = 0; i < groups.length(); i++) { - ObjectGroup* group = groups[i]; - AutoRealm ar(cx, group); - AutoSweepObjectGroup sweep(group); - if (auto* newScript = group->newScript(sweep)) { - if (!newScript->maybeAnalyze(cx, group, nullptr, - /* force = */ true)) { - return AbortReason::Alloc; - } - } else if (auto* preliminaryObjects = - group->maybePreliminaryObjects(sweep)) { - preliminaryObjects->maybeAnalyze(cx, group, /* force = */ true); - } else { - MOZ_CRASH("Unexpected aborted preliminary group"); - } - } - } - - if (builder.hadActionableAbort()) { - JSScript* abortScript; - jsbytecode* abortPc; - const char* abortMessage; - builder.actionableAbortLocationAndMessage(&abortScript, &abortPc, - &abortMessage); - TrackIonAbort(cx, abortScript, abortPc, abortMessage); - } - - if (cx->isThrowingOverRecursed()) { - // Non-analysis compilations should never fail with stack overflow. - MOZ_CRASH("Stack overflow during compilation"); - } - - return reason; - } - - AssertBasicGraphCoherency(mirGen->graph()); - return AbortReason::NoAbort; -} - static AbortReasonOr CreateWarpSnapshot(JSContext* cx, MIRGenerator* mirGen, HandleScript script) { @@ -1706,21 +1632,11 @@ script->jitScript()->setHadIonOSR(); } - WarpSnapshot* snapshot = nullptr; - if (JitOptions.warpBuilder) { - AbortReasonOr result = - CreateWarpSnapshot(cx, mirGen, script); - if (result.isErr()) { - return result.unwrapErr(); - } - snapshot = result.unwrap(); - } else { - AbortReason reason = BuildMIR(cx, mirGen, info, constraints, baselineFrame, - baselineFrameSize); - if (reason != AbortReason::NoAbort) { - return reason; - } + AbortReasonOr result = CreateWarpSnapshot(cx, mirGen, script); + if (result.isErr()) { + return result.unwrapErr(); } + WarpSnapshot* snapshot = result.unwrap(); // If possible, compile the script off thread. if (options.offThreadCompilationAvailable()) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/IonIC.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/IonIC.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/IonIC.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/IonIC.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -250,13 +250,6 @@ } } - if (!ic->idempotent()) { - // Monitor changes to cache entry. - if (!ic->monitoredResult()) { - JitScript::MonitorBytecodeType(cx, ic->script(), ic->pc(), res); - } - } - return true; } @@ -294,8 +287,6 @@ } } - // Monitor changes to cache entry. - JitScript::MonitorBytecodeType(cx, ic->script(), ic->pc(), res); return true; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitContext.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitContext.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitContext.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitContext.h 2020-11-17 19:31:31.000000000 +0000 @@ -62,6 +62,7 @@ #ifdef DEBUG // Whether this thread is actively Ion compiling (does not include Wasm or // IonBuilder). + // TODO(no-TI): fix IonBuilder references in comments. bool inIonBackend_ = false; // Whether this thread is actively Ion compiling in a context where a minor diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitOptions.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitOptions.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitOptions.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitOptions.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -345,13 +345,6 @@ smallFunctionMaxBytecodeLength = 2000; } -void DefaultJitOptions::setWarpEnabled(bool enable) { - // WarpBuilder doesn't use optimization levels. - warpBuilder = enable; - disableOptimizationLevels = enable; - normalIonWarmUpThreshold = enable ? 1500 : 1000; -} - void DefaultJitOptions::setNormalIonWarmUpThreshold(uint32_t warmUpThreshold) { normalIonWarmUpThreshold = warmUpThreshold; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitOptions.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitOptions.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitOptions.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitOptions.h 2020-11-17 19:31:31.000000000 +0000 @@ -131,7 +131,6 @@ void resetFullIonWarmUpThreshold(); void enableGvn(bool val); void setFastWarmUp(); - void setWarpEnabled(bool enable); bool eagerIonCompilation() const { return normalIonWarmUpThreshold == 0; } }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitScript.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitScript.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitScript.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitScript.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -40,41 +40,14 @@ using mozilla::CheckedInt; -/* static */ -size_t JitScript::NumTypeSets(JSScript* script) { - // We rely on |num| not overflowing below. - static_assert(JSScript::MaxBytecodeTypeSets == UINT16_MAX, - "JSScript typesets should have safe range to avoid overflow"); - static_assert(JSFunction::NArgsBits == 16, - "JSFunction nargs should have safe range to avoid overflow"); - - if (!IsTypeInferenceEnabled()) { - return 0; - } - - size_t num = script->numBytecodeTypeSets() + 1 /* this */; - if (JSFunction* fun = script->function()) { - num += fun->nargs(); - } - - return num; -} - -JitScript::JitScript(JSScript* script, Offset typeSetOffset, - Offset bytecodeTypeMapOffset, Offset endOffset, +JitScript::JitScript(JSScript* script, Offset endOffset, const char* profileString) : profileString_(profileString), - typeSetOffset_(typeSetOffset), - bytecodeTypeMapOffset_(bytecodeTypeMapOffset), endOffset_(endOffset), - icScript_(script->getWarmUpCount(), typeSetOffset - offsetOfICScript(), + icScript_(script->getWarmUpCount(), endOffset - offsetOfICScript(), /*depth=*/0) { setTypesGeneration(script->zone()->types.generation); - if (IsTypeInferenceEnabled()) { - initElements(typeSetOffset, numTypeSets()); - } - // Ensure the baselineScript_ and ionScript_ fields match the BaselineDisabled // and IonDisabled script flags. if (!script->canBaselineCompile()) { @@ -116,14 +89,10 @@ } } - size_t numTypeSets = JitScript::NumTypeSets(this); - static_assert(sizeof(JitScript) % sizeof(uintptr_t) == 0, "Trailing arrays must be aligned properly"); static_assert(sizeof(ICEntry) % sizeof(uintptr_t) == 0, "Trailing arrays must be aligned properly"); - static_assert(sizeof(StackTypeSet) % sizeof(uintptr_t) == 0, - "Trailing arrays must be aligned properly"); static_assert( sizeof(JitScript) == offsetof(JitScript, icScript_) + sizeof(ICScript), @@ -132,10 +101,6 @@ // Calculate allocation size. CheckedInt allocSize = sizeof(JitScript); allocSize += CheckedInt(numICEntries()) * sizeof(ICEntry); - if (IsTypeInferenceEnabled()) { - allocSize += CheckedInt(numTypeSets) * sizeof(StackTypeSet); - allocSize += CheckedInt(numBytecodeTypeSets()) * sizeof(uint32_t); - } if (!allocSize.isValid()) { ReportAllocationOverflow(cx); return false; @@ -147,17 +112,11 @@ return false; } - uint32_t typeSetOffset = sizeof(JitScript) + numICEntries() * sizeof(ICEntry); - uint32_t bytecodeTypeMapOffset = - typeSetOffset + numTypeSets * sizeof(StackTypeSet); UniquePtr jitScript( - new (raw) JitScript(this, typeSetOffset, bytecodeTypeMapOffset, - allocSize.value(), profileString)); + new (raw) JitScript(this, allocSize.value(), profileString)); - // Sanity check the length computations. + // Sanity check the length computation. MOZ_ASSERT(jitScript->numICEntries() == numICEntries()); - MOZ_ASSERT_IF(IsTypeInferenceEnabled(), - jitScript->numTypeSets() == numTypeSets); // We need to call prepareForDestruction on JitScript before we |delete| it. auto prepareForDestruction = mozilla::MakeScopeExit( @@ -167,10 +126,6 @@ return false; } - if (IsTypeInferenceEnabled()) { - jitScript->initBytecodeTypeMap(this); - } - prepareForDestruction.release(); warmUpData_.initJitScript(jitScript.release()); AddCellMemory(this, allocSize.value(), MemoryUse::JitScript); @@ -179,27 +134,6 @@ // Baseline Interpreter code. updateJitCodeRaw(cx->runtime()); -#ifdef DEBUG - if (IsTypeInferenceEnabled()) { - AutoSweepJitScript sweep(this); - StackTypeSet* typeArray = this->jitScript()->typeArrayDontCheckGeneration(); - for (unsigned i = 0; i < numBytecodeTypeSets(); i++) { - InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u %p", - InferSpewColor(&typeArray[i]), &typeArray[i], - InferSpewColorReset(), i, this); - } - StackTypeSet* thisTypes = this->jitScript()->thisTypes(sweep, this); - InferSpew(ISpewOps, "typeSet: %sT%p%s this %p", InferSpewColor(thisTypes), - thisTypes, InferSpewColorReset(), this); - unsigned nargs = function() ? function()->nargs() : 0; - for (unsigned i = 0; i < nargs; i++) { - StackTypeSet* types = this->jitScript()->argTypes(sweep, this, i); - InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u %p", InferSpewColor(types), - types, InferSpewColorReset(), i, this); - } - } -#endif - return true; } @@ -347,67 +281,8 @@ } } -#ifdef DEBUG -void JitScript::printTypes(JSContext* cx, HandleScript script) { - AutoSweepJitScript sweep(script); - MOZ_ASSERT(script->jitScript() == this); - - AutoEnterAnalysis enter(nullptr, script->zone()); - Fprinter out(stderr); - - if (script->function()) { - fprintf(stderr, "Function"); - } else if (script->isForEval()) { - fprintf(stderr, "Eval"); - } else { - fprintf(stderr, "Main"); - } - fprintf(stderr, " %#" PRIxPTR " %s:%u ", uintptr_t(script.get()), - script->filename(), script->lineno()); - - if (script->function()) { - if (JSAtom* name = script->function()->explicitName()) { - name->dumpCharsNoNewline(out); - } - } - - fprintf(stderr, "\n this:"); - thisTypes(sweep, script)->print(); - - for (uint32_t i = 0; script->function() && i < script->function()->nargs(); - i++) { - fprintf(stderr, "\n arg%u:", i); - argTypes(sweep, script, i)->print(); - } - fprintf(stderr, "\n"); - - for (BytecodeLocation it : AllBytecodesIterable(script)) { - { - fprintf(stderr, "%p:", script.get()); - Sprinter sprinter(cx); - if (!sprinter.init()) { - return; - } - Disassemble1(cx, script, it.toRawBytecode(), it.bytecodeToOffset(script), - true, &sprinter); - fprintf(stderr, "%s", sprinter.string()); - } - - if (it.opHasTypeSet()) { - StackTypeSet* types = bytecodeTypes(sweep, script, it.toRawBytecode()); - fprintf(stderr, " typeset %u:", uint32_t(types - typeArray(sweep))); - types->print(); - fprintf(stderr, "\n"); - } - } - - fprintf(stderr, "\n"); -} -#endif /* DEBUG */ - /* static */ void JitScript::Destroy(Zone* zone, JitScript* script) { - script->unlinkDependentWasmImports(); script->prepareForDestruction(zone); js_delete(script); @@ -434,13 +309,6 @@ if (entryOffset < pcOffset) { return 1; } - if (entry.isForPrologue()) { - // Prologue ICEntries are used for function argument type checks. - // Ignore these entries and return 1 because these entries appear in - // the ICEntry list before the other ICEntry (if any) at offset 0. - MOZ_ASSERT(entryOffset == 0); - return 1; - } return 0; }, loc); @@ -458,7 +326,6 @@ MOZ_ASSERT(mid < numICEntries()); ICEntry& entry = icEntry(mid); - MOZ_ASSERT(!entry.isForPrologue()); MOZ_ASSERT(entry.pcOffset() == pcOffset); return &entry; } @@ -479,7 +346,7 @@ ICEntry* lastEntry = &icEntry(numICEntries() - 1); ICEntry* curEntry = prevLookedUpEntry; while (curEntry >= firstEntry && curEntry <= lastEntry) { - if (curEntry->pcOffset() == pcOffset && !curEntry->isForPrologue()) { + if (curEntry->pcOffset() == pcOffset) { return curEntry; } curEntry++; @@ -503,7 +370,7 @@ // pcOffset does not necessarily have an ICEntry, so we want to return the // first ICEntry for which the following is true: // - // !entry.isForPrologue() && entry.pcOffset() >= pcOffset + // entry.pcOffset() >= pcOffset // // Fortunately, ComputeBinarySearchMid returns exactly this entry. @@ -512,7 +379,6 @@ if (mid < numICEntries()) { ICEntry& entry = icEntry(mid); - MOZ_ASSERT(!entry.isForPrologue()); MOZ_ASSERT(entry.pcOffset() >= pcOffset); return &entry; } @@ -551,39 +417,25 @@ lastStub = lastStub->next(); } - if (lastStub->isFallback()) { - // Unlink all stubs allocated in the optimized space. - ICStub* stub = entry.firstStub(); - ICStub* prev = nullptr; - - while (stub->next()) { - if (!stub->allocatedInFallbackSpace()) { - // Note: this is called when discarding JIT code, after invalidating - // all Warp code, so we don't need to check for that here. - lastStub->toFallbackStub()->clearUsedByTranspiler(); - lastStub->toFallbackStub()->unlinkStubDontInvalidateWarp(zone, prev, - stub); - stub = stub->next(); - continue; - } + MOZ_ASSERT(lastStub->isFallback()); - prev = stub; + // Unlink all stubs allocated in the optimized space. + ICStub* stub = entry.firstStub(); + ICStub* prev = nullptr; + + while (stub->next()) { + if (!stub->allocatedInFallbackSpace()) { + // Note: this is called when discarding JIT code, after invalidating + // all Warp code, so we don't need to check for that here. + lastStub->toFallbackStub()->clearUsedByTranspiler(); + lastStub->toFallbackStub()->unlinkStubDontInvalidateWarp(zone, prev, + stub); stub = stub->next(); + continue; } - if (lastStub->isMonitoredFallback()) { - // Monitor stubs can't make calls, so are always in the - // optimized stub space. - ICTypeMonitor_Fallback* lastMonStub = - lastStub->toMonitoredFallbackStub()->maybeFallbackMonitorStub(); - if (lastMonStub) { - lastMonStub->resetMonitorStubChain(zone); - } - } - } else if (lastStub->isTypeMonitor_Fallback()) { - lastStub->toTypeMonitor_Fallback()->resetMonitorStubChain(zone); - } else { - MOZ_CRASH("Unknown fallback stub"); + prev = stub; + stub = stub->next(); } } @@ -600,60 +452,6 @@ #endif } -void JitScript::noteAccessedGetter(uint32_t pcOffset) { - ICEntry& entry = icEntryFromPCOffset(pcOffset); - ICFallbackStub* stub = entry.fallbackStub(); - - if (stub->isGetProp_Fallback()) { - stub->toGetProp_Fallback()->noteAccessedGetter(); - } -} - -void JitScript::noteHasDenseAdd(uint32_t pcOffset) { - ICEntry& entry = icEntryFromPCOffset(pcOffset); - ICFallbackStub* stub = entry.fallbackStub(); - - if (stub->isSetElem_Fallback()) { - stub->toSetElem_Fallback()->noteHasDenseAdd(); - } -} - -void JitScript::unlinkDependentWasmImports() { - // Remove any links from wasm::Instances that contain optimized FFI calls into - // this JitScript. - if (dependentWasmImports_) { - for (DependentWasmImport& dep : *dependentWasmImports_) { - dep.instance->deoptimizeImportExit(dep.importIndex); - } - dependentWasmImports_.reset(); - } -} - -bool JitScript::addDependentWasmImport(JSContext* cx, wasm::Instance& instance, - uint32_t idx) { - if (!dependentWasmImports_) { - dependentWasmImports_ = cx->make_unique>(cx); - if (!dependentWasmImports_) { - return false; - } - } - return dependentWasmImports_->emplaceBack(instance, idx); -} - -void JitScript::removeDependentWasmImport(wasm::Instance& instance, - uint32_t idx) { - if (!dependentWasmImports_) { - return; - } - - for (DependentWasmImport& dep : *dependentWasmImports_) { - if (dep.instance == &instance && dep.importIndex == idx) { - dependentWasmImports_->erase(&dep); - break; - } - } -} - JitScript::CachedIonData::CachedIonData(EnvironmentObject* templateEnv, IonBytecodeInfo bytecodeInfo) : templateEnv(templateEnv), bytecodeInfo(bytecodeInfo) {} @@ -867,29 +665,6 @@ } } -void JitScript::initBytecodeTypeMap(JSScript* script) { - MOZ_ASSERT(IsTypeInferenceEnabled()); - MOZ_ASSERT(jit::IsBaselineInterpreterEnabled()); - MOZ_ASSERT(numICEntries() == script->numICEntries()); - - // Index of the next bytecode type map entry to initialize. - uint32_t typeMapIndex = 0; - uint32_t* const typeMap = bytecodeTypeMap(); - - // For JOF_TYPESET ops: initialize bytecode type map entries. - for (BytecodeLocation loc : js::AllBytecodesIterable(script)) { - JSOp op = loc.getOp(); - // Note: if the script is very large there will be more JOF_TYPESET ops - // than bytecode type sets. See JSScript::MaxBytecodeTypeSets. - if (BytecodeOpHasTypeSet(op) && - typeMapIndex < JSScript::MaxBytecodeTypeSets) { - typeMap[typeMapIndex] = loc.bytecodeToOffset(script); - typeMapIndex++; - } - } - MOZ_ASSERT(typeMapIndex == script->numBytecodeTypeSets()); -} - InliningRoot* JitScript::getOrCreateInliningRoot(JSContext* cx, JSScript* script) { if (!inliningRoot_) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitScript.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitScript.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitScript.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitScript.h 2020-11-17 19:31:32.000000000 +0000 @@ -22,16 +22,6 @@ namespace js { namespace jit { -// Describes a single wasm::ImportExit which jumps (via an import with -// the given index) directly to a JitScript. -struct DependentWasmImport { - wasm::Instance* instance; - size_t importIndex; - - DependentWasmImport(wasm::Instance& instance, size_t importIndex) - : instance(&instance), importIndex(importIndex) {} -}; - // Information about a script's bytecode, used by IonBuilder. This is cached // in JitScript. struct IonBytecodeInfo { @@ -215,44 +205,28 @@ // JitScript. Other stubs are stored in the optimized stub space stored in // JitZone and can be purged more eagerly. See JitScript::purgeOptimizedStubs. // -// An ICScript contains a list of IC entries, in the following order: -// -// - Type monitor IC for |this|. -// - Type monitor IC for each formal argument. -// - IC for each JOF_IC bytecode op. +// An ICScript contains a list of IC entries. There's one IC for each JOF_IC +// bytecode op. // // The ICScript also contains the warmUpCount for the script. // -// Type Inference Data -// =================== -// JitScript also contains Type Inference data, most importantly: -// -// * An array of StackTypeSets for type monitoring of |this|, formal arguments, -// JOF_TYPESET ops. These TypeSets record the types we observed and have -// constraints to trigger invalidation of Ion code when the TypeSets change. -// -// * The bytecode type map to map from StackTypeSet index to bytecode offset. -// -// * List of Ion compilations inlining this script, for invalidation. -// -// The StackTypeSet array and bytecode type map are empty when TI is disabled. +// Inlining Data +// ============= +// JitScript also contains a list of Warp compilations inlining this script, for +// invalidation. // // Memory Layout // ============= // JitScript contains an ICScript as the last field. ICScript has a trailing -// (variable length) ICEntry array. Following the ICScript, JitScript has -// several additional trailing arrays. The memory layout is as follows: +// (variable length) ICEntry array. The memory layout is as follows: // // Item | Offset // ------------------------+------------------------ // JitScript | 0 // -->ICScript (field) | // ICEntry[] | icEntriesOffset() -// StackTypeSet[] | typeSetOffset() -// uint32_t[] | bytecodeTypeMapOffset() -// (= bytecode type map) | // -// These offsets are also used to compute numICEntries and numTypeSets. +// These offsets are also used to compute numICEntries. class alignas(uintptr_t) JitScript final : public TrailingArray { friend class ::JSScript; @@ -261,12 +235,9 @@ // Like JSScript::jitCodeRaw_ but when the script has an IonScript this can // point to a separate entry point that skips the argument type checks. + // TODO(no-TI): remove. uint8_t* jitCodeSkipArgCheck_ = nullptr; - // If non-null, the list of wasm::Modules that contain an optimized call - // directly to this script. - js::UniquePtr> dependentWasmImports_; - // Profile string used by the profiler for Baseline Interpreter frames. const char* profileString_ = nullptr; @@ -317,19 +288,9 @@ // IonCompilingScriptPtr or a valid IonScript*. IonScript* ionScript_ = nullptr; - // Offset of the StackTypeSet array. - Offset typeSetOffset_ = 0; - - // Offset of the bytecode type map. - Offset bytecodeTypeMapOffset_ = 0; - // The size of this allocation. Offset endOffset_ = 0; - // This field is used to avoid binary searches for the sought entry when - // bytecode map queries are in linear order. - uint32_t bytecodeTypeMapHint_ = 0; - struct Flags { // Flag set when discarding JIT code to indicate this script is on the stack // and type information and JIT code should not be discarded. @@ -358,17 +319,10 @@ // End of fields. Offset icEntriesOffset() const { return offsetOfICEntries(); } - Offset typeSetOffset() const { return typeSetOffset_; } - Offset bytecodeTypeMapOffset() const { return bytecodeTypeMapOffset_; } Offset endOffset() const { return endOffset_; } ICEntry* icEntries() { return icScript_.icEntries(); } - StackTypeSet* typeArrayDontCheckGeneration() { - MOZ_ASSERT(IsTypeInferenceEnabled()); - return offsetToPointer(typeSetOffset()); - } - uint32_t typesGeneration() const { return uint32_t(flags_.typesGeneration); } void setTypesGeneration(uint32_t generation) { MOZ_ASSERT(generation <= 1); @@ -387,9 +341,7 @@ } public: - JitScript(JSScript* script, Offset typeSetOffset, - Offset bytecodeTypeMapOffset, Offset endOffset, - const char* profileString); + JitScript(JSScript* script, Offset endOffset, const char* profileString); #ifdef DEBUG ~JitScript() { @@ -403,8 +355,6 @@ } #endif - void initBytecodeTypeMap(JSScript* script); - MOZ_MUST_USE bool ensureHasCachedIonData(JSContext* cx, HandleScript script); bool hasFreezeConstraints(const js::AutoSweepJitScript& sweep) const { @@ -445,12 +395,6 @@ } uint32_t numICEntries() const { return icScript_.numICEntries(); } - uint32_t numTypeSets() const { - MOZ_ASSERT(IsTypeInferenceEnabled()); - return numElements(typeSetOffset(), bytecodeTypeMapOffset()); - } - - uint32_t* bytecodeTypeMapHint() { return &bytecodeTypeMapHint_; } bool active() const { return flags_.active; } void setActive() { flags_.active = true; } @@ -463,82 +407,6 @@ return profileString_; } - /* Array of type sets for variables and JOF_TYPESET ops. */ - StackTypeSet* typeArray(const js::AutoSweepJitScript& sweep) { - MOZ_ASSERT(sweep.jitScript() == this); - return typeArrayDontCheckGeneration(); - } - - uint32_t* bytecodeTypeMap() { - MOZ_ASSERT(IsTypeInferenceEnabled()); - return offsetToPointer(bytecodeTypeMapOffset()); - } - - inline StackTypeSet* thisTypes(const AutoSweepJitScript& sweep, - JSScript* script); - inline StackTypeSet* argTypes(const AutoSweepJitScript& sweep, - JSScript* script, unsigned i); - - static size_t NumTypeSets(JSScript* script); - - /* Get the type set for values observed at an opcode. */ - inline StackTypeSet* bytecodeTypes(const AutoSweepJitScript& sweep, - JSScript* script, jsbytecode* pc); - - template - static inline TYPESET* BytecodeTypes(JSScript* script, jsbytecode* pc, - uint32_t* bytecodeMap, uint32_t* hint, - TYPESET* typeArray); - - /* - * Monitor a bytecode pushing any value. This must be called for any opcode - * which is JOF_TYPESET, and where either the script has not been analyzed - * by type inference or where the pc has type barriers. For simplicity, we - * always monitor JOF_TYPESET opcodes in the interpreter and stub calls, - * and only look at barriers when generating JIT code for the script. - */ - static void MonitorBytecodeType(JSContext* cx, JSScript* script, - jsbytecode* pc, const js::Value& val); - static void MonitorBytecodeType(JSContext* cx, JSScript* script, - jsbytecode* pc, TypeSet::Type type); - - static inline void MonitorBytecodeType(JSContext* cx, JSScript* script, - jsbytecode* pc, StackTypeSet* types, - const js::Value& val); - - private: - static void MonitorBytecodeTypeSlow(JSContext* cx, JSScript* script, - jsbytecode* pc, StackTypeSet* types, - TypeSet::Type type); - - static void MonitorMagicValueBytecodeType(JSContext* cx, JSScript* script, - jsbytecode* pc, - const js::Value& rval); - - public: - /* Monitor an assignment at a SETELEM on a non-integer identifier. */ - static inline void MonitorAssign(JSContext* cx, HandleObject obj, jsid id); - - /* Add a type for a variable in a script. */ - static inline void MonitorThisType(JSContext* cx, JSScript* script, - TypeSet::Type type); - static inline void MonitorThisType(JSContext* cx, JSScript* script, - const js::Value& value); - static inline void MonitorArgType(JSContext* cx, JSScript* script, - unsigned arg, TypeSet::Type type); - static inline void MonitorArgType(JSContext* cx, JSScript* script, - unsigned arg, const js::Value& value); - - /* - * Freeze all the stack type sets in a script, for a compilation. Returns - * copies of the type sets which will be checked against the actual ones - * under FinishCompilation, to detect any type changes. - */ - static bool FreezeTypeSets(CompilerConstraintList* constraints, - JSScript* script, TemporaryTypeSet** pThisTypes, - TemporaryTypeSet** pArgTypes, - TemporaryTypeSet** pBytecodeTypes); - static void Destroy(Zone* zone, JitScript* script); static constexpr Offset offsetOfICEntries() { return sizeof(JitScript); } @@ -563,10 +431,6 @@ void incWarmUpCount(uint32_t amount) { icScript_.warmUpCount_ += amount; } void resetWarmUpCount(uint32_t count); -#ifdef DEBUG - void printTypes(JSContext* cx, HandleScript script); -#endif - void prepareForDestruction(Zone* zone) { // When the script contains pointers to nursery things, the store buffer can // contain entries that point into the fallback stub space. Since we can @@ -590,13 +454,6 @@ ICEntry& icEntry(size_t index) { return icScript_.icEntry(index); } - // Used to inform IonBuilder that a getter has been used and we must - // use a type barrier. - void noteAccessedGetter(uint32_t pcOffset); - // Used to inform IonBuilder that a SetElem has written to out-of-bounds - // indices, to determine whether we need a hole check. - void noteHasDenseAdd(uint32_t pcOffset); - void trace(JSTracer* trc); void purgeOptimizedStubs(JSScript* script); @@ -619,12 +476,6 @@ return icScript_.icEntryFromPCOffset(pcOffset, prevLookedUpEntry); } - MOZ_MUST_USE bool addDependentWasmImport(JSContext* cx, - wasm::Instance& instance, - uint32_t idx); - void removeDependentWasmImport(wasm::Instance& instance, uint32_t idx); - void unlinkDependentWasmImports(); - size_t allocBytes() const { return endOffset(); } EnvironmentObject* templateEnvironment() const { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitScript-inl.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitScript-inl.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/JitScript-inl.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/JitScript-inl.h 2020-11-17 19:31:31.000000000 +0000 @@ -20,69 +20,6 @@ namespace js { namespace jit { -inline StackTypeSet* JitScript::thisTypes(const AutoSweepJitScript& sweep, - JSScript* script) { - return typeArray(sweep) + script->numBytecodeTypeSets(); -} - -/* - * Note: for non-escaping arguments, argTypes reflect only the initial type of - * the variable (e.g. passed values for argTypes, or undefined for localTypes) - * and not types from subsequent assignments. - */ - -inline StackTypeSet* JitScript::argTypes(const AutoSweepJitScript& sweep, - JSScript* script, unsigned i) { - MOZ_ASSERT(i < script->function()->nargs()); - return typeArray(sweep) + script->numBytecodeTypeSets() + 1 /* this */ + i; -} - -template -/* static */ inline TYPESET* JitScript::BytecodeTypes(JSScript* script, - jsbytecode* pc, - uint32_t* bytecodeMap, - uint32_t* hint, - TYPESET* typeArray) { - MOZ_ASSERT(BytecodeOpHasTypeSet(JSOp(*pc))); - uint32_t offset = script->pcToOffset(pc); - - // See if this pc is the next typeset opcode after the last one looked up. - size_t numBytecodeTypeSets = script->numBytecodeTypeSets(); - if ((*hint + 1) < numBytecodeTypeSets && bytecodeMap[*hint + 1] == offset) { - (*hint)++; - return typeArray + *hint; - } - - // See if this pc is the same as the last one looked up. - if (bytecodeMap[*hint] == offset) { - return typeArray + *hint; - } - - // Fall back to a binary search. We'll either find the exact offset, or - // there are more JOF_TYPESET opcodes than nTypeSets in the script (as can - // happen if the script is very long) and we'll use the last location. - size_t loc; - bool found = - mozilla::BinarySearch(bytecodeMap, 0, numBytecodeTypeSets, offset, &loc); - if (found) { - MOZ_ASSERT(bytecodeMap[loc] == offset); - } else { - MOZ_ASSERT(numBytecodeTypeSets == JSScript::MaxBytecodeTypeSets); - loc = numBytecodeTypeSets - 1; - } - - *hint = mozilla::AssertedCast(loc); - return typeArray + *hint; -} - -inline StackTypeSet* JitScript::bytecodeTypes(const AutoSweepJitScript& sweep, - JSScript* script, - jsbytecode* pc) { - MOZ_ASSERT(CurrentThreadCanAccessZone(script->zone())); - return BytecodeTypes(script, pc, bytecodeTypeMap(), bytecodeTypeMapHint(), - typeArray(sweep)); -} - inline AutoKeepJitScripts::AutoKeepJitScripts(JSContext* cx) : zone_(cx->zone()->types), prev_(zone_.keepJitScripts) { zone_.keepJitScripts = true; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/Lowering.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/Lowering.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/Lowering.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/Lowering.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -2875,84 +2875,6 @@ } } -void LIRGenerator::visitFilterTypeSet(MFilterTypeSet* ins) { - redefine(ins, ins->input()); -} - -void LIRGenerator::visitTypeBarrier(MTypeBarrier* ins) { - // Requesting a non-GC pointer is safe here since we never re-enter C++ - // from inside a type barrier test. - - const TemporaryTypeSet* types = ins->resultTypeSet(); - - MIRType inputType = ins->getOperand(0)->type(); - MOZ_ASSERT(inputType == ins->type()); - - // Handle typebarrier that will always bail. - // (Emit LBail for visibility). - if (ins->alwaysBails()) { - LBail* bail = new (alloc()) LBail(); - assignSnapshot(bail, ins->bailoutKind()); - add(bail, ins); - redefine(ins, ins->input()); - return; - } - - bool hasSpecificObjects = - !types->unknownObject() && types->getObjectCount() > 0; - - // Handle typebarrier with Value as input. - if (inputType == MIRType::Value) { - LDefinition objTemp = - hasSpecificObjects ? temp() : LDefinition::BogusTemp(); - if (ins->canRedefineInput()) { - LTypeBarrierV* barrier = new (alloc()) - LTypeBarrierV(useBox(ins->input()), tempToUnbox(), objTemp); - assignSnapshot(barrier, ins->bailoutKind()); - add(barrier, ins); - redefine(ins, ins->input()); - } else { - LTypeBarrierV* barrier = new (alloc()) - LTypeBarrierV(useBoxAtStart(ins->input()), tempToUnbox(), objTemp); - assignSnapshot(barrier, ins->bailoutKind()); - defineBoxReuseInput(barrier, ins, 0); - } - return; - } - - // The payload needs to be tested if it either might be null or might have - // an object that should be excluded from the barrier. - bool needsObjectBarrier = false; - if (inputType == MIRType::ObjectOrNull) { - needsObjectBarrier = true; - } - if (inputType == MIRType::Object && - !types->hasType(TypeSet::AnyObjectType()) && - ins->barrierKind() != BarrierKind::TypeTagOnly) { - needsObjectBarrier = true; - } - - if (needsObjectBarrier) { - LDefinition tmp = hasSpecificObjects ? temp() : LDefinition::BogusTemp(); - if (ins->canRedefineInput()) { - LTypeBarrierO* barrier = - new (alloc()) LTypeBarrierO(useRegister(ins->input()), tmp); - assignSnapshot(barrier, ins->bailoutKind()); - add(barrier, ins); - redefine(ins, ins->getOperand(0)); - } else { - LTypeBarrierO* barrier = - new (alloc()) LTypeBarrierO(useRegisterAtStart(ins->input()), tmp); - assignSnapshot(barrier, ins->bailoutKind()); - defineReuseInput(barrier, ins, 0); - } - return; - } - - // Handle remaining cases: No-op, unbox did everything. - redefine(ins, ins->getOperand(0)); -} - // Returns true iff |def| is a constant that's either not a GC thing or is not // allocated in the nursery. static bool IsNonNurseryConstant(MDefinition* def) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/MCallOptimize.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/MCallOptimize.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/MCallOptimize.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/MCallOptimize.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,4103 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/Casting.h" - -#include "jsmath.h" - -#include "builtin/AtomicsObject.h" -#include "builtin/DataViewObject.h" -#include "builtin/MapObject.h" -#include "builtin/String.h" -#include "builtin/TestingFunctions.h" -#include "jit/BaselineInspector.h" -#include "jit/InlinableNatives.h" -#include "jit/IonBuilder.h" -#include "jit/JitRealm.h" -#include "jit/Lowering.h" -#include "jit/MIR.h" -#include "jit/MIRGraph.h" -#include "js/experimental/JitInfo.h" // JSJitInfo -#include "js/RegExpFlags.h" // JS::RegExpFlag, JS::RegExpFlags -#include "js/ScalarType.h" // js::Scalar::Type -#include "vm/ArgumentsObject.h" -#include "vm/ArrayBufferObject.h" -#include "vm/JSObject.h" -#include "vm/PlainObject.h" // js::PlainObject -#include "vm/ProxyObject.h" -#include "vm/SelfHosting.h" -#include "vm/SharedArrayObject.h" -#include "vm/TypedArrayObject.h" -#include "wasm/WasmInstance.h" - -#include "jit/shared/Lowering-shared-inl.h" -#include "vm/JSScript-inl.h" -#include "vm/NativeObject-inl.h" -#include "vm/StringObject-inl.h" - -using mozilla::ArrayLength; -using mozilla::AssertedCast; -using mozilla::Maybe; - -using JS::RegExpFlag; -using JS::RegExpFlags; - -namespace js { -namespace jit { - -IonBuilder::InliningResult IonBuilder::inlineNativeCall(CallInfo& callInfo, - JSFunction* target) { - MOZ_ASSERT(target->isNative()); - - if (!optimizationInfo().inlineNative()) { - return InliningStatus_NotInlined; - } - - bool isWasmCall = target->isWasmWithJitEntry(); - if (!isWasmCall && - (!target->hasJitInfo() || - target->jitInfo()->type() != JSJitInfo::InlinableNative)) { - // Reaching here means we tried to inline a native for which there is no - // Ion specialization. - return InliningStatus_NotInlined; - } - - // Don't inline if we're constructing and new.target != callee. This can - // happen with Reflect.construct or derived class constructors. - if (callInfo.constructing() && callInfo.getNewTarget() != callInfo.callee()) { - return InliningStatus_NotInlined; - } - - if (shouldAbortOnPreliminaryGroups(callInfo.thisArg())) { - return InliningStatus_NotInlined; - } - for (size_t i = 0; i < callInfo.argc(); i++) { - if (shouldAbortOnPreliminaryGroups(callInfo.getArg(i))) { - return InliningStatus_NotInlined; - } - } - - if (isWasmCall) { - return inlineWasmCall(callInfo, target); - } - - InlinableNative inlNative = target->jitInfo()->inlinableNative; - - if (target->realm() != script()->realm() && - !CanInlineNativeCrossRealm(inlNative)) { - return InliningStatus_NotInlined; - } - - switch (inlNative) { - // Array natives. - case InlinableNative::Array: - return inlineArray(callInfo, target->realm()); - case InlinableNative::ArrayIsArray: - return inlineArrayIsArray(callInfo); - case InlinableNative::ArrayJoin: - return inlineArrayJoin(callInfo); - case InlinableNative::ArrayPop: - return inlineArrayPopShift(callInfo, MArrayPopShift::Pop); - case InlinableNative::ArrayShift: - return inlineArrayPopShift(callInfo, MArrayPopShift::Shift); - case InlinableNative::ArrayPush: - return inlineArrayPush(callInfo); - case InlinableNative::ArraySlice: - return inlineArraySlice(callInfo); - - // Array intrinsics. - case InlinableNative::IntrinsicNewArrayIterator: - return inlineNewIterator(callInfo, MNewIterator::ArrayIterator); - case InlinableNative::IntrinsicArrayIteratorPrototypeOptimizable: - return inlineArrayIteratorPrototypeOptimizable(callInfo); - - // Atomic natives. - case InlinableNative::AtomicsCompareExchange: - return inlineAtomicsCompareExchange(callInfo); - case InlinableNative::AtomicsExchange: - return inlineAtomicsExchange(callInfo); - case InlinableNative::AtomicsLoad: - return inlineAtomicsLoad(callInfo); - case InlinableNative::AtomicsStore: - return inlineAtomicsStore(callInfo); - case InlinableNative::AtomicsAdd: - case InlinableNative::AtomicsSub: - case InlinableNative::AtomicsAnd: - case InlinableNative::AtomicsOr: - case InlinableNative::AtomicsXor: - return inlineAtomicsBinop(callInfo, inlNative); - case InlinableNative::AtomicsIsLockFree: - return inlineAtomicsIsLockFree(callInfo); - - // Boolean natives. - case InlinableNative::Boolean: - return inlineBoolean(callInfo); - - // DataView natives. - case InlinableNative::DataViewGetInt8: - return inlineDataViewGet(callInfo, Scalar::Int8); - case InlinableNative::DataViewGetUint8: - return inlineDataViewGet(callInfo, Scalar::Uint8); - case InlinableNative::DataViewGetInt16: - return inlineDataViewGet(callInfo, Scalar::Int16); - case InlinableNative::DataViewGetUint16: - return inlineDataViewGet(callInfo, Scalar::Uint16); - case InlinableNative::DataViewGetInt32: - return inlineDataViewGet(callInfo, Scalar::Int32); - case InlinableNative::DataViewGetUint32: - return inlineDataViewGet(callInfo, Scalar::Uint32); - case InlinableNative::DataViewGetFloat32: - return inlineDataViewGet(callInfo, Scalar::Float32); - case InlinableNative::DataViewGetFloat64: - return inlineDataViewGet(callInfo, Scalar::Float64); - case InlinableNative::DataViewGetBigInt64: - return inlineDataViewGet(callInfo, Scalar::BigInt64); - case InlinableNative::DataViewGetBigUint64: - return inlineDataViewGet(callInfo, Scalar::BigUint64); - case InlinableNative::DataViewSetInt8: - return inlineDataViewSet(callInfo, Scalar::Int8); - case InlinableNative::DataViewSetUint8: - return inlineDataViewSet(callInfo, Scalar::Uint8); - case InlinableNative::DataViewSetInt16: - return inlineDataViewSet(callInfo, Scalar::Int16); - case InlinableNative::DataViewSetUint16: - return inlineDataViewSet(callInfo, Scalar::Uint16); - case InlinableNative::DataViewSetInt32: - return inlineDataViewSet(callInfo, Scalar::Int32); - case InlinableNative::DataViewSetUint32: - return inlineDataViewSet(callInfo, Scalar::Uint32); - case InlinableNative::DataViewSetFloat32: - return inlineDataViewSet(callInfo, Scalar::Float32); - case InlinableNative::DataViewSetFloat64: - return inlineDataViewSet(callInfo, Scalar::Float64); - case InlinableNative::DataViewSetBigInt64: - return inlineDataViewSet(callInfo, Scalar::BigInt64); - case InlinableNative::DataViewSetBigUint64: - return inlineDataViewSet(callInfo, Scalar::BigUint64); - -#ifdef JS_HAS_INTL_API - // Intl natives. - case InlinableNative::IntlGuardToCollator: - case InlinableNative::IntlGuardToDateTimeFormat: - case InlinableNative::IntlGuardToDisplayNames: - case InlinableNative::IntlGuardToListFormat: - case InlinableNative::IntlGuardToNumberFormat: - case InlinableNative::IntlGuardToPluralRules: - case InlinableNative::IntlGuardToRelativeTimeFormat: - return inlineGuardToClass(callInfo, inlNative); -#else - case InlinableNative::IntlGuardToCollator: - case InlinableNative::IntlGuardToDateTimeFormat: - case InlinableNative::IntlGuardToDisplayNames: - case InlinableNative::IntlGuardToListFormat: - case InlinableNative::IntlGuardToNumberFormat: - case InlinableNative::IntlGuardToPluralRules: - case InlinableNative::IntlGuardToRelativeTimeFormat: - MOZ_CRASH("Intl API disabled"); -#endif - - // Math natives. - case InlinableNative::MathAbs: - return inlineMathAbs(callInfo); - case InlinableNative::MathFloor: - return inlineMathFloor(callInfo); - case InlinableNative::MathCeil: - return inlineMathCeil(callInfo); - case InlinableNative::MathRound: - return inlineMathRound(callInfo); - case InlinableNative::MathClz32: - return inlineMathClz32(callInfo); - case InlinableNative::MathSqrt: - return inlineMathSqrt(callInfo); - case InlinableNative::MathATan2: - return inlineMathAtan2(callInfo); - case InlinableNative::MathHypot: - return inlineMathHypot(callInfo); - case InlinableNative::MathMax: - return inlineMathMinMax(callInfo, true /* max */); - case InlinableNative::MathMin: - return inlineMathMinMax(callInfo, false /* max */); - case InlinableNative::MathPow: - return inlineMathPow(callInfo); - case InlinableNative::MathRandom: - return inlineMathRandom(callInfo); - case InlinableNative::MathImul: - return inlineMathImul(callInfo); - case InlinableNative::MathFRound: - return inlineMathFRound(callInfo); - case InlinableNative::MathTrunc: - return inlineMathTrunc(callInfo); - case InlinableNative::MathSign: - return inlineMathSign(callInfo); - case InlinableNative::MathSin: - return inlineMathFunction(callInfo, UnaryMathFunction::Sin); - case InlinableNative::MathTan: - return inlineMathFunction(callInfo, UnaryMathFunction::Tan); - case InlinableNative::MathCos: - return inlineMathFunction(callInfo, UnaryMathFunction::Cos); - case InlinableNative::MathExp: - return inlineMathFunction(callInfo, UnaryMathFunction::Exp); - case InlinableNative::MathLog: - return inlineMathFunction(callInfo, UnaryMathFunction::Log); - case InlinableNative::MathASin: - return inlineMathFunction(callInfo, UnaryMathFunction::ASin); - case InlinableNative::MathATan: - return inlineMathFunction(callInfo, UnaryMathFunction::ATan); - case InlinableNative::MathACos: - return inlineMathFunction(callInfo, UnaryMathFunction::ACos); - case InlinableNative::MathLog10: - return inlineMathFunction(callInfo, UnaryMathFunction::Log10); - case InlinableNative::MathLog2: - return inlineMathFunction(callInfo, UnaryMathFunction::Log2); - case InlinableNative::MathLog1P: - return inlineMathFunction(callInfo, UnaryMathFunction::Log1P); - case InlinableNative::MathExpM1: - return inlineMathFunction(callInfo, UnaryMathFunction::ExpM1); - case InlinableNative::MathCosH: - return inlineMathFunction(callInfo, UnaryMathFunction::CosH); - case InlinableNative::MathSinH: - return inlineMathFunction(callInfo, UnaryMathFunction::SinH); - case InlinableNative::MathTanH: - return inlineMathFunction(callInfo, UnaryMathFunction::TanH); - case InlinableNative::MathACosH: - return inlineMathFunction(callInfo, UnaryMathFunction::ACosH); - case InlinableNative::MathASinH: - return inlineMathFunction(callInfo, UnaryMathFunction::ASinH); - case InlinableNative::MathATanH: - return inlineMathFunction(callInfo, UnaryMathFunction::ATanH); - case InlinableNative::MathCbrt: - return inlineMathFunction(callInfo, UnaryMathFunction::Cbrt); - - // Reflect natives. - case InlinableNative::ReflectGetPrototypeOf: - return inlineReflectGetPrototypeOf(callInfo); - - // RegExp natives. - case InlinableNative::RegExpMatcher: - return inlineRegExpMatcher(callInfo); - case InlinableNative::RegExpSearcher: - return inlineRegExpSearcher(callInfo); - case InlinableNative::RegExpTester: - return inlineRegExpTester(callInfo); - case InlinableNative::IsRegExpObject: - return inlineIsRegExpObject(callInfo); - case InlinableNative::IsPossiblyWrappedRegExpObject: - return inlineIsPossiblyWrappedRegExpObject(callInfo); - case InlinableNative::RegExpPrototypeOptimizable: - return inlineRegExpPrototypeOptimizable(callInfo); - case InlinableNative::RegExpInstanceOptimizable: - return inlineRegExpInstanceOptimizable(callInfo); - case InlinableNative::GetFirstDollarIndex: - return inlineGetFirstDollarIndex(callInfo); - case InlinableNative::IntrinsicNewRegExpStringIterator: - return inlineNewIterator(callInfo, MNewIterator::RegExpStringIterator); - - // String natives. - case InlinableNative::String: - return inlineStringObject(callInfo); - case InlinableNative::StringCharCodeAt: - return inlineStrCharCodeAt(callInfo); - case InlinableNative::StringFromCharCode: - return inlineStrFromCharCode(callInfo); - case InlinableNative::StringFromCodePoint: - return inlineStrFromCodePoint(callInfo); - case InlinableNative::StringCharAt: - return inlineStrCharAt(callInfo); - case InlinableNative::StringToLowerCase: - return inlineStringConvertCase(callInfo, MStringConvertCase::LowerCase); - case InlinableNative::StringToUpperCase: - return inlineStringConvertCase(callInfo, MStringConvertCase::UpperCase); - - // String intrinsics. - case InlinableNative::IntrinsicStringReplaceString: - return inlineStringReplaceString(callInfo); - case InlinableNative::IntrinsicStringSplitString: - return inlineStringSplitString(callInfo); - case InlinableNative::IntrinsicNewStringIterator: - return inlineNewIterator(callInfo, MNewIterator::StringIterator); - - // Object natives. - case InlinableNative::Object: - return inlineObject(callInfo); - case InlinableNative::ObjectCreate: - return inlineObjectCreate(callInfo); - case InlinableNative::ObjectIs: - return inlineObjectIs(callInfo); - case InlinableNative::ObjectIsPrototypeOf: - return inlineObjectIsPrototypeOf(callInfo); - case InlinableNative::ObjectToString: - return inlineObjectToString(callInfo); - - // Testing functions. - case InlinableNative::TestBailout: - return inlineBailout(callInfo); - case InlinableNative::TestAssertFloat32: - return inlineAssertFloat32(callInfo); - case InlinableNative::TestAssertRecoveredOnBailout: - return inlineAssertRecoveredOnBailout(callInfo); - - // Slot intrinsics. - case InlinableNative::IntrinsicUnsafeSetReservedSlot: - return inlineUnsafeSetReservedSlot(callInfo); - case InlinableNative::IntrinsicUnsafeGetReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType::Value); - case InlinableNative::IntrinsicUnsafeGetObjectFromReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType::Object); - case InlinableNative::IntrinsicUnsafeGetInt32FromReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType::Int32); - case InlinableNative::IntrinsicUnsafeGetStringFromReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType::String); - case InlinableNative::IntrinsicUnsafeGetBooleanFromReservedSlot: - return inlineUnsafeGetReservedSlot(callInfo, MIRType::Boolean); - - // Utility intrinsics. - case InlinableNative::IntrinsicIsCallable: - return inlineIsCallable(callInfo); - case InlinableNative::IntrinsicIsConstructor: - return inlineIsConstructor(callInfo); - case InlinableNative::IntrinsicToObject: - return inlineToObject(callInfo); - case InlinableNative::IntrinsicIsObject: - return inlineIsObject(callInfo); - case InlinableNative::IntrinsicIsCrossRealmArrayConstructor: - return inlineIsCrossRealmArrayConstructor(callInfo); - case InlinableNative::IntrinsicToInteger: - return inlineToInteger(callInfo); - case InlinableNative::IntrinsicToLength: - return inlineToLength(callInfo); - case InlinableNative::IntrinsicIsConstructing: - return inlineIsConstructing(callInfo); - case InlinableNative::IntrinsicSubstringKernel: - return inlineSubstringKernel(callInfo); - case InlinableNative::IntrinsicGuardToArrayIterator: - case InlinableNative::IntrinsicGuardToMapIterator: - case InlinableNative::IntrinsicGuardToSetIterator: - case InlinableNative::IntrinsicGuardToStringIterator: - case InlinableNative::IntrinsicGuardToRegExpStringIterator: - case InlinableNative::IntrinsicGuardToWrapForValidIterator: - case InlinableNative::IntrinsicGuardToIteratorHelper: - case InlinableNative::IntrinsicGuardToAsyncIteratorHelper: - return inlineGuardToClass(callInfo, inlNative); - case InlinableNative::IntrinsicObjectHasPrototype: - return inlineObjectHasPrototype(callInfo); - case InlinableNative::IntrinsicFinishBoundFunctionInit: - return inlineFinishBoundFunctionInit(callInfo); - case InlinableNative::IntrinsicIsPackedArray: - return inlineIsPackedArray(callInfo); - - // Map intrinsics. - case InlinableNative::IntrinsicGuardToMapObject: - return inlineGuardToClass(callInfo, inlNative); - case InlinableNative::IntrinsicGetNextMapEntryForIterator: - return inlineGetNextEntryForIterator(callInfo, - MGetNextEntryForIterator::Map); - - // Set intrinsics. - case InlinableNative::IntrinsicGuardToSetObject: - return inlineGuardToClass(callInfo, inlNative); - case InlinableNative::IntrinsicGetNextSetEntryForIterator: - return inlineGetNextEntryForIterator(callInfo, - MGetNextEntryForIterator::Set); - - // ArrayBuffer intrinsics. - case InlinableNative::IntrinsicGuardToArrayBuffer: - return inlineGuardToClass(callInfo, inlNative); - case InlinableNative::IntrinsicArrayBufferByteLength: - return inlineArrayBufferByteLength(callInfo); - case InlinableNative::IntrinsicPossiblyWrappedArrayBufferByteLength: - return inlinePossiblyWrappedArrayBufferByteLength(callInfo); - - // SharedArrayBuffer intrinsics. - case InlinableNative::IntrinsicGuardToSharedArrayBuffer: - return inlineGuardToClass(callInfo, inlNative); - - // TypedArray intrinsics. - case InlinableNative::TypedArrayConstructor: - return inlineTypedArray(callInfo, target->native()); - case InlinableNative::IntrinsicIsTypedArrayConstructor: - return inlineIsTypedArrayConstructor(callInfo); - case InlinableNative::IntrinsicIsTypedArray: - return inlineIsTypedArray(callInfo); - case InlinableNative::IntrinsicIsPossiblyWrappedTypedArray: - return inlineIsPossiblyWrappedTypedArray(callInfo); - case InlinableNative::IntrinsicPossiblyWrappedTypedArrayLength: - return inlinePossiblyWrappedTypedArrayLength(callInfo); - case InlinableNative::IntrinsicTypedArrayLength: - return inlineTypedArrayLength(callInfo); - case InlinableNative::IntrinsicTypedArrayByteOffset: - return inlineTypedArrayByteOffset(callInfo); - case InlinableNative::IntrinsicTypedArrayElementShift: - return inlineTypedArrayElementShift(callInfo); - - case InlinableNative::NumberToString: - case InlinableNative::StringToString: - case InlinableNative::StringValueOf: - case InlinableNative::IntrinsicIsSuspendedGenerator: - // Not supported in Ion. - return InliningStatus_NotInlined; - - case InlinableNative::Limit: - break; - } - - MOZ_CRASH("Shouldn't get here"); -} - -IonBuilder::InliningResult IonBuilder::inlineNativeGetter(CallInfo& callInfo, - JSFunction* target) { - MOZ_ASSERT(target->isNative()); - JSNative native = target->native(); - - if (!optimizationInfo().inlineNative()) { - return InliningStatus_NotInlined; - } - - MDefinition* thisArg = callInfo.thisArg(); - TemporaryTypeSet* thisTypes = thisArg->resultTypeSet(); - MOZ_ASSERT(callInfo.argc() == 0); - - if (!thisTypes) { - return InliningStatus_NotInlined; - } - - // Note: target might be a cross-realm native! - - // Try to optimize typed array lengths. - if (TypedArrayObject::isOriginalLengthGetter(native)) { - if (thisTypes->forAllClasses(constraints(), IsTypedArrayClass) != - TemporaryTypeSet::ForAllResult::ALL_TRUE) { - return InliningStatus_NotInlined; - } - - MInstruction* length = addTypedArrayLength(thisArg); - current->push(length); - return InliningStatus_Inlined; - } - - // Try to optimize typed array byteOffsets. - if (TypedArrayObject::isOriginalByteOffsetGetter(native)) { - if (thisTypes->forAllClasses(constraints(), IsTypedArrayClass) != - TemporaryTypeSet::ForAllResult::ALL_TRUE) { - return InliningStatus_NotInlined; - } - - MInstruction* byteOffset = addTypedArrayByteOffset(thisArg); - current->push(byteOffset); - return InliningStatus_Inlined; - } - - // Try to optimize DataView byteLengths. - if (DataViewObject::isOriginalByteLengthGetter(native)) { - const JSClass* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &DataViewObject::class_) { - return InliningStatus_NotInlined; - } - - auto* length = MArrayBufferViewLength::New(alloc(), thisArg); - current->add(length); - current->push(length); - return InliningStatus_Inlined; - } - - // Try to optimize DataView byteOffsets. - if (DataViewObject::isOriginalByteOffsetGetter(native)) { - const JSClass* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &DataViewObject::class_) { - return InliningStatus_NotInlined; - } - - auto* byteOffset = MArrayBufferViewByteOffset::New(alloc(), thisArg); - current->add(byteOffset); - current->push(byteOffset); - return InliningStatus_Inlined; - } - - // Try to optimize RegExp getters. - RegExpFlags mask = RegExpFlag::NoFlags; - if (RegExpObject::isOriginalFlagGetter(native, &mask)) { - const JSClass* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &RegExpObject::class_) { - return InliningStatus_NotInlined; - } - - MLoadFixedSlot* flags = - MLoadFixedSlot::New(alloc(), thisArg, RegExpObject::flagsSlot()); - current->add(flags); - flags->setResultType(MIRType::Int32); - MConstant* maskConst = MConstant::New(alloc(), Int32Value(mask.value())); - current->add(maskConst); - auto* maskedFlag = MBitAnd::New(alloc(), flags, maskConst, MIRType::Int32); - current->add(maskedFlag); - - MDefinition* result = convertToBoolean(maskedFlag); - current->push(result); - return InliningStatus_Inlined; - } - - return InliningStatus_NotInlined; -} - -TemporaryTypeSet* IonBuilder::getInlineReturnTypeSet() { - return bytecodeTypes(pc); -} - -MIRType IonBuilder::getInlineReturnType() { - TemporaryTypeSet* returnTypes = getInlineReturnTypeSet(); - return returnTypes->getKnownMIRType(); -} - -IonBuilder::InliningResult IonBuilder::inlineMathFunction( - CallInfo& callInfo, UnaryMathFunction function) { - if (callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (callInfo.argc() != 1) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Double) { - return InliningStatus_NotInlined; - } - if (!IsNumberType(callInfo.getArg(0)->type())) { - return InliningStatus_NotInlined; - } - - callInfo.callee()->setImplicitlyUsedUnchecked(); - callInfo.thisArg()->setImplicitlyUsedUnchecked(); - - MMathFunction* ins = - MMathFunction::New(alloc(), callInfo.getArg(0), function); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineArray(CallInfo& callInfo, - Realm* targetRealm) { - uint32_t initLength = 0; - - JSObject* templateObject = - inspector->getTemplateObjectForNative(pc, ArrayConstructor); - // This is shared by ArrayConstructor and array_construct (std_Array). - if (!templateObject) { - templateObject = inspector->getTemplateObjectForNative(pc, array_construct); - } - - if (!templateObject) { - return InliningStatus_NotInlined; - } - - if (templateObject->nonCCWRealm() != targetRealm) { - return InliningStatus_NotInlined; - } - - // Multiple arguments imply array initialization, not just construction. - if (callInfo.argc() >= 2) { - initLength = callInfo.argc(); - - TypeSet::ObjectKey* key = TypeSet::ObjectKey::get(templateObject); - if (!key->unknownProperties()) { - HeapTypeSetKey elemTypes = key->property(JSID_VOID); - - for (uint32_t i = 0; i < initLength; i++) { - MDefinition* value = callInfo.getArg(i); - if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), - value->resultTypeSet())) { - elemTypes.freeze(constraints()); - return InliningStatus_NotInlined; - } - } - } - } - - // A single integer argument denotes initial length. - if (callInfo.argc() == 1) { - MDefinition* arg = callInfo.getArg(0); - if (arg->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - if (!arg->isConstant()) { - callInfo.setImplicitlyUsedUnchecked(); - MNewArrayDynamicLength* ins = MNewArrayDynamicLength::New( - alloc(), constraints(), templateObject, - templateObject->group()->initialHeap(constraints()), arg); - current->add(ins); - current->push(ins); - - // This may throw, so we need a resume point. - MOZ_TRY(resumeAfter(ins)); - - return InliningStatus_Inlined; - } - - // Negative lengths generate a RangeError, unhandled by the inline path. - initLength = arg->toConstant()->toInt32(); - if (initLength > NativeObject::MAX_DENSE_ELEMENTS_COUNT) { - return InliningStatus_NotInlined; - } - MOZ_ASSERT(initLength <= INT32_MAX); - - // Make sure initLength matches the template object's length. This is - // not guaranteed to be the case, for instance if we're inlining the - // MConstant may come from an outer script. - if (initLength != templateObject->as().length()) { - return InliningStatus_NotInlined; - } - - // Don't inline large allocations. - if (initLength > ArrayObject::EagerAllocationMaxLength) { - return InliningStatus_NotInlined; - } - } - - callInfo.setImplicitlyUsedUnchecked(); - - MOZ_TRY(jsop_newarray(templateObject, initLength)); - - MNewArray* array = current->peek(-1)->toNewArray(); - if (callInfo.argc() >= 2) { - for (uint32_t i = 0; i < initLength; i++) { - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - MDefinition* value = callInfo.getArg(i); - - MConstant* id = MConstant::New(alloc(), Int32Value(i)); - current->add(id); - - MOZ_TRY(initArrayElementFastPath(array, id, value, - /* addResumePoint = */ false)); - } - - MInstruction* setLength = setInitializedLength(array, initLength); - MOZ_TRY(resumeAfter(setLength)); - } - - return InliningStatus_Inlined; -} - -static bool IsArrayClass(const JSClass* clasp) { - return clasp == &ArrayObject::class_; -} - -IonBuilder::InliningResult IonBuilder::inlineArrayIsArray(CallInfo& callInfo) { - if (callInfo.constructing() || callInfo.argc() != 1) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.getArg(0); - - if (!arg->mightBeType(MIRType::Object)) { - pushConstant(BooleanValue(false)); - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; - } - - using ForAllResult = TemporaryTypeSet::ForAllResult; - - TemporaryTypeSet* types = arg->resultTypeSet(); - - // Fast path for non-proxy objects. - if (arg->type() == MIRType::Object && types && - types->forAllClasses(constraints(), IsProxyClass) == - ForAllResult::ALL_FALSE) { - // Definitely not a proxy. Now check for the array classes. - ForAllResult result = types->forAllClasses(constraints(), IsArrayClass); - - if (result == ForAllResult::ALL_FALSE || result == ForAllResult::ALL_TRUE) { - // Definitely an array or definitely not an array, so we can - // constant fold. - pushConstant(BooleanValue(result == ForAllResult::ALL_TRUE)); - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; - } - - // We have some array classes and some non-array classes, so we have to - // check at runtime. - MOZ_ASSERT(result == ForAllResult::MIXED); - - MHasClass* hasClass = MHasClass::New(alloc(), arg, &ArrayObject::class_); - current->add(hasClass); - current->push(hasClass); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; - } - - // The value might be a primitive or a proxy. MIsArray handles these cases. - MIsArray* isArray = MIsArray::New(alloc(), arg); - current->add(isArray); - current->push(isArray); - - MOZ_TRY(resumeAfter(isArray)); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineArrayPopShift( - CallInfo& callInfo, MArrayPopShift::Mode mode) { - if (callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType returnType = getInlineReturnType(); - if (returnType == MIRType::Undefined || returnType == MIRType::Null) { - return InliningStatus_NotInlined; - } - if (callInfo.thisArg()->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - // Pop and shift are only handled for dense arrays that have never been - // used in an iterator: popping elements does not account for suppressing - // deleted properties in active iterators. - // Don't optimize shift if the array may be non-extensible (this matters - // when there are holes). Don't optimize pop if the array may be - // non-extensible, so we don't need to adjust the capacity for - // non-extensible arrays (non-extensible objects always have a capacity - // equal to their initialized length). We check this here because there's - // no non-extensible ObjectElements flag so we would need an extra guard - // on the BaseShape flags. - ObjectGroupFlags unhandledFlags = - OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW | - OBJECT_FLAG_ITERATED | OBJECT_FLAG_NON_EXTENSIBLE_ELEMENTS; - - MDefinition* obj = callInfo.thisArg(); - TemporaryTypeSet* thisTypes = obj->resultTypeSet(); - if (!thisTypes) { - return InliningStatus_NotInlined; - } - const JSClass* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_) { - return InliningStatus_NotInlined; - } - if (thisTypes->hasObjectFlags(constraints(), unhandledFlags)) { - return InliningStatus_NotInlined; - } - - // Watch out for extra indexed properties on the object or its prototype. - bool hasIndexedProperty; - MOZ_TRY_VAR(hasIndexedProperty, - ElementAccessHasExtraIndexedProperty(this, obj)); - if (hasIndexedProperty) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); - - TemporaryTypeSet* returnTypes = getInlineReturnTypeSet(); - bool needsHoleCheck = - thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_NON_PACKED); - bool maybeUndefined = returnTypes->hasType(TypeSet::UndefinedType()); - - BarrierKind barrier = PropertyReadNeedsTypeBarrier( - analysisContext, alloc(), constraints(), obj, nullptr, returnTypes); - if (barrier != BarrierKind::NoBarrier) { - returnType = MIRType::Value; - } - - MArrayPopShift* ins = - MArrayPopShift::New(alloc(), obj, mode, needsHoleCheck, maybeUndefined); - current->add(ins); - current->push(ins); - ins->setResultType(returnType); - - MOZ_TRY(resumeAfter(ins)); - MOZ_TRY(pushTypeBarrier(ins, returnTypes, barrier)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineArrayJoin(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::String) { - return InliningStatus_NotInlined; - } - if (callInfo.thisArg()->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (callInfo.getArg(0)->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - - // If we can confirm that the class is an array, the codegen - // for MArrayJoin can be notified to check for common empty and one-item - // arrays. - bool optimizeForArray = ([&]() { - TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet(); - if (!thisTypes) { - return false; - } - - const JSClass* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_) { - return false; - } - - return true; - })(); - - callInfo.setImplicitlyUsedUnchecked(); - - MArrayJoin* ins = MArrayJoin::New(alloc(), callInfo.thisArg(), - callInfo.getArg(0), optimizeForArray); - - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineArrayPush(CallInfo& callInfo) { - const uint32_t inlineArgsLimit = 10; - if (callInfo.argc() < 1 || callInfo.argc() > inlineArgsLimit || - callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - // XXX bug 1493903. - if (callInfo.argc() != 1) { - return InliningStatus_NotInlined; - } - - MDefinition* obj = callInfo.thisArg(); - for (uint32_t i = 0; i < callInfo.argc(); i++) { - MDefinition* value = callInfo.getArg(i); - if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, - nullptr, &value, - /* canModify = */ false)) { - return InliningStatus_NotInlined; - } - } - - if (getInlineReturnType() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - if (obj->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* thisTypes = obj->resultTypeSet(); - if (!thisTypes) { - return InliningStatus_NotInlined; - } - const JSClass* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_) { - return InliningStatus_NotInlined; - } - - bool hasIndexedProperty; - MOZ_TRY_VAR(hasIndexedProperty, - ElementAccessHasExtraIndexedProperty(this, obj)); - if (hasIndexedProperty) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet::DoubleConversion conversion = - thisTypes->convertDoubleElements(constraints()); - if (conversion == TemporaryTypeSet::AmbiguousDoubleConversion) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - bool toDouble = conversion == TemporaryTypeSet::AlwaysConvertToDoubles || - conversion == TemporaryTypeSet::MaybeConvertToDoubles; - - obj = addMaybeCopyElementsForWrite(obj, /* checkNative = */ false); - - // If we have more than one argument, we are splitting the function into - // multiple inlined calls to Array.push. - // - // Still, in case of bailouts, we have to keep the atomicity of the call, as - // we cannot resume within Array.push function. To do so, we register a - // resume point which would be captured by the upcoming MArrayPush - // instructions, and this resume point contains an instruction which - // truncates the length of the Array, to its original length in case of - // bailouts, and resume before the Array.push call. - MResumePoint* lastRp = nullptr; - MInstruction* truncate = nullptr; - if (callInfo.argc() > 1) { - MInstruction* elements = MElements::New(alloc(), obj); - MInstruction* length = MArrayLength::New(alloc(), elements); - truncate = MSetArrayLength::New(alloc(), obj, length); - truncate->setRecoveredOnBailout(); - - current->add(elements); - current->add(length); - current->add(truncate); - - // Restore the stack, such that resume points are created with the stack - // as it was before the call. - if (!callInfo.pushPriorCallStack(current)) { - return abort(AbortReason::Alloc); - } - } - - MInstruction* ins = nullptr; - for (uint32_t i = 0; i < callInfo.argc(); i++) { - MDefinition* value = callInfo.getArg(i); - if (toDouble) { - MInstruction* valueDouble = MToDouble::New(alloc(), value); - current->add(valueDouble); - value = valueDouble; - } - - if (needsPostBarrier(value)) { - MInstruction* elements = MElements::New(alloc(), obj); - current->add(elements); - MInstruction* initLength = MInitializedLength::New(alloc(), elements); - current->add(initLength); - current->add( - MPostWriteElementBarrier::New(alloc(), obj, value, initLength)); - } - - ins = MArrayPush::New(alloc(), obj, value); - current->add(ins); - - if (callInfo.argc() > 1) { - // Restore that call stack and the array length. - MOZ_TRY(resumeAt(ins, pc)); - ins->resumePoint()->addStore(alloc(), truncate, lastRp); - lastRp = ins->resumePoint(); - } - } - - if (callInfo.argc() > 1) { - // Fix the stack to represent the state after the call execution. - callInfo.popPriorCallStack(current); - } - current->push(ins); - - if (callInfo.argc() > 1) { - ins = MNop::New(alloc()); - current->add(ins); - } - - MOZ_TRY(resumeAfter(ins)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineArraySlice(CallInfo& callInfo) { - if (callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MDefinition* obj = callInfo.thisArg(); - - // Ensure |this| and result are objects. - if (getInlineReturnType() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (obj->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - // Arguments for the sliced region must be integers. - if (callInfo.argc() > 0) { - if (callInfo.getArg(0)->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - if (callInfo.argc() > 1) { - if (callInfo.getArg(1)->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - } - } - - // |this| must be a dense array. - TemporaryTypeSet* thisTypes = obj->resultTypeSet(); - if (!thisTypes) { - return InliningStatus_NotInlined; - } - - const JSClass* clasp = thisTypes->getKnownClass(constraints()); - if (clasp != &ArrayObject::class_) { - return InliningStatus_NotInlined; - } - - // Watch out for extra indexed properties on the object or its prototype. - bool hasIndexedProperty; - MOZ_TRY_VAR(hasIndexedProperty, - ElementAccessHasExtraIndexedProperty(this, obj)); - if (hasIndexedProperty) { - return InliningStatus_NotInlined; - } - - // The group of the result will be dynamically fixed up to match the input - // object, allowing us to handle 'this' objects that might have more than - // one group. Make sure that no singletons can be sliced here. - for (unsigned i = 0; i < thisTypes->getObjectCount(); i++) { - TypeSet::ObjectKey* key = thisTypes->getObject(i); - if (key && key->isSingleton()) { - return InliningStatus_NotInlined; - } - } - - // Inline the call. - JSObject* templateObj = - inspector->getTemplateObjectForNative(pc, js::array_slice); - if (!templateObj) { - return InliningStatus_NotInlined; - } - - if (!templateObj->is()) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MDefinition* begin; - if (callInfo.argc() > 0) { - begin = callInfo.getArg(0); - } else { - begin = constant(Int32Value(0)); - } - - MDefinition* end; - if (callInfo.argc() > 1) { - end = callInfo.getArg(1); - } else if (clasp == &ArrayObject::class_) { - MElements* elements = MElements::New(alloc(), obj); - current->add(elements); - - end = MArrayLength::New(alloc(), elements); - current->add(end->toInstruction()); - } - - MArraySlice* ins = - MArraySlice::New(alloc(), obj, begin, end, templateObj, - templateObj->group()->initialHeap(constraints())); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - MOZ_TRY(pushTypeBarrier(ins, getInlineReturnTypeSet(), BarrierKind::TypeSet)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineBoolean(CallInfo& callInfo) { - if (callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - if (callInfo.argc() > 0) { - MDefinition* result = convertToBoolean(callInfo.getArg(0)); - current->push(result); - } else { - pushConstant(BooleanValue(false)); - } - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineNewIterator( - CallInfo& callInfo, MNewIterator::Type type) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 0); - - JSObject* templateObject = nullptr; - switch (type) { - case MNewIterator::ArrayIterator: - templateObject = inspector->getTemplateObjectForNative( - pc, js::intrinsic_NewArrayIterator); - MOZ_ASSERT_IF(templateObject, templateObject->is()); - break; - case MNewIterator::StringIterator: - templateObject = inspector->getTemplateObjectForNative( - pc, js::intrinsic_NewStringIterator); - MOZ_ASSERT_IF(templateObject, templateObject->is()); - break; - case MNewIterator::RegExpStringIterator: - templateObject = inspector->getTemplateObjectForNative( - pc, js::intrinsic_NewRegExpStringIterator); - MOZ_ASSERT_IF(templateObject, - templateObject->is()); - break; - } - - if (!templateObject) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MConstant* templateConst = - MConstant::NewConstraintlessObject(alloc(), templateObject); - current->add(templateConst); - - MNewIterator* ins = - MNewIterator::New(alloc(), constraints(), templateConst, type); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineArrayIteratorPrototypeOptimizable( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 0); - - if (!ensureArrayIteratorPrototypeNextNotModified()) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - pushConstant(BooleanValue(true)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathAbs(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType returnType = getInlineReturnType(); - MIRType argType = callInfo.getArg(0)->type(); - if (!IsNumberType(argType)) { - return InliningStatus_NotInlined; - } - - // Either argType == returnType, or - // argType == Double or Float32, returnType == Int, or - // argType == Float32, returnType == Double - if (argType != returnType && - !(IsFloatingPointType(argType) && returnType == MIRType::Int32) && - !(argType == MIRType::Float32 && returnType == MIRType::Double)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - // If the arg is a Float32, we specialize the op as double, it will be - // specialized as float32 if necessary later. - MIRType absType = (argType == MIRType::Float32) ? MIRType::Double : argType; - MInstruction* ins = MAbs::New(alloc(), callInfo.getArg(0), absType); - current->add(ins); - - current->push(ins); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathFloor(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType argType = callInfo.getArg(0)->type(); - MIRType returnType = getInlineReturnType(); - - // Math.floor(int(x)) == int(x) - if (argType == MIRType::Int32 && returnType == MIRType::Int32) { - callInfo.setImplicitlyUsedUnchecked(); - // The int operand may be something which bails out if the actual value - // is not in the range of the result type of the MIR. We need to tell - // the optimizer to preserve this bailout even if the final result is - // fully truncated. - MLimitedTruncate* ins = MLimitedTruncate::New( - alloc(), callInfo.getArg(0), MDefinition::IndirectTruncate); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - if (IsFloatingPointType(argType)) { - if (returnType == MIRType::Int32) { - callInfo.setImplicitlyUsedUnchecked(); - MFloor* ins = MFloor::New(alloc(), callInfo.getArg(0)); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - if (returnType == MIRType::Double) { - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* ins = nullptr; - if (MNearbyInt::HasAssemblerSupport(RoundingMode::Down)) { - ins = MNearbyInt::New(alloc(), callInfo.getArg(0), argType, - RoundingMode::Down); - } else { - ins = MMathFunction::New(alloc(), callInfo.getArg(0), - UnaryMathFunction::Floor); - } - - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - } - - return InliningStatus_NotInlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathCeil(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType argType = callInfo.getArg(0)->type(); - MIRType returnType = getInlineReturnType(); - - // Math.ceil(int(x)) == int(x) - if (argType == MIRType::Int32 && returnType == MIRType::Int32) { - callInfo.setImplicitlyUsedUnchecked(); - // The int operand may be something which bails out if the actual value - // is not in the range of the result type of the MIR. We need to tell - // the optimizer to preserve this bailout even if the final result is - // fully truncated. - MLimitedTruncate* ins = MLimitedTruncate::New( - alloc(), callInfo.getArg(0), MDefinition::IndirectTruncate); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - if (IsFloatingPointType(argType)) { - if (returnType == MIRType::Int32) { - callInfo.setImplicitlyUsedUnchecked(); - MCeil* ins = MCeil::New(alloc(), callInfo.getArg(0)); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - if (returnType == MIRType::Double) { - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* ins = nullptr; - if (MNearbyInt::HasAssemblerSupport(RoundingMode::Up)) { - ins = MNearbyInt::New(alloc(), callInfo.getArg(0), argType, - RoundingMode::Up); - } else { - ins = MMathFunction::New(alloc(), callInfo.getArg(0), - UnaryMathFunction::Ceil); - } - - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - } - - return InliningStatus_NotInlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathClz32(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType returnType = getInlineReturnType(); - if (returnType != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - if (!IsNumberType(callInfo.getArg(0)->type())) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MClz* ins = MClz::New(alloc(), callInfo.getArg(0), MIRType::Int32); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathRound(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType returnType = getInlineReturnType(); - MIRType argType = callInfo.getArg(0)->type(); - - // Math.round(int(x)) == int(x) - if (argType == MIRType::Int32 && returnType == MIRType::Int32) { - callInfo.setImplicitlyUsedUnchecked(); - // The int operand may be something which bails out if the actual value - // is not in the range of the result type of the MIR. We need to tell - // the optimizer to preserve this bailout even if the final result is - // fully truncated. - MLimitedTruncate* ins = MLimitedTruncate::New( - alloc(), callInfo.getArg(0), MDefinition::IndirectTruncate); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - if (IsFloatingPointType(argType) && returnType == MIRType::Int32) { - callInfo.setImplicitlyUsedUnchecked(); - MRound* ins = MRound::New(alloc(), callInfo.getArg(0)); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - if (IsFloatingPointType(argType) && returnType == MIRType::Double) { - callInfo.setImplicitlyUsedUnchecked(); - MMathFunction* ins = MMathFunction::New(alloc(), callInfo.getArg(0), - UnaryMathFunction::Round); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - return InliningStatus_NotInlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathSqrt(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType argType = callInfo.getArg(0)->type(); - if (getInlineReturnType() != MIRType::Double) { - return InliningStatus_NotInlined; - } - if (!IsNumberType(argType)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MSqrt* sqrt = MSqrt::New(alloc(), callInfo.getArg(0), MIRType::Double); - current->add(sqrt); - current->push(sqrt); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathAtan2(CallInfo& callInfo) { - if (callInfo.argc() != 2 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Double) { - return InliningStatus_NotInlined; - } - - MIRType argType0 = callInfo.getArg(0)->type(); - MIRType argType1 = callInfo.getArg(1)->type(); - - if (!IsNumberType(argType0) || !IsNumberType(argType1)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MAtan2* atan2 = MAtan2::New(alloc(), callInfo.getArg(0), callInfo.getArg(1)); - current->add(atan2); - current->push(atan2); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathHypot(CallInfo& callInfo) { - if (callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - uint32_t argc = callInfo.argc(); - if (argc < 2 || argc > 4) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Double) { - return InliningStatus_NotInlined; - } - - MDefinitionVector vector(alloc()); - if (!vector.reserve(argc)) { - return InliningStatus_NotInlined; - } - - for (uint32_t i = 0; i < argc; ++i) { - MDefinition* arg = callInfo.getArg(i); - if (!IsNumberType(arg->type())) { - return InliningStatus_NotInlined; - } - vector.infallibleAppend(arg); - } - - callInfo.setImplicitlyUsedUnchecked(); - MHypot* hypot = MHypot::New(alloc(), vector); - - if (!hypot) { - return InliningStatus_NotInlined; - } - - current->add(hypot); - current->push(hypot); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathPow(CallInfo& callInfo) { - if (callInfo.argc() != 2 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - bool emitted = false; - MOZ_TRY(powTrySpecialized(&emitted, callInfo.getArg(0), callInfo.getArg(1), - getInlineReturnType())); - - if (!emitted) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathRandom(CallInfo& callInfo) { - if (callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Double) { - return InliningStatus_NotInlined; - } - - // MRandom JIT code directly accesses the RNG. It's (barely) possible to - // inline Math.random without it having been called yet, so ensure RNG - // state that isn't guaranteed to be initialized already. - script()->realm()->getOrCreateRandomNumberGenerator(); - - callInfo.setImplicitlyUsedUnchecked(); - - MRandom* rand = MRandom::New(alloc()); - current->add(rand); - current->push(rand); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathImul(CallInfo& callInfo) { - if (callInfo.argc() != 2 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType returnType = getInlineReturnType(); - if (returnType != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - if (!IsNumberType(callInfo.getArg(0)->type())) { - return InliningStatus_NotInlined; - } - if (!IsNumberType(callInfo.getArg(1)->type())) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* first = MTruncateToInt32::New(alloc(), callInfo.getArg(0)); - current->add(first); - - MInstruction* second = MTruncateToInt32::New(alloc(), callInfo.getArg(1)); - current->add(second); - - MMul* ins = MMul::New(alloc(), first, second, MIRType::Int32, MMul::Integer); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathFRound(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - // MIRType can't be Float32, as this point, as getInlineReturnType uses JSVal - // types to infer the returned MIR type. - TemporaryTypeSet* returned = getInlineReturnTypeSet(); - if (returned->empty()) { - // As there's only one possible returned type, just add it to the observed - // returned typeset - returned->addType(TypeSet::DoubleType(), alloc_->lifoAlloc()); - } else { - MIRType returnType = getInlineReturnType(); - if (!IsNumberType(returnType)) { - return InliningStatus_NotInlined; - } - } - - MIRType arg = callInfo.getArg(0)->type(); - if (!IsNumberType(arg)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MToFloat32* ins = MToFloat32::New(alloc(), callInfo.getArg(0)); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathTrunc(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType argType = callInfo.getArg(0)->type(); - MIRType returnType = getInlineReturnType(); - - // Math.trunc(int(x)) == int(x) - if (argType == MIRType::Int32 && returnType == MIRType::Int32) { - callInfo.setImplicitlyUsedUnchecked(); - // The int operand may be something which bails out if the actual value - // is not in the range of the result type of the MIR. We need to tell - // the optimizer to preserve this bailout even if the final result is - // fully truncated. - MLimitedTruncate* ins = MLimitedTruncate::New( - alloc(), callInfo.getArg(0), MDefinition::IndirectTruncate); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - if (IsFloatingPointType(argType)) { - if (returnType == MIRType::Int32) { - callInfo.setImplicitlyUsedUnchecked(); - MTrunc* ins = MTrunc::New(alloc(), callInfo.getArg(0)); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - if (returnType == MIRType::Double) { - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* ins = nullptr; - if (MNearbyInt::HasAssemblerSupport(RoundingMode::TowardsZero)) { - ins = MNearbyInt::New(alloc(), callInfo.getArg(0), argType, - RoundingMode::TowardsZero); - } else { - ins = MMathFunction::New(alloc(), callInfo.getArg(0), - UnaryMathFunction::Trunc); - } - - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - } - - return InliningStatus_NotInlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathSign(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType argType = callInfo.getArg(0)->type(); - MIRType returnType = getInlineReturnType(); - - if (returnType != MIRType::Int32 && returnType != MIRType::Double) { - return InliningStatus_NotInlined; - } - - if (!IsFloatingPointType(argType) && - !(argType == MIRType::Int32 && returnType == MIRType::Int32)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - auto* ins = MSign::New(alloc(), callInfo.getArg(0), returnType); - current->add(ins); - current->push(ins); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineMathMinMax(CallInfo& callInfo, - bool max) { - if (callInfo.argc() < 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MIRType returnType = getInlineReturnType(); - if (!IsNumberType(returnType)) { - return InliningStatus_NotInlined; - } - - MDefinitionVector int32_cases(alloc()); - for (unsigned i = 0; i < callInfo.argc(); i++) { - MDefinition* arg = callInfo.getArg(i); - - switch (arg->type()) { - case MIRType::Int32: - if (!int32_cases.append(arg)) { - return abort(AbortReason::Alloc); - } - break; - case MIRType::Double: - case MIRType::Float32: - // Don't force a double MMinMax for arguments that would be a NOP - // when doing an integer MMinMax. - if (arg->isConstant()) { - double cte = arg->toConstant()->numberToDouble(); - // min(int32, cte >= INT32_MAX) = int32 - if (cte >= INT32_MAX && !max) { - break; - } - // max(int32, cte <= INT32_MIN) = int32 - if (cte <= INT32_MIN && max) { - break; - } - } - - // Force double MMinMax if argument is a "effectfull" double. - returnType = MIRType::Double; - break; - default: - return InliningStatus_NotInlined; - } - } - - if (int32_cases.length() == 0) { - returnType = MIRType::Double; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MDefinitionVector& cases = - (returnType == MIRType::Int32) ? int32_cases : callInfo.argv(); - - if (cases.length() == 1) { - MLimitedTruncate* limit = - MLimitedTruncate::New(alloc(), cases[0], MDefinition::NoTruncate); - current->add(limit); - current->push(limit); - return InliningStatus_Inlined; - } - - // Chain N-1 MMinMax instructions to compute the MinMax. - MMinMax* last = MMinMax::New(alloc(), cases[0], cases[1], returnType, max); - current->add(last); - - for (unsigned i = 2; i < cases.length(); i++) { - MMinMax* ins = - MMinMax::New(alloc().fallible(), last, cases[i], returnType, max); - if (!ins) { - return abort(AbortReason::Alloc); - } - current->add(ins); - last = ins; - } - - current->push(last); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineStringObject(CallInfo& callInfo) { - if (callInfo.argc() != 1 || !callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - // ConvertToString doesn't support objects. - if (callInfo.getArg(0)->mightBeType(MIRType::Object)) { - return InliningStatus_NotInlined; - } - - JSObject* templateObj = - inspector->getTemplateObjectForNative(pc, StringConstructor); - if (!templateObj) { - return InliningStatus_NotInlined; - } - MOZ_ASSERT(templateObj->is()); - - callInfo.setImplicitlyUsedUnchecked(); - - MNewStringObject* ins = - MNewStringObject::New(alloc(), callInfo.getArg(0), templateObj); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineStringSplitString( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 2); - - MDefinition* strArg = callInfo.getArg(0); - MDefinition* sepArg = callInfo.getArg(1); - - if (strArg->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - - if (sepArg->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - - JSContext* cx = TlsContext.get(); - ObjectGroup* group = ObjectGroupRealm::getStringSplitStringGroup(cx); - if (!group) { - return InliningStatus_NotInlined; - } - - TypeSet::ObjectKey* retKey = TypeSet::ObjectKey::get(group); - if (retKey->unknownProperties()) { - return InliningStatus_NotInlined; - } - - HeapTypeSetKey key = retKey->property(JSID_VOID); - if (!key.maybeTypes()) { - return InliningStatus_NotInlined; - } - - if (!key.maybeTypes()->hasType(TypeSet::StringType())) { - key.freeze(constraints()); - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - MStringSplit* ins = - MStringSplit::New(alloc(), constraints(), strArg, sepArg, group); - current->add(ins); - current->push(ins); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineObjectHasPrototype( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 2); - - MDefinition* objArg = callInfo.getArg(0); - MDefinition* protoArg = callInfo.getArg(1); - - if (objArg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (protoArg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - // Inline only when both obj and proto are singleton objects and - // obj does not have uncacheable proto and obj.__proto__ is proto. - TemporaryTypeSet* objTypes = objArg->resultTypeSet(); - if (!objTypes || objTypes->unknownObject() || - objTypes->getObjectCount() != 1) { - return InliningStatus_NotInlined; - } - - TypeSet::ObjectKey* objKey = objTypes->getObject(0); - if (!objKey || !objKey->hasStableClassAndProto(constraints())) { - return InliningStatus_NotInlined; - } - if (!objKey->isSingleton() || !objKey->singleton()->is()) { - return InliningStatus_NotInlined; - } - - JSObject* obj = &objKey->singleton()->as(); - if (obj->hasUncacheableProto()) { - return InliningStatus_NotInlined; - } - - JSObject* actualProto = checkNurseryObject(objKey->proto().toObjectOrNull()); - if (actualProto == nullptr) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* protoTypes = protoArg->resultTypeSet(); - if (!protoTypes || protoTypes->unknownObject() || - protoTypes->getObjectCount() != 1) { - return InliningStatus_NotInlined; - } - - TypeSet::ObjectKey* protoKey = protoTypes->getObject(0); - if (!protoKey || !protoKey->hasStableClassAndProto(constraints())) { - return InliningStatus_NotInlined; - } - if (!protoKey->isSingleton() || !protoKey->singleton()->is()) { - return InliningStatus_NotInlined; - } - - JSObject* proto = &protoKey->singleton()->as(); - pushConstant(BooleanValue(proto == actualProto)); - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineFinishBoundFunctionInit( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 3); - MOZ_ASSERT(BytecodeIsPopped(pc)); - - MDefinition* boundFunction = callInfo.getArg(0); - MDefinition* targetFunction = callInfo.getArg(1); - MDefinition* argCount = callInfo.getArg(2); - - if (boundFunction->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (targetFunction->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (argCount->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - auto* ins = MFinishBoundFunctionInit::New(alloc(), boundFunction, - targetFunction, argCount); - current->add(ins); - - pushConstant(UndefinedValue()); - - MOZ_TRY(resumeAfter(ins)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsPackedArray(CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - MDefinition* obj = callInfo.getArg(0); - - if (obj->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - auto* ins = MIsPackedArray::New(alloc(), obj); - current->add(ins); - current->push(ins); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineReflectGetPrototypeOf( - CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MDefinition* target = callInfo.getArg(0); - if (target->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - auto* ins = MGetPrototypeOf::New(alloc(), target); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - MOZ_TRY(pushTypeBarrier(ins, getInlineReturnTypeSet(), BarrierKind::TypeSet)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineStrCharCodeAt(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - if (callInfo.thisArg()->type() != MIRType::String && - callInfo.thisArg()->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - MIRType argType = callInfo.getArg(0)->type(); - if (argType != MIRType::Int32 && argType != MIRType::Double) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* index = MToIntegerInt32::New(alloc(), callInfo.getArg(0)); - current->add(index); - - MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg()); - current->add(length); - - index = addBoundsCheck(index, length); - - MCharCodeAt* charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index); - current->add(charCode); - current->push(charCode); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineStrFromCharCode( - CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::String) { - return InliningStatus_NotInlined; - } - - MDefinition* codeUnit = callInfo.getArg(0); - if (codeUnit->type() != MIRType::Int32) { - // Don't try inline String.fromCharCode() for types which may lead to a - // bailout in MTruncateToInt32. - if (MTruncateToInt32::mightHaveSideEffects(codeUnit)) { - return InliningStatus_NotInlined; - } - - codeUnit = MTruncateToInt32::New(alloc(), codeUnit); - current->add(codeUnit->toInstruction()); - } - - callInfo.setImplicitlyUsedUnchecked(); - - MFromCharCode* string = MFromCharCode::New(alloc(), codeUnit); - current->add(string); - current->push(string); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineStrFromCodePoint( - CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::String) { - return InliningStatus_NotInlined; - } - MIRType argType = callInfo.getArg(0)->type(); - if (argType != MIRType::Int32 && argType != MIRType::Double) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - auto* codePoint = MToNumberInt32::New(alloc(), callInfo.getArg(0)); - current->add(codePoint); - - MFromCodePoint* string = MFromCodePoint::New(alloc(), codePoint); - current->add(string); - current->push(string); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineStrCharAt(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::String) { - return InliningStatus_NotInlined; - } - if (callInfo.thisArg()->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - MIRType argType = callInfo.getArg(0)->type(); - if (argType != MIRType::Int32 && argType != MIRType::Double) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* index = MToIntegerInt32::New(alloc(), callInfo.getArg(0)); - current->add(index); - - MStringLength* length = MStringLength::New(alloc(), callInfo.thisArg()); - current->add(length); - - index = addBoundsCheck(index, length); - - // String.charAt(x) = String.fromCharCode(String.charCodeAt(x)) - MCharCodeAt* charCode = MCharCodeAt::New(alloc(), callInfo.thisArg(), index); - current->add(charCode); - - MFromCharCode* string = MFromCharCode::New(alloc(), charCode); - current->add(string); - current->push(string); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineStringConvertCase( - CallInfo& callInfo, MStringConvertCase::Mode mode) { - if (callInfo.argc() != 0 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::String) { - return InliningStatus_NotInlined; - } - if (callInfo.thisArg()->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - auto* ins = MStringConvertCase::New(alloc(), callInfo.thisArg(), mode); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineRegExpMatcher(CallInfo& callInfo) { - // This is called from Self-hosted JS, after testing each argument, - // most of following tests should be passed. - - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 3); - - MDefinition* rxArg = callInfo.getArg(0); - MDefinition* strArg = callInfo.getArg(1); - MDefinition* lastIndexArg = callInfo.getArg(2); - - if (rxArg->type() != MIRType::Object && rxArg->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* rxTypes = rxArg->resultTypeSet(); - const JSClass* clasp = - rxTypes ? rxTypes->getKnownClass(constraints()) : nullptr; - if (clasp != &RegExpObject::class_) { - return InliningStatus_NotInlined; - } - - if (strArg->type() != MIRType::String && strArg->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - if (lastIndexArg->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - JSContext* cx = TlsContext.get(); - if (!cx->realm()->jitRealm()->ensureRegExpMatcherStubExists(cx)) { - cx->clearPendingException(); // OOM or overrecursion. - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* matcher = - MRegExpMatcher::New(alloc(), rxArg, strArg, lastIndexArg); - current->add(matcher); - current->push(matcher); - - MOZ_TRY(resumeAfter(matcher)); - MOZ_TRY( - pushTypeBarrier(matcher, getInlineReturnTypeSet(), BarrierKind::TypeSet)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineRegExpSearcher( - CallInfo& callInfo) { - // This is called from Self-hosted JS, after testing each argument, - // most of following tests should be passed. - - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 3); - - MDefinition* rxArg = callInfo.getArg(0); - MDefinition* strArg = callInfo.getArg(1); - MDefinition* lastIndexArg = callInfo.getArg(2); - - if (rxArg->type() != MIRType::Object && rxArg->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* regexpTypes = rxArg->resultTypeSet(); - const JSClass* clasp = - regexpTypes ? regexpTypes->getKnownClass(constraints()) : nullptr; - if (clasp != &RegExpObject::class_) { - return InliningStatus_NotInlined; - } - - if (strArg->type() != MIRType::String && strArg->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - if (lastIndexArg->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - JSContext* cx = TlsContext.get(); - if (!cx->realm()->jitRealm()->ensureRegExpSearcherStubExists(cx)) { - cx->clearPendingException(); // OOM or overrecursion. - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* searcher = - MRegExpSearcher::New(alloc(), rxArg, strArg, lastIndexArg); - current->add(searcher); - current->push(searcher); - - MOZ_TRY(resumeAfter(searcher)); - MOZ_TRY(pushTypeBarrier(searcher, getInlineReturnTypeSet(), - BarrierKind::TypeSet)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineRegExpTester(CallInfo& callInfo) { - // This is called from Self-hosted JS, after testing each argument, - // most of following tests should be passed. - - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 3); - - MDefinition* rxArg = callInfo.getArg(0); - MDefinition* strArg = callInfo.getArg(1); - MDefinition* lastIndexArg = callInfo.getArg(2); - - if (rxArg->type() != MIRType::Object && rxArg->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* rxTypes = rxArg->resultTypeSet(); - const JSClass* clasp = - rxTypes ? rxTypes->getKnownClass(constraints()) : nullptr; - if (clasp != &RegExpObject::class_) { - return InliningStatus_NotInlined; - } - - if (strArg->type() != MIRType::String && strArg->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - if (lastIndexArg->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - JSContext* cx = TlsContext.get(); - if (!cx->realm()->jitRealm()->ensureRegExpTesterStubExists(cx)) { - cx->clearPendingException(); // OOM or overrecursion. - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* tester = - MRegExpTester::New(alloc(), rxArg, strArg, lastIndexArg); - current->add(tester); - current->push(tester); - - MOZ_TRY(resumeAfter(tester)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsRegExpObject( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.getArg(0); - - bool isRegExpObjectKnown = false; - bool isRegExpObjectConstant; - if (arg->type() == MIRType::Object) { - TemporaryTypeSet* types = arg->resultTypeSet(); - const JSClass* clasp = - types ? types->getKnownClass(constraints()) : nullptr; - if (clasp) { - isRegExpObjectKnown = true; - isRegExpObjectConstant = (clasp == &RegExpObject::class_); - } - } else if (!arg->mightBeType(MIRType::Object)) { - // NB: This case only happens when Phi-nodes flow into IsRegExpObject. - // IsRegExpObject itself will never be called with a non-Object value. - isRegExpObjectKnown = true; - isRegExpObjectConstant = false; - } else if (arg->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - if (isRegExpObjectKnown) { - pushConstant(BooleanValue(isRegExpObjectConstant)); - } else { - MHasClass* hasClass = MHasClass::New(alloc(), arg, &RegExpObject::class_); - current->add(hasClass); - current->push(hasClass); - } - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsPossiblyWrappedRegExpObject( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.getArg(0); - if (arg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* types = arg->resultTypeSet(); - if (!types) { - return InliningStatus_NotInlined; - } - - // Don't inline if the argument might be a wrapper. - if (types->forAllClasses(constraints(), IsProxyClass) != - TemporaryTypeSet::ForAllResult::ALL_FALSE) { - return InliningStatus_NotInlined; - } - - if (const JSClass* clasp = types->getKnownClass(constraints())) { - pushConstant(BooleanValue(clasp == &RegExpObject::class_)); - } else { - MHasClass* hasClass = MHasClass::New(alloc(), arg, &RegExpObject::class_); - current->add(hasClass); - current->push(hasClass); - } - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineRegExpPrototypeOptimizable( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - MDefinition* protoArg = callInfo.getArg(0); - - if (protoArg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* opt = MRegExpPrototypeOptimizable::New(alloc(), protoArg); - current->add(opt); - current->push(opt); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineRegExpInstanceOptimizable( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 2); - - MDefinition* rxArg = callInfo.getArg(0); - MDefinition* protoArg = callInfo.getArg(1); - - if (rxArg->type() != MIRType::Object && rxArg->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - if (protoArg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* opt = MRegExpInstanceOptimizable::New(alloc(), rxArg, protoArg); - current->add(opt); - current->push(opt); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineGetFirstDollarIndex( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - MDefinition* strArg = callInfo.getArg(0); - - if (strArg->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* ins = MGetFirstDollarIndex::New(alloc(), strArg); - current->add(ins); - current->push(ins); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineStringReplaceString( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 3); - - if (getInlineReturnType() != MIRType::String) { - return InliningStatus_NotInlined; - } - - MDefinition* strArg = callInfo.getArg(0); - MDefinition* patArg = callInfo.getArg(1); - MDefinition* replArg = callInfo.getArg(2); - - if (strArg->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - - if (patArg->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - - if (replArg->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* cte = MStringReplace::New(alloc(), strArg, patArg, replArg); - current->add(cte); - current->push(cte); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineSubstringKernel( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 3); - - // Return: String. - if (getInlineReturnType() != MIRType::String) { - return InliningStatus_NotInlined; - } - - // Arg 0: String. - if (callInfo.getArg(0)->type() != MIRType::String) { - return InliningStatus_NotInlined; - } - - // Arg 1: Int. - if (callInfo.getArg(1)->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - // Arg 2: Int. - if (callInfo.getArg(2)->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MSubstr* substr = MSubstr::New(alloc(), callInfo.getArg(0), - callInfo.getArg(1), callInfo.getArg(2)); - current->add(substr); - current->push(substr); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineObject(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.getArg(0); - if (arg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - current->push(arg); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineObjectCreate(CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - JSObject* templateObject = - inspector->getTemplateObjectForNative(pc, obj_create); - if (!templateObject) { - return InliningStatus_NotInlined; - } - - MOZ_ASSERT(templateObject->is()); - MOZ_ASSERT(!templateObject->isSingleton()); - - // Ensure the argument matches the template object's prototype. - MDefinition* arg = callInfo.getArg(0); - if (JSObject* proto = templateObject->staticPrototype()) { - if (IsInsideNursery(proto)) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* types = arg->resultTypeSet(); - if (!types || types->maybeSingleton() != proto) { - return InliningStatus_NotInlined; - } - - MOZ_ASSERT(types->getKnownMIRType() == MIRType::Object); - } else { - if (arg->type() != MIRType::Null) { - return InliningStatus_NotInlined; - } - } - - callInfo.setImplicitlyUsedUnchecked(); - - bool emitted = false; - MOZ_TRY(newObjectTryTemplateObject(&emitted, templateObject)); - - MOZ_ASSERT(emitted); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineObjectIs(CallInfo& callInfo) { - if (callInfo.argc() < 2 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - MDefinition* left = callInfo.getArg(0); - MDefinition* right = callInfo.getArg(1); - MIRType leftType = left->type(); - MIRType rightType = right->type(); - - auto mightBeFloatingPointType = [](MDefinition* def) { - return def->mightBeType(MIRType::Double) || - def->mightBeType(MIRType::Float32); - }; - - bool strictEq; - bool incompatibleTypes = false; - if (leftType == rightType) { - // We can only compare the arguments with strict-equals semantics if - // they aren't floating-point types or values which might be floating- - // point types. Otherwise we need to use MSameValue. - strictEq = leftType != MIRType::Value ? !IsFloatingPointType(leftType) - : (!mightBeFloatingPointType(left) && - !mightBeFloatingPointType(right)); - } else if (leftType == MIRType::Value) { - // Also use strict-equals when comparing a value with a non-number or - // the value cannot be a floating-point type. - strictEq = !IsNumberType(rightType) || !mightBeFloatingPointType(left); - } else if (rightType == MIRType::Value) { - // Dual case to the previous one, only with reversed operands. - strictEq = !IsNumberType(leftType) || !mightBeFloatingPointType(right); - } else if (IsNumberType(leftType) && IsNumberType(rightType)) { - // Both arguments are numbers, but with different representations. We - // can't use strict-equals semantics to compare the operands, but - // instead need to use MSameValue. - strictEq = false; - } else { - incompatibleTypes = true; - } - - if (incompatibleTypes) { - // The result is always |false| when comparing incompatible types. - pushConstant(BooleanValue(false)); - } else if (strictEq) { - // Specialize |Object.is(lhs, rhs)| as |lhs === rhs|. - MOZ_TRY(jsop_compare(JSOp::StrictEq, left, right)); - } else { - MSameValue* ins = MSameValue::New(alloc(), left, right); - - // The more specific operand is expected to be in the rhs. - if (IsNumberType(leftType) && rightType == MIRType::Value) { - ins->swapOperands(); - } - - current->add(ins); - current->push(ins); - } - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineObjectIsPrototypeOf( - CallInfo& callInfo) { - if (callInfo.constructing() || callInfo.argc() != 1) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - MDefinition* thisArg = callInfo.thisArg(); - if (thisArg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.getArg(0); - - auto* ins = MInstanceOf::New(alloc(), arg, thisArg); - current->add(ins); - current->push(ins); - MOZ_TRY(resumeAfter(ins)); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineObjectToString( - CallInfo& callInfo) { - if (callInfo.constructing() || callInfo.argc() != 0) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::String) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.thisArg(); - if (arg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* types = arg->resultTypeSet(); - if (!types || types->unknownObject()) { - return InliningStatus_NotInlined; - } - - // Don't optimize if this might be a proxy. - using ForAllResult = TemporaryTypeSet::ForAllResult; - if (types->forAllClasses(constraints(), IsProxyClass) != - ForAllResult::ALL_FALSE) { - return InliningStatus_NotInlined; - } - - // Make sure there's no Symbol.toStringTag property. - jsid toStringTag = - SYMBOL_TO_JSID(realm->runtime()->wellKnownSymbols().toStringTag); - bool res; - MOZ_TRY_VAR(res, testNotDefinedProperty(arg, toStringTag)); - if (!res) { - return InliningStatus_NotInlined; - } - - // At this point we know we're going to inline this. - callInfo.setImplicitlyUsedUnchecked(); - - // Try to constant fold some common cases. - if (const JSClass* knownClass = types->getKnownClass(constraints())) { - if (knownClass == &PlainObject::class_) { - pushConstant(StringValue(names().objectObject)); - return InliningStatus_Inlined; - } - if (IsArrayClass(knownClass)) { - pushConstant(StringValue(names().objectArray)); - return InliningStatus_Inlined; - } - if (knownClass == &JSFunction::class_) { - pushConstant(StringValue(names().objectFunction)); - return InliningStatus_Inlined; - } - } - - MObjectClassToString* toString = MObjectClassToString::New(alloc(), arg); - current->add(toString); - current->push(toString); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineGuardToClass( - CallInfo& callInfo, InlinableNative native) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - const JSClass* clasp = InlinableNativeGuardToClass(native); - - if (callInfo.getArg(0)->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet(); - const JSClass* knownClass = - types ? types->getKnownClass(constraints()) : nullptr; - - if (knownClass && knownClass == clasp) { - current->push(callInfo.getArg(0)); - } else { - MGuardToClass* guardToClass = - MGuardToClass::New(alloc(), callInfo.getArg(0), clasp); - current->add(guardToClass); - current->push(guardToClass); - } - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineGetNextEntryForIterator( - CallInfo& callInfo, MGetNextEntryForIterator::Mode mode) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 2); - - MDefinition* iterArg = callInfo.getArg(0); - MDefinition* resultArg = callInfo.getArg(1); - - // Self-hosted code has already validated |iterArg| is a (possibly boxed) - // Map- or SetIterator object. - if (iterArg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - if (resultArg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* resultTypes = resultArg->resultTypeSet(); - const JSClass* resultClasp = - resultTypes ? resultTypes->getKnownClass(constraints()) : nullptr; - if (resultClasp != &ArrayObject::class_) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* next = - MGetNextEntryForIterator::New(alloc(), iterArg, resultArg, mode); - current->add(next); - current->push(next); - - MOZ_TRY(resumeAfter(next)); - return InliningStatus_Inlined; -} - -static bool IsArrayBufferObject(CompilerConstraintList* constraints, - MDefinition* def) { - MOZ_ASSERT(def->type() == MIRType::Object); - - TemporaryTypeSet* types = def->resultTypeSet(); - if (!types) { - return false; - } - - return types->getKnownClass(constraints) == &ArrayBufferObject::class_; -} - -IonBuilder::InliningResult IonBuilder::inlineArrayBufferByteLength( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - MDefinition* objArg = callInfo.getArg(0); - if (objArg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (getInlineReturnType() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - MInstruction* ins = addArrayBufferByteLength(objArg); - current->push(ins); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult -IonBuilder::inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - MDefinition* objArg = callInfo.getArg(0); - if (objArg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (getInlineReturnType() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - if (!IsArrayBufferObject(constraints(), objArg)) { - return InliningStatus_NotInlined; - } - - MInstruction* ins = addArrayBufferByteLength(objArg); - current->push(ins); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineTypedArray(CallInfo& callInfo, - Native native) { - if (!callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (getInlineReturnType() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (callInfo.argc() == 0 || callInfo.argc() > 3) { - return InliningStatus_NotInlined; - } - - JSObject* templateObject = inspector->getTemplateObjectForNative(pc, native); - if (!templateObject) { - return InliningStatus_NotInlined; - } - MOZ_ASSERT(templateObject->is()); - TypedArrayObject* obj = &templateObject->as(); - - // Do not optimize when we see a template object with a singleton type, - // since it hits at most once. - if (templateObject->isSingleton()) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.getArg(0); - MInstruction* ins; - if (arg->type() == MIRType::Int32) { - if (!arg->isConstant()) { - ins = MNewTypedArrayDynamicLength::New( - alloc(), constraints(), templateObject, - templateObject->group()->initialHeap(constraints()), arg); - } else { - // Negative lengths must throw a RangeError. (We don't track that this - // might have previously thrown, when determining whether to inline, so we - // have to deal with this error case when inlining.) - int32_t providedLen = arg->maybeConstantValue()->toInt32(); - if (providedLen <= 0) { - return InliningStatus_NotInlined; - } - - uint32_t len = AssertedCast(providedLen); - if (obj->length().get() != len) { - return InliningStatus_NotInlined; - } - - MConstant* templateConst = - MConstant::NewConstraintlessObject(alloc(), obj); - current->add(templateConst); - ins = MNewTypedArray::New(alloc(), constraints(), templateConst, - obj->group()->initialHeap(constraints())); - } - } else if (arg->type() == MIRType::Object) { - TemporaryTypeSet* types = arg->resultTypeSet(); - if (!types) { - return InliningStatus_NotInlined; - } - - // Don't inline if the argument might be a wrapper. - if (types->forAllClasses(constraints(), IsProxyClass) != - TemporaryTypeSet::ForAllResult::ALL_FALSE) { - return InliningStatus_NotInlined; - } - - // Don't inline if we saw mixed use of (Shared)ArrayBuffers and other - // objects. - auto IsArrayBufferMaybeSharedClass = [](const JSClass* clasp) { - return clasp == &ArrayBufferObject::class_ || - clasp == &SharedArrayBufferObject::class_; - }; - switch ( - types->forAllClasses(constraints(), IsArrayBufferMaybeSharedClass)) { - case TemporaryTypeSet::ForAllResult::ALL_FALSE: - ins = MNewTypedArrayFromArray::New( - alloc(), constraints(), templateObject, - templateObject->group()->initialHeap(constraints()), arg); - break; - case TemporaryTypeSet::ForAllResult::ALL_TRUE: - MDefinition* byteOffset; - if (callInfo.argc() > 1) { - byteOffset = callInfo.getArg(1); - } else { - byteOffset = constant(UndefinedValue()); - } - - MDefinition* length; - if (callInfo.argc() > 2) { - length = callInfo.getArg(2); - } else { - length = constant(UndefinedValue()); - } - - ins = MNewTypedArrayFromArrayBuffer::New( - alloc(), constraints(), templateObject, - templateObject->group()->initialHeap(constraints()), arg, - byteOffset, length); - break; - case TemporaryTypeSet::ForAllResult::EMPTY: - case TemporaryTypeSet::ForAllResult::MIXED: - return InliningStatus_NotInlined; - } - } else { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - current->add(ins); - current->push(ins); - MOZ_TRY(resumeAfter(ins)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsTypedArrayConstructor( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - if (callInfo.getArg(0)->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - // Try inlining with a constant if the argument is definitely a TypedArray - // constructor. - TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet(); - if (!types || types->unknownObject() || types->getObjectCount() == 0) { - return InliningStatus_NotInlined; - } - for (unsigned i = 0; i < types->getObjectCount(); i++) { - JSObject* singleton = types->getSingleton(i); - if (!singleton || !IsTypedArrayConstructor(singleton)) { - return InliningStatus_NotInlined; - } - } - - callInfo.setImplicitlyUsedUnchecked(); - - pushConstant(BooleanValue(true)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsTypedArrayHelper( - CallInfo& callInfo, WrappingBehavior wrappingBehavior) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (callInfo.getArg(0)->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - // The test is elaborate: in-line only if there is exact - // information. - - TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet(); - if (!types) { - return InliningStatus_NotInlined; - } - - // Wrapped typed arrays won't appear to be typed arrays per a - // |forAllClasses| query. If wrapped typed arrays are to be considered - // typed arrays, a negative answer is not conclusive. - auto isPossiblyWrapped = [this, wrappingBehavior, types]() { - if (wrappingBehavior != AllowWrappedTypedArrays) { - return false; - } - - switch (types->forAllClasses(constraints(), IsProxyClass)) { - case TemporaryTypeSet::ForAllResult::ALL_FALSE: - case TemporaryTypeSet::ForAllResult::EMPTY: - break; - case TemporaryTypeSet::ForAllResult::ALL_TRUE: - case TemporaryTypeSet::ForAllResult::MIXED: - return true; - } - return false; - }; - - bool result = false; - bool isConstant = true; - bool possiblyWrapped = false; - switch (types->forAllClasses(constraints(), IsTypedArrayClass)) { - case TemporaryTypeSet::ForAllResult::ALL_FALSE: - if (isPossiblyWrapped()) { - // Don't inline if we never saw typed arrays, but always only proxies. - return InliningStatus_NotInlined; - } - - [[fallthrough]]; - - case TemporaryTypeSet::ForAllResult::EMPTY: - result = false; - break; - - case TemporaryTypeSet::ForAllResult::ALL_TRUE: - result = true; - break; - - case TemporaryTypeSet::ForAllResult::MIXED: - isConstant = false; - possiblyWrapped = isPossiblyWrapped(); - break; - } - - if (isConstant) { - pushConstant(BooleanValue(result)); - } else { - auto* ins = - MIsTypedArray::New(alloc(), callInfo.getArg(0), possiblyWrapped); - current->add(ins); - current->push(ins); - - if (possiblyWrapped) { - MOZ_TRY(resumeAfter(ins)); - } - } - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsTypedArray(CallInfo& callInfo) { - return inlineIsTypedArrayHelper(callInfo, RejectWrappedTypedArrays); -} - -IonBuilder::InliningResult IonBuilder::inlineIsPossiblyWrappedTypedArray( - CallInfo& callInfo) { - return inlineIsTypedArrayHelper(callInfo, AllowWrappedTypedArrays); -} - -static bool IsTypedArrayObject(CompilerConstraintList* constraints, - MDefinition* def) { - MOZ_ASSERT(def->type() == MIRType::Object); - - TemporaryTypeSet* types = def->resultTypeSet(); - if (!types) { - return false; - } - - return types->forAllClasses(constraints, IsTypedArrayClass) == - TemporaryTypeSet::ForAllResult::ALL_TRUE; -} - -IonBuilder::InliningResult IonBuilder::inlinePossiblyWrappedTypedArrayLength( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - if (callInfo.getArg(0)->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (getInlineReturnType() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - if (!IsTypedArrayObject(constraints(), callInfo.getArg(0))) { - return InliningStatus_NotInlined; - } - - MInstruction* length = addTypedArrayLength(callInfo.getArg(0)); - current->push(length); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineTypedArrayLength( - CallInfo& callInfo) { - return inlinePossiblyWrappedTypedArrayLength(callInfo); -} - -IonBuilder::InliningResult IonBuilder::inlineTypedArrayByteOffset( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - if (callInfo.getArg(0)->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (getInlineReturnType() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - if (!IsTypedArrayObject(constraints(), callInfo.getArg(0))) { - return InliningStatus_NotInlined; - } - - MInstruction* byteOffset = addTypedArrayByteOffset(callInfo.getArg(0)); - current->push(byteOffset); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineTypedArrayElementShift( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - if (callInfo.getArg(0)->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - if (getInlineReturnType() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - if (!IsTypedArrayObject(constraints(), callInfo.getArg(0))) { - return InliningStatus_NotInlined; - } - - auto* ins = MTypedArrayElementShift::New(alloc(), callInfo.getArg(0)); - current->add(ins); - current->push(ins); - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineUnsafeSetReservedSlot( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 3); - - if (getInlineReturnType() != MIRType::Undefined) { - return InliningStatus_NotInlined; - } - - MDefinition* obj = callInfo.getArg(0); - if (obj->type() != MIRType::Object && obj->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.getArg(1); - if (arg->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - // Don't inline if we don't have a constant slot. - if (!arg->isConstant()) { - return InliningStatus_NotInlined; - } - uint32_t slot = uint32_t(arg->toConstant()->toInt32()); - - // Don't inline if it's not a fixed slot. - if (slot >= NativeObject::MAX_FIXED_SLOTS) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MStoreFixedSlot* store = - MStoreFixedSlot::NewBarriered(alloc(), obj, slot, callInfo.getArg(2)); - current->add(store); - current->push(store); - - if (needsPostBarrier(callInfo.getArg(2))) { - current->add(MPostWriteBarrier::New(alloc(), obj, callInfo.getArg(2))); - } - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineUnsafeGetReservedSlot( - CallInfo& callInfo, MIRType knownValueType) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 2); - - MDefinition* obj = callInfo.getArg(0); - if (obj->type() != MIRType::Object && obj->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.getArg(1); - if (arg->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - // Don't inline if we don't have a constant slot. - if (!arg->isConstant()) { - return InliningStatus_NotInlined; - } - uint32_t slot = uint32_t(arg->toConstant()->toInt32()); - - // Don't inline if it's not a fixed slot. - if (slot >= NativeObject::MAX_FIXED_SLOTS) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), obj, slot); - current->add(load); - current->push(load); - if (knownValueType != MIRType::Value) { - // We know what type we have in this slot. Assert that this is in fact - // what we've seen coming from this slot in the past, then tell the - // MLoadFixedSlot about its result type. That will make us do an - // infallible unbox as part of the slot load and then we'll barrier on - // the unbox result. That way the type barrier code won't end up doing - // MIRType checks and conditional unboxing. - MOZ_ASSERT_IF(!getInlineReturnTypeSet()->empty(), - getInlineReturnType() == knownValueType); - load->setResultType(knownValueType); - } - - // We don't track reserved slot types, so always emit a barrier. - MOZ_TRY( - pushTypeBarrier(load, getInlineReturnTypeSet(), BarrierKind::TypeSet)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsCallable(CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - MDefinition* arg = callInfo.getArg(0); - - // Try inlining with constant true/false: only objects may be callable at - // all, and if we know the class check if it is callable. - bool isCallableKnown = false; - bool isCallableConstant; - if (arg->type() == MIRType::Object) { - TemporaryTypeSet* types = arg->resultTypeSet(); - const JSClass* clasp = - types ? types->getKnownClass(constraints()) : nullptr; - if (clasp && !clasp->isProxy()) { - isCallableKnown = true; - isCallableConstant = clasp->nonProxyCallable(); - } - } else if (!arg->mightBeType(MIRType::Object)) { - // Primitive (including undefined and null). - isCallableKnown = true; - isCallableConstant = false; - } else if (arg->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - if (isCallableKnown) { - MConstant* constant = - MConstant::New(alloc(), BooleanValue(isCallableConstant)); - current->add(constant); - current->push(constant); - return InliningStatus_Inlined; - } - - MIsCallable* isCallable = MIsCallable::New(alloc(), arg); - current->add(isCallable); - current->push(isCallable); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsConstructor(CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - if (callInfo.getArg(0)->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MIsConstructor* ins = MIsConstructor::New(alloc(), callInfo.getArg(0)); - current->add(ins); - current->push(ins); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsObject(CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - if (callInfo.getArg(0)->type() == MIRType::Object) { - pushConstant(BooleanValue(true)); - } else { - MIsObject* isObject = MIsObject::New(alloc(), callInfo.getArg(0)); - current->add(isObject); - current->push(isObject); - } - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineToObject(CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (getInlineReturnType() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - MDefinition* object = callInfo.getArg(0); - if (object->type() != MIRType::Object && object->type() != MIRType::Value) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - // If we know the input type is an object, nop ToObject. - if (object->type() == MIRType::Object) { - current->push(object); - } else { - auto* ins = MToObject::New(alloc(), object); - current->add(ins); - current->push(ins); - - MOZ_TRY(resumeAfter(ins)); - MOZ_TRY( - pushTypeBarrier(ins, getInlineReturnTypeSet(), BarrierKind::TypeSet)); - } - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineIsCrossRealmArrayConstructor( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - MDefinition* arg = callInfo.getArg(0); - if (arg->type() != MIRType::Object) { - return InliningStatus_NotInlined; - } - - TemporaryTypeSet* types = arg->resultTypeSet(); - Realm* realm = types->getKnownRealm(constraints()); - if (!realm || realm != script()->realm()) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - // Inline only if argument is absolutely *not* a wrapper or a cross-realm - // object. - pushConstant(BooleanValue(false)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineToInteger(CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - MDefinition* input = callInfo.getArg(0); - - // Only optimize cases where |input| contains only number, null, undefined, or - // boolean. - if (!input->definitelyType({MIRType::Int32, MIRType::Double, MIRType::Float32, - MIRType::Null, MIRType::Undefined, - MIRType::Boolean})) { - return InliningStatus_NotInlined; - } - - // Only optimize cases where the output is int32 or double. - MIRType returnType = getInlineReturnType(); - if (returnType != MIRType::Int32 && returnType != MIRType::Double) { - return InliningStatus_NotInlined; - } - - if (returnType == MIRType::Int32) { - auto* toInt32 = MToIntegerInt32::New(alloc(), input); - current->add(toInt32); - current->push(toInt32); - } else { - MInstruction* ins; - if (MNearbyInt::HasAssemblerSupport(RoundingMode::TowardsZero)) { - ins = MNearbyInt::New(alloc(), input, MIRType::Double, - RoundingMode::TowardsZero); - } else { - ins = MMathFunction::New(alloc(), input, UnaryMathFunction::Trunc); - } - current->add(ins); - - auto* nanToZero = MNaNToZero::New(alloc(), ins); - current->add(nanToZero); - current->push(nanToZero); - } - - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineToLength(CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 1); - - MDefinition* input = callInfo.getArg(0); - - // Optimize int32 => number. - if (input->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - if (!IsNumberType(getInlineReturnType())) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - // ToLength(int32) is equivalent to max(int32, 0). - bool isMax = true; - MDefinition* constZero = constant(Int32Value(0)); - MMinMax* max = MMinMax::New(alloc(), input, constZero, MIRType::Int32, isMax); - current->add(max); - current->push(max); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineBailout(CallInfo& callInfo) { - callInfo.setImplicitlyUsedUnchecked(); - - current->add(MBail::New(alloc())); - - MConstant* undefined = MConstant::New(alloc(), UndefinedValue()); - current->add(undefined); - current->push(undefined); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineAssertFloat32(CallInfo& callInfo) { - if (callInfo.argc() != 2) { - return InliningStatus_NotInlined; - } - - MDefinition* secondArg = callInfo.getArg(1); - - MOZ_ASSERT(secondArg->type() == MIRType::Boolean); - MOZ_ASSERT(secondArg->isConstant()); - - bool mustBeFloat32 = secondArg->toConstant()->toBoolean(); - current->add(MAssertFloat32::New(alloc(), callInfo.getArg(0), mustBeFloat32)); - - MConstant* undefined = MConstant::New(alloc(), UndefinedValue()); - current->add(undefined); - current->push(undefined); - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineAssertRecoveredOnBailout( - CallInfo& callInfo) { - if (callInfo.argc() != 2) { - return InliningStatus_NotInlined; - } - - // Don't assert for recovered instructions when recovering is disabled. - if (JitOptions.disableRecoverIns) { - return InliningStatus_NotInlined; - } - - if (JitOptions.checkRangeAnalysis) { - // If we are checking the range of all instructions, then the guards - // inserted by Range Analysis prevent the use of recover - // instruction. Thus, we just disable these checks. - current->push(constant(UndefinedValue())); - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; - } - - MDefinition* secondArg = callInfo.getArg(1); - - MOZ_ASSERT(secondArg->type() == MIRType::Boolean); - MOZ_ASSERT(secondArg->isConstant()); - - bool mustBeRecovered = secondArg->toConstant()->toBoolean(); - MAssertRecoveredOnBailout* assert = MAssertRecoveredOnBailout::New( - alloc(), callInfo.getArg(0), mustBeRecovered); - current->add(assert); - current->push(assert); - - // Create an instruction sequence which implies that the argument of the - // assertRecoveredOnBailout function would be encoded at least in one - // Snapshot. - MNop* nop = MNop::New(alloc()); - current->add(nop); - MOZ_TRY(resumeAfter(nop)); - current->add(MEncodeSnapshot::New(alloc())); - - current->pop(); - current->push(constant(UndefinedValue())); - callInfo.setImplicitlyUsedUnchecked(); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineAtomicsCompareExchange( - CallInfo& callInfo) { - if (callInfo.argc() != 4 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - // These guards are desirable here and in subsequent atomics to - // avoid bad bailouts with MTruncateToInt32, see - // https://bugzilla.mozilla.org/show_bug.cgi?id=1141986#c20. - MDefinition* oldval = callInfo.getArg(2); - if (MTruncateToInt32::mightHaveSideEffects(oldval)) { - return InliningStatus_NotInlined; - } - - MDefinition* newval = callInfo.getArg(3); - if (MTruncateToInt32::mightHaveSideEffects(newval)) { - return InliningStatus_NotInlined; - } - - Scalar::Type arrayType; - TemporaryTypeSet::TypedArraySharedness sharedness; - if (!atomicsMeetsPreconditions(callInfo, &arrayType, &sharedness)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* elements; - MDefinition* index; - atomicsCheckBounds(callInfo, &elements, &index); - - MCompareExchangeTypedArrayElement* cas = - MCompareExchangeTypedArrayElement::New(alloc(), elements, index, - arrayType, oldval, newval); - cas->setResultType(getInlineReturnType()); - current->add(cas); - current->push(cas); - - MOZ_TRY(resumeAfter(cas)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineAtomicsExchange( - CallInfo& callInfo) { - if (callInfo.argc() != 3 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MDefinition* value = callInfo.getArg(2); - if (MTruncateToInt32::mightHaveSideEffects(value)) { - return InliningStatus_NotInlined; - } - - Scalar::Type arrayType; - TemporaryTypeSet::TypedArraySharedness sharedness; - if (!atomicsMeetsPreconditions(callInfo, &arrayType, &sharedness)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* elements; - MDefinition* index; - atomicsCheckBounds(callInfo, &elements, &index); - - MInstruction* exchange = MAtomicExchangeTypedArrayElement::New( - alloc(), elements, index, value, arrayType); - exchange->setResultType(getInlineReturnType()); - current->add(exchange); - current->push(exchange); - - MOZ_TRY(resumeAfter(exchange)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineAtomicsLoad(CallInfo& callInfo) { - if (callInfo.argc() != 2 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - Scalar::Type arrayType; - TemporaryTypeSet::TypedArraySharedness sharedness; - if (!atomicsMeetsPreconditions(callInfo, &arrayType, &sharedness)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* elements; - MDefinition* index; - atomicsCheckBounds(callInfo, &elements, &index); - - MemoryBarrierRequirement barrier = DoesRequireMemoryBarrier; - if (sharedness == TemporaryTypeSet::KnownUnshared) { - barrier = DoesNotRequireMemoryBarrier; - } - - auto* load = - MLoadUnboxedScalar::New(alloc(), elements, index, arrayType, barrier); - load->setResultType(getInlineReturnType()); - current->add(load); - current->push(load); - - // Loads are considered effectful (if they execute a memory barrier). - if (barrier == DoesRequireMemoryBarrier) { - MOZ_TRY(resumeAfter(load)); - } - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineAtomicsStore(CallInfo& callInfo) { - if (callInfo.argc() != 3 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - // Atomics.store() is annoying because it returns the result of converting - // the value by ToInteger(), not the input value, nor the result of - // converting the value by ToInt32(). It is especially annoying because - // almost nobody uses the result value. - // - // As an expedient compromise, therefore, we inline only if the result is - // obviously unused or if the argument is already Int32 and thus requires no - // conversion. - - MDefinition* value = callInfo.getArg(2); - if (!BytecodeIsPopped(pc) && value->type() != MIRType::Int32) { - return InliningStatus_NotInlined; - } - - if (MTruncateToInt32::mightHaveSideEffects(value)) { - return InliningStatus_NotInlined; - } - - Scalar::Type arrayType; - TemporaryTypeSet::TypedArraySharedness sharedness; - if (!atomicsMeetsPreconditions(callInfo, &arrayType, &sharedness, - DontCheckAtomicResult)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* elements; - MDefinition* index; - atomicsCheckBounds(callInfo, &elements, &index); - - MemoryBarrierRequirement barrier = DoesRequireMemoryBarrier; - if (sharedness == TemporaryTypeSet::KnownUnshared) { - barrier = DoesNotRequireMemoryBarrier; - } - - MDefinition* toWrite = value; - if (toWrite->type() != MIRType::Int32) { - toWrite = MTruncateToInt32::New(alloc(), toWrite); - current->add(toWrite->toInstruction()); - } - auto* store = MStoreUnboxedScalar::New(alloc(), elements, index, toWrite, - arrayType, barrier); - current->add(store); - current->push(value); // Either Int32 or not used; in either case correct - - MOZ_TRY(resumeAfter(store)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineAtomicsBinop( - CallInfo& callInfo, InlinableNative target) { - if (callInfo.argc() != 3 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MDefinition* value = callInfo.getArg(2); - if (MTruncateToInt32::mightHaveSideEffects(value)) { - return InliningStatus_NotInlined; - } - - Scalar::Type arrayType; - TemporaryTypeSet::TypedArraySharedness sharedness; - if (!atomicsMeetsPreconditions(callInfo, &arrayType, &sharedness)) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* elements; - MDefinition* index; - atomicsCheckBounds(callInfo, &elements, &index); - - AtomicOp k = AtomicFetchAddOp; - switch (target) { - case InlinableNative::AtomicsAdd: - k = AtomicFetchAddOp; - break; - case InlinableNative::AtomicsSub: - k = AtomicFetchSubOp; - break; - case InlinableNative::AtomicsAnd: - k = AtomicFetchAndOp; - break; - case InlinableNative::AtomicsOr: - k = AtomicFetchOrOp; - break; - case InlinableNative::AtomicsXor: - k = AtomicFetchXorOp; - break; - default: - MOZ_CRASH("Bad atomic operation"); - } - - MAtomicTypedArrayElementBinop* binop = MAtomicTypedArrayElementBinop::New( - alloc(), k, elements, index, arrayType, value); - binop->setResultType(getInlineReturnType()); - current->add(binop); - current->push(binop); - - MOZ_TRY(resumeAfter(binop)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineAtomicsIsLockFree( - CallInfo& callInfo) { - if (callInfo.argc() != 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - MAtomicIsLockFree* ilf = MAtomicIsLockFree::New(alloc(), callInfo.getArg(0)); - current->add(ilf); - current->push(ilf); - - return InliningStatus_Inlined; -} - -bool IonBuilder::atomicsMeetsPreconditions( - CallInfo& callInfo, Scalar::Type* arrayType, - TemporaryTypeSet::TypedArraySharedness* sharedness, - AtomicCheckResult checkResult) { - if (!JitSupportsAtomics()) { - return false; - } - - if (callInfo.getArg(0)->type() != MIRType::Object) { - return false; - } - - if (callInfo.getArg(1)->type() != MIRType::Int32) { - return false; - } - - // Ensure that the first argument is a TypedArray. - // - // Then check both that the element type is something we can - // optimize and that the return type is suitable for that element - // type. - - TemporaryTypeSet* arg0Types = callInfo.getArg(0)->resultTypeSet(); - if (!arg0Types) { - return false; - } - - *arrayType = arg0Types->getTypedArrayType(constraints(), sharedness); - switch (*arrayType) { - case Scalar::Int8: - case Scalar::Uint8: - case Scalar::Int16: - case Scalar::Uint16: - case Scalar::Int32: - return checkResult == DontCheckAtomicResult || - getInlineReturnType() == MIRType::Int32; - case Scalar::Uint32: - return checkResult == DontCheckAtomicResult || - getInlineReturnType() == MIRType::Double; - case Scalar::BigInt64: - case Scalar::BigUint64: - // Bug 1638295: Not yet implemented. - [[fallthrough]]; - default: - // Excludes floating types and Uint8Clamped. - return false; - } -} - -void IonBuilder::atomicsCheckBounds(CallInfo& callInfo, MInstruction** elements, - MDefinition** index) { - // Perform bounds checking and extract the elements vector. - MDefinition* obj = callInfo.getArg(0); - MInstruction* length = nullptr; - *index = callInfo.getArg(1); - *elements = nullptr; - addTypedArrayLengthAndData(obj, DoBoundsCheck, index, &length, elements); -} - -IonBuilder::InliningResult IonBuilder::inlineIsConstructing( - CallInfo& callInfo) { - MOZ_ASSERT(!callInfo.constructing()); - MOZ_ASSERT(callInfo.argc() == 0); - MOZ_ASSERT(script()->isFunction(), - "isConstructing() should only be called in function scripts"); - - if (getInlineReturnType() != MIRType::Boolean) { - return InliningStatus_NotInlined; - } - - callInfo.setImplicitlyUsedUnchecked(); - - if (inliningDepth_ == 0) { - MInstruction* ins = MIsConstructing::New(alloc()); - current->add(ins); - current->push(ins); - return InliningStatus_Inlined; - } - - bool constructing = inlineCallInfo_->constructing(); - pushConstant(BooleanValue(constructing)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineDataViewGet(CallInfo& callInfo, - Scalar::Type type) { - if (callInfo.argc() < 1 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MDefinition* obj = callInfo.thisArg(); - TemporaryTypeSet* thisTypes = obj->resultTypeSet(); - const JSClass* clasp = - thisTypes ? thisTypes->getKnownClass(constraints()) : nullptr; - if (clasp != &DataViewObject::class_) { - return InliningStatus_NotInlined; - } - - MDefinition* index = callInfo.getArg(0); - if (!IsNumberType(index->type())) { - return InliningStatus_NotInlined; - } - - MDefinition* littleEndian; - if (Scalar::byteSize(type) > 1) { - if (callInfo.argc() > 1) { - littleEndian = convertToBoolean(callInfo.getArg(1)); - } else { - littleEndian = constant(BooleanValue(false)); - } - } - - callInfo.setImplicitlyUsedUnchecked(); - - // Calling |dataView.getUint32()| will result in a double for values that - // don't fit in an int32. We have to bailout if this happens and the - // instruction is not known to return a double. - bool allowDouble = getInlineReturnTypeSet()->hasType(TypeSet::DoubleType()); - MIRType knownType = MIRTypeForArrayBufferViewRead(type, allowDouble); - - MInstruction* indexInt32 = MToIntegerInt32::New(alloc(), index); - current->add(indexInt32); - index = indexInt32; - - // Get bounds-check, then get elements, and add all instructions. - MInstruction* elements; - addDataViewData(obj, type, &index, &elements); - - // Load the element. - MInstruction* load; - if (Scalar::byteSize(type) == 1) { - load = MLoadUnboxedScalar::New(alloc(), elements, index, type); - } else { - load = - MLoadDataViewElement::New(alloc(), elements, index, littleEndian, type); - } - current->add(load); - current->push(load); - - // Note: we can ignore the type barrier here, we know the type must be valid - // and unbarriered. - load->setResultType(knownType); - - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineDataViewSet(CallInfo& callInfo, - Scalar::Type type) { - if (callInfo.argc() < 2 || callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - MDefinition* obj = callInfo.thisArg(); - TemporaryTypeSet* thisTypes = obj->resultTypeSet(); - const JSClass* clasp = - thisTypes ? thisTypes->getKnownClass(constraints()) : nullptr; - if (clasp != &DataViewObject::class_) { - return InliningStatus_NotInlined; - } - - MDefinition* index = callInfo.getArg(0); - if (!IsNumberType(index->type())) { - return InliningStatus_NotInlined; - } - - MDefinition* value = callInfo.getArg(1); - if (!Scalar::isBigIntType(type)) { - if (!IsNumberType(value->type())) { - return InliningStatus_NotInlined; - } - } else { - if (value->type() != MIRType::BigInt) { - return InliningStatus_NotInlined; - } - } - - MDefinition* littleEndian; - if (Scalar::byteSize(type) > 1) { - if (callInfo.argc() > 2) { - littleEndian = convertToBoolean(callInfo.getArg(2)); - } else { - littleEndian = constant(BooleanValue(false)); - } - } - - callInfo.setImplicitlyUsedUnchecked(); - - MInstruction* indexInt32 = MToIntegerInt32::New(alloc(), index); - current->add(indexInt32); - index = indexInt32; - - // Get bounds-check, then get elements, and add all instructions. - MInstruction* elements; - addDataViewData(obj, type, &index, &elements); - - // Store the element. - MInstruction* store; - if (Scalar::byteSize(type) == 1) { - store = MStoreUnboxedScalar::New(alloc(), elements, index, value, type); - } else { - store = MStoreDataViewElement::New(alloc(), elements, index, value, - littleEndian, type); - } - current->add(store); - - pushConstant(UndefinedValue()); - - MOZ_TRY(resumeAfter(store)); - return InliningStatus_Inlined; -} - -IonBuilder::InliningResult IonBuilder::inlineWasmCall(CallInfo& callInfo, - JSFunction* target) { - MOZ_ASSERT(target->isWasmWithJitEntry()); - - // Don't inline wasm constructors. - if (callInfo.constructing()) { - return InliningStatus_NotInlined; - } - - if (target->realm() != script()->realm()) { - return InliningStatus_NotInlined; - } - - wasm::Instance& inst = wasm::ExportedFunctionToInstance(target); - uint32_t funcIndex = inst.code().getFuncIndex(target); - - auto bestTier = inst.code().bestTier(); - const wasm::FuncExport& funcExport = - inst.metadata(bestTier).lookupFuncExport(funcIndex); - const wasm::FuncType& sig = funcExport.funcType(); - - // Check that the function doesn't take or return non-compatible JS - // argument types before adding nodes to the MIR graph, otherwise they'd be - // dead code. - if (sig.temporarilyUnsupportedReftypeForInlineEntry() || - !JitOptions.enableWasmIonFastCalls) { - return InliningStatus_NotInlined; - } - - // If there are too many arguments, don't inline (we won't be able to store - // the arguments in the LIR node). - static_assert(wasm::MaxArgsForJitInlineCall <= MaxNumLInstructionOperands, - "inlined arguments can all be LIR operands"); - if (sig.args().length() > wasm::MaxArgsForJitInlineCall) { - return InliningStatus_NotInlined; - } - - // If there are too many results, don't inline as we don't currently - // add MWasmStackResults. - if (sig.results().length() > wasm::MaxResultsForJitInlineCall) { - return InliningStatus_NotInlined; - } - - // Bug 1631656 - Don't try to inline with I64 args on 32-bit platforms because - // it is more difficult (because it requires multiple LIR arguments per I64). - // - // Bug 1631650 - On 64-bit platforms, we also give up inlining for I64 args - // spilled to the stack because it causes problems with register allocation. -#ifdef JS_64BIT - const bool inlineWithI64 = true; -#else - const bool inlineWithI64 = false; -#endif - ABIArgGenerator abi; - for (const auto& valType : sig.args()) { - MIRType mirType = ToMIRType(valType); - ABIArg abiArg = abi.next(mirType); - if (mirType == MIRType::Int64 && - (!inlineWithI64 || (abiArg.kind() == ABIArg::Stack))) { - return InliningStatus_NotInlined; - } - } - - auto* call = MIonToWasmCall::New(alloc(), inst.object(), funcExport); - if (!call) { - return abort(AbortReason::Alloc); - } - - // An invariant in this loop is that any type conversion operation that has - // externally visible effects, such as invoking valueOf on an object argument, - // must bailout so that we don't have to worry about replaying effects during - // argument conversion. - Maybe undefined; - for (size_t i = 0; i < sig.args().length(); i++) { - if (!alloc().ensureBallast()) { - return abort(AbortReason::Alloc); - } - - // Add undefined if an argument is missing. - if (i >= callInfo.argc() && !undefined) { - undefined.emplace(constant(UndefinedValue())); - } - - MDefinition* arg = i >= callInfo.argc() ? *undefined : callInfo.getArg(i); - - MInstruction* conversion = nullptr; - switch (sig.args()[i].kind()) { - case wasm::ValType::I32: - conversion = MTruncateToInt32::New(alloc(), arg); - break; - case wasm::ValType::I64: - conversion = MToInt64::New(alloc(), arg); - break; - case wasm::ValType::F32: - conversion = MToFloat32::New(alloc(), arg); - break; - case wasm::ValType::F64: - conversion = MToDouble::New(alloc(), arg); - break; - case wasm::ValType::V128: - MOZ_CRASH("impossible per above check"); - case wasm::ValType::Ref: - switch (sig.args()[i].refTypeKind()) { - case wasm::RefType::Extern: - // Transform the JS representation into an AnyRef representation. - // The resulting type is MIRType::RefOrNull. These cases are all - // effect-free. - switch (arg->type()) { - case MIRType::Object: - case MIRType::ObjectOrNull: - conversion = MWasmAnyRefFromJSObject::New(alloc(), arg); - break; - case MIRType::Null: - conversion = MWasmNullConstant::New(alloc()); - break; - default: - conversion = MWasmBoxValue::New(alloc(), arg); - break; - } - break; - default: - MOZ_CRASH("impossible per above check"); - } - break; - } - - current->add(conversion); - call->initArg(i, conversion); - } - - current->add(call); - - // Add any post-function call conversions that are necessary. - MInstruction* postConversion = call; - const wasm::ValTypeVector& results = sig.results(); - MOZ_ASSERT(results.length() <= 1, "Multi-value returns not supported."); - if (results.length() == 0) { - // No results to convert. - } else { - switch (results[0].kind()) { - case wasm::ValType::I64: - // Ion expects a BigInt from I64 types. - postConversion = MInt64ToBigInt::New(alloc(), call); - - // Make non-movable so we can attach a resume point. - postConversion->setNotMovable(); - - current->add(postConversion); - break; - default: - // No spectre.index_masking of i32 results required, as the generated - // stub takes care of that. - break; - } - } - current->push(postConversion); - MOZ_TRY(resumeAfter(postConversion)); - - callInfo.setImplicitlyUsedUnchecked(); - - return InliningStatus_Inlined; -} - -#define ADD_NATIVE(native) \ - const JSJitInfo JitInfo_##native{{nullptr}, \ - {uint16_t(InlinableNative::native)}, \ - {0}, \ - JSJitInfo::InlinableNative}; -INLINABLE_NATIVE_LIST(ADD_NATIVE) -#undef ADD_NATIVE - -} // namespace jit -} // namespace js diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/mips-shared/SharedICHelpers-mips-shared.h 2020-11-17 19:31:32.000000000 +0000 @@ -50,21 +50,6 @@ *callOffset = CodeOffset(masm.currentOffset()); } -inline void EmitEnterTypeMonitorIC( - MacroAssembler& masm, - size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub()) { - // This is expected to be called from within an IC, when ICStubReg - // is properly initialized to point to the stub. - masm.loadPtr(Address(ICStubReg, (uint32_t)monitorStubOffset), ICStubReg); - - // Load stubcode pointer from BaselineStubEntry. - // R2 won't be active when we call ICs, so we can use it. - masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg()); - - // Jump to the stubcode. - masm.branch(R2.scratchReg()); -} - inline void EmitReturnFromIC(MacroAssembler& masm) { masm.branch(ra); } inline void EmitBaselineLeaveStubFrame(MacroAssembler& masm, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/MIR.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/MIR.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/MIR.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/MIR.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -19,9 +19,7 @@ #include "builtin/RegExp.h" #include "jit/AtomicOperations.h" -#include "jit/BaselineInspector.h" #include "jit/CompileInfo.h" -#include "jit/IonBuilder.h" #include "jit/JitSpewer.h" #include "jit/KnownClass.h" #include "jit/MIRGraph.h" @@ -351,7 +349,7 @@ return false; } - return !resultTypeSet() || resultTypeSet()->hasType(TypeSet::MagicArgType()); + return true; } bool MDefinition::definitelyType(std::initializer_list types) const { @@ -367,8 +365,7 @@ MOZ_ASSERT(std::all_of(types.begin(), types.end(), isSpecializedNonMagic)); if (type() == MIRType::Value) { - TemporaryTypeSet* resultTypes = resultTypeSet(); - return resultTypes && !resultTypes->empty() && resultTypes->isSubset(types); + return false; } auto contains = [&types](MIRType type) { @@ -461,12 +458,7 @@ return false; } - TemporaryTypeSet* types = resultTypeSet(); - if (!types) { - return true; - } - - return types->maybeEmulatesUndefined(constraints); + return true; } static bool MaybeCallable(CompilerConstraintList* constraints, @@ -475,12 +467,8 @@ return false; } - TemporaryTypeSet* types = op->resultTypeSet(); - if (!types) { - return true; - } - - return types->maybeCallable(constraints); + // TODO(no-TI): clean up all this code. + return true; } void MTest::cacheOperandMightEmulateUndefined( @@ -896,10 +884,6 @@ } } -bool MDefinition::emptyResultTypeSet() const { - return resultTypeSet() && resultTypeSet()->empty(); -} - MConstant* MConstant::New(TempAllocator& alloc, const Value& v, CompilerConstraintList* constraints) { return new (alloc) MConstant(alloc, v, constraints); @@ -933,39 +917,6 @@ return new (alloc) MConstant(v); } -static TemporaryTypeSet* MakeSingletonTypeSetFromKey( - TempAllocator& tempAlloc, CompilerConstraintList* constraints, - TypeSet::ObjectKey* key) { - // Invalidate when this object's ObjectGroup gets unknown properties. This - // happens for instance when we mutate an object's __proto__, in this case - // we want to invalidate and mark this TypeSet as containing AnyObject - // (because mutating __proto__ will change an object's ObjectGroup). - MOZ_ASSERT(constraints); - (void)key->hasStableClassAndProto(constraints); - - LifoAlloc* alloc = tempAlloc.lifoAlloc(); - return alloc->new_(alloc, TypeSet::ObjectType(key)); -} - -TemporaryTypeSet* jit::MakeSingletonTypeSet(TempAllocator& alloc, - CompilerConstraintList* constraints, - JSObject* obj) { - return MakeSingletonTypeSetFromKey(alloc, constraints, - TypeSet::ObjectKey::get(obj)); -} - -TemporaryTypeSet* jit::MakeSingletonTypeSet(TempAllocator& alloc, - CompilerConstraintList* constraints, - ObjectGroup* obj) { - return MakeSingletonTypeSetFromKey(alloc, constraints, - TypeSet::ObjectKey::get(obj)); -} - -static TemporaryTypeSet* MakeUnknownTypeSet(TempAllocator& tempAlloc) { - LifoAlloc* alloc = tempAlloc.lifoAlloc(); - return alloc->new_(alloc, TypeSet::UnknownType()); -} - #ifdef DEBUG bool jit::IonCompilationCanUseNurseryPointers() { @@ -1023,27 +974,12 @@ // other types as the result type encodes all needed information. MOZ_ASSERT_IF(IsInsideNursery(&vp.toObject()), IonCompilationCanUseNurseryPointers()); - if (!JitOptions.warpBuilder) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, &vp.toObject())); - } break; case MIRType::MagicOptimizedArguments: case MIRType::MagicOptimizedOut: case MIRType::MagicHole: case MIRType::MagicIsConstructing: - break; case MIRType::MagicUninitializedLexical: - // JS_UNINITIALIZED_LEXICAL does not escape to script and is not - // observed in type sets. However, it may flow around freely during - // Ion compilation. Give it an unknown typeset to poison any type sets - // it merges with. - // - // TODO We could track uninitialized lexicals more precisely by tracking - // them in type sets. - if (!JitOptions.warpBuilder) { - setResultTypeSet(MakeUnknownTypeSet(alloc)); - } break; default: MOZ_CRASH("Unexpected type"); @@ -1828,70 +1764,6 @@ return this; } -#ifdef JS_JITSPEW -void MTypeBarrier::printOpcode(GenericPrinter& out) const { - PrintOpcodeName(out, op()); - out.printf(" "); - getOperand(0)->printName(out); -} -#endif - -bool MTypeBarrier::congruentTo(const MDefinition* def) const { - if (!def->isTypeBarrier()) { - return false; - } - const MTypeBarrier* other = def->toTypeBarrier(); - if (barrierKind() != other->barrierKind() || isGuard() != other->isGuard()) { - return false; - } - if (!resultTypeSet()->equals(other->resultTypeSet())) { - return false; - } - return congruentIfOperandsEqual(other); -} - -MDefinition* MTypeBarrier::foldsTo(TempAllocator& alloc) { - MIRType type = resultTypeSet()->getKnownMIRType(); - if (type == MIRType::Value || type == MIRType::Object) { - return this; - } - - if (!input()->isConstant()) { - return this; - } - - if (input()->type() != type) { - return this; - } - - return input(); -} - -bool MTypeBarrier::canRedefineInput() { - // LTypeBarrier does not need its own def usually, because we can use the - // input's allocation (LIRGenerator::redefineInput). However, if Spectre - // mitigations are enabled, guardObjectType may zero the object register on - // speculatively executed paths, so LTypeBarrier needs to have its own def - // then to guarantee all uses will see this potentially-zeroed value. - - if (!JitOptions.spectreObjectMitigationsBarriers) { - return true; - } - - if (barrierKind() == BarrierKind::TypeTagOnly) { - return true; - } - - TemporaryTypeSet* types = resultTypeSet(); - bool hasSpecificObjects = - !types->unknownObject() && types->getObjectCount() > 0; - if (!hasSpecificObjects) { - return true; - } - - return false; -} - #ifdef DEBUG void MPhi::assertLoopPhi() const { // getLoopPredecessorOperand and getLoopBackedgeOperand rely on these @@ -2071,51 +1943,6 @@ return first; } -MDefinition* MPhi::foldsFilterTypeSet() { - // Fold phi with as operands a combination of 'subject' and - // MFilterTypeSet(subject) to 'subject'. - - if (inputs_.length() == 0) { - return nullptr; - } - - MDefinition* subject = getOperand(0); - if (subject->isFilterTypeSet()) { - subject = subject->toFilterTypeSet()->input(); - } - - // Not same type, don't fold. - if (subject->type() != type()) { - return nullptr; - } - - // Phi is better typed (has typeset). Don't fold. - if (resultTypeSet() && !subject->resultTypeSet()) { - return nullptr; - } - - // Phi is better typed (according to typeset). Don't fold. - if (subject->resultTypeSet() && resultTypeSet()) { - if (!subject->resultTypeSet()->isSubset(resultTypeSet())) { - return nullptr; - } - } - - for (size_t i = 1, e = numOperands(); i < e; i++) { - MDefinition* op = getOperand(i); - if (op == subject) { - continue; - } - if (op->isFilterTypeSet() && op->toFilterTypeSet()->input() == subject) { - continue; - } - - return nullptr; - } - - return subject; -} - MDefinition* MPhi::foldsTo(TempAllocator& alloc) { if (MDefinition* def = operandIfRedundant()) { return def; @@ -2125,10 +1952,6 @@ return def; } - if (MDefinition* def = foldsFilterTypeSet()) { - return def; - } - return this; } @@ -2186,58 +2009,16 @@ return true; } -static inline TemporaryTypeSet* MakeMIRTypeSet(TempAllocator& alloc, - MIRType type) { - MOZ_ASSERT(type != MIRType::Value); - - TypeSet::Type ntype = TypeSet::GetMaybeUntrackedType(type); - - return alloc.lifoAlloc()->new_(alloc.lifoAlloc(), ntype); -} - -bool jit::MergeTypes(TempAllocator& alloc, MIRType* ptype, - TemporaryTypeSet** ptypeSet, MIRType newType, - TemporaryTypeSet* newTypeSet) { - if (newTypeSet && newTypeSet->empty()) { - return true; - } - LifoAlloc::AutoFallibleScope fallibleAllocator(alloc.lifoAlloc()); +static void MergeTypes(MIRType* ptype, MIRType newType) { + // TODO(no-TI): clean up if (newType != *ptype) { if (IsTypeRepresentableAsDouble(newType) && IsTypeRepresentableAsDouble(*ptype)) { *ptype = MIRType::Double; } else if (*ptype != MIRType::Value) { - if (!*ptypeSet) { - *ptypeSet = MakeMIRTypeSet(alloc, *ptype); - if (!*ptypeSet) { - return false; - } - } *ptype = MIRType::Value; - } else if (*ptypeSet && (*ptypeSet)->empty()) { - *ptype = newType; - } - } - if (*ptypeSet) { - if (!newTypeSet && newType != MIRType::Value) { - newTypeSet = MakeMIRTypeSet(alloc, newType); - if (!newTypeSet) { - return false; - } - } - if (newTypeSet) { - if (!newTypeSet->isSubset(*ptypeSet)) { - *ptypeSet = - TypeSet::unionSets(*ptypeSet, newTypeSet, alloc.lifoAlloc()); - if (!*ptypeSet) { - return false; - } - } - } else { - *ptypeSet = nullptr; } } - return true; } // Tests whether 'types' includes all possible values represented by @@ -2272,32 +2053,6 @@ } } -// Tests if two type combos (type/typeset) are equal. -bool jit::EqualTypes(MIRType type1, TemporaryTypeSet* typeset1, MIRType type2, - TemporaryTypeSet* typeset2) { - // Types should equal. - if (type1 != type2) { - return false; - } - - // Both have equal type and no typeset. - if (!typeset1 && !typeset2) { - return true; - } - - // If only one instructions has a typeset. - // Test if the typset contains the same information as the MIRType. - if (typeset1 && !typeset2) { - return TypeSetIncludes(typeset1, type2, nullptr); - } - if (!typeset1 && typeset2) { - return TypeSetIncludes(typeset2, type1, nullptr); - } - - // Typesets should equal. - return typeset1->equals(typeset2); -} - bool MPhi::specializeType(TempAllocator& alloc) { #ifdef DEBUG MOZ_ASSERT(!specialized_); @@ -2310,48 +2065,21 @@ if (hasBackedgeType_) { // The type of this phi has already been populated with potential types // that could come in via loop backedges. + // TODO(no-TI): clean up. start = 0; } else { setResultType(getOperand(0)->type()); - setResultTypeSet(getOperand(0)->resultTypeSet()); start = 1; } MIRType resultType = this->type(); - TemporaryTypeSet* resultTypeSet = this->resultTypeSet(); for (size_t i = start; i < inputs_.length(); i++) { MDefinition* def = getOperand(i); - if (!MergeTypes(alloc, &resultType, &resultTypeSet, def->type(), - def->resultTypeSet())) { - return false; - } + MergeTypes(&resultType, def->type()); } setResultType(resultType); - setResultTypeSet(resultTypeSet); - return true; -} - -bool MPhi::addBackedgeType(TempAllocator& alloc, MIRType type, - TemporaryTypeSet* typeSet) { - MOZ_ASSERT(!specialized_); - - if (hasBackedgeType_) { - MIRType resultType = this->type(); - TemporaryTypeSet* resultTypeSet = this->resultTypeSet(); - - if (!MergeTypes(alloc, &resultType, &resultTypeSet, type, typeSet)) { - return false; - } - - setResultType(resultType); - setResultTypeSet(resultTypeSet); - } else { - setResultType(type); - setResultTypeSet(typeSet); - hasBackedgeType_ = true; - } return true; } @@ -2398,61 +2126,18 @@ return true; } - if (TemporaryTypeSet* types = def->resultTypeSet()) { - if (this->resultTypeSet()) { - return types->isSubset(this->resultTypeSet()); - } - if (this->type() == MIRType::Value || types->empty()) { - return true; - } - return this->type() == types->getKnownMIRType(); - } - if (def->type() == MIRType::Value) { // This phi must be able to be any value. - return this->type() == MIRType::Value && - (!this->resultTypeSet() || this->resultTypeSet()->unknown()); + return this->type() == MIRType::Value; } return this->mightBeType(def->type()); } -bool MPhi::checkForTypeChange(TempAllocator& alloc, MDefinition* ins, - bool* ptypeChange) { - MIRType resultType = this->type(); - TemporaryTypeSet* resultTypeSet = this->resultTypeSet(); - - if (JitOptions.warpBuilder) { - // WarpBuilder does not specialize phis during MIR building and does not - // rely on MIR type information. - MOZ_ASSERT(resultType == MIRType::Value); - MOZ_ASSERT(!resultTypeSet); - return true; - } - - if (!MergeTypes(alloc, &resultType, &resultTypeSet, ins->type(), - ins->resultTypeSet())) { - return false; - } - - if (resultType != this->type() || resultTypeSet != this->resultTypeSet()) { - *ptypeChange = true; - setResultType(resultType); - setResultTypeSet(resultTypeSet); - } - return true; -} - MBox::MBox(TempAllocator& alloc, MDefinition* ins) : MUnaryInstruction(classOpcode, ins) { + // TODO(no-TI): move to MIR.h setResultType(MIRType::Value); - if (ins->resultTypeSet()) { - setResultTypeSet(ins->resultTypeSet()); - } else if (ins->type() != MIRType::Value) { - if (!JitOptions.warpBuilder) { - setResultTypeSet(MakeMIRTypeSet(alloc, ins->type())); - } - } setMovable(); } @@ -2845,35 +2530,6 @@ return this; } -void MFilterTypeSet::trySpecializeFloat32(TempAllocator& alloc) { - MDefinition* in = input(); - if (in->type() != MIRType::Float32) { - return; - } - - setResultType(MIRType::Float32); -} - -bool MFilterTypeSet::canProduceFloat32() const { - // A FilterTypeSet should be a producer if the input is a producer too. - // Also, be overly conservative by marking as not float32 producer when the - // input is a phi, as phis can be cyclic (phiA -> FilterTypeSet -> phiB -> - // phiA) and FilterTypeSet doesn't belong in the Float32 phi analysis. - return !input()->isPhi() && input()->canProduceFloat32(); -} - -bool MFilterTypeSet::canConsumeFloat32(MUse* operand) const { - MOZ_ASSERT(getUseFor(0) == operand); - // A FilterTypeSet should be a consumer if all uses are consumer. See also - // comment below MFilterTypeSet::canProduceFloat32. - bool allConsumerUses = true; - for (MUseDefIterator use(this); allConsumerUses && use; use++) { - allConsumerUses &= - !use.def()->isPhi() && use.def()->canConsumeFloat32(use.use()); - } - return allConsumerUses; -} - void MBinaryArithInstruction::trySpecializeFloat32(TempAllocator& alloc) { MOZ_ASSERT(IsNumberType(type())); @@ -4933,16 +4589,6 @@ pc_(pc), vmCall_(vmCall) { setResultType(MIRType::Object); - if (templateObject() && !JitOptions.warpBuilder) { - if (TemporaryTypeSet* types = - MakeSingletonTypeSet(alloc, constraints, templateObject())) { - setResultTypeSet(types); - if (types->convertDoubleElements(constraints) == - TemporaryTypeSet::AlwaysConvertToDoubles) { - convertDoubleElements_ = true; - } - } - } } MDefinition::AliasType MLoadFixedSlot::mightAlias( @@ -5615,21 +5261,6 @@ return false; } -TemporaryTypeSet* InlinePropertyTable::buildTypeSetForFunction( - TempAllocator& tempAlloc, JSFunction* func) const { - LifoAlloc* alloc = tempAlloc.lifoAlloc(); - TemporaryTypeSet* types = alloc->new_(); - if (!types) { - return nullptr; - } - for (size_t i = 0; i < numEntries(); i++) { - if (entries_[i]->func == func) { - types->addType(TypeSet::ObjectType(entries_[i]->group), alloc); - } - } - return types; -} - bool InlinePropertyTable::appendRoots(MRootList& roots) const { for (const Entry* entry : entries_) { if (!entry->appendRoots(roots)) { @@ -6428,655 +6059,6 @@ return input; } -bool jit::ElementAccessIsDenseNative(CompilerConstraintList* constraints, - MDefinition* obj, MDefinition* id) { - if (obj->mightBeType(MIRType::String)) { - return false; - } - - if (id->type() != MIRType::Int32 && id->type() != MIRType::Double) { - return false; - } - - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types) { - return false; - } - - // Typed arrays are native classes but do not have dense elements. - const JSClass* clasp = types->getKnownClass(constraints); - return clasp && clasp->isNative() && !IsTypedArrayClass(clasp); -} - -bool jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints, - MDefinition* obj, MDefinition* id, - Scalar::Type* arrayType) { - if (obj->mightBeType(MIRType::String)) { - return false; - } - - if (id->type() != MIRType::Int32 && id->type() != MIRType::Double) { - return false; - } - - TemporaryTypeSet* types = obj->resultTypeSet(); - if (!types) { - return false; - } - - *arrayType = types->getTypedArrayType(constraints); - - if (*arrayType == Scalar::MaxTypedArrayViewType) { - return false; - } - - return true; -} - -bool jit::ElementAccessIsPacked(CompilerConstraintList* constraints, - MDefinition* obj) { - TemporaryTypeSet* types = obj->resultTypeSet(); - return types && !types->hasObjectFlags(constraints, OBJECT_FLAG_NON_PACKED); -} - -bool jit::ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, - MDefinition* obj) { - TemporaryTypeSet* types = obj->resultTypeSet(); - return !types || - types->hasObjectFlags(constraints, OBJECT_FLAG_COPY_ON_WRITE); -} - -bool jit::ElementAccessMightBeNonExtensible(CompilerConstraintList* constraints, - MDefinition* obj) { - TemporaryTypeSet* types = obj->resultTypeSet(); - return !types || types->hasObjectFlags(constraints, - OBJECT_FLAG_NON_EXTENSIBLE_ELEMENTS); -} - -AbortReasonOr jit::ElementAccessHasExtraIndexedProperty( - IonBuilder* builder, MDefinition* obj) { - TemporaryTypeSet* types = obj->resultTypeSet(); - - if (!types || types->hasObjectFlags(builder->constraints(), - OBJECT_FLAG_LENGTH_OVERFLOW)) { - return true; - } - - return TypeCanHaveExtraIndexedProperties(builder, types); -} - -MIRType jit::DenseNativeElementType(CompilerConstraintList* constraints, - MDefinition* obj) { - TemporaryTypeSet* types = obj->resultTypeSet(); - MIRType elementType = MIRType::None; - unsigned count = types->getObjectCount(); - - for (unsigned i = 0; i < count; i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - - if (key->unknownProperties()) { - return MIRType::None; - } - - HeapTypeSetKey elementTypes = key->property(JSID_VOID); - - MIRType type = elementTypes.knownMIRType(constraints); - if (type == MIRType::None) { - return MIRType::None; - } - - if (elementType == MIRType::None) { - elementType = type; - } else if (elementType != type) { - return MIRType::None; - } - } - - return elementType; -} - -static BarrierKind PropertyReadNeedsTypeBarrier( - CompilerConstraintList* constraints, TypeSet::ObjectKey* key, - PropertyName* name, TypeSet* observed) { - // If the object being read from has types for the property which haven't - // been observed at this access site, the read could produce a new type and - // a barrier is needed. Note that this only covers reads from properties - // which are accounted for by type information, i.e. native data properties - // and elements. - // - // We also need a barrier if the object is a proxy, because then all bets - // are off, just as if it has unknown properties. - if (key->unknownProperties() || observed->empty() || - key->clasp()->isProxy()) { - return BarrierKind::TypeSet; - } - - if (!name && IsTypedArrayClass(key->clasp())) { - Scalar::Type arrayType = GetTypedArrayClassType(key->clasp()); - MIRType type = MIRTypeForArrayBufferViewRead(arrayType, true); - if (observed->mightBeMIRType(type)) { - return BarrierKind::NoBarrier; - } - return BarrierKind::TypeSet; - } - - jsid id = name ? NameToId(name) : JSID_VOID; - HeapTypeSetKey property = key->property(id); - if (property.maybeTypes()) { - if (!TypeSetIncludes(observed, MIRType::Value, property.maybeTypes())) { - // If all possible objects have been observed, we don't have to - // guard on the specific object types. - if (property.maybeTypes()->objectsAreSubset(observed)) { - property.freeze(constraints); - return BarrierKind::TypeTagOnly; - } - return BarrierKind::TypeSet; - } - } - - // Type information for global objects is not required to reflect the - // initial 'undefined' value for properties, in particular global - // variables declared with 'var'. Until the property is assigned a value - // other than undefined, a barrier is required. - if (key->isSingleton()) { - JSObject* obj = key->singleton(); - if (name && CanHaveEmptyPropertyTypesForOwnProperty(obj) && - (!property.maybeTypes() || property.maybeTypes()->empty())) { - return BarrierKind::TypeSet; - } - } - - property.freeze(constraints); - return BarrierKind::NoBarrier; -} - -BarrierKind jit::PropertyReadNeedsTypeBarrier( - JSContext* propertycx, TempAllocator& alloc, - CompilerConstraintList* constraints, TypeSet::ObjectKey* key, - PropertyName* name, TemporaryTypeSet* observed, bool updateObserved) { - if (!updateObserved) { - return PropertyReadNeedsTypeBarrier(constraints, key, name, observed); - } - - // If this access has never executed, try to add types to the observed set - // according to any property which exists on the object or its prototype. - if (observed->empty() && name) { - TypeSet::ObjectKey* obj = key; - do { - if (!obj->clasp()->isNative()) { - break; - } - - if (propertycx) { - obj->ensureTrackedProperty(propertycx, NameToId(name)); - } - - if (obj->unknownProperties()) { - break; - } - - HeapTypeSetKey property = obj->property(NameToId(name)); - if (property.maybeTypes()) { - TypeSet::TypeList types; - if (!property.maybeTypes()->enumerateTypes(&types)) { - break; - } - if (types.length() == 1) { - // Note: the return value here is ignored. - observed->addType(types[0], alloc.lifoAlloc()); - } - break; - } - - if (!obj->proto().isObject()) { - break; - } - obj = TypeSet::ObjectKey::get(obj->proto().toObject()); - } while (obj); - } - - return PropertyReadNeedsTypeBarrier(constraints, key, name, observed); -} - -BarrierKind jit::PropertyReadNeedsTypeBarrier( - JSContext* propertycx, TempAllocator& alloc, - CompilerConstraintList* constraints, MDefinition* obj, PropertyName* name, - TemporaryTypeSet* observed) { - if (observed->unknown()) { - return BarrierKind::NoBarrier; - } - - TypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject()) { - return BarrierKind::TypeSet; - } - - BarrierKind res = BarrierKind::NoBarrier; - - bool updateObserved = types->getObjectCount() == 1; - for (size_t i = 0; i < types->getObjectCount(); i++) { - if (TypeSet::ObjectKey* key = types->getObject(i)) { - BarrierKind kind = PropertyReadNeedsTypeBarrier( - propertycx, alloc, constraints, key, name, observed, updateObserved); - if (kind == BarrierKind::TypeSet) { - return BarrierKind::TypeSet; - } - - if (kind == BarrierKind::TypeTagOnly) { - MOZ_ASSERT(res == BarrierKind::NoBarrier || - res == BarrierKind::TypeTagOnly); - res = BarrierKind::TypeTagOnly; - } else { - MOZ_ASSERT(kind == BarrierKind::NoBarrier); - } - } - } - - return res; -} - -AbortReasonOr jit::PropertyReadOnPrototypeNeedsTypeBarrier( - IonBuilder* builder, MDefinition* obj, PropertyName* name, - TemporaryTypeSet* observed) { - if (observed->unknown()) { - return BarrierKind::NoBarrier; - } - - TypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject()) { - return BarrierKind::TypeSet; - } - - BarrierKind res = BarrierKind::NoBarrier; - - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - while (true) { - if (!builder->alloc().ensureBallast()) { - return builder->abort(AbortReason::Alloc); - } - if (!key->hasStableClassAndProto(builder->constraints())) { - return BarrierKind::TypeSet; - } - if (!key->proto().isObject()) { - break; - } - JSObject* proto = builder->checkNurseryObject(key->proto().toObject()); - key = TypeSet::ObjectKey::get(proto); - BarrierKind kind = PropertyReadNeedsTypeBarrier(builder->constraints(), - key, name, observed); - if (kind == BarrierKind::TypeSet) { - return BarrierKind::TypeSet; - } - - if (kind == BarrierKind::TypeTagOnly) { - MOZ_ASSERT(res == BarrierKind::NoBarrier || - res == BarrierKind::TypeTagOnly); - res = BarrierKind::TypeTagOnly; - } else { - MOZ_ASSERT(kind == BarrierKind::NoBarrier); - } - } - } - - return res; -} - -bool jit::PropertyReadIsIdempotent(CompilerConstraintList* constraints, - MDefinition* obj, PropertyName* name) { - // Determine if reading a property from obj is likely to be idempotent. - - TypeSet* types = obj->resultTypeSet(); - if (!types || types->unknownObject()) { - return false; - } - - for (size_t i = 0; i < types->getObjectCount(); i++) { - if (TypeSet::ObjectKey* key = types->getObject(i)) { - if (key->unknownProperties()) { - return false; - } - - // Check if the property has been reconfigured or is a getter. - HeapTypeSetKey property = key->property(NameToId(name)); - if (property.nonData(constraints)) { - return false; - } - } - } - - return true; -} - -AbortReasonOr PrototypeHasIndexedProperty(IonBuilder* builder, - JSObject* obj) { - do { - TypeSet::ObjectKey* key = - TypeSet::ObjectKey::get(builder->checkNurseryObject(obj)); - if (ClassCanHaveExtraProperties(key->clasp())) { - return true; - } - if (key->unknownProperties()) { - return true; - } - HeapTypeSetKey index = key->property(JSID_VOID); - if (index.nonData(builder->constraints()) || - index.isOwnProperty(builder->constraints())) { - return true; - } - obj = obj->staticPrototype(); - if (!builder->alloc().ensureBallast()) { - return builder->abort(AbortReason::Alloc); - } - } while (obj); - - return false; -} - -// Whether obj or any of its prototypes have an indexed property. -AbortReasonOr jit::TypeCanHaveExtraIndexedProperties( - IonBuilder* builder, TemporaryTypeSet* types) { - const JSClass* clasp = types->getKnownClass(builder->constraints()); - - // Note: typed arrays have indexed properties not accounted for by type - // information, though these are all in bounds and will be accounted for - // by JIT paths. - if (!clasp || - (ClassCanHaveExtraProperties(clasp) && !IsTypedArrayClass(clasp))) { - return true; - } - - if (types->hasObjectFlags(builder->constraints(), - OBJECT_FLAG_SPARSE_INDEXES)) { - return true; - } - - JSObject* proto; - if (!types->getCommonPrototype(builder->constraints(), &proto)) { - return true; - } - - if (!proto) { - return false; - } - - return PrototypeHasIndexedProperty(builder, proto); -} - -static bool PropertyTypeIncludes(TempAllocator& alloc, HeapTypeSetKey property, - MDefinition* value, MIRType implicitType) { - // If implicitType is not MIRType::None, it is an additional type which the - // property implicitly includes. In this case, make a new type set which - // explicitly contains the type. - TypeSet* types = property.maybeTypes(); - if (implicitType != MIRType::None) { - TypeSet::Type newType = TypeSet::PrimitiveType(implicitType); - if (types) { - types = types->clone(alloc.lifoAlloc()); - } else { - types = alloc.lifoAlloc()->new_(); - } - if (!types) { - return false; - } - types->addType(newType, alloc.lifoAlloc()); - } - - return TypeSetIncludes(types, value->type(), value->resultTypeSet()); -} - -static bool TryAddTypeBarrierForWrite(TempAllocator& alloc, - CompilerConstraintList* constraints, - MBasicBlock* current, - TemporaryTypeSet* objTypes, - PropertyName* name, MDefinition** pvalue, - MIRType implicitType) { - // Return whether pvalue was modified to include a type barrier ensuring - // that writing the value to objTypes/id will not require changing type - // information. - - // All objects in the set must have the same types for name. Otherwise, we - // could bail out without subsequently triggering a type change that - // invalidates the compiled code. - Maybe aggregateProperty; - - for (size_t i = 0; i < objTypes->getObjectCount(); i++) { - TypeSet::ObjectKey* key = objTypes->getObject(i); - if (!key) { - continue; - } - - if (key->unknownProperties()) { - return false; - } - - jsid id = name ? NameToId(name) : JSID_VOID; - HeapTypeSetKey property = key->property(id); - if (!property.maybeTypes() || property.couldBeConstant(constraints)) { - return false; - } - - if (PropertyTypeIncludes(alloc, property, *pvalue, implicitType)) { - return false; - } - - // This freeze is not required for correctness, but ensures that we - // will recompile if the property types change and the barrier can - // potentially be removed. - property.freeze(constraints); - - if (!aggregateProperty) { - aggregateProperty.emplace(property); - } else { - if (!aggregateProperty->maybeTypes()->equals(property.maybeTypes())) { - return false; - } - } - } - - MOZ_ASSERT(aggregateProperty); - - MIRType propertyType = aggregateProperty->knownMIRType(constraints); - switch (propertyType) { - case MIRType::Boolean: - case MIRType::Int32: - case MIRType::Double: - case MIRType::String: - case MIRType::Symbol: - case MIRType::BigInt: { - // The property is a particular primitive type, guard by unboxing the - // value before the write. - if (!(*pvalue)->mightBeType(propertyType)) { - // The value's type does not match the property type. Just do a VM - // call as it will always trigger invalidation of the compiled code. - MOZ_ASSERT_IF((*pvalue)->type() != MIRType::Value, - (*pvalue)->type() != propertyType); - return false; - } - MInstruction* ins = - MUnbox::New(alloc, *pvalue, propertyType, MUnbox::Fallible); - current->add(ins); - *pvalue = ins; - return true; - } - default:; - } - - if ((*pvalue)->type() != MIRType::Value) { - return false; - } - - TemporaryTypeSet* types = - aggregateProperty->maybeTypes()->clone(alloc.lifoAlloc()); - if (!types) { - return false; - } - - // If all possible objects can be stored without a barrier, we don't have to - // guard on the specific object types. - BarrierKind kind = BarrierKind::TypeSet; - if ((*pvalue)->resultTypeSet() && - (*pvalue)->resultTypeSet()->objectsAreSubset(types)) { - kind = BarrierKind::TypeTagOnly; - } - - MInstruction* ins = MTypeBarrier::New(alloc, *pvalue, types, kind); - current->add(ins); - ins->setNotMovable(); - if (ins->type() == MIRType::Undefined) { - ins = MConstant::New(alloc, UndefinedValue()); - current->add(ins); - } else if (ins->type() == MIRType::Null) { - ins = MConstant::New(alloc, NullValue()); - current->add(ins); - } - *pvalue = ins; - return true; -} - -static MInstruction* AddGroupGuard(TempAllocator& alloc, MBasicBlock* current, - MDefinition* obj, TypeSet::ObjectKey* key, - bool bailOnEquality) { - MInstruction* guard; - - if (key->isGroup()) { - guard = MGuardObjectGroup::New(alloc, obj, key->group(), bailOnEquality); - } else { - MConstant* singletonConst = - MConstant::NewConstraintlessObject(alloc, key->singleton()); - current->add(singletonConst); - guard = - MGuardObjectIdentity::New(alloc, obj, singletonConst, bailOnEquality); - } - - current->add(guard); - - // For now, never move object group / identity guards. - guard->setNotMovable(); - - return guard; -} - -// Whether value can be written to property without changing type information. -bool jit::CanWriteProperty(TempAllocator& alloc, - CompilerConstraintList* constraints, - HeapTypeSetKey property, MDefinition* value, - MIRType implicitType /* = MIRType::None */) { - if (property.couldBeConstant(constraints)) { - return false; - } - return PropertyTypeIncludes(alloc, property, value, implicitType); -} - -bool jit::PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, - CompilerConstraintList* constraints, - MBasicBlock* current, - MDefinition** pobj, PropertyName* name, - MDefinition** pvalue, bool canModify, - MIRType implicitType) { - // If any value being written is not reflected in the type information for - // objects which obj could represent, a type barrier is needed when writing - // the value. As for propertyReadNeedsTypeBarrier, this only applies for - // properties that are accounted for by type information, i.e. normal data - // properties and elements. - - TemporaryTypeSet* types = (*pobj)->resultTypeSet(); - if (!types || types->unknownObject()) { - return true; - } - - // If all of the objects being written to have property types which already - // reflect the value, no barrier at all is needed. Additionally, if all - // objects being written to have the same types for the property, and those - // types do *not* reflect the value, add a type barrier for the value. - - bool success = true; - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - - if (!key->hasStableClassAndProto(constraints)) { - return true; - } - - // TI doesn't track TypedArray indexes and should never insert a type - // barrier for them. - if (!name && IsTypedArrayClass(key->clasp())) { - continue; - } - - jsid id = name ? NameToId(name) : JSID_VOID; - HeapTypeSetKey property = key->property(id); - if (!CanWriteProperty(alloc, constraints, property, *pvalue, - implicitType)) { - // Either pobj or pvalue needs to be modified to filter out the - // types which the value could have but are not in the property, - // or a VM call is required. A VM call is always required if pobj - // and pvalue cannot be modified. - if (!canModify) { - return true; - } - success = TryAddTypeBarrierForWrite(alloc, constraints, current, types, - name, pvalue, implicitType); - break; - } - } - - if (success) { - return false; - } - - // If all of the objects except one have property types which reflect the - // value, and the remaining object has no types at all for the property, - // add a guard that the object does not have that remaining object's type. - - if (types->getObjectCount() <= 1) { - return true; - } - - TypeSet::ObjectKey* excluded = nullptr; - for (size_t i = 0; i < types->getObjectCount(); i++) { - TypeSet::ObjectKey* key = types->getObject(i); - if (!key) { - continue; - } - - if (!key->hasStableClassAndProto(constraints)) { - return true; - } - - if (!name && IsTypedArrayClass(key->clasp())) { - continue; - } - - jsid id = name ? NameToId(name) : JSID_VOID; - HeapTypeSetKey property = key->property(id); - if (CanWriteProperty(alloc, constraints, property, *pvalue, implicitType)) { - continue; - } - - if ((property.maybeTypes() && !property.maybeTypes()->empty()) || - excluded) { - return true; - } - excluded = key; - } - - MOZ_ASSERT(excluded); - - *pobj = AddGroupGuard(alloc, current, *pobj, excluded, - /* bailOnEquality = */ true); - return false; -} - MIonToWasmCall* MIonToWasmCall::New(TempAllocator& alloc, WasmInstanceObject* instanceObj, const wasm::FuncExport& funcExport) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/MIRGraph.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/MIRGraph.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/MIRGraph.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/MIRGraph.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -1395,9 +1395,7 @@ if (!entryDef->addInputSlow(exitDef)) { return false; } - if (!entryDef->checkForTypeChange(alloc, exitDef, &typeChange)) { - return false; - } + // TODO(no-TI): remove hadTypeChange *hadTypeChange |= typeChange; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/MIR.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/MIR.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/MIR.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/MIR.h 2020-11-17 19:31:31.000000000 +0000 @@ -82,7 +82,6 @@ }; class CompactBufferWriter; -class IonBuilder; class Range; template @@ -471,7 +470,6 @@ Opcode op_; // Opcode. uint16_t flags_; // Bit flags. Range* range_; // Any computed range for this def. - TemporaryTypeSet* resultTypeSet_; // Optional refinement of the result type. union { MDefinition* loadDependency_; // Implicit dependency (store, call, etc.) of this @@ -527,7 +525,6 @@ op_(op), flags_(0), range_(nullptr), - resultTypeSet_(nullptr), loadDependency_(nullptr), trackedSite_(nullptr), bailoutKind_(BailoutKind::Unknown), @@ -540,7 +537,6 @@ op_(other.op_), flags_(other.flags_), range_(other.range_), - resultTypeSet_(other.resultTypeSet_), loadDependency_(other.loadDependency_), trackedSite_(other.trackedSite_), bailoutKind_(other.bailoutKind_), @@ -733,9 +729,6 @@ // is MIRType::Int32. MIRType type() const { return resultType_; } - TemporaryTypeSet* resultTypeSet() const { return resultTypeSet_; } - bool emptyResultTypeSet() const; - bool mightBeType(MIRType type) const { MOZ_ASSERT(type != MIRType::Value); MOZ_ASSERT(type != MIRType::ObjectOrNull); @@ -749,7 +742,7 @@ } if (this->type() == MIRType::Value) { - return !resultTypeSet() || resultTypeSet()->mightBeMIRType(type); + return true; } return false; @@ -909,7 +902,6 @@ inline MControlInstruction* toControlInstruction(); void setResultType(MIRType type) { resultType_ = type; } - void setResultTypeSet(TemporaryTypeSet* types) { resultTypeSet_ = types; } virtual AliasSet getAliasSet() const { // Instructions are effectful by default. return AliasSet::Store(AliasSet::Any); @@ -1443,7 +1435,6 @@ truncate_(NoTruncate), truncateLimit_(limit) { setResultType(MIRType::Int32); - setResultTypeSet(input->resultTypeSet()); setMovable(); } @@ -1719,10 +1710,9 @@ class MParameter : public MNullaryInstruction { int32_t index_; - MParameter(int32_t index, TemporaryTypeSet* types) + explicit MParameter(int32_t index) : MNullaryInstruction(classOpcode), index_(index) { setResultType(MIRType::Value); - setResultTypeSet(types); } public: @@ -2045,24 +2035,8 @@ bool possiblyCalls() const override { return true; } }; -// Fabricate a type set containing only the type of the specified object. -TemporaryTypeSet* MakeSingletonTypeSet(TempAllocator& alloc, - CompilerConstraintList* constraints, - JSObject* obj); - -TemporaryTypeSet* MakeSingletonTypeSet(TempAllocator& alloc, - CompilerConstraintList* constraints, - ObjectGroup* obj); - -MOZ_MUST_USE bool MergeTypes(TempAllocator& alloc, MIRType* ptype, - TemporaryTypeSet** ptypeSet, MIRType newType, - TemporaryTypeSet* newTypeSet); - bool TypeSetIncludes(TypeSet* types, MIRType input, TypeSet* inputTypes); -bool EqualTypes(MIRType type1, TemporaryTypeSet* typeset1, MIRType type2, - TemporaryTypeSet* typeset2); - class MNewArray : public MUnaryInstruction, public NoTypePolicy::Data { private: // Number of elements to allocate for the array. @@ -2136,10 +2110,6 @@ initialHeap_(initialHeap) { MOZ_ASSERT(!templateObject()->isSingleton()); setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, templateObject())); - } } public: @@ -2175,10 +2145,6 @@ initialHeap_(initialHeap) { setGuard(); // Need to throw if length is negative. setResultType(MIRType::Object); - if (!JitOptions.warpBuilder && !templateObject->isSingleton()) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, templateObject)); - } } public: @@ -2208,10 +2174,6 @@ initialHeap_(initialHeap) { MOZ_ASSERT(!templateObject()->isSingleton()); setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, templateObject())); - } } public: @@ -2246,10 +2208,6 @@ MOZ_ASSERT(!templateObject->isSingleton()); setGuard(); // Need to throw if length is negative. setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, templateObject)); - } } public: @@ -2286,10 +2244,6 @@ MOZ_ASSERT(!templateObject->isSingleton()); setGuard(); // Can throw during construction. setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, templateObject)); - } } public: @@ -2326,10 +2280,6 @@ MOZ_ASSERT(!templateObject->isSingleton()); setGuard(); // Can throw during construction. setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, templateObject)); - } } public: @@ -2368,11 +2318,6 @@ MOZ_ASSERT_IF(mode != ObjectLiteral, templateObject()); setResultType(MIRType::Object); - JSObject* obj = templateObject(); - if (obj && !JitOptions.warpBuilder) { - setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, obj)); - } - // The constant is kept separated in a MConstant, this way we can safely // mark it during GC if we recover the object allocation. Otherwise, by // making it emittedAtUses, we do not produce register allocations for @@ -2429,10 +2374,6 @@ MConstant* templateConst, Type type) : MUnaryInstruction(classOpcode, templateConst), type_(type) { setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, templateObject())); - } templateConst->setEmittedAtUses(); } @@ -3406,13 +3347,7 @@ type == MIRType::Symbol || type == MIRType::BigInt || type == MIRType::Object); - TemporaryTypeSet* resultSet = ins->resultTypeSet(); - if (resultSet && type == MIRType::Object) { - resultSet = resultSet->cloneObjectsOnly(alloc.lifoAlloc()); - } - setResultType(type); - setResultTypeSet(resultSet); setMovable(); if (mode_ == TypeBarrier || mode_ == Fallible) { @@ -3459,7 +3394,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(ins->resultTypeSet()); } public: @@ -3490,7 +3424,6 @@ : MUnaryInstruction(classOpcode, ins) { setGuard(); setResultType(MIRType::Object); - setResultTypeSet(ins->resultTypeSet()); } public: @@ -3580,10 +3513,6 @@ : MUnaryInstruction(classOpcode, templateConst), initialHeap_(initialHeap) { setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, templateObject())); - } } public: @@ -3787,7 +3716,6 @@ explicit MGuardArgumentsObjectNotOverriddenIterator(MDefinition* argsObj) : MUnaryInstruction(classOpcode, argsObj) { setResultType(MIRType::Object); - setResultTypeSet(argsObj->resultTypeSet()); setMovable(); setGuard(); } @@ -6360,10 +6288,6 @@ MDefinition* string, MDefinition* sep, ObjectGroup* group) : MBinaryInstruction(classOpcode, string, sep), group_(group) { setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - TemporaryTypeSet* types = MakeSingletonTypeSet(alloc, constraints, group); - setResultTypeSet(types); - } } public: @@ -6581,11 +6505,6 @@ // Whether this phi's type already includes information for def. bool typeIncludes(MDefinition* def); - // Add types for this phi which speculate about new inputs that may come in - // via a loop backedge. - MOZ_MUST_USE bool addBackedgeType(TempAllocator& alloc, MIRType type, - TemporaryTypeSet* typeSet); - // Mark all phis in |iterators|, and the phis they flow into, as having // implicit uses. static MOZ_MUST_USE bool markIteratorPhis(const PhiVector& iterators); @@ -6618,14 +6537,8 @@ MOZ_ALWAYS_TRUE(addInputSlow(ins)); } - // Update the type of this phi after adding |ins| as an input. Set - // |*ptypeChange| to true if the type changed. - bool checkForTypeChange(TempAllocator& alloc, MDefinition* ins, - bool* ptypeChange); - MDefinition* foldsTo(TempAllocator& alloc) override; MDefinition* foldsTernary(TempAllocator& alloc); - MDefinition* foldsFilterTypeSet(); bool congruentTo(const MDefinition* ins) const override; bool updateForReplacement(MDefinition* def) override; @@ -6673,7 +6586,6 @@ MBeta(MDefinition* val, const Range* comp) : MUnaryInstruction(classOpcode, val), comparison_(comp) { setResultType(val->type()); - setResultTypeSet(val->resultTypeSet()); } public: @@ -6893,7 +6805,6 @@ explicit MLexicalCheck(MDefinition* input) : MUnaryInstruction(classOpcode, input) { setResultType(MIRType::Value); - setResultTypeSet(input->resultTypeSet()); setMovable(); setGuard(); @@ -6993,9 +6904,6 @@ source_(source), hasShared_(hasShared) { setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, source)); - } } public: @@ -7325,12 +7233,6 @@ MDefinition* envChain, MConstant* cst, const LambdaFunctionInfo& info) : MBinaryInstruction(classOpcode, envChain, cst), info_(info) { setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - JSFunction* fun = info.funUnsafe(); - if (!info.singletonType && !info.useSingletonForClone) { - setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, fun)); - } - } } public: @@ -7359,13 +7261,6 @@ : MTernaryInstruction(classOpcode, envChain, newTarget, cst), info_(info) { setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - JSFunction* fun = info.funUnsafe(); - MOZ_ASSERT(!info.useSingletonForClone); - if (!info.singletonType) { - setResultTypeSet(MakeSingletonTypeSet(alloc, constraints, fun)); - } - } } public: @@ -7576,7 +7471,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(object->resultTypeSet()); } public: @@ -9132,9 +9026,6 @@ bool hasFunction(JSFunction* func) const; bool hasObjectGroup(ObjectGroup* group) const; - TemporaryTypeSet* buildTypeSetForFunction(TempAllocator& tempAlloc, - JSFunction* func) const; - // Remove targets that vetoed inlining from the InlinePropertyTable. void trimTo(const InliningTargets& targets, const BoolVector& choiceSet); @@ -9573,7 +9464,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(obj->resultTypeSet()); if (!JitOptions.warpBuilder) { // Ion has special handling for shape guard bailouts. setBailoutKind(BailoutKind::ShapeGuard); @@ -9612,7 +9502,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(obj->resultTypeSet()); } public: @@ -9644,7 +9533,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(obj->resultTypeSet()); } public: @@ -9675,7 +9563,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(obj->resultTypeSet()); } public: @@ -9697,7 +9584,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(obj->resultTypeSet()); } public: @@ -9720,7 +9606,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(proxy->resultTypeSet()); } public: @@ -9989,7 +9874,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(obj->resultTypeSet()); } public: @@ -10012,7 +9896,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(obj->resultTypeSet()); } public: @@ -10160,7 +10043,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(fun->resultTypeSet()); } public: @@ -10196,7 +10078,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(fun->resultTypeSet()); } public: @@ -10227,7 +10108,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(fun->resultTypeSet()); } public: @@ -10270,7 +10150,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(fun->resultTypeSet()); } public: @@ -10315,7 +10194,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(obj->resultTypeSet()); if (!JitOptions.warpBuilder) { // Ion has special handling for shape guard bailouts. setBailoutKind(BailoutKind::ShapeGuard); @@ -11948,10 +11826,6 @@ numFormals_(numFormals), templateObject_(templateObject) { setResultType(MIRType::Object); - if (!JitOptions.warpBuilder) { - setResultTypeSet( - MakeSingletonTypeSet(alloc, constraints, templateObject)); - } } public: @@ -11969,91 +11843,6 @@ } }; -class MFilterTypeSet : public MUnaryInstruction, - public FilterTypeSetPolicy::Data { - MFilterTypeSet(MDefinition* def, TemporaryTypeSet* types) - : MUnaryInstruction(classOpcode, def) { - MOZ_ASSERT(!types->unknown()); - setResultType(types->getKnownMIRType()); - setResultTypeSet(types); - } - - public: - INSTRUCTION_HEADER(FilterTypeSet) - TRIVIAL_NEW_WRAPPERS - - bool congruentTo(const MDefinition* def) const override { return false; } - AliasSet getAliasSet() const override { return AliasSet::None(); } - virtual bool neverHoist() const override { return resultTypeSet()->empty(); } - void computeRange(TempAllocator& alloc) override; - - bool isFloat32Commutative() const override { - return IsFloatingPointType(type()); - } - - bool canProduceFloat32() const override; - bool canConsumeFloat32(MUse* operand) const override; - void trySpecializeFloat32(TempAllocator& alloc) override; -}; - -// Given a value, guard that the value is in a particular TypeSet, then returns -// that value. -class MTypeBarrier : public MUnaryInstruction, public TypeBarrierPolicy::Data { - BarrierKind barrierKind_; - - MTypeBarrier(MDefinition* def, TemporaryTypeSet* types, - BarrierKind kind = BarrierKind::TypeSet) - : MUnaryInstruction(classOpcode, def), barrierKind_(kind) { - MOZ_ASSERT(kind == BarrierKind::TypeTagOnly || - kind == BarrierKind::TypeSet); - - MOZ_ASSERT(!types->unknown()); - setResultType(types->getKnownMIRType()); - setResultTypeSet(types); - - setGuard(); - setMovable(); - } - - public: - INSTRUCTION_HEADER(TypeBarrier) - TRIVIAL_NEW_WRAPPERS - -#ifdef JS_JITSPEW - void printOpcode(GenericPrinter& out) const override; -#endif - - bool congruentTo(const MDefinition* def) const override; - - AliasSet getAliasSet() const override { return AliasSet::None(); } - virtual bool neverHoist() const override { return resultTypeSet()->empty(); } - BarrierKind barrierKind() const { return barrierKind_; } - MDefinition* foldsTo(TempAllocator& alloc) override; - - bool canRedefineInput(); - - bool alwaysBails() const { - // If mirtype of input doesn't agree with mirtype of barrier, - // we will definitely bail. - MIRType type = resultTypeSet()->getKnownMIRType(); - if (type == MIRType::Value) { - return false; - } - if (input()->type() == MIRType::Value) { - return false; - } - if (input()->type() == MIRType::ObjectOrNull) { - // The ObjectOrNull optimization is only performed when the - // barrier's type is MIRType::Null. - MOZ_ASSERT(type == MIRType::Null); - return false; - } - return input()->type() != type; - } - - ALLOW_CLONE(MTypeBarrier) -}; - // Given a value being written to another object, update the generational store // buffer if the value is in the nursery and object is in the tenured heap. class MPostWriteBarrier : public MBinaryInstruction, @@ -12601,7 +12390,6 @@ : MUnaryInstruction(classOpcode, thisVal) { setGuard(); setResultType(MIRType::Value); - setResultTypeSet(thisVal->resultTypeSet()); } public: @@ -12619,7 +12407,6 @@ : MUnaryInstruction(classOpcode, thisVal) { setGuard(); setResultType(MIRType::Value); - setResultTypeSet(thisVal->resultTypeSet()); } public: @@ -12840,13 +12627,7 @@ MCheckIsObj(TempAllocator& alloc, MDefinition* value, uint8_t checkKind) : MUnaryInstruction(classOpcode, value), checkKind_(checkKind) { - TemporaryTypeSet* resultSet = value->resultTypeSet(); - if (resultSet) { - resultSet = resultSet->cloneObjectsOnly(alloc.lifoAlloc()); - } - setResultType(MIRType::Object); - setResultTypeSet(resultSet); setGuard(); } @@ -12866,7 +12647,6 @@ : MUnaryInstruction(classOpcode, toCheck) { setGuard(); setResultType(MIRType::Value); - setResultTypeSet(toCheck->resultTypeSet()); } public: @@ -12888,7 +12668,6 @@ : MUnaryInstruction(classOpcode, heritage) { setGuard(); setResultType(MIRType::Value); - setResultTypeSet(heritage->resultTypeSet()); } public: @@ -12903,7 +12682,6 @@ : MUnaryInstruction(classOpcode, toCheck) { setGuard(); setResultType(MIRType::Value); - setResultTypeSet(toCheck->resultTypeSet()); } public: @@ -12951,7 +12729,6 @@ setGuard(); setMovable(); setResultType(MIRType::Object); - setResultTypeSet(array->resultTypeSet()); } public: @@ -13067,7 +12844,6 @@ explicit MInitHomeObject(MDefinition* function, MDefinition* homeObject) : MBinaryInstruction(classOpcode, function, homeObject) { setResultType(MIRType::Object); - setResultTypeSet(function->resultTypeSet()); } public: @@ -13155,7 +12931,6 @@ MGuardHasGetterSetter(MDefinition* obj, Shape* shape) : MUnaryInstruction(classOpcode, obj), shape_(shape) { setResultType(MIRType::Object); - setResultTypeSet(obj->resultTypeSet()); setMovable(); setGuard(); } @@ -14697,47 +14472,6 @@ // Helper functions used to decide how to build MIR. -bool ElementAccessIsDenseNative(CompilerConstraintList* constraints, - MDefinition* obj, MDefinition* id); -bool ElementAccessIsTypedArray(CompilerConstraintList* constraints, - MDefinition* obj, MDefinition* id, - Scalar::Type* arrayType); -bool ElementAccessIsPacked(CompilerConstraintList* constraints, - MDefinition* obj); -bool ElementAccessMightBeCopyOnWrite(CompilerConstraintList* constraints, - MDefinition* obj); -bool ElementAccessMightBeNonExtensible(CompilerConstraintList* constraints, - MDefinition* obj); -AbortReasonOr ElementAccessHasExtraIndexedProperty(IonBuilder* builder, - MDefinition* obj); -MIRType DenseNativeElementType(CompilerConstraintList* constraints, - MDefinition* obj); -BarrierKind PropertyReadNeedsTypeBarrier( - JSContext* propertycx, TempAllocator& alloc, - CompilerConstraintList* constraints, TypeSet::ObjectKey* key, - PropertyName* name, TemporaryTypeSet* observed, bool updateObserved); -BarrierKind PropertyReadNeedsTypeBarrier(JSContext* propertycx, - TempAllocator& alloc, - CompilerConstraintList* constraints, - MDefinition* obj, PropertyName* name, - TemporaryTypeSet* observed); -AbortReasonOr PropertyReadOnPrototypeNeedsTypeBarrier( - IonBuilder* builder, MDefinition* obj, PropertyName* name, - TemporaryTypeSet* observed); -bool PropertyReadIsIdempotent(CompilerConstraintList* constraints, - MDefinition* obj, PropertyName* name); -bool CanWriteProperty(TempAllocator& alloc, CompilerConstraintList* constraints, - HeapTypeSetKey property, MDefinition* value, - MIRType implicitType = MIRType::None); -bool PropertyWriteNeedsTypeBarrier(TempAllocator& alloc, - CompilerConstraintList* constraints, - MBasicBlock* current, MDefinition** pobj, - PropertyName* name, MDefinition** pvalue, - bool canModify, - MIRType implicitType = MIRType::None); -AbortReasonOr TypeCanHaveExtraIndexedProperties(IonBuilder* builder, - TemporaryTypeSet* types); - inline MIRType MIRTypeForArrayBufferViewRead(Scalar::Type arrayType, bool observedDouble) { switch (arrayType) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/moz.build firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/moz.build --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/moz.build 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/moz.build 2020-11-17 19:31:31.000000000 +0000 @@ -29,7 +29,6 @@ "BaselineFrame.cpp", "BaselineFrameInfo.cpp", "BaselineIC.cpp", - "BaselineInspector.cpp", "BaselineJIT.cpp", "BitSet.cpp", "BytecodeAnalysis.cpp", @@ -48,7 +47,6 @@ "InstructionReordering.cpp", "Ion.cpp", "IonAnalysis.cpp", - "IonBuilder.cpp", "IonCacheIRCompiler.cpp", "IonCompileTask.cpp", "IonIC.cpp", @@ -69,7 +67,6 @@ "LIR.cpp", "Lowering.cpp", "MacroAssembler.cpp", - "MCallOptimize.cpp", "MIR.cpp", "MIRGraph.cpp", "MoveResolver.cpp", @@ -87,7 +84,6 @@ "shared/Lowering-shared.cpp", "Sink.cpp", "Snapshots.cpp", - "TIOracle.cpp", "TrialInlining.cpp", "TypePolicy.cpp", "ValueNumbering.cpp", diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/none/SharedICHelpers-none.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/none/SharedICHelpers-none.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/none/SharedICHelpers-none.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/none/SharedICHelpers-none.h 2020-11-17 19:31:31.000000000 +0000 @@ -15,9 +15,6 @@ inline void EmitRestoreTailCallReg(MacroAssembler&) { MOZ_CRASH(); } inline void EmitRepushTailCallReg(MacroAssembler&) { MOZ_CRASH(); } inline void EmitCallIC(MacroAssembler&, CodeOffset*) { MOZ_CRASH(); } -inline void EmitEnterTypeMonitorIC(MacroAssembler&, size_t v = 0) { - MOZ_CRASH(); -} inline void EmitReturnFromIC(MacroAssembler&) { MOZ_CRASH(); } inline void EmitBaselineLeaveStubFrame(MacroAssembler&, bool v = false) { MOZ_CRASH(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/RangeAnalysis.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/RangeAnalysis.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/RangeAnalysis.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/RangeAnalysis.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -1726,10 +1726,6 @@ setRange(output); } -void MFilterTypeSet::computeRange(TempAllocator& alloc) { - setRange(new (alloc) Range(getOperand(0))); -} - static Range* GetArrayBufferViewRange(TempAllocator& alloc, Scalar::Type type) { switch (type) { case Scalar::Uint8Clamped: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/shared/LIR-shared.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/shared/LIR-shared.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/shared/LIR-shared.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/shared/LIR-shared.h 2020-11-17 19:31:31.000000000 +0000 @@ -6133,41 +6133,6 @@ const LDefinition* temp() { return getTemp(0); } }; -// Guard that a value is in a TypeSet. -class LTypeBarrierV : public LInstructionHelper { - public: - LIR_HEADER(TypeBarrierV) - - LTypeBarrierV(const LBoxAllocation& input, const LDefinition& unboxTemp, - const LDefinition& objTemp) - : LInstructionHelper(classOpcode) { - setBoxOperand(Input, input); - setTemp(0, unboxTemp); - setTemp(1, objTemp); - } - - static const size_t Input = 0; - - const MTypeBarrier* mir() const { return mir_->toTypeBarrier(); } - const LDefinition* unboxTemp() { return getTemp(0); } - const LDefinition* objTemp() { return getTemp(1); } -}; - -// Guard that a object is in a TypeSet. -class LTypeBarrierO : public LInstructionHelper<1, 1, 1> { - public: - LIR_HEADER(TypeBarrierO) - - LTypeBarrierO(const LAllocation& obj, const LDefinition& temp) - : LInstructionHelper(classOpcode) { - setOperand(0, obj); - setTemp(0, temp); - } - const MTypeBarrier* mir() const { return mir_->toTypeBarrier(); } - const LAllocation* object() { return getOperand(0); } - const LDefinition* temp() { return getTemp(0); } -}; - // Generational write barrier used when writing an object to another object. class LPostWriteBarrierO : public LInstructionHelper<0, 2, 1> { public: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/shared/Lowering-shared-inl.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/shared/Lowering-shared-inl.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/shared/Lowering-shared-inl.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/shared/Lowering-shared-inl.h 2020-11-17 19:31:32.000000000 +0000 @@ -367,32 +367,6 @@ } else { ensureDefined(as); def->setVirtualRegister(as->virtualRegister()); - -#ifdef DEBUG - if (JitOptions.runExtraChecks && def->resultTypeSet() && - as->resultTypeSet() && - !def->resultTypeSet()->equals(as->resultTypeSet())) { - switch (def->type()) { - case MIRType::Object: - case MIRType::ObjectOrNull: - case MIRType::String: - case MIRType::Symbol: - case MIRType::BigInt: { - LAssertResultT* check = - new (alloc()) LAssertResultT(useRegister(def)); - add(check, def->toInstruction()); - break; - } - case MIRType::Value: { - LAssertResultV* check = new (alloc()) LAssertResultV(useBox(def)); - add(check, def->toInstruction()); - break; - } - default: - break; - } - } -#endif } } @@ -649,9 +623,6 @@ return inner->virtualRegister(); } } - if (mir->isTypeBarrier() && mir->toTypeBarrier()->canRedefineInput()) { - return VirtualRegisterOfPayload(mir->toTypeBarrier()->input()); - } return mir->virtualRegister() + VREG_DATA_OFFSET; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/TIOracle.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/TIOracle.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/TIOracle.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/TIOracle.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "jit/TIOracle.h" - -#include "jit/IonBuilder.h" -#include "vm/TypedArrayObject.h" - -#include "vm/JSScript-inl.h" -#include "vm/TypeInference-inl.h" - -using namespace js; -using namespace js::jit; - -using ObjectKey = js::TypeSet::ObjectKey; - -TIOracle::TIOracle(IonBuilder* builder, CompilerConstraintList* constraints) - : builder_(builder), constraints_(constraints) {} - -TIOracle::Group::Group(JSObject* raw) : raw_(ObjectKey::get(raw)) {} -TIOracle::Group::Group(ObjectGroup* raw) : raw_(ObjectKey::get(raw)) {} - -AbortReasonOr TIOracle::ensureBallast() { - if (!builder_->alloc().ensureBallast()) { - return builder_->abort(AbortReason::Alloc); - } - return Ok(); -} - -TIOracle::TypeSet TIOracle::resultTypeSet(MDefinition* def) { - return TIOracle::TypeSet(def->resultTypeSet()); -} - -TIOracle::Object TIOracle::wrapObject(JSObject* object) { - return TIOracle::Object(builder_->checkNurseryObject(object)); -} - -bool TIOracle::hasStableClass(TIOracle::Object obj) { - ObjectKey* key = ObjectKey::get(obj.toRaw()); - return key->hasStableClassAndProto(constraints_); -} - -bool TIOracle::hasStableProto(TIOracle::Object obj) { - ObjectKey* key = ObjectKey::get(obj.toRaw()); - return key->hasStableClassAndProto(constraints_); -} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/TIOracle.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/TIOracle.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/TIOracle.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/TIOracle.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,113 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: set ts=8 sts=2 et sw=2 tw=80: - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef jit_TIOracle_h -#define jit_TIOracle_h - -#include "jit/Ion.h" -#include "vm/TypeInference.h" - -namespace js { -namespace jit { - -// [SMDOC] TI Oracle -// -// The SpiderMonkey VM collects runtime type inference data as it proceeds that -// describe the possible set of types that may exist at different locations. -// During IonMonkey compilation, the compiler may decide to depend on this TI -// data. To ensure that this is safe, even if the TI data changes in the future, -// IonMonkey registers invalidation hooks on the data it depends on. -// -// The TIOracle interface makes sure that we attach the right constraints by -// providing a layer of abstraction between IonBuilder and TI. Instead of having -// direct access to TI and being responsible for attaching the right -// constraints, IonBuilder queries the TIOracle. The TIOracle is responsible for -// attaching the correct constraints so that the results of queries continue to -// be true for the lifetime of the compiled script. - -class IonBuilder; -class MDefinition; - -class TIOracle { - public: - class Object { - JSObject* raw_; - explicit Object(JSObject* raw) : raw_(raw) {} - - friend class TIOracle; - - public: - JSObject* toRaw() { return raw_; } - - // You must be certain the object is guaranteed through TI and/or - // precise guards. - static Object unsafeFromRaw(JSObject* raw) { return Object(raw); } - - explicit operator bool() { return !!raw_; } - }; - - // Note: this is called TIOracle::Group even though it is currently - // wrapping an ObjectKey. This is because, conceptually, ObjectKey - // is nothing more than "ObjectGroup plus the ability to retrieve - // the lone object in a singleton group". - class Group { - using ObjectKey = js::TypeSet::ObjectKey; - - ObjectKey* raw_; - explicit Group(ObjectKey* raw) : raw_(raw) {} - explicit Group(JSObject* raw); - explicit Group(ObjectGroup* raw); - - friend class TIOracle; - - public: - ObjectKey* toRaw() { return raw_; } - - template - static Group unsafeFromRaw(T raw) { - return Group(raw); - } - - explicit operator bool() { return !!raw_; } - }; - - class TypeSet { - TemporaryTypeSet* raw_; - explicit TypeSet(TemporaryTypeSet* raw) : raw_(raw) {} - - friend class TIOracle; - - public: - TemporaryTypeSet* toRaw() { return raw_; } - - static TypeSet unsafeFromRaw(TemporaryTypeSet* raw) { return TypeSet(raw); } - - explicit operator bool() { return !!raw_; } - }; - - explicit TIOracle(IonBuilder* builder, CompilerConstraintList* constraints); - - IonBuilder* builder() { return builder_; } - CompilerConstraintList* constraints() { return constraints_; } - - AbortReasonOr ensureBallast(); - - TypeSet resultTypeSet(MDefinition* def); - - private: - Object wrapObject(JSObject* object); - - bool hasStableClass(Object obj); - bool hasStableProto(Object obj); - - IonBuilder* builder_; - CompilerConstraintList* constraints_; -}; - -} // namespace jit -} // namespace js - -#endif /* jit_TIOracle_h */ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/TypePolicy.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/TypePolicy.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/TypePolicy.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/TypePolicy.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -314,65 +314,6 @@ return BoxInputsPolicy::staticAdjustInputs(alloc, def); } -bool TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, - MInstruction* def) const { - MTypeBarrier* ins = def->toTypeBarrier(); - MIRType inputType = ins->getOperand(0)->type(); - MIRType outputType = ins->type(); - - // Input and output type are already in accordance. - if (inputType == outputType) { - return true; - } - - // Output is a value, currently box the input. - if (outputType == MIRType::Value) { - // XXX: Possible optimization: decrease resultTypeSet to only include - // the inputType. This will remove the need for boxing. - MOZ_ASSERT(inputType != MIRType::Value); - ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); - return true; - } - - // Box input if needed. - if (inputType != MIRType::Value) { - MOZ_ASSERT(ins->alwaysBails()); - ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); - } - - // We can't unbox a value to null/undefined/lazyargs. So keep output - // also a value. - // Note: Using setResultType shouldn't be done in TypePolicies, - // Here it is fine, since the type barrier has no uses. - if (IsNullOrUndefined(outputType) || - outputType == MIRType::MagicOptimizedArguments) { - MOZ_ASSERT(!ins->hasDefUses()); - ins->setResultType(MIRType::Value); - return true; - } - - // Unbox / propagate the right type. - MUnbox::Mode mode = MUnbox::TypeBarrier; - MInstruction* replace = - MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode); - if (!ins->isMovable()) { - replace->setNotMovable(); - } - - ins->block()->insertBefore(ins, replace); - ins->replaceOperand(0, replace); - if (!replace->typePolicy()->adjustInputs(alloc, replace)) { - return false; - } - - // The TypeBarrier is equivalent to removing branches with unexpected - // types. The unexpected types would have changed Range Analysis - // predictions. As such, we need to prevent destructive optimizations. - ins->block()->flagOperandsOfPrunedBranches(replace); - - return true; -} - bool TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { MDefinition* op = ins->getOperand(0); switch (op->type()) { @@ -1120,88 +1061,6 @@ return true; } -bool FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, - MInstruction* ins) const { - MOZ_ASSERT(ins->numOperands() == 1); - MIRType inputType = ins->getOperand(0)->type(); - MIRType outputType = ins->type(); - - // Special case when output is a Float32, but input isn't. - if (outputType == MIRType::Float32 && inputType != MIRType::Float32) { - // Create a MToFloat32 to add between the MFilterTypeSet and - // its uses. - MInstruction* replace = MToFloat32::New(alloc, ins); - ins->justReplaceAllUsesWithExcept(replace); - ins->block()->insertAfter(ins, replace); - - // Reset the type to not MIRType::Float32 - // Note: setResultType shouldn't happen in TypePolicies, - // Here it is fine, since there is just one use we just - // added ourself. And the resulting type after MToFloat32 - // equals the original type. - ins->setResultType(ins->resultTypeSet()->getKnownMIRType()); - outputType = ins->type(); - - // Do the type analysis - if (!replace->typePolicy()->adjustInputs(alloc, replace)) { - return false; - } - - // Fall through to let the MFilterTypeSet adjust its input based - // on its new type. - } - - // Input and output type are already in accordance. - if (inputType == outputType) { - return true; - } - - // Output is a value, box the input. - if (outputType == MIRType::Value) { - MOZ_ASSERT(inputType != MIRType::Value); - ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); - return true; - } - - // The outputType should be a subset of the inputType else we are in code - // that has never executed yet. Bail to see the new type (if that hasn't - // happened yet). - if (inputType != MIRType::Value) { - MBail* bail = MBail::New(alloc); - ins->block()->insertBefore(ins, bail); - bail->setDependency(ins->dependency()); - ins->setDependency(bail); - ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0))); - } - - // We can't unbox a value to null/undefined/lazyargs. So keep output - // also a value. - // Note: Using setResultType shouldn't be done in TypePolicies, - // Here it is fine, since the type barrier has no uses. - if (IsNullOrUndefined(outputType) || - outputType == MIRType::MagicOptimizedArguments) { - MOZ_ASSERT(!ins->hasDefUses()); - ins->setResultType(MIRType::Value); - return true; - } - - // Unbox / propagate the right type. - MUnbox::Mode mode = MUnbox::Infallible; - MInstruction* replace = - MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode); - - ins->block()->insertBefore(ins, replace); - ins->replaceOperand(0, replace); - if (!replace->typePolicy()->adjustInputs(alloc, replace)) { - return false; - } - - // Carry over the dependency the MFilterTypeSet had. - replace->setDependency(ins->dependency()); - - return true; -} - bool TypedArrayIndexPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const { MOZ_ASSERT(ins->isTypedArrayIndexToInt32()); @@ -1227,7 +1086,6 @@ _(CallSetElementPolicy) \ _(ClampPolicy) \ _(ComparePolicy) \ - _(FilterTypeSetPolicy) \ _(PowPolicy) \ _(SameValuePolicy) \ _(SignPolicy) \ @@ -1240,7 +1098,6 @@ _(ToBigIntPolicy) \ _(ToStringPolicy) \ _(ToInt64Policy) \ - _(TypeBarrierPolicy) \ _(TypedArrayIndexPolicy) #define TEMPLATE_TYPE_POLICY_LIST(_) \ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/TypePolicy.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/TypePolicy.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/TypePolicy.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/TypePolicy.h 2020-11-17 19:31:31.000000000 +0000 @@ -131,14 +131,6 @@ MInstruction* ins) const override; }; -class TypeBarrierPolicy final : public TypePolicy { - public: - constexpr TypeBarrierPolicy() = default; - EMPTY_DATA_; - MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, - MInstruction* ins) const override; -}; - class CallPolicy final : public TypePolicy { public: constexpr CallPolicy() = default; @@ -506,14 +498,6 @@ EMPTY_DATA_; MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, MInstruction* ins) const override; -}; - -class FilterTypeSetPolicy final : public TypePolicy { - public: - constexpr FilterTypeSetPolicy() = default; - EMPTY_DATA_; - MOZ_MUST_USE bool adjustInputs(TempAllocator& alloc, - MInstruction* ins) const override; }; // Policy for MTypedArrayIndexToInt32. Operand is either Double or Int32. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/VMFunctionList-inl.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/VMFunctionList-inl.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/VMFunctionList-inl.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/VMFunctionList-inl.h 2020-11-17 19:31:32.000000000 +0000 @@ -121,7 +121,6 @@ _(DoSpreadCallFallback, js::jit::DoSpreadCallFallback) \ _(DoStringToInt64, js::jit::DoStringToInt64) \ _(DoTrialInlining, js::jit::DoTrialInlining) \ - _(DoTypeUpdateFallback, js::jit::DoTypeUpdateFallback) \ _(EnterWith, js::jit::EnterWith) \ _(FinalSuspend, js::jit::FinalSuspend) \ _(FinishBoundFunctionInit, JSFunction::finishBoundFunctionInit) \ @@ -307,7 +306,6 @@ _(DoSetPropFallback, js::jit::DoSetPropFallback, 1) \ _(DoToBoolFallback, js::jit::DoToBoolFallback, 0) \ _(DoToPropertyKeyFallback, js::jit::DoToPropertyKeyFallback, 0) \ - _(DoTypeMonitorFallback, js::jit::DoTypeMonitorFallback, 0) \ _(DoTypeOfFallback, js::jit::DoTypeOfFallback, 0) \ _(DoUnaryArithFallback, js::jit::DoUnaryArithFallback, 1) diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/VMFunctions.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/VMFunctions.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/VMFunctions.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/VMFunctions.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -908,6 +908,7 @@ bool ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval) { MOZ_ASSERT(obj->is()); + // TODO(no-TI): remove AutoDetectInvalidation. AutoDetectInvalidation adi(cx, rval); JS::RootedValueArray<2> argv(cx); @@ -917,14 +918,7 @@ return false; } - // If the result is |undefined|, the array was probably empty and we - // have to monitor the return value. rval.set(argv[0]); - if (rval.isUndefined()) { - jsbytecode* pc; - JSScript* script = cx->currentScript(&pc); - JitScript::MonitorBytecodeType(cx, script, pc, rval); - } return true; } @@ -987,14 +981,7 @@ return false; } - // If the result is |undefined|, the array was probably empty and we - // have to monitor the return value. rval.set(argv[0]); - if (rval.isUndefined()) { - jsbytecode* pc; - JSScript* script = cx->currentScript(&pc); - JitScript::MonitorBytecodeType(cx, script, pc, rval); - } return true; } @@ -1155,22 +1142,7 @@ bool GetIntrinsicValue(JSContext* cx, HandlePropertyName name, MutableHandleValue rval) { - if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, rval)) { - return false; - } - - // This function is called when we try to compile a cold getintrinsic - // op. MCallGetIntrinsicValue has an AliasSet of None for optimization - // purposes, as its side effect is not observable from JS. We are - // guaranteed to bail out after this function, but because of its AliasSet, - // type info will not be reflowed. Manually monitor here. - if (!JitOptions.warpBuilder) { - jsbytecode* pc; - JSScript* script = cx->currentScript(&pc); - JitScript::MonitorBytecodeType(cx, script, pc, rval); - } - - return true; + return GlobalObject::getIntrinsicValue(cx, cx->global(), name, rval); } bool CreateThisFromIC(JSContext* cx, HandleObject callee, @@ -2446,9 +2418,6 @@ } } - // Note: we don't have to call JitScript::MonitorBytecodeType because we - // monitored the string-type when attaching the IC stub. - res.setString(str); return true; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/WarpBuilder.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/WarpBuilder.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/WarpBuilder.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/WarpBuilder.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -191,8 +191,7 @@ if (info().funMaybeLazy()) { // Initialize |this| parameter. - MParameter* thisv = - MParameter::New(alloc(), MParameter::THIS_SLOT, nullptr); + MParameter* thisv = MParameter::New(alloc(), MParameter::THIS_SLOT); osrBlock->add(thisv); osrBlock->initSlot(info().thisSlot(), thisv); @@ -209,7 +208,7 @@ uint32_t slot = info().argSlotUnchecked(i); MInstruction* osrv; if (!needsArgsObj || !info().argsObjAliasesFormals()) { - osrv = MParameter::New(alloc().fallible(), i, nullptr); + osrv = MParameter::New(alloc().fallible(), i); } else if (script_->formalIsAliased(i)) { osrv = MConstant::New(alloc().fallible(), UndefinedValue()); } else { @@ -444,14 +443,13 @@ if (info().funMaybeLazy()) { // Initialize |this|. - MParameter* param = - MParameter::New(alloc(), MParameter::THIS_SLOT, nullptr); + MParameter* param = MParameter::New(alloc(), MParameter::THIS_SLOT); current->add(param); current->initSlot(info().thisSlot(), param); // Initialize arguments. for (uint32_t i = 0; i < info().nargs(); i++) { - MParameter* param = MParameter::New(alloc().fallible(), i, nullptr); + MParameter* param = MParameter::New(alloc().fallible(), i); if (!param) { return false; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/WarpOracle.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/WarpOracle.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/WarpOracle.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/WarpOracle.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -28,6 +28,7 @@ #include "vm/Instrumentation.h" #include "vm/Opcodes.h" +#include "jit/InlineScriptTree-inl.h" #include "vm/BytecodeIterator-inl.h" #include "vm/BytecodeLocation-inl.h" #include "vm/EnvironmentObject-inl.h" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/x64/SharedICHelpers-x64.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/x64/SharedICHelpers-x64.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/x64/SharedICHelpers-x64.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/x64/SharedICHelpers-x64.h 2020-11-17 19:31:32.000000000 +0000 @@ -34,17 +34,6 @@ *callOffset = CodeOffset(masm.currentOffset()); } -inline void EmitEnterTypeMonitorIC( - MacroAssembler& masm, - size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub()) { - // This is expected to be called from within an IC, when ICStubReg - // is properly initialized to point to the stub. - masm.loadPtr(Address(ICStubReg, (int32_t)monitorStubOffset), ICStubReg); - - // Jump to the stubcode. - masm.jmp(Operand(ICStubReg, (int32_t)ICStub::offsetOfStubCode())); -} - inline void EmitReturnFromIC(MacroAssembler& masm) { masm.ret(); } inline void EmitBaselineLeaveStubFrame(MacroAssembler& masm, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/x86/SharedICHelpers-x86.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/x86/SharedICHelpers-x86.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit/x86/SharedICHelpers-x86.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit/x86/SharedICHelpers-x86.h 2020-11-17 19:31:31.000000000 +0000 @@ -34,17 +34,6 @@ *callOffset = CodeOffset(masm.currentOffset()); } -inline void EmitEnterTypeMonitorIC( - MacroAssembler& masm, - size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub()) { - // This is expected to be called from within an IC, when ICStubReg - // is properly initialized to point to the stub. - masm.loadPtr(Address(ICStubReg, (int32_t)monitorStubOffset), ICStubReg); - - // Jump to the stubcode. - masm.jmp(Operand(ICStubReg, (int32_t)ICStub::offsetOfStubCode())); -} - inline void EmitReturnFromIC(MacroAssembler& masm) { masm.ret(); } inline void EmitBaselineLeaveStubFrame(MacroAssembler& masm, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/arguments/bug1227287.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/arguments/bug1227287.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/arguments/bug1227287.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/arguments/bug1227287.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,5 +1,4 @@ -// |jit-test| --no-warp -// Ion/Warp has known issues with function.arguments. See bug 1626294. +// Note: Ion/Warp have known issues with function.arguments. See bug 1626294. function f(y) { y = 1; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/bug1100623.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/bug1100623.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/bug1100623.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/bug1100623.js 2020-11-17 19:31:30.000000000 +0000 @@ -1,6 +1,4 @@ -// |jit-test| error: baz is null; --no-warp -// Disable WarpBuilder because the expression decompiler is not used for Ion -// frames currently. See bug 831120. +// |jit-test| error: baz is null var document = {getElementById: () => null}; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/expression-autopsy.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/expression-autopsy.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/expression-autopsy.js 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/expression-autopsy.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,7 +1,3 @@ -// |jit-test| --no-warp -// Disable WarpBuilder because the expression decompiler is not used for Ion -// frames currently. See bug 831120. - load(libdir + "asserts.js"); load(libdir + "iteration.js"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/iterable-error-messages.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/iterable-error-messages.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/iterable-error-messages.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/iterable-error-messages.js 2020-11-17 19:31:30.000000000 +0000 @@ -1,7 +1,3 @@ -// |jit-test| --no-warp -// Disable WarpBuilder because the expression decompiler is not used for Ion -// frames currently. See bug 831120. - function assertThrowsMsgEndsWith(f, msg) { try { f(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/monitor-type-function.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/monitor-type-function.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/monitor-type-function.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/monitor-type-function.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -// |jit-test| skip-if: !isTypeInferenceEnabled() - -function f(x) { - return f.toString(); -} - -monitorType(f, 0, "unknown"); -monitorType(f, 1, "unknownObject"); -monitorType(f, 2, Symbol()); -monitorType(f, 2, this); -monitorType(null, 0, 1); - -for (var i = 0; i < 12; i++) { - monitorType(f, 3, {}); - monitorType(undefined, 20, this); - f(i); -} - -function h() { - monitorType(g, 1, {}); - monitorType(g, 2, "unknown"); - monitorType(null, 1, {}); -} -function g() { - return new h(); -} -for (var i = 0; i < 12; i++) { - new g(); -} diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/property-error-message-fix-disabled.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/property-error-message-fix-disabled.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/property-error-message-fix-disabled.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/property-error-message-fix-disabled.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,6 +1,4 @@ -// |jit-test| --disable-property-error-message-fix; --no-warp -// Disable WarpBuilder because the expression decompiler is not used for Ion -// frames currently. See bug 831120. +// |jit-test| --disable-property-error-message-fix function check(f, message) { let caught = false; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/property-error-message-fix.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/property-error-message-fix.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/basic/property-error-message-fix.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/basic/property-error-message-fix.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,7 +1,3 @@ -// |jit-test| --no-warp -// Disable WarpBuilder because the expression decompiler is not used for Ion -// frames currently. See bug 831120. - function check(f, message) { let caught = false; try { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/debug/bug-1444604-reduced.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/debug/bug-1444604-reduced.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/debug/bug-1444604-reduced.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/debug/bug-1444604-reduced.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,6 +1,3 @@ -// |jit-test| --no-warp -// This is hitting bug 1505387 with WarpBuilder and eager compilation. - // LiveSavedFrameCache should not be confused by eval-in-frame-prev links. const g = newGlobal({newCompartment: true}); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/gc/bug-1667336.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/gc/bug-1667336.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/gc/bug-1667336.js 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/gc/bug-1667336.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,4 +1,4 @@ -// |jit-test| --ion-offthread-compile=off; --warp; skip-if: helperThreadCount() === 0 +// |jit-test| --ion-offthread-compile=off; skip-if: helperThreadCount() === 0 var g = newGlobal(); gczeal(9, 1); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/dce-with-rinstructions.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/dce-with-rinstructions.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/dce-with-rinstructions.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/dce-with-rinstructions.js 2020-11-17 19:31:31.000000000 +0000 @@ -5,7 +5,7 @@ setJitCompilerOption("ion.full.warmup.trigger", 20); var i; -var warp = getJitCompilerOptions()["warp.enable"]; +var warp = true; // Prevent GC from cancelling/discarding Ion compilations. gczeal(0); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-arrays.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-arrays.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-arrays.js 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-arrays.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,5 +1,4 @@ -// |jit-test| --no-warp - +// |jit-test| --no-ion // Warp lacks Scalar Replacement support (bug 1650233). Re-evaluate after that // bug has been fixed. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-cow-arrays.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-cow-arrays.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-cow-arrays.js 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-cow-arrays.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,5 +1,4 @@ -// |jit-test| --no-warp - +// |jit-test| --no-ion // Warp has COW arrays disabled (bug 1626854). Re-evaluate after that bug has // been fixed. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-empty-new-object.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-empty-new-object.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-empty-new-object.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-empty-new-object.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,5 +1,4 @@ -// |jit-test| --no-warp - +// |jit-test| --no-ion // Warp lacks Scalar Replacement support (bug 1650233). Re-evaluate after that // bug has been fixed. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-lambdas.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-lambdas.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-lambdas.js 2020-11-15 14:37:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-lambdas.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,5 +1,4 @@ -// |jit-test| --no-warp; --ion-osr=off - +// |jit-test| --no-ion; --ion-osr=off // Warp lacks Scalar Replacement support (bug 1650233). Re-evaluate after that // bug has been fixed. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-objects.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-objects.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/ion/recover-objects.js 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/ion/recover-objects.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,5 +1,4 @@ -// |jit-test| --no-warp; --ion-pgo=on - +// |jit-test| --no-ion; --ion-pgo=on // Warp lacks Scalar Replacement support (bug 1650233). Re-evaluate after that // bug has been fixed. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/parser/dumpStencil-01.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/parser/dumpStencil-01.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/parser/dumpStencil-01.js 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/parser/dumpStencil-01.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,3 +1,24 @@ -dumpStencil("x"); +dumpStencil("a"); +dumpStencil("ab"); +dumpStencil("abc"); +dumpStencil("/a/"); +dumpStencil("/ab/"); +dumpStencil("/abc/"); +dumpStencil("1"); +dumpStencil("1.2"); +dumpStencil("true"); +dumpStencil("[]"); +dumpStencil("[1]"); +dumpStencil("[1, 2]"); +dumpStencil("({})"); +dumpStencil("({x: 10})"); +dumpStencil("({x: a})"); +dumpStencil("({x:10, y: 20})"); +dumpStencil("({x:10, y: a})"); +dumpStencil("({x:10, [y]: a})"); dumpStencil("function y() {}"); +dumpStencil("(function y() {})"); +dumpStencil("(function() {})"); +dumpStencil("1n"); +dumpStencil("100n"); dumpStencil("export var z;", { module : true }); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/promise/newpromisecapability-error-message.js firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/promise/newpromisecapability-error-message.js --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jit-test/tests/promise/newpromisecapability-error-message.js 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jit-test/tests/promise/newpromisecapability-error-message.js 2020-11-17 19:31:31.000000000 +0000 @@ -1,7 +1,3 @@ -// |jit-test| --no-warp -// Disable WarpBuilder because the expression decompiler is not used for Ion -// frames currently. See bug 831120. - load(libdir + "asserts.js"); let foo = {}; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsapi.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsapi.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsapi.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsapi.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -5305,9 +5305,6 @@ case JSJITCOMPILER_SPECTRE_JIT_TO_CXX_CALLS: jit::JitOptions.spectreJitToCxxCalls = !!value; break; - case JSJITCOMPILER_WARP_ENABLE: - jit::JitOptions.setWarpEnabled(!!value); - break; case JSJITCOMPILER_WASM_FOLD_OFFSETS: jit::JitOptions.wasmFoldOffsets = !!value; break; @@ -5379,9 +5376,6 @@ case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE: *valueOut = rt->canUseOffthreadIonCompilation(); break; - case JSJITCOMPILER_WARP_ENABLE: - *valueOut = jit::JitOptions.warpBuilder; - break; case JSJITCOMPILER_WASM_FOLD_OFFSETS: *valueOut = jit::JitOptions.wasmFoldOffsets ? 1 : 0; break; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsapi.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsapi.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsapi.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsapi.h 2020-11-17 19:31:32.000000000 +0000 @@ -2662,7 +2662,6 @@ Register(SPECTRE_STRING_MITIGATIONS, "spectre.string-mitigations") \ Register(SPECTRE_VALUE_MASKING, "spectre.value-masking") \ Register(SPECTRE_JIT_TO_CXX_CALLS, "spectre.jit-to-C++-calls") \ - Register(WARP_ENABLE, "warp.enable") \ Register(WASM_FOLD_OFFSETS, "wasm.fold-offsets") \ Register(WASM_DELAY_TIER2, "wasm.delay-tier2") \ Register(WASM_JIT_BASELINE, "wasm.baseline") \ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsapi-tests/testJitMinimalFunc.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsapi-tests/testJitMinimalFunc.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsapi-tests/testJitMinimalFunc.h 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsapi-tests/testJitMinimalFunc.h 2020-11-17 19:31:32.000000000 +0000 @@ -67,7 +67,7 @@ } MParameter* createParameter() { - MParameter* p = MParameter::New(alloc, numParams++, nullptr); + MParameter* p = MParameter::New(alloc, numParams++); return p; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsapi-tests/testParserAtom.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsapi-tests/testParserAtom.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsapi-tests/testParserAtom.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsapi-tests/testParserAtom.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -34,10 +34,10 @@ // Check that the well-known empty atom matches for different entry points. const ParserAtom* ref = cx->parserNames().empty; CHECK(ref); - CHECK(atomTable.internAscii(cx, ascii, 0).unwrap() == ref); - CHECK(atomTable.internLatin1(cx, latin1, 0).unwrap() == ref); - CHECK(atomTable.internUtf8(cx, utf8, 0).unwrap() == ref); - CHECK(atomTable.internChar16(cx, char16, 0).unwrap() == ref); + CHECK(atomTable.internAscii(cx, ascii, 0) == ref); + CHECK(atomTable.internLatin1(cx, latin1, 0) == ref); + CHECK(atomTable.internUtf8(cx, utf8, 0) == ref); + CHECK(atomTable.internChar16(cx, char16, 0) == ref); // Check concatenation works on empty atoms. const ParserAtom* concat[] = { @@ -45,7 +45,7 @@ cx->parserNames().empty, }; mozilla::Range concatRange(concat, 2); - CHECK(atomTable.concatAtoms(cx, concatRange).unwrap() == ref); + CHECK(atomTable.concatAtoms(cx, concatRange) == ref); return true; } @@ -72,17 +72,17 @@ const ParserAtom* ref = cx->parserNames().lookupTiny(&a, 1); CHECK(ref); - CHECK(atomTable.internAscii(cx, ascii, 1).unwrap() == ref); - CHECK(atomTable.internLatin1(cx, latin1, 1).unwrap() == ref); - CHECK(atomTable.internUtf8(cx, utf8, 1).unwrap() == ref); - CHECK(atomTable.internChar16(cx, char16, 1).unwrap() == ref); + CHECK(atomTable.internAscii(cx, ascii, 1) == ref); + CHECK(atomTable.internLatin1(cx, latin1, 1) == ref); + CHECK(atomTable.internUtf8(cx, utf8, 1) == ref); + CHECK(atomTable.internChar16(cx, char16, 1) == ref); const ParserAtom* concat[] = { ref, cx->parserNames().empty, }; mozilla::Range concatRange(concat, 2); - CHECK(atomTable.concatAtoms(cx, concatRange).unwrap() == ref); + CHECK(atomTable.concatAtoms(cx, concatRange) == ref); // Note: If Latin1-Extended characters become supported, then UTF-8 behaviour // should be tested. @@ -114,17 +114,17 @@ const ParserAtom* ref = cx->parserNames().lookupTiny(ascii, 2); CHECK(ref); - CHECK(atomTable.internAscii(cx, ascii, 2).unwrap() == ref); - CHECK(atomTable.internLatin1(cx, latin1, 2).unwrap() == ref); - CHECK(atomTable.internUtf8(cx, utf8, 2).unwrap() == ref); - CHECK(atomTable.internChar16(cx, char16, 2).unwrap() == ref); + CHECK(atomTable.internAscii(cx, ascii, 2) == ref); + CHECK(atomTable.internLatin1(cx, latin1, 2) == ref); + CHECK(atomTable.internUtf8(cx, utf8, 2) == ref); + CHECK(atomTable.internChar16(cx, char16, 2) == ref); const ParserAtom* concat[] = { cx->parserNames().lookupTiny(ascii + 0, 1), cx->parserNames().lookupTiny(ascii + 1, 1), }; mozilla::Range concatRange(concat, 2); - CHECK(atomTable.concatAtoms(cx, concatRange).unwrap() == ref); + CHECK(atomTable.concatAtoms(cx, concatRange) == ref); // Note: If Latin1-Extended characters become supported, then UTF-8 behaviour // should be tested. @@ -150,19 +150,19 @@ std::vector inputs; for (const char16_t* arg : args) { size_t len = std::char_traits::length(arg); - const ParserAtom* atom = atomTable.internChar16(cx, arg, len).unwrap(); + const ParserAtom* atom = atomTable.internChar16(cx, arg, len); inputs.push_back(atom); } // Concatenate twice to test new vs existing pathways. mozilla::Range range(inputs.data(), inputs.size()); - const ParserAtom* once = atomTable.concatAtoms(cx, range).unwrap(); - const ParserAtom* twice = atomTable.concatAtoms(cx, range).unwrap(); + const ParserAtom* once = atomTable.concatAtoms(cx, range); + const ParserAtom* twice = atomTable.concatAtoms(cx, range); // Intern expected value literal _after_ the concat code to allow // allocation pathways a chance to be tested. size_t exp_len = std::char_traits::length(exp); - const ParserAtom* ref = atomTable.internChar16(cx, exp, exp_len).unwrap(); + const ParserAtom* ref = atomTable.internChar16(cx, exp, exp_len); return (once == ref) && (twice == ref); }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsnum.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsnum.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/jsnum.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/jsnum.cpp 2020-11-17 19:31:32.000000000 +0000 @@ -874,7 +874,7 @@ indexValue.emplace(si); } - return parserAtoms.internAscii(cx, start, length).unwrapOr(nullptr); + return parserAtoms.internAscii(cx, start, length); } /* Returns a non-nullptr pointer to inside cbuf. */ @@ -1680,7 +1680,7 @@ numStr < cbuf.sbuf + cbuf.sbufSize); size_t length = strlen(numStr); - return parserAtoms.internAscii(cx, numStr, length).unwrapOr(nullptr); + return parserAtoms.internAscii(cx, numStr, length); } JSLinearString* js::IndexToString(JSContext* cx, uint32_t index) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/shell/fuzz-flags.txt firefox-trunk-85.0~a1~hg20201117r557492/js/src/shell/fuzz-flags.txt --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/shell/fuzz-flags.txt 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/shell/fuzz-flags.txt 2020-11-17 19:31:32.000000000 +0000 @@ -53,8 +53,6 @@ --spectre-mitigations=off --spectre-mitigations=on --more-compartments ---warp ---no-warp --fast-warmup # GC-related diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/shell/js.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/shell/js.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/shell/js.cpp 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/shell/js.cpp 2020-11-17 19:31:31.000000000 +0000 @@ -4844,22 +4844,6 @@ return false; } - // Similarly, don't allow enabling or disabling Warp at runtime. Bytecode and - // VM data structures depend on whether TI is enabled/disabled. - if (opt == JSJITCOMPILER_WARP_ENABLE) { - uint32_t warpEnabled; - if (!JS_GetGlobalJitCompilerOption(cx, JSJITCOMPILER_WARP_ENABLE, - &warpEnabled)) { - return false; - } - if (bool(number) != warpEnabled) { - JS_ReportErrorASCII( - cx, "Enabling or disabling Warp at runtime is not supported."); - return false; - } - return true; - } - // Throw if disabling the JITs and there's JIT code on the stack, to avoid // assertion failures. if ((opt == JSJITCOMPILER_BASELINE_ENABLE || @@ -10483,11 +10467,8 @@ JS::SetUseOffThreadParseGlobal(useOffThreadParseGlobal); - // First check some options that set default warm-up thresholds, so these - // thresholds can be overridden below by --ion-eager and other flags. - if (op.getBoolOption("no-warp")) { - jit::JitOptions.setWarpEnabled(false); - } + // Check --fast-warmup first because it sets default warm-up thresholds. These + // thresholds can then be overridden below by --ion-eager and other flags. if (op.getBoolOption("fast-warmup")) { jit::JitOptions.setFastWarmUp(); } @@ -11258,8 +11239,6 @@ !op.addBoolOption('\0', "no-ion", "Disable IonMonkey") || !op.addBoolOption('\0', "no-ion-for-main-context", "Disable IonMonkey for the main context only") || - !op.addBoolOption('\0', "warp", "Enable WarpBuilder (default)") || - !op.addBoolOption('\0', "no-warp", "Disable WarpBuilder") || !op.addIntOption('\0', "inlining-entry-threshold", "COUNT", "The minimum stub entry count before trial-inlining a" " call", diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/tests/lib/tests.py firefox-trunk-85.0~a1~hg20201117r557492/js/src/tests/lib/tests.py --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/tests/lib/tests.py 2020-11-15 14:38:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/tests/lib/tests.py 2020-11-17 19:31:32.000000000 +0000 @@ -46,18 +46,6 @@ ["--baseline-eager"], ["--ion-eager", "--ion-offthread-compile=off", "--more-compartments"], ], - # Used for testing WarpBuilder. - "warp": [["--warp"], ["--warp", "--ion-eager", "--ion-offthread-compile=off"]], - "nowarp": [ - ["--no-warp"], - [ - "--no-warp", - "--ion-eager", - "--ion-offthread-compile=off", - "--more-compartments", - ], - ["--no-warp", "--baseline-eager"], - ], # Run reduced variants on debug builds, since they take longer time. "debug": [ [], # no flags, normal baseline and ion diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/util/StringBuffer.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/util/StringBuffer.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/util/StringBuffer.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/util/StringBuffer.cpp 2020-11-17 19:31:36.000000000 +0000 @@ -162,20 +162,22 @@ } if (isLatin1()) { - auto result = parserAtoms.internLatin1(cx_, latin1Chars().begin(), len); - if (result.isErr()) { + const frontend::ParserAtom* result = + parserAtoms.internLatin1(cx_, latin1Chars().begin(), len); + if (!result) { return nullptr; } latin1Chars().clear(); - return result.unwrap(); + return result; } - auto result = parserAtoms.internChar16(cx_, twoByteChars().begin(), len); - if (result.isErr()) { + const frontend::ParserAtom* result = + parserAtoms.internChar16(cx_, twoByteChars().begin(), len); + if (!result) { return nullptr; } twoByteChars().clear(); - return result.unwrap(); + return result; } bool js::ValueToStringBufferSlow(JSContext* cx, const Value& arg, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/ArgumentsObject.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/ArgumentsObject.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/ArgumentsObject.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/ArgumentsObject.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -506,19 +506,10 @@ MOZ_ASSERT(!(attrs & JSPROP_READONLY)); attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */ - RootedFunction callee(cx, &argsobj->callee()); - RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee)); - if (!script) { - return false; - } - if (JSID_IS_INT(id)) { unsigned arg = unsigned(JSID_TO_INT(id)); if (arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg)) { argsobj->setElement(cx, arg, v); - if (arg < script->function()->nargs()) { - jit::JitScript::MonitorArgType(cx, script, arg, v); - } return result.succeed(); } } else { @@ -726,15 +717,7 @@ } } else { if (desc.hasValue()) { - RootedFunction callee(cx, &argsobj->callee()); - RootedScript script(cx, JSFunction::getOrCreateScript(cx, callee)); - if (!script) { - return false; - } argsobj->setElement(cx, arg, desc.value()); - if (arg < script->function()->nargs()) { - jit::JitScript::MonitorArgType(cx, script, arg, desc.value()); - } } if (desc.hasWritable() && !desc.writable()) { if (!argsobj->markElementDeleted(cx, arg)) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/EnvironmentObject.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/EnvironmentObject.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/EnvironmentObject.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/EnvironmentObject.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -1587,10 +1587,6 @@ return true; } } - - if (action == SET) { - jit::JitScript::MonitorArgType(cx, script, i, vp); - } } // It is possible that an optimized out value flows to this diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/Instrumentation.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/Instrumentation.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/Instrumentation.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/Instrumentation.cpp 2020-11-17 19:31:36.000000000 +0000 @@ -99,10 +99,8 @@ InstrumentationKind kind) { for (size_t i = 0; i < mozilla::ArrayLength(instrumentationNames); i++) { if (kind == (InstrumentationKind)(1 << i)) { - return parserAtoms - .internAscii(cx, instrumentationNames[i], - strlen(instrumentationNames[i])) - .unwrapOr(nullptr); + return parserAtoms.internAscii(cx, instrumentationNames[i], + strlen(instrumentationNames[i])); } } MOZ_CRASH("Unexpected instrumentation kind"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/Interpreter.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/Interpreter.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/Interpreter.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/Interpreter.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -334,10 +334,7 @@ ctorScript->setDefaultClassConstructorSpan(classStartOffset, classEndOffset, line, column); - // Update TI info for the new function. - if (!JSFunction::setTypeForScriptedFunction(cx, ctor)) { - return nullptr; - } + MOZ_RELEASE_ASSERT(!IsTypeInferenceEnabled()); DebugAPI::onNewScript(cx, ctorScript); @@ -469,11 +466,6 @@ break; } - if (state.isInvoke()) { - InvokeState& invoke = *state.asInvoke(); - TypeMonitorCall(cx, invoke.args(), invoke.constructing()); - } - bool ok = Interpret(cx, state); return ok; @@ -1865,23 +1857,10 @@ static MOZ_ALWAYS_INLINE bool SetObjectElementOperation( JSContext* cx, HandleObject obj, HandleId id, HandleValue value, - HandleValue receiver, bool strict, JSScript* script = nullptr, - jsbytecode* pc = nullptr) { + HandleValue receiver, bool strict) { // receiver != obj happens only at super[expr], where we expect to find the // property. People probably aren't building hashtables with |super| // anyway. - JitScript::MonitorAssign(cx, obj, id); - - if (obj->isNative() && JSID_IS_INT(id)) { - uint32_t length = obj->as().getDenseInitializedLength(); - int32_t i = JSID_TO_INT(id); - if ((uint32_t)i >= length) { - // Annotate script if provided with information (e.g. baseline) - if (script && script->hasJitScript() && IsSetElemPC(pc)) { - script->jitScript()->noteHasDenseAdd(script->pcToOffset(pc)); - } - } - } // Set the HadElementsAccess flag on the object if needed. This flag is // used to do more eager dictionary-mode conversion for objects that are @@ -2370,7 +2349,6 @@ ADVANCE_AND_DISPATCH(JSOpLength_Resume); } - JitScript::MonitorBytecodeType(cx, script, REGS.pc, REGS.sp[-1]); MOZ_ASSERT(GetBytecodeLength(REGS.pc) == JSOpLength_Call); ADVANCE_AND_DISPATCH(JSOpLength_Call); } @@ -3017,8 +2995,6 @@ if (!GetPropertyOperation(cx, REGS.fp(), script, REGS.pc, lval, lval)) { goto error; } - - JitScript::MonitorBytecodeType(cx, script, REGS.pc, lval); cx->debugOnlyCheck(lval); } END_CASE(GetProp) @@ -3032,7 +3008,6 @@ goto error; } - JitScript::MonitorBytecodeType(cx, script, REGS.pc, rref); cx->debugOnlyCheck(rref); REGS.sp--; @@ -3046,8 +3021,6 @@ if (!GetNameBoundInEnvironment(cx, env, id, rval)) { goto error; } - - JitScript::MonitorBytecodeType(cx, script, REGS.pc, rval); cx->debugOnlyCheck(rval); } END_CASE(GetBoundName) @@ -3144,7 +3117,6 @@ } } - JitScript::MonitorBytecodeType(cx, script, REGS.pc, res); REGS.sp--; } END_CASE(GetElem) @@ -3164,7 +3136,6 @@ goto error; } - JitScript::MonitorBytecodeType(cx, script, REGS.pc, res); REGS.sp -= 2; } END_CASE(GetElemSuper) @@ -3231,7 +3202,6 @@ } REGS.sp = args.spAfterCall(); - JitScript::MonitorBytecodeType(cx, script, REGS.pc, REGS.sp[-1]); } END_CASE(Eval) @@ -3339,7 +3309,6 @@ } } Value* newsp = args.spAfterCall(); - JitScript::MonitorBytecodeType(cx, script, REGS.pc, newsp[-1]); REGS.sp = newsp; ADVANCE_AND_DISPATCH(JSOpLength_Call); } @@ -3375,8 +3344,6 @@ } } - TypeMonitorCall(cx, args, construct); - { InvokeState state(cx, args, construct); @@ -3477,7 +3444,6 @@ } PUSH_COPY(rval); - JitScript::MonitorBytecodeType(cx, script, REGS.pc, rval); static_assert(JSOpLength_GetName == JSOpLength_GetGName, "We're sharing the END_CASE so the lengths better match"); } @@ -3490,8 +3456,6 @@ if (!GetImportOperation(cx, envChain, script, REGS.pc, rval)) { goto error; } - - JitScript::MonitorBytecodeType(cx, script, REGS.pc, rval); } END_CASE(GetImport) @@ -3502,7 +3466,6 @@ } PUSH_COPY(rval); - JitScript::MonitorBytecodeType(cx, script, REGS.pc, rval); } END_CASE(GetIntrinsic) @@ -3659,7 +3622,6 @@ } #endif PUSH_COPY(val); - JitScript::MonitorBytecodeType(cx, script, REGS.pc, REGS.sp[-1]); } END_CASE(GetAliasedVar) @@ -5061,18 +5023,6 @@ return SetObjectElementOperation(cx, obj, id, value, receiver, strict); } -bool js::SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, - HandleValue value, HandleValue receiver, bool strict, - HandleScript script, jsbytecode* pc) { - MOZ_ASSERT(pc); - RootedId id(cx); - if (!ToPropertyKey(cx, index, &id)) { - return false; - } - return SetObjectElementOperation(cx, obj, id, value, receiver, strict, script, - pc); -} - bool js::InitElementArray(JSContext* cx, jsbytecode* pc, HandleArrayObject arr, uint32_t index, HandleValue value) { return InitArrayElemOperation(cx, pc, arr, index, value); @@ -5364,7 +5314,6 @@ } } - JitScript::MonitorBytecodeType(cx, script, pc, res); return true; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/Interpreter.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/Interpreter.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/Interpreter.h 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/Interpreter.h 2020-11-17 19:31:36.000000000 +0000 @@ -518,9 +518,6 @@ bool SetObjectElementWithReceiver(JSContext* cx, HandleObject obj, HandleValue index, HandleValue value, HandleValue receiver, bool strict); -bool SetObjectElement(JSContext* cx, HandleObject obj, HandleValue index, - HandleValue value, HandleValue receiver, bool strict, - HandleScript script, jsbytecode* pc); bool InitElementArray(JSContext* cx, jsbytecode* pc, HandleArrayObject arr, uint32_t index, HandleValue value); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSFunction.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSFunction.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSFunction.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSFunction.cpp 2020-11-17 19:31:36.000000000 +0000 @@ -550,7 +550,6 @@ IsGenerator = 1 << 1, IsAsync = 1 << 2, IsLazy = 1 << 3, - HasSingletonType = 1 << 4, }; /* NB: Keep this in sync with CloneInnerInterpretedFunction. */ @@ -573,10 +572,6 @@ return xdr->fail(JS::TranscodeResult_Failure_NotInterpretedFun); } - if (fun->isSingleton()) { - xdrFlags |= HasSingletonType; - } - if (fun->isGenerator()) { xdrFlags |= IsGenerator; } @@ -656,17 +651,7 @@ } objp.set(fun); - // If this function has an enclosing-scope, it is accesible by script and - // should use an updated ObjectGroup. Note that the singleton flag is not - // computed correctly until the enclosing-script has been compiled. The - // delazification of a script will apply types to inner functions at that - // time. - if (enclosingScope) { - bool singleton = (xdrFlags & HasSingletonType); - if (!JSFunction::setTypeForScriptedFunction(cx, fun, singleton)) { - return xdr->fail(JS::TranscodeResult_Throw); - } - } + MOZ_RELEASE_ASSERT(!IsTypeInferenceEnabled()); } if (xdrFlags & IsLazy) { @@ -2244,16 +2229,14 @@ clone->initEnvironment(enclosingEnv); } + MOZ_RELEASE_ASSERT(!IsTypeInferenceEnabled()); + /* * Clone the function, reusing its script. We can use the same group as * the original function provided that its prototype is correct. */ if (fun->staticPrototype() == clone->staticPrototype()) { clone->setGroup(fun->group()); - } else if (setTypeForFunction) { - if (!JSFunction::setTypeForScriptedFunction(cx, clone)) { - return nullptr; - } } return clone; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSFunction.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSFunction.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSFunction.h 2020-11-15 14:38:06.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSFunction.h 2020-11-17 19:31:37.000000000 +0000 @@ -688,10 +688,6 @@ inline const js::FunctionExtended* toExtendedOffMainThread() const; inline const js::Value& getExtendedSlotOffMainThread(size_t which) const; - /* Constructs a new type for the function if necessary. */ - static bool setTypeForScriptedFunction(JSContext* cx, js::HandleFunction fun, - bool singleton = false); - /* GC support. */ js::gc::AllocKind getAllocKind() const { static_assert( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSObject.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSObject.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSObject.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSObject.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -2385,7 +2385,8 @@ } if (index.inspect()) { - if (index.inspect().value() < obj->as().length().get()) { + if (index.inspect().value() < + obj->as().length().get()) { propp->setTypedArrayElement(index.inspect().value()); } else { propp->setNotFound(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSScript.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSScript.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSScript.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSScript.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -4239,9 +4239,8 @@ } MOZ_ASSERT(cloneScript->hasBytecode()); - if (!JSFunction::setTypeForScriptedFunction(cx, clone)) { - return nullptr; - } + + MOZ_RELEASE_ASSERT(!IsTypeInferenceEnabled()); return clone; } @@ -4370,7 +4369,8 @@ HandleObject functionOrGlobal, HandleScriptSourceObject sourceObject, MutableHandle> scopes) { - if (src->treatAsRunOnce() && !src->isFunction()) { + if (src->treatAsRunOnce()) { + MOZ_ASSERT(!src->isFunction()); JS_ReportErrorASCII(cx, "No cloning toplevel run-once scripts"); return nullptr; } @@ -4725,6 +4725,15 @@ frame.unaliasedLocal(frameSlot) = ObjectValue(*argsobj); } } + + // JS_OPTIMIZED_ARGUMENTS may also have been stored to a local slot + // during bailout. Update those local slots. + for (uint32_t i = 0; i < script->nfixed(); i++) { + Value& value = frame.unaliasedLocal(i); + if (value.isMagic() && value.whyMagic() == JS_OPTIMIZED_ARGUMENTS) { + frame.unaliasedLocal(i) = ObjectValue(*argsobj); + } + } } /* static */ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSScript.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSScript.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/JSScript.h 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/JSScript.h 2020-11-17 19:31:37.000000000 +0000 @@ -1648,9 +1648,6 @@ MOZ_MUST_USE bool hasFlag(ImmutableFlags flag) const { return immutableFlags_.hasFlag(flag); } - void setFlag(ImmutableFlags flag, bool b = true) { - immutableFlags_.setFlag(flag, b); - } void clearFlag(ImmutableFlags flag) { immutableFlags_.clearFlag(flag); } // MutableFlags accessors. @@ -1686,7 +1683,7 @@ IMMUTABLE_FLAG_GETTER(forceStrict, ForceStrict) IMMUTABLE_FLAG_GETTER(hasNonSyntacticScope, HasNonSyntacticScope) IMMUTABLE_FLAG_GETTER(noScriptRval, NoScriptRval) - // TreatAsRunOnce: custom logic below. + IMMUTABLE_FLAG_GETTER(treatAsRunOnce, TreatAsRunOnce) IMMUTABLE_FLAG_GETTER(strict, Strict) IMMUTABLE_FLAG_GETTER(hasModuleGoal, HasModuleGoal) IMMUTABLE_FLAG_GETTER(hasInnerFunctions, HasInnerFunctions) @@ -1709,7 +1706,6 @@ IMMUTABLE_FLAG_GETTER(argumentsHasVarBinding, ArgumentsHasVarBinding) IMMUTABLE_FLAG_GETTER(alwaysNeedsArgsObj, AlwaysNeedsArgsObj) IMMUTABLE_FLAG_GETTER(hasMappedArgsObj, HasMappedArgsObj) - IMMUTABLE_FLAG_GETTER(isLikelyConstructorWrapper, IsLikelyConstructorWrapper) MUTABLE_FLAG_GETTER_SETTER(hasRunOnce, HasRunOnce) MUTABLE_FLAG_GETTER_SETTER(hasBeenCloned, HasBeenCloned) @@ -1734,18 +1730,6 @@ #undef FLAG_GETTER #undef FLAG_GETTER_SETTER - // See ImmutableScriptFlagsEnum::TreatAsRunOnce. - bool treatAsRunOnce() const { - MOZ_ASSERT(!hasEnclosingScript(), - "TreatAsRunOnce is undefined if enclosing script is lazy"); - return hasFlag(ImmutableFlags::TreatAsRunOnce); - } - void initTreatAsRunOnce(bool flag) { - MOZ_ASSERT(!hasBytecode(), - "TreatAsRunOnce can only be updated on lazy scripts"); - setFlag(ImmutableFlags::TreatAsRunOnce, flag); - } - GeneratorKind generatorKind() const { return isGenerator() ? GeneratorKind::Generator : GeneratorKind::NotGenerator; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/NativeObject.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/NativeObject.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/NativeObject.cpp 2020-11-15 14:38:06.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/NativeObject.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -2411,23 +2411,6 @@ return true; } - if (!jit::JitOptions.warpBuilder) { - // Set the accessed-getter flag for IonBuilder. - jsbytecode* pc; - JSScript* script = cx->currentScript(&pc); - if (script && script->hasJitScript()) { - switch (JSOp(*pc)) { - case JSOp::GetProp: - case JSOp::CallProp: - case JSOp::Length: - script->jitScript()->noteAccessedGetter(script->pcToOffset(pc)); - break; - default: - break; - } - } - } - if constexpr (!allowGC) { return false; } else { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/ObjectGroup.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/ObjectGroup.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/ObjectGroup.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/ObjectGroup.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -140,53 +140,8 @@ /* static */ bool ObjectGroup::useSingletonForClone(JSFunction* fun) { - if (!IsTypeInferenceEnabled()) { - return false; - } - - if (!fun->isInterpreted()) { - return false; - } - - if (fun->isArrow()) { - return false; - } - - if (fun->isSingleton()) { - return false; - } - - /* - * When a function is being used as a wrapper for another function, it - * improves precision greatly to distinguish between different instances of - * the wrapper; otherwise we will conflate much of the information about - * the wrapped functions. - * - * An important example is the Class.create function at the core of the - * Prototype.js library, which looks like: - * - * var Class = { - * create: function() { - * return function() { - * this.initialize.apply(this, arguments); - * } - * } - * }; - * - * Each instance of the innermost function will have a different wrapped - * initialize method. We capture this, along with similar cases, by looking - * for short scripts which use both .apply and arguments. For such scripts, - * whenever creating a new instance of the function we both give that - * instance a singleton type and clone the underlying script. - */ - - if (!fun->baseScript()->isLikelyConstructorWrapper()) { - return false; - } - uint32_t begin = fun->baseScript()->sourceStart(); - uint32_t end = fun->baseScript()->sourceEnd(); - - return end - begin <= 100; + MOZ_RELEASE_ASSERT(!IsTypeInferenceEnabled()); + return false; } /* static */ @@ -239,7 +194,7 @@ return false; } - if (script->function() && !script->treatAsRunOnce()) { + if (script->function()) { return false; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/ObjectGroup.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/ObjectGroup.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/ObjectGroup.h 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/ObjectGroup.h 2020-11-17 19:31:37.000000000 +0000 @@ -360,8 +360,6 @@ inline bool shouldPreTenure(const AutoSweepObjectGroup& sweep); inline bool shouldPreTenureDontCheckGeneration(); - gc::InitialHeap initialHeap(CompilerConstraintList* constraints); - inline bool canPreTenure(const AutoSweepObjectGroup& sweep); inline bool fromAllocationSite(const AutoSweepObjectGroup& sweep); inline void setShouldPreTenure(const AutoSweepObjectGroup& sweep, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/Opcodes.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/Opcodes.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/Opcodes.h 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/Opcodes.h 2020-11-17 19:31:37.000000000 +0000 @@ -2941,7 +2941,7 @@ * Operands: uint8_t hops, uint24_t slot * Stack: => aliasedVar */ \ - MACRO(GetAliasedVar, get_aliased_var, NULL, 5, 0, 1, JOF_ENVCOORD|JOF_NAME|JOF_TYPESET|JOF_IC) \ + MACRO(GetAliasedVar, get_aliased_var, NULL, 5, 0, 1, JOF_ENVCOORD|JOF_NAME) \ /* * Get the value of a module import by name and pushes it onto the stack. * @@ -2950,7 +2950,7 @@ * Operands: uint32_t nameIndex * Stack: => val */ \ - MACRO(GetImport, get_import, NULL, 5, 0, 1, JOF_ATOM|JOF_NAME|JOF_TYPESET|JOF_IC) \ + MACRO(GetImport, get_import, NULL, 5, 0, 1, JOF_ATOM|JOF_NAME) \ /* * Get the value of a binding from the environment `env`. If the name is * not bound in `env`, throw a ReferenceError. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/PlainObject.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/PlainObject.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/PlainObject.cpp 2020-11-15 14:38:06.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/PlainObject.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -161,14 +161,7 @@ res = NewBuiltinClassInstanceWithKind(cx, newKind); } - if (res) { - MOZ_ASSERT(res->nonCCWRealm() == callee->realm()); - JSScript* script = JSFunction::getOrCreateScript(cx, callee); - if (!script) { - return nullptr; - } - jit::JitScript::MonitorThisType(cx, script, TypeSet::ObjectType(res)); - } + MOZ_ASSERT_IF(res, res->nonCCWRealm() == callee->realm()); return res; } @@ -193,10 +186,6 @@ /* Reshape the singleton before passing it as the 'this' value. */ NativeObject::clear(cx, nobj); - JSScript* calleeScript = callee->nonLazyScript(); - jit::JitScript::MonitorThisType(cx, calleeScript, - TypeSet::ObjectType(nobj)); - return nobj; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/StencilEnums.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/StencilEnums.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/StencilEnums.h 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/StencilEnums.h 2020-11-17 19:31:37.000000000 +0000 @@ -105,17 +105,6 @@ // On top-level global/eval/module scripts, this is set when the embedding // ensures this script will not be re-used. In this case, parser literals may // be exposed directly instead of being cloned. - // - // For non-lazy functions, this is set when the function is almost-certain to - // be run once (and its parents transitively the same). In this case, the - // function may be marked as a singleton to improve typeset precision. Note - // that under edge cases with fun.caller the function may still run multiple - // times. - // - // For lazy functions, the situation is more complex. If enclosing script is - // not yet compiled, this flag is undefined and should not be used. As the - // enclosing script is compiled, this flag is updated to the same definition - // the eventual non-lazy function will use. TreatAsRunOnce = 1 << 7, // ---- @@ -254,10 +243,6 @@ // is set independently of whether we actually use an `arguments` binding. The // conditions are specified in the ECMAScript spec. HasMappedArgsObj = 1 << 27, - - // All of 'this', 'arguments' and f.apply() are used. This is likely to be a - // wrapper. This is a heuristic that affects Type Inference. - IsLikelyConstructorWrapper = 1 << 28, }; enum class MutableScriptFlagsEnum : uint32_t { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/TypeInference.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/TypeInference.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/TypeInference.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/TypeInference.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -322,44 +322,6 @@ // TypeSet ///////////////////////////////////////////////////////////////////// -TemporaryTypeSet::TemporaryTypeSet(LifoAlloc* alloc, Type type) { - MOZ_ASSERT(!jit::JitOptions.warpBuilder); - - if (type.isUnknown()) { - flags |= TYPE_FLAG_BASE_MASK; - return; - } - if (type.isPrimitive()) { - flags = PrimitiveTypeFlag(type); - if (flags == TYPE_FLAG_DOUBLE) { - flags |= TYPE_FLAG_INT32; - } - return; - } - if (type.isAnyObject()) { - flags |= TYPE_FLAG_ANYOBJECT; - return; - } - if (type.isGroup()) { - AutoSweepObjectGroup sweep(type.group()); - if (type.group()->unknownProperties(sweep)) { - flags |= TYPE_FLAG_ANYOBJECT; - return; - } - } - setBaseObjectCount(1); - objectSet = reinterpret_cast(type.objectKey()); - - if (type.isGroup()) { - ObjectGroup* ngroup = type.group(); - AutoSweepObjectGroup sweep(ngroup); - if (ngroup->newScript(sweep) && - ngroup->newScript(sweep)->initializedGroup()) { - addType(ObjectType(ngroup->newScript(sweep)->initializedGroup()), alloc); - } - } -} - static TypeFlags MIRTypeToTypeFlags(jit::MIRType type) { switch (type) { case jit::MIRType::Undefined: @@ -914,167 +876,6 @@ return isAboutToBeFinalized; } -bool TypeSet::cloneIntoUninitialized(LifoAlloc* alloc, - TemporaryTypeSet* result) const { - unsigned objectCount = baseObjectCount(); - unsigned capacity = - (objectCount >= 2) ? TypeHashSet::Capacity(objectCount) : 0; - - ObjectKey** newSet; - if (capacity) { - // We allocate an extra word right before the array that stores the - // capacity, so make sure we clone that as well. - newSet = alloc->newArray(capacity + 1); - if (!newSet) { - return false; - } - newSet++; - PodCopy(newSet - 1, objectSet - 1, capacity + 1); - } - - new (result) TemporaryTypeSet(flags, capacity ? newSet : objectSet); - return true; -} - -TemporaryTypeSet* TypeSet::clone(LifoAlloc* alloc) const { - TemporaryTypeSet* res = alloc->pod_malloc(); - if (!res || !cloneIntoUninitialized(alloc, res)) { - return nullptr; - } - return res; -} - -TemporaryTypeSet* TypeSet::cloneObjectsOnly(LifoAlloc* alloc) { - TemporaryTypeSet* res = clone(alloc); - if (!res) { - return nullptr; - } - - res->flags &= ~TYPE_FLAG_BASE_MASK | TYPE_FLAG_ANYOBJECT; - - return res; -} - -TemporaryTypeSet* TypeSet::cloneWithoutObjects(LifoAlloc* alloc) { - TemporaryTypeSet* res = alloc->new_(); - if (!res) { - return nullptr; - } - - res->flags = flags & ~TYPE_FLAG_ANYOBJECT; - res->setBaseObjectCount(0); - return res; -} - -/* static */ -TemporaryTypeSet* TypeSet::unionSets(TypeSet* a, TypeSet* b, LifoAlloc* alloc) { - TemporaryTypeSet* res = alloc->new_( - a->baseFlags() | b->baseFlags(), static_cast(nullptr)); - if (!res) { - return nullptr; - } - - if (!res->unknownObject()) { - for (size_t i = 0; i < a->getObjectCount() && !res->unknownObject(); i++) { - if (ObjectKey* key = a->getObject(i)) { - res->addType(ObjectType(key), alloc); - } - } - for (size_t i = 0; i < b->getObjectCount() && !res->unknownObject(); i++) { - if (ObjectKey* key = b->getObject(i)) { - res->addType(ObjectType(key), alloc); - } - } - } - - return res; -} - -/* static */ -TemporaryTypeSet* TypeSet::removeSet(TemporaryTypeSet* input, - TemporaryTypeSet* removal, - LifoAlloc* alloc) { - // Only allow removal of primitives and the "AnyObject" flag. - MOZ_ASSERT(!removal->unknown()); - MOZ_ASSERT_IF(!removal->unknownObject(), removal->getObjectCount() == 0); - - uint32_t flags = input->baseFlags() & ~removal->baseFlags(); - TemporaryTypeSet* res = - alloc->new_(flags, static_cast(nullptr)); - if (!res) { - return nullptr; - } - - res->setBaseObjectCount(0); - if (removal->unknownObject() || input->unknownObject()) { - return res; - } - - for (size_t i = 0; i < input->getObjectCount(); i++) { - if (!input->getObject(i)) { - continue; - } - - res->addType(TypeSet::ObjectType(input->getObject(i)), alloc); - } - - return res; -} - -/* static */ -TemporaryTypeSet* TypeSet::intersectSets(TemporaryTypeSet* a, - TemporaryTypeSet* b, - LifoAlloc* alloc) { - TemporaryTypeSet* res; - res = alloc->new_(a->baseFlags() & b->baseFlags(), - static_cast(nullptr)); - if (!res) { - return nullptr; - } - - res->setBaseObjectCount(0); - if (res->unknownObject()) { - return res; - } - - MOZ_ASSERT(!a->unknownObject() || !b->unknownObject()); - - if (a->unknownObject()) { - for (size_t i = 0; i < b->getObjectCount(); i++) { - if (b->getObject(i)) { - res->addType(ObjectType(b->getObject(i)), alloc); - } - } - return res; - } - - if (b->unknownObject()) { - for (size_t i = 0; i < a->getObjectCount(); i++) { - if (a->getObject(i)) { - res->addType(ObjectType(a->getObject(i)), alloc); - } - } - return res; - } - - MOZ_ASSERT(!a->unknownObject() && !b->unknownObject()); - - for (size_t i = 0; i < a->getObjectCount(); i++) { - for (size_t j = 0; j < b->getObjectCount(); j++) { - if (b->getObject(j) != a->getObject(i)) { - continue; - } - if (!b->getObject(j)) { - continue; - } - res->addType(ObjectType(b->getObject(j)), alloc); - break; - } - } - - return res; -} - ///////////////////////////////////////////////////////////////////// // Compiler constraints ///////////////////////////////////////////////////////////////////// @@ -1101,18 +902,7 @@ // be allocated off thread, using the current JIT context's allocator. class CompilerConstraint { public: - // Property being queried by the compiler. - HeapTypeSetKey property; - - // Contents of the property at the point when the query was performed. This - // may differ from the actual property types later in compilation as the - // main thread performs side effects. - TemporaryTypeSet* expected; - - CompilerConstraint(LifoAlloc* alloc, const HeapTypeSetKey& property) - : property(property), - expected(property.maybeTypes() ? property.maybeTypes()->clone(alloc) - : nullptr) {} + explicit CompilerConstraint(LifoAlloc* alloc) {} // Generate the type constraint recording the assumption made by this // compilation. Returns true if the assumption originally made still holds. @@ -1121,14 +911,6 @@ }; class js::CompilerConstraintList { - public: - struct FrozenScript { - JSScript* script; - TemporaryTypeSet* thisTypes; - TemporaryTypeSet* argTypes; - TemporaryTypeSet* bytecodeTypes; - }; - private: // OOM during generation of some constraint. bool failed_; @@ -1139,1483 +921,126 @@ // Constraints generated on heap properties. Vector constraints; - // Scripts whose stack type sets were frozen for the compilation. - Vector frozenScripts; - public: explicit CompilerConstraintList(jit::TempAllocator& alloc) - : failed_(false), - alloc_(alloc.lifoAlloc()), - constraints(alloc), - frozenScripts(alloc) {} - - void add(CompilerConstraint* constraint) { - if (!constraint || !constraints.append(constraint)) { - setFailed(); - } - } - - void freezeScript(JSScript* script, TemporaryTypeSet* thisTypes, - TemporaryTypeSet* argTypes, - TemporaryTypeSet* bytecodeTypes) { - FrozenScript entry; - entry.script = script; - entry.thisTypes = thisTypes; - entry.argTypes = argTypes; - entry.bytecodeTypes = bytecodeTypes; - if (!frozenScripts.append(entry)) { - setFailed(); - } - } - - size_t length() { return constraints.length(); } - - CompilerConstraint* get(size_t i) { return constraints[i]; } - - size_t numFrozenScripts() { return frozenScripts.length(); } - - const FrozenScript& frozenScript(size_t i) { return frozenScripts[i]; } - - bool failed() { return failed_; } - void setFailed() { failed_ = true; } - LifoAlloc* alloc() const { return alloc_; } -}; - -CompilerConstraintList* js::NewCompilerConstraintList( - jit::TempAllocator& alloc) { - return alloc.lifoAlloc()->new_(alloc); -} - -/* static */ -bool JitScript::FreezeTypeSets(CompilerConstraintList* constraints, - JSScript* script, TemporaryTypeSet** pThisTypes, - TemporaryTypeSet** pArgTypes, - TemporaryTypeSet** pBytecodeTypes) { - LifoAlloc* alloc = constraints->alloc(); - AutoSweepJitScript sweep(script); - JitScript* jitScript = script->jitScript(); - StackTypeSet* existing = jitScript->typeArray(sweep); - - size_t count = jitScript->numTypeSets(); - TemporaryTypeSet* types = - alloc->newArrayUninitialized(count); - if (!types) { - return false; - } - - for (size_t i = 0; i < count; i++) { - if (!existing[i].cloneIntoUninitialized(alloc, &types[i])) { - return false; - } - } - - size_t thisTypesIndex = jitScript->thisTypes(sweep, script) - existing; - *pThisTypes = types + thisTypesIndex; - - if (script->function() && script->function()->nargs() > 0) { - size_t firstArgIndex = jitScript->argTypes(sweep, script, 0) - existing; - *pArgTypes = types + firstArgIndex; - } else { - *pArgTypes = nullptr; - } - - *pBytecodeTypes = types; - - constraints->freezeScript(script, *pThisTypes, *pArgTypes, *pBytecodeTypes); - return true; -} - -namespace { - -template -class CompilerConstraintInstance : public CompilerConstraint { - T data; - - public: - CompilerConstraintInstance(LifoAlloc* alloc, - const HeapTypeSetKey& property, const T& data) - : CompilerConstraint(alloc, property), data(data) {} - - bool generateTypeConstraint(JSContext* cx, - RecompileInfo recompileInfo) override; -}; - -// Constraint generated from a CompilerConstraint when linking the compilation. -template -class TypeCompilerConstraint : public TypeConstraint { - // Compilation which this constraint may invalidate. - RecompileInfo compilation; - - T data; - - public: - TypeCompilerConstraint(RecompileInfo compilation, const T& data) - : compilation(compilation), data(data) {} - - const char* kind() override { return data.kind(); } - - void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) override { - if (data.invalidateOnNewType(type)) { - cx->zone()->types.addPendingRecompile(cx, compilation); - } - } - - void newPropertyState(JSContext* cx, TypeSet* source) override { - if (data.invalidateOnNewPropertyState(source)) { - cx->zone()->types.addPendingRecompile(cx, compilation); - } - } - - void newObjectState(JSContext* cx, ObjectGroup* group) override { - // Note: Once the object has unknown properties, no more notifications - // will be sent on changes to its state, so always invalidate any - // associated compilations. - AutoSweepObjectGroup sweep(group); - if (group->unknownProperties(sweep) || - data.invalidateOnNewObjectState(sweep, group)) { - cx->zone()->types.addPendingRecompile(cx, compilation); - } - } - - bool sweep(TypeZone& zone, TypeConstraint** res) override { - if (data.shouldSweep() || compilation.shouldSweep(zone)) { - return false; - } - *res = zone.typeLifoAlloc().new_ >(compilation, - data); - return true; - } - - Compartment* maybeCompartment() override { return data.maybeCompartment(); } -}; - -template -bool CompilerConstraintInstance::generateTypeConstraint( - JSContext* cx, RecompileInfo recompileInfo) { - // This should only be called in suppress-GC contexts, but the static - // analysis doesn't know this. - MOZ_ASSERT(cx->suppressGC); - JS::AutoSuppressGCAnalysis suppress; - - if (property.object()->unknownProperties()) { - return false; - } - - if (!property.instantiate(cx)) { - return false; - } - - AutoSweepObjectGroup sweep(property.object()->maybeGroup()); - if (property.object()->maybeGroup()->unknownProperties(sweep)) { - return false; - } - if (!data.constraintHolds(sweep, cx, property, expected)) { - return false; - } - - return property.maybeTypes()->addConstraint( - cx, - cx->typeLifoAlloc().new_ >(recompileInfo, data), - /* callExisting = */ false); -} - -} /* anonymous namespace */ - -const JSClass* TypeSet::ObjectKey::clasp() { - return isGroup() ? group()->clasp() : singleton()->getClass(); -} - -TaggedProto TypeSet::ObjectKey::proto() { - return isGroup() ? group()->proto() : singleton()->taggedProto(); -} - -ObjectGroup* TypeSet::ObjectKey::maybeGroup() { - if (isGroup()) { - return group(); - } - if (!singleton()->hasLazyGroup()) { - return singleton()->group(); - } - return nullptr; -} - -bool TypeSet::ObjectKey::unknownProperties() { - if (ObjectGroup* group = maybeGroup()) { - AutoSweepObjectGroup sweep(group); - return group->unknownProperties(sweep); - } - return false; -} - -HeapTypeSetKey TypeSet::ObjectKey::property(jsid id) { - MOZ_ASSERT(!unknownProperties()); - - HeapTypeSetKey property; - property.object_ = this; - property.id_ = id; - if (ObjectGroup* group = maybeGroup()) { - AutoSweepObjectGroup sweep(group); - if (!group->unknownProperties(sweep)) { - property.maybeTypes_ = group->maybeGetProperty(sweep, id); - } - } - - return property; -} - -void TypeSet::ObjectKey::ensureTrackedProperty(JSContext* cx, jsid id) { - // If we are accessing a lazily defined property which actually exists in - // the VM and has not been instantiated yet, instantiate it now if we are - // on the main thread and able to do so. - if (!JSID_IS_VOID(id) && !JSID_IS_EMPTY(id)) { - MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); - if (isSingleton()) { - JSObject* obj = singleton(); - if (obj->isNative() && obj->as().containsPure(id)) { - EnsureTrackPropertyTypes(cx, obj, id); - } - } - } -} - -void js::EnsureTrackPropertyTypes(JSContext* cx, JSObject* obj, jsid id) { - if (!IsTypeInferenceEnabled()) { - return; - } - id = IdToTypeId(id); - - if (obj->isSingleton()) { - AutoEnterAnalysis enter(cx); - if (obj->hasLazyGroup()) { - AutoEnterOOMUnsafeRegion oomUnsafe; - RootedObject objRoot(cx, obj); - if (!JSObject::getGroup(cx, objRoot)) { - oomUnsafe.crash( - "Could not allocate ObjectGroup in EnsureTrackPropertyTypes"); - } - } - ObjectGroup* group = obj->group(); - AutoSweepObjectGroup sweep(group); - if (!group->unknownProperties(sweep) && - !group->getProperty(sweep, cx, obj, id)) { - MOZ_ASSERT(group->unknownProperties(sweep)); - return; - } - } - - MOZ_ASSERT(obj->group()->unknownPropertiesDontCheckGeneration() || - TrackPropertyTypes(obj, id)); -} - -bool HeapTypeSetKey::instantiate(JSContext* cx) { - if (maybeTypes()) { - return true; - } - if (object()->isSingleton()) { - RootedObject obj(cx, object()->singleton()); - if (!JSObject::getGroup(cx, obj)) { - cx->clearPendingException(); - return false; - } - } - JSObject* obj = object()->isSingleton() ? object()->singleton() : nullptr; - AutoSweepObjectGroup sweep(object()->maybeGroup()); - maybeTypes_ = object()->maybeGroup()->getProperty(sweep, cx, obj, id()); - return maybeTypes_ != nullptr; -} - -static bool CheckFrozenTypeSet(const AutoSweepJitScript& sweep, JSContext* cx, - TemporaryTypeSet* frozen, StackTypeSet* actual) { - // Return whether the types frozen for a script during compilation are - // still valid. Also check for any new types added to the frozen set during - // compilation, and add them to the actual stack type sets. These new types - // indicate places where the compiler relaxed its possible inputs to be - // more tolerant of potential new types. - - if (!actual->isSubset(frozen)) { - return false; - } - - if (!frozen->isSubset(actual)) { - TypeSet::TypeList list; - frozen->enumerateTypes(&list); - - for (size_t i = 0; i < list.length(); i++) { - actual->addType(sweep, cx, list[i]); - } - } - - return true; -} - -namespace { - -/* - * As for TypeConstraintFreeze, but describes an implicit freeze constraint - * added for stack types within a script. Applies to all compilations of the - * script, not just a single one. - */ -class TypeConstraintFreezeStack : public TypeConstraint { - JSScript* script_; - - public: - explicit TypeConstraintFreezeStack(JSScript* script) : script_(script) {} - - const char* kind() override { return "freezeStack"; } - - void newType(JSContext* cx, TypeSet* source, TypeSet::Type type) override { - /* - * Unlike TypeConstraintFreeze, triggering this constraint once does - * not disable it on future changes to the type set. - */ - cx->zone()->types.addPendingRecompile(cx, script_); - } - - bool sweep(TypeZone& zone, TypeConstraint** res) override { - if (IsAboutToBeFinalizedUnbarriered(&script_)) { - return false; - } - *res = zone.typeLifoAlloc().new_(script_); - return true; - } - - Compartment* maybeCompartment() override { return script_->compartment(); } -}; - -} /* anonymous namespace */ - -bool js::FinishCompilation(JSContext* cx, HandleScript script, - CompilerConstraintList* constraints, - IonCompilationId compilationId, bool* isValidOut) { - MOZ_ASSERT(IsTypeInferenceEnabled()); - MOZ_ASSERT(*cx->zone()->types.currentCompilationId() == compilationId); - - if (constraints->failed()) { - return false; - } - - RecompileInfo recompileInfo(script, compilationId); - - bool succeeded = true; - - for (size_t i = 0; i < constraints->length(); i++) { - CompilerConstraint* constraint = constraints->get(i); - if (!constraint->generateTypeConstraint(cx, recompileInfo)) { - succeeded = false; - } - } - - for (size_t i = 0; i < constraints->numFrozenScripts(); i++) { - const CompilerConstraintList::FrozenScript& entry = - constraints->frozenScript(i); - // It could happen that one of the compiled scripts was made a - // debuggee mid-compilation (e.g., via setting a breakpoint). If so, - // throw away the compilation. - if (entry.script->isDebuggee()) { - succeeded = false; - break; - } - - JitScript* jitScript = entry.script->jitScript(); - AutoSweepJitScript sweep(entry.script); - if (!CheckFrozenTypeSet(sweep, cx, entry.thisTypes, - jitScript->thisTypes(sweep, entry.script))) { - succeeded = false; - } - unsigned nargs = - entry.script->function() ? entry.script->function()->nargs() : 0; - for (size_t i = 0; i < nargs; i++) { - if (!CheckFrozenTypeSet(sweep, cx, &entry.argTypes[i], - jitScript->argTypes(sweep, entry.script, i))) { - succeeded = false; - } - } - for (size_t i = 0; i < entry.script->numBytecodeTypeSets(); i++) { - if (!CheckFrozenTypeSet(sweep, cx, &entry.bytecodeTypes[i], - &jitScript->typeArray(sweep)[i])) { - succeeded = false; - } - } - - // Add this compilation to the inlinedCompilations list of each inlined - // script, so we can invalidate it on changes to stack type sets. - if (entry.script != script) { - if (!jitScript->addInlinedCompilation(sweep, recompileInfo)) { - succeeded = false; - } - } - - // If necessary, add constraints to trigger invalidation on the script - // after any future changes to the stack type sets. - if (jitScript->hasFreezeConstraints(sweep)) { - continue; - } - - size_t count = jitScript->numTypeSets(); - StackTypeSet* array = jitScript->typeArray(sweep); - for (size_t i = 0; i < count; i++) { - if (!array[i].addConstraint( - cx, - cx->typeLifoAlloc().new_(entry.script), - false)) { - succeeded = false; - } - } - - if (succeeded) { - jitScript->setHasFreezeConstraints(sweep); - } - } - - if (!succeeded) { - script->resetWarmUpCounterToDelayIonCompilation(); - *isValidOut = false; - return true; - } - - *isValidOut = true; - return true; -} - -static void CheckDefinitePropertiesTypeSet(const AutoSweepJitScript& sweep, - JSContext* cx, - TemporaryTypeSet* frozen, - StackTypeSet* actual) { - // The definite properties analysis happens on the main thread, so no new - // types can have been added to actual. The analysis may have updated the - // contents of |frozen| though with new speculative types, and these need - // to be reflected in |actual| for AddClearDefiniteFunctionUsesInScript - // to work. - if (!frozen->isSubset(actual)) { - TypeSet::TypeList list; - frozen->enumerateTypes(&list); - - for (size_t i = 0; i < list.length(); i++) { - actual->addType(sweep, cx, list[i]); - } - } -} - -void js::FinishDefinitePropertiesAnalysis(JSContext* cx, - CompilerConstraintList* constraints) { -#ifdef DEBUG - // Assert no new types have been added to the StackTypeSets. Do this before - // calling CheckDefinitePropertiesTypeSet, as it may add new types to the - // StackTypeSets and break these invariants if a script is inlined more - // than once. See also CheckDefinitePropertiesTypeSet. - for (size_t i = 0; i < constraints->numFrozenScripts(); i++) { - const CompilerConstraintList::FrozenScript& entry = - constraints->frozenScript(i); - JSScript* script = entry.script; - JitScript* jitScript = script->jitScript(); - - AutoSweepJitScript sweep(script); - MOZ_ASSERT(jitScript->thisTypes(sweep, script)->isSubset(entry.thisTypes)); - - unsigned nargs = - entry.script->function() ? entry.script->function()->nargs() : 0; - for (size_t j = 0; j < nargs; j++) { - StackTypeSet* argTypes = jitScript->argTypes(sweep, script, j); - MOZ_ASSERT(argTypes->isSubset(&entry.argTypes[j])); - } - - for (size_t j = 0; j < script->numBytecodeTypeSets(); j++) { - MOZ_ASSERT( - jitScript->typeArray(sweep)[j].isSubset(&entry.bytecodeTypes[j])); - } - } -#endif - - for (size_t i = 0; i < constraints->numFrozenScripts(); i++) { - const CompilerConstraintList::FrozenScript& entry = - constraints->frozenScript(i); - JSScript* script = entry.script; - JitScript* jitScript = script->jitScript(); - - AutoSweepJitScript sweep(script); - CheckDefinitePropertiesTypeSet(sweep, cx, entry.thisTypes, - jitScript->thisTypes(sweep, script)); - - unsigned nargs = script->function() ? script->function()->nargs() : 0; - for (size_t j = 0; j < nargs; j++) { - StackTypeSet* argTypes = jitScript->argTypes(sweep, script, j); - CheckDefinitePropertiesTypeSet(sweep, cx, &entry.argTypes[j], argTypes); - } - - for (size_t j = 0; j < script->numBytecodeTypeSets(); j++) { - CheckDefinitePropertiesTypeSet(sweep, cx, &entry.bytecodeTypes[j], - &jitScript->typeArray(sweep)[j]); - } - } -} - -namespace { - -// Constraint which triggers recompilation of a script if any type is added to a -// type set. */ -class ConstraintDataFreeze { - public: - ConstraintDataFreeze() = default; - - const char* kind() { return "freeze"; } - - bool invalidateOnNewType(TypeSet::Type type) { return true; } - bool invalidateOnNewPropertyState(TypeSet* property) { return true; } - bool invalidateOnNewObjectState(const AutoSweepObjectGroup& sweep, - ObjectGroup* group) { - return false; - } - - bool constraintHolds(const AutoSweepObjectGroup& sweep, JSContext* cx, - const HeapTypeSetKey& property, - TemporaryTypeSet* expected) { - return expected ? property.maybeTypes()->isSubset(expected) - : property.maybeTypes()->empty(); - } - - bool shouldSweep() { return false; } - - Compartment* maybeCompartment() { return nullptr; } -}; - -} /* anonymous namespace */ - -void HeapTypeSetKey::freeze(CompilerConstraintList* constraints) { - LifoAlloc* alloc = constraints->alloc(); - LifoAlloc::AutoFallibleScope fallibleAllocator(alloc); - - using T = CompilerConstraintInstance; - constraints->add(alloc->new_(alloc, *this, ConstraintDataFreeze())); -} - -static inline jit::MIRType GetMIRTypeFromTypeFlags(TypeFlags flags) { - switch (flags) { - case TYPE_FLAG_UNDEFINED: - return jit::MIRType::Undefined; - case TYPE_FLAG_NULL: - return jit::MIRType::Null; - case TYPE_FLAG_BOOLEAN: - return jit::MIRType::Boolean; - case TYPE_FLAG_INT32: - return jit::MIRType::Int32; - case (TYPE_FLAG_INT32 | TYPE_FLAG_DOUBLE): - return jit::MIRType::Double; - case TYPE_FLAG_STRING: - return jit::MIRType::String; - case TYPE_FLAG_SYMBOL: - return jit::MIRType::Symbol; - case TYPE_FLAG_BIGINT: - return jit::MIRType::BigInt; - case TYPE_FLAG_LAZYARGS: - return jit::MIRType::MagicOptimizedArguments; - case TYPE_FLAG_ANYOBJECT: - return jit::MIRType::Object; - default: - return jit::MIRType::Value; - } -} - -jit::MIRType TemporaryTypeSet::getKnownMIRType() { - TypeFlags flags = baseFlags(); - jit::MIRType type; - - if (baseObjectCount()) { - type = flags ? jit::MIRType::Value : jit::MIRType::Object; - } else { - type = GetMIRTypeFromTypeFlags(flags); - } - - /* - * If the type set is totally empty then it will be treated as unknown, - * but we still need to record the dependency as adding a new type can give - * it a definite type tag. This is not needed if there are enough types - * that the exact tag is unknown, as it will stay unknown as more types are - * added to the set. - */ - DebugOnly empty = flags == 0 && baseObjectCount() == 0; - MOZ_ASSERT_IF(empty, type == jit::MIRType::Value); - - return type; -} - -jit::MIRType HeapTypeSetKey::knownMIRType(CompilerConstraintList* constraints) { - TypeSet* types = maybeTypes(); - - if (!types || types->unknown()) { - return jit::MIRType::Value; - } - - TypeFlags flags = types->baseFlags() & ~TYPE_FLAG_ANYOBJECT; - jit::MIRType type; - - if (types->unknownObject() || types->getObjectCount()) { - type = flags ? jit::MIRType::Value : jit::MIRType::Object; - } else { - type = GetMIRTypeFromTypeFlags(flags); - } - - if (type != jit::MIRType::Value) { - freeze(constraints); - } - - /* - * If the type set is totally empty then it will be treated as unknown, - * but we still need to record the dependency as adding a new type can give - * it a definite type tag. This is not needed if there are enough types - * that the exact tag is unknown, as it will stay unknown as more types are - * added to the set. - */ - MOZ_ASSERT_IF(types->empty(), type == jit::MIRType::Value); - - return type; -} - -bool HeapTypeSetKey::isOwnProperty(CompilerConstraintList* constraints, - bool allowEmptyTypesForGlobal /* = false*/) { - if (maybeTypes() && - (!maybeTypes()->empty() || maybeTypes()->nonDataProperty())) { - return true; - } - if (object()->isSingleton()) { - JSObject* obj = object()->singleton(); - MOZ_ASSERT(CanHaveEmptyPropertyTypesForOwnProperty(obj) == - obj->is()); - if (!allowEmptyTypesForGlobal) { - if (CanHaveEmptyPropertyTypesForOwnProperty(obj)) { - return true; - } - } - } - freeze(constraints); - return false; -} - -JSObject* TemporaryTypeSet::maybeSingleton() { - if (baseFlags() != 0 || baseObjectCount() != 1) { - return nullptr; - } - - return getSingleton(0); -} - -TemporaryTypeSet::ObjectKey* TemporaryTypeSet::maybeSingleObject() { - if (baseFlags() != 0 || baseObjectCount() != 1) { - return nullptr; - } - - return getObject(0); -} - -JSObject* HeapTypeSetKey::singleton(CompilerConstraintList* constraints) { - HeapTypeSet* types = maybeTypes(); - - if (!types || types->nonDataProperty() || types->baseFlags() != 0 || - types->getObjectCount() != 1) { - return nullptr; - } - - JSObject* obj = types->getSingleton(0); - - if (obj) { - freeze(constraints); - } - - return obj; -} - -bool HeapTypeSetKey::needsBarrier(CompilerConstraintList* constraints) { - TypeSet* types = maybeTypes(); - if (!types) { - return false; - } - bool result = types->unknownObject() || types->getObjectCount() > 0 || - types->hasAnyFlag(TYPE_FLAG_PRIMITIVE_GCTHING); - if (!result) { - freeze(constraints); - } - return result; -} - -namespace { - -// Constraint which triggers recompilation if an object acquires particular -// flags. -class ConstraintDataFreezeObjectFlags { - public: - // Flags we are watching for on this object. - ObjectGroupFlags flags; - - explicit ConstraintDataFreezeObjectFlags(ObjectGroupFlags flags) - : flags(flags) { - MOZ_ASSERT(flags); - } - - const char* kind() { return "freezeObjectFlags"; } - - bool invalidateOnNewType(TypeSet::Type type) { return false; } - bool invalidateOnNewPropertyState(TypeSet* property) { return false; } - bool invalidateOnNewObjectState(const AutoSweepObjectGroup& sweep, - ObjectGroup* group) { - return group->hasAnyFlags(sweep, flags); - } - - bool constraintHolds(const AutoSweepObjectGroup& sweep, JSContext* cx, - const HeapTypeSetKey& property, - TemporaryTypeSet* expected) { - return !invalidateOnNewObjectState(sweep, property.object()->maybeGroup()); - } - - bool shouldSweep() { return false; } - - Compartment* maybeCompartment() { return nullptr; } -}; - -} /* anonymous namespace */ - -bool TypeSet::ObjectKey::hasFlags(CompilerConstraintList* constraints, - ObjectGroupFlags flags) { - MOZ_ASSERT(flags); - - if (ObjectGroup* group = maybeGroup()) { - AutoSweepObjectGroup sweep(group); - if (group->hasAnyFlags(sweep, flags)) { - return true; - } - } - - HeapTypeSetKey objectProperty = property(JSID_EMPTY); - LifoAlloc* alloc = constraints->alloc(); - - using T = CompilerConstraintInstance; - constraints->add(alloc->new_(alloc, objectProperty, - ConstraintDataFreezeObjectFlags(flags))); - return false; -} - -bool TypeSet::ObjectKey::hasStableClassAndProto( - CompilerConstraintList* constraints) { - return !hasFlags(constraints, OBJECT_FLAG_UNKNOWN_PROPERTIES); -} - -bool TemporaryTypeSet::hasObjectFlags(CompilerConstraintList* constraints, - ObjectGroupFlags flags) { - if (unknownObject()) { - return true; - } - - /* - * Treat type sets containing no objects as having all object flags, - * to spare callers from having to check this. - */ - if (baseObjectCount() == 0) { - return true; - } - - unsigned count = getObjectCount(); - for (unsigned i = 0; i < count; i++) { - ObjectKey* key = getObject(i); - if (key && key->hasFlags(constraints, flags)) { - return true; - } - } - - return false; -} - -gc::InitialHeap ObjectGroup::initialHeap(CompilerConstraintList* constraints) { - // If this object is not required to be pretenured but could be in the - // future, add a constraint to trigger recompilation if the requirement - // changes. - - AutoSweepObjectGroup sweep(this); - if (shouldPreTenure(sweep)) { - return gc::TenuredHeap; - } - - if (!canPreTenure(sweep)) { - return gc::DefaultHeap; - } - - HeapTypeSetKey objectProperty = - TypeSet::ObjectKey::get(this)->property(JSID_EMPTY); - LifoAlloc* alloc = constraints->alloc(); - - using T = CompilerConstraintInstance; - constraints->add( - alloc->new_(alloc, objectProperty, - ConstraintDataFreezeObjectFlags(OBJECT_FLAG_PRE_TENURE))); - - return gc::DefaultHeap; -} - -namespace { - -// Constraint which triggers recompilation when a typed array's data becomes -// invalid. -class ConstraintDataFreezeObjectForTypedArrayData { - NativeObject* obj; - - void* viewData; - uint32_t length; - - public: - explicit ConstraintDataFreezeObjectForTypedArrayData(TypedArrayObject& tarray) - : obj(&tarray), - viewData(tarray.dataPointerUnshared()), - length(tarray.length().deprecatedGetUint32()) { - MOZ_ASSERT(tarray.isSingleton()); - MOZ_ASSERT(!tarray.isSharedMemory()); - } - - const char* kind() { return "freezeObjectForTypedArrayData"; } - - bool invalidateOnNewType(TypeSet::Type type) { return false; } - bool invalidateOnNewPropertyState(TypeSet* property) { return false; } - bool invalidateOnNewObjectState(const AutoSweepObjectGroup& sweep, - ObjectGroup* group) { - MOZ_ASSERT(obj->group() == group); - TypedArrayObject& tarr = obj->as(); - return tarr.dataPointerUnshared() != viewData || - tarr.length().deprecatedGetUint32() != length; - } - - bool constraintHolds(const AutoSweepObjectGroup& sweep, JSContext* cx, - const HeapTypeSetKey& property, - TemporaryTypeSet* expected) { - return !invalidateOnNewObjectState(sweep, property.object()->maybeGroup()); - } - - bool shouldSweep() { - // Note: |viewData| is only used for equality testing. - return IsAboutToBeFinalizedUnbarriered(&obj); - } - - Compartment* maybeCompartment() { return obj->compartment(); } -}; - -} /* anonymous namespace */ - -void TypeSet::ObjectKey::watchStateChangeForTypedArrayData( - CompilerConstraintList* constraints) { - TypedArrayObject& tarray = singleton()->as(); - HeapTypeSetKey objectProperty = property(JSID_EMPTY); - LifoAlloc* alloc = constraints->alloc(); - - using T = - CompilerConstraintInstance; - constraints->add( - alloc->new_(alloc, objectProperty, - ConstraintDataFreezeObjectForTypedArrayData(tarray))); -} - -static void ObjectStateChange(const AutoSweepObjectGroup& sweep, JSContext* cx, - ObjectGroup* group, bool markingUnknown) { - if (group->unknownProperties(sweep)) { - return; - } - - /* All constraints listening to state changes are on the empty id. */ - HeapTypeSet* types = group->maybeGetProperty(sweep, JSID_EMPTY); - - /* Mark as unknown after getting the types, to avoid assertion. */ - if (markingUnknown) { - group->addFlags(sweep, - OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES); - } - - if (types) { - if (!cx->isHelperThreadContext()) { - TypeConstraint* constraint = types->constraintList(sweep); - while (constraint) { - constraint->newObjectState(cx, group); - constraint = constraint->next(); - } - } else { - MOZ_ASSERT(!types->constraintList(sweep)); - } - } -} - -namespace { - -class ConstraintDataFreezePropertyState { - public: - enum Which { NON_DATA, NON_WRITABLE } which; - - explicit ConstraintDataFreezePropertyState(Which which) : which(which) {} - - const char* kind() { - return (which == NON_DATA) ? "freezeNonDataProperty" - : "freezeNonWritableProperty"; - } - - bool invalidateOnNewType(TypeSet::Type type) { return false; } - bool invalidateOnNewPropertyState(TypeSet* property) { - return (which == NON_DATA) ? property->nonDataProperty() - : property->nonWritableProperty(); - } - bool invalidateOnNewObjectState(const AutoSweepObjectGroup& sweep, - ObjectGroup* group) { - return false; - } - - bool constraintHolds(const AutoSweepObjectGroup& sweep, JSContext* cx, - const HeapTypeSetKey& property, - TemporaryTypeSet* expected) { - return !invalidateOnNewPropertyState(property.maybeTypes()); - } - - bool shouldSweep() { return false; } - - Compartment* maybeCompartment() { return nullptr; } -}; - -} /* anonymous namespace */ - -bool HeapTypeSetKey::nonData(CompilerConstraintList* constraints) { - if (maybeTypes() && maybeTypes()->nonDataProperty()) { - return true; - } - - LifoAlloc* alloc = constraints->alloc(); - - using T = CompilerConstraintInstance; - constraints->add( - alloc->new_(alloc, *this, - ConstraintDataFreezePropertyState( - ConstraintDataFreezePropertyState::NON_DATA))); - return false; -} - -bool HeapTypeSetKey::nonWritable(CompilerConstraintList* constraints) { - if (maybeTypes() && maybeTypes()->nonWritableProperty()) { - return true; - } - - LifoAlloc* alloc = constraints->alloc(); - - using T = CompilerConstraintInstance; - constraints->add( - alloc->new_(alloc, *this, - ConstraintDataFreezePropertyState( - ConstraintDataFreezePropertyState::NON_WRITABLE))); - return false; -} - -namespace { - -class ConstraintDataConstantProperty { - public: - explicit ConstraintDataConstantProperty() = default; - - const char* kind() { return "constantProperty"; } - - bool invalidateOnNewType(TypeSet::Type type) { return false; } - bool invalidateOnNewPropertyState(TypeSet* property) { - return property->nonConstantProperty(); - } - bool invalidateOnNewObjectState(const AutoSweepObjectGroup& sweep, - ObjectGroup* group) { - return false; - } - - bool constraintHolds(const AutoSweepObjectGroup& sweep, JSContext* cx, - const HeapTypeSetKey& property, - TemporaryTypeSet* expected) { - return !invalidateOnNewPropertyState(property.maybeTypes()); - } - - bool shouldSweep() { return false; } - - Compartment* maybeCompartment() { return nullptr; } -}; - -} /* anonymous namespace */ - -bool HeapTypeSetKey::constant(CompilerConstraintList* constraints, - Value* valOut) { - if (nonData(constraints)) { - return false; - } - - // Only singleton object properties can be marked as constants. - JSObject* obj = object()->singleton(); - if (!obj || !obj->isNative()) { - return false; - } - - if (maybeTypes() && maybeTypes()->nonConstantProperty()) { - return false; - } - - // Get the current value of the property. - Shape* shape = obj->as().lookupPure(id()); - if (!shape || !shape->isDataProperty() || shape->hadOverwrite()) { - return false; - } - - Value val = obj->as().getSlot(shape->slot()); - - // If the value is a pointer to an object in the nursery, don't optimize. - if (val.isGCThing() && IsInsideNursery(val.toGCThing())) { - return false; - } - - // If the value is a string that's not atomic, don't optimize. - if (val.isString() && !val.toString()->isAtom()) { - return false; - } - - *valOut = val; - - LifoAlloc* alloc = constraints->alloc(); - using T = CompilerConstraintInstance; - constraints->add( - alloc->new_(alloc, *this, ConstraintDataConstantProperty())); - return true; -} - -// A constraint that never triggers recompilation. -class ConstraintDataInert { - public: - explicit ConstraintDataInert() = default; - - const char* kind() { return "inert"; } - - bool invalidateOnNewType(TypeSet::Type type) { return false; } - bool invalidateOnNewPropertyState(TypeSet* property) { return false; } - bool invalidateOnNewObjectState(const AutoSweepObjectGroup& sweep, - ObjectGroup* group) { - return false; - } - - bool constraintHolds(const AutoSweepObjectGroup& sweep, JSContext* cx, - const HeapTypeSetKey& property, - TemporaryTypeSet* expected) { - return true; - } - - bool shouldSweep() { return false; } - - Compartment* maybeCompartment() { return nullptr; } -}; - -bool HeapTypeSetKey::couldBeConstant(CompilerConstraintList* constraints) { - // Only singleton object properties can be marked as constants. - if (!object()->isSingleton()) { - return false; - } - - if (!maybeTypes() || !maybeTypes()->nonConstantProperty()) { - return true; - } - - // It is possible for a property that was not marked as constant to - // 'become' one, if we throw away the type property during a GC and - // regenerate it with the constant flag set. ObjectGroup::sweep only removes - // type properties if they have no constraints attached to them, so add - // inert constraints to pin these properties in place. - - LifoAlloc* alloc = constraints->alloc(); - using T = CompilerConstraintInstance; - constraints->add(alloc->new_(alloc, *this, ConstraintDataInert())); - - return false; -} - -bool TemporaryTypeSet::filtersType(const TemporaryTypeSet* other, - Type filteredType) const { - if (other->unknown()) { - return unknown(); - } - - for (TypeFlags flag = 1; flag < TYPE_FLAG_ANYOBJECT; flag <<= 1) { - Type type = PrimitiveTypeFromTypeFlag(flag); - if (type != filteredType && other->hasType(type) && !hasType(type)) { - return false; - } - } - - if (other->unknownObject()) { - return unknownObject(); - } - - for (size_t i = 0; i < other->getObjectCount(); i++) { - ObjectKey* key = other->getObject(i); - if (key) { - Type type = ObjectType(key); - if (type != filteredType && !hasType(type)) { - return false; - } - } - } - - return true; -} - -TemporaryTypeSet::DoubleConversion TemporaryTypeSet::convertDoubleElements( - CompilerConstraintList* constraints) { - if (unknownObject() || !getObjectCount()) { - return AmbiguousDoubleConversion; - } - - bool alwaysConvert = true; - bool maybeConvert = false; - bool dontConvert = false; - - for (unsigned i = 0; i < getObjectCount(); i++) { - ObjectKey* key = getObject(i); - if (!key) { - continue; - } - - if (key->unknownProperties()) { - alwaysConvert = false; - continue; - } - - HeapTypeSetKey property = key->property(JSID_VOID); - property.freeze(constraints); - - // We can't convert to double elements for objects which do not have - // double in their element types (as the conversion may render the type - // information incorrect), nor for non-array objects (as their elements - // may point to emptyObjectElements or emptyObjectElementsShared, which - // cannot be converted). - if (!property.maybeTypes() || - !property.maybeTypes()->hasType(DoubleType()) || - key->clasp() != &ArrayObject::class_) { - dontConvert = true; - alwaysConvert = false; - continue; - } - - // Only bother with converting known packed arrays whose possible - // element types are int or double. Other arrays require type tests - // when elements are accessed regardless of the conversion. - if (property.knownMIRType(constraints) == jit::MIRType::Double && - !key->hasFlags(constraints, OBJECT_FLAG_NON_PACKED)) { - maybeConvert = true; - } else { - alwaysConvert = false; - } - } - - MOZ_ASSERT_IF(alwaysConvert, maybeConvert); - - if (maybeConvert && dontConvert) { - return AmbiguousDoubleConversion; - } - if (alwaysConvert) { - return AlwaysConvertToDoubles; - } - if (maybeConvert) { - return MaybeConvertToDoubles; - } - return DontConvertToDoubles; -} - -const JSClass* TemporaryTypeSet::getKnownClass( - CompilerConstraintList* constraints) { - if (unknownObject()) { - return nullptr; - } - - const JSClass* clasp = nullptr; - unsigned count = getObjectCount(); - - for (unsigned i = 0; i < count; i++) { - const JSClass* nclasp = getObjectClass(i); - if (!nclasp) { - continue; - } - - if (getObject(i)->unknownProperties()) { - return nullptr; - } - - if (clasp && clasp != nclasp) { - return nullptr; - } - clasp = nclasp; - } - - if (clasp) { - for (unsigned i = 0; i < count; i++) { - ObjectKey* key = getObject(i); - if (key && !key->hasStableClassAndProto(constraints)) { - return nullptr; - } - } - } - - return clasp; -} - -Realm* TemporaryTypeSet::getKnownRealm(CompilerConstraintList* constraints) { - if (unknownObject()) { - return nullptr; - } - - Realm* realm = nullptr; - unsigned count = getObjectCount(); - - for (unsigned i = 0; i < count; i++) { - const JSClass* clasp = getObjectClass(i); - if (!clasp) { - continue; - } - - // If clasp->isProxy(), this might be a cross-compartment wrapper and - // CCWs don't have a (single) realm, so we give up. If the object has - // unknownProperties(), hasStableClassAndProto (called below) will - // return |false| so fail now before attaching any constraints. - if (clasp->isProxy() || getObject(i)->unknownProperties()) { - return nullptr; - } - - MOZ_ASSERT(hasSingleton(i) || hasGroup(i)); - - Realm* nrealm = - hasSingleton(i) ? getSingleton(i)->nonCCWRealm() : getGroup(i)->realm(); - MOZ_ASSERT(nrealm); - if (!realm) { - realm = nrealm; - continue; - } - if (realm != nrealm) { - return nullptr; - } - } - - if (realm) { - for (unsigned i = 0; i < count; i++) { - ObjectKey* key = getObject(i); - if (key && !key->hasStableClassAndProto(constraints)) { - return nullptr; - } - } - } - - return realm; -} - -void TemporaryTypeSet::getTypedArraySharedness( - CompilerConstraintList* constraints, TypedArraySharedness* sharedness) { - // In the future this will inspect the object set. - *sharedness = UnknownSharedness; -} - -TemporaryTypeSet::ForAllResult TemporaryTypeSet::forAllClasses( - CompilerConstraintList* constraints, bool (*func)(const JSClass* clasp)) { - if (unknownObject()) { - return ForAllResult::MIXED; - } - - unsigned count = getObjectCount(); - if (count == 0) { - return ForAllResult::EMPTY; - } - - bool true_results = false; - bool false_results = false; - for (unsigned i = 0; i < count; i++) { - const JSClass* clasp = getObjectClass(i); - if (!clasp) { - continue; - } - if (!getObject(i)->hasStableClassAndProto(constraints)) { - return ForAllResult::MIXED; - } - if (func(clasp)) { - true_results = true; - if (false_results) { - return ForAllResult::MIXED; - } - } else { - false_results = true; - if (true_results) { - return ForAllResult::MIXED; - } - } - } - - MOZ_ASSERT(true_results != false_results); - - return true_results ? ForAllResult::ALL_TRUE : ForAllResult::ALL_FALSE; -} - -Scalar::Type TemporaryTypeSet::getTypedArrayType( - CompilerConstraintList* constraints, TypedArraySharedness* sharedness) { - const JSClass* clasp = getKnownClass(constraints); - - if (clasp && IsTypedArrayClass(clasp)) { - if (sharedness) { - getTypedArraySharedness(constraints, sharedness); - } - return GetTypedArrayClassType(clasp); - } - return Scalar::MaxTypedArrayViewType; -} - -bool TemporaryTypeSet::isDOMClass(CompilerConstraintList* constraints, - DOMObjectKind* kind) { - if (unknownObject()) { - return false; - } - - *kind = DOMObjectKind::Unknown; - bool isFirst = true; - - unsigned count = getObjectCount(); - for (unsigned i = 0; i < count; i++) { - const JSClass* clasp = getObjectClass(i); - if (!clasp) { - continue; - } - if (!clasp->isDOMClass() || - !getObject(i)->hasStableClassAndProto(constraints)) { - return false; - } + : failed_(false), alloc_(alloc.lifoAlloc()), constraints(alloc) {} - DOMObjectKind thisKind = - clasp->isProxy() ? DOMObjectKind::Proxy : DOMObjectKind::Native; - if (isFirst) { - *kind = thisKind; - isFirst = false; - continue; - } - if (*kind != thisKind) { - *kind = DOMObjectKind::Unknown; + void add(CompilerConstraint* constraint) { + if (!constraint || !constraints.append(constraint)) { + setFailed(); } } - return count > 0; -} + size_t length() { return constraints.length(); } -bool TemporaryTypeSet::maybeCallable(CompilerConstraintList* constraints) { - if (!maybeObject()) { - return false; - } + CompilerConstraint* get(size_t i) { return constraints[i]; } - if (unknownObject()) { - return true; - } + bool failed() { return failed_; } + void setFailed() { failed_ = true; } + LifoAlloc* alloc() const { return alloc_; } +}; - unsigned count = getObjectCount(); - for (unsigned i = 0; i < count; i++) { - const JSClass* clasp = getObjectClass(i); - if (!clasp) { - continue; - } - if (clasp->isProxy() || clasp->nonProxyCallable()) { - return true; - } - if (!getObject(i)->hasStableClassAndProto(constraints)) { - return true; - } - } +CompilerConstraintList* js::NewCompilerConstraintList( + jit::TempAllocator& alloc) { + return alloc.lifoAlloc()->new_(alloc); +} - return false; +const JSClass* TypeSet::ObjectKey::clasp() { + return isGroup() ? group()->clasp() : singleton()->getClass(); } -bool TemporaryTypeSet::maybeEmulatesUndefined( - CompilerConstraintList* constraints) { - if (!maybeObject()) { - return false; - } +TaggedProto TypeSet::ObjectKey::proto() { + return isGroup() ? group()->proto() : singleton()->taggedProto(); +} - if (unknownObject()) { - return true; +ObjectGroup* TypeSet::ObjectKey::maybeGroup() { + if (isGroup()) { + return group(); } - - unsigned count = getObjectCount(); - for (unsigned i = 0; i < count; i++) { - // The object emulates undefined if clasp->emulatesUndefined() or if - // it's a WrapperObject, see EmulatesUndefined. Since all wrappers are - // proxies, we can just check for that. - const JSClass* clasp = getObjectClass(i); - if (!clasp) { - continue; - } - if (clasp->emulatesUndefined() || clasp->isProxy()) { - return true; - } - if (!getObject(i)->hasStableClassAndProto(constraints)) { - return true; - } + if (!singleton()->hasLazyGroup()) { + return singleton()->group(); } - - return false; + return nullptr; } -bool TemporaryTypeSet::getCommonPrototype(CompilerConstraintList* constraints, - JSObject** proto) { - if (unknownObject()) { - return false; +bool TypeSet::ObjectKey::unknownProperties() { + if (ObjectGroup* group = maybeGroup()) { + AutoSweepObjectGroup sweep(group); + return group->unknownProperties(sweep); } + return false; +} - *proto = nullptr; - bool isFirst = true; - unsigned count = getObjectCount(); - - for (unsigned i = 0; i < count; i++) { - ObjectKey* key = getObject(i); - if (!key) { - continue; +void TypeSet::ObjectKey::ensureTrackedProperty(JSContext* cx, jsid id) { + // If we are accessing a lazily defined property which actually exists in + // the VM and has not been instantiated yet, instantiate it now if we are + // on the main thread and able to do so. + if (!JSID_IS_VOID(id) && !JSID_IS_EMPTY(id)) { + MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime())); + if (isSingleton()) { + JSObject* obj = singleton(); + if (obj->isNative() && obj->as().containsPure(id)) { + EnsureTrackPropertyTypes(cx, obj, id); + } } + } +} - if (key->unknownProperties()) { - return false; - } +void js::EnsureTrackPropertyTypes(JSContext* cx, JSObject* obj, jsid id) { + if (!IsTypeInferenceEnabled()) { + return; + } + id = IdToTypeId(id); - TaggedProto nproto = key->proto(); - if (isFirst) { - if (nproto.isDynamic()) { - return false; - } - *proto = nproto.toObjectOrNull(); - isFirst = false; - } else { - if (nproto != TaggedProto(*proto)) { - return false; + if (obj->isSingleton()) { + AutoEnterAnalysis enter(cx); + if (obj->hasLazyGroup()) { + AutoEnterOOMUnsafeRegion oomUnsafe; + RootedObject objRoot(cx, obj); + if (!JSObject::getGroup(cx, objRoot)) { + oomUnsafe.crash( + "Could not allocate ObjectGroup in EnsureTrackPropertyTypes"); } } - } - - // Guard against mutating __proto__. - for (unsigned i = 0; i < count; i++) { - if (ObjectKey* key = getObject(i)) { - MOZ_ALWAYS_TRUE(key->hasStableClassAndProto(constraints)); + ObjectGroup* group = obj->group(); + AutoSweepObjectGroup sweep(group); + if (!group->unknownProperties(sweep) && + !group->getProperty(sweep, cx, obj, id)) { + MOZ_ASSERT(group->unknownProperties(sweep)); + return; } } - return true; + MOZ_ASSERT(obj->group()->unknownPropertiesDontCheckGeneration() || + TrackPropertyTypes(obj, id)); } -bool TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, - jsid id) { - if (unknownObject()) { - return true; +static void ObjectStateChange(const AutoSweepObjectGroup& sweep, JSContext* cx, + ObjectGroup* group, bool markingUnknown) { + if (group->unknownProperties(sweep)) { + return; } - for (unsigned i = 0; i < getObjectCount(); i++) { - ObjectKey* key = getObject(i); - if (!key) { - continue; - } + /* All constraints listening to state changes are on the empty id. */ + HeapTypeSet* types = group->maybeGetProperty(sweep, JSID_EMPTY); - if (key->unknownProperties()) { - return true; - } + /* Mark as unknown after getting the types, to avoid assertion. */ + if (markingUnknown) { + group->addFlags(sweep, + OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES); + } - HeapTypeSetKey property = key->property(id); - if (property.needsBarrier(constraints)) { - return true; + if (types) { + if (!cx->isHelperThreadContext()) { + TypeConstraint* constraint = types->constraintList(sweep); + while (constraint) { + constraint->newObjectState(cx, group); + constraint = constraint->next(); + } + } else { + MOZ_ASSERT(!types->constraintList(sweep)); } } - - return false; } bool js::ClassCanHaveExtraProperties(const JSClass* clasp) { @@ -2707,14 +1132,6 @@ return; } - RootedScript script(cx); - for (auto base = zone->cellIter(); !base.done(); base.next()) { - if (JitScript* jitScript = base->maybeJitScript()) { - script = base->asJSScript(); - jitScript->printTypes(cx, script); - } - } - for (auto group = zone->cellIter(); !group.done(); group.next()) { AutoSweepObjectGroup sweep(group); @@ -3342,207 +1759,6 @@ Compartment* maybeCompartment() override { return group->compartment(); } }; -bool js::AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group, - JSScript* script, - JSScript* calleeScript) { - // Look for any uses of the specified calleeScript in type sets for - // |script|, and add constraints to ensure that if the type sets' contents - // change then the definite properties are cleared from the type. - // This ensures that the inlining performed when the definite properties - // analysis was done is stable. We only need to look at type sets which - // contain a single object, as IonBuilder does not inline polymorphic sites - // during the definite properties analysis. - - TypeSet::ObjectKey* calleeKey = - TypeSet::ObjectType(calleeScript->function()).objectKey(); - - AutoSweepJitScript sweep(script); - JitScript* jitScript = script->jitScript(); - unsigned count = jitScript->numTypeSets(); - StackTypeSet* typeArray = jitScript->typeArray(sweep); - - for (unsigned i = 0; i < count; i++) { - StackTypeSet* types = &typeArray[i]; - if (!types->unknownObject() && types->getObjectCount() == 1) { - if (calleeKey != types->getObject(0)) { - // Also check if the object is the Function.call or - // Function.apply native. IonBuilder uses the presence of these - // functions during inlining. - JSObject* singleton = types->getSingleton(0); - if (!singleton || !singleton->is()) { - continue; - } - JSFunction* fun = &singleton->as(); - if (!fun->isNative()) { - continue; - } - if (fun->native() != fun_call && fun->native() != fun_apply) { - continue; - } - } - // This is a type set that might have been used when inlining - // |calleeScript| into |script|. - if (!types->addConstraint( - cx, cx->typeLifoAlloc().new_( - group))) { - return false; - } - } - } - - return true; -} - -///////////////////////////////////////////////////////////////////// -// Interface functions -///////////////////////////////////////////////////////////////////// - -void js::TypeMonitorCallSlow(JSContext* cx, JSObject* callee, - const CallArgs& args, bool constructing) { - unsigned nargs = callee->as().nargs(); - JSScript* script = callee->as().nonLazyScript(); - - if (!constructing) { - JitScript::MonitorThisType(cx, script, args.thisv()); - } - - /* - * Add constraints going up to the minimum of the actual and formal count. - * If there are more actuals than formals the later values can only be - * accessed through the arguments object, which is monitored. - */ - unsigned arg = 0; - for (; arg < args.length() && arg < nargs; arg++) { - JitScript::MonitorArgType(cx, script, arg, args[arg]); - } - - /* Watch for fewer actuals than formals to the call. */ - for (; arg < nargs; arg++) { - JitScript::MonitorArgType(cx, script, arg, UndefinedValue()); - } -} - -/* static */ -void JitScript::MonitorBytecodeType(JSContext* cx, JSScript* script, - jsbytecode* pc, TypeSet::Type type) { - if (!IsTypeInferenceEnabled()) { - return; - } - cx->check(script, type); - - AutoEnterAnalysis enter(cx); - - AutoSweepJitScript sweep(script); - StackTypeSet* types = script->jitScript()->bytecodeTypes(sweep, script, pc); - if (types->hasType(type)) { - return; - } - - InferSpew(ISpewOps, "bytecodeType: %p %05zu: %s", script, - script->pcToOffset(pc), TypeSet::TypeString(type).get()); - types->addType(sweep, cx, type); -} - -/* static */ -void JitScript::MonitorBytecodeTypeSlow(JSContext* cx, JSScript* script, - jsbytecode* pc, StackTypeSet* types, - TypeSet::Type type) { - if (!IsTypeInferenceEnabled()) { - return; - } - cx->check(script, type); - - AutoEnterAnalysis enter(cx); - - AutoSweepJitScript sweep(script); - - MOZ_ASSERT(types == script->jitScript()->bytecodeTypes(sweep, script, pc)); - MOZ_ASSERT(!types->hasType(type)); - - InferSpew(ISpewOps, "bytecodeType: %p %05zu: %s", script, - script->pcToOffset(pc), TypeSet::TypeString(type).get()); - types->addType(sweep, cx, type); -} - -/* static */ -void JitScript::MonitorMagicValueBytecodeType(JSContext* cx, JSScript* script, - jsbytecode* pc, - const js::Value& rval) { - MOZ_ASSERT(IsTypeInferenceEnabled()); - MOZ_ASSERT(rval.isMagic()); - - // It's possible that we arrived here from bailing out of Ion, and that - // Ion proved that the value is dead and optimized out. In such cases, - // do nothing. - if (rval.whyMagic() == JS_OPTIMIZED_OUT) { - return; - } - - // Ops like GetAliasedVar can return the magic TDZ value. - MOZ_ASSERT(rval.whyMagic() == JS_UNINITIALIZED_LEXICAL); - MOZ_ASSERT(JSOp(*GetNextPc(pc)) == JSOp::CheckThis || - JSOp(*GetNextPc(pc)) == JSOp::CheckThisReinit || - JSOp(*GetNextPc(pc)) == JSOp::CheckReturn || - JSOp(*GetNextPc(pc)) == JSOp::CheckAliasedLexical); - - MonitorBytecodeType(cx, script, pc, TypeSet::UnknownType()); -} - -/* static */ -void JitScript::MonitorBytecodeType(JSContext* cx, JSScript* script, - jsbytecode* pc, const js::Value& rval) { - MOZ_ASSERT(BytecodeOpHasTypeSet(JSOp(*pc))); - - if (!IsTypeInferenceEnabled()) { - return; - } - - if (!script->hasJitScript()) { - return; - } - - if (MOZ_UNLIKELY(rval.isMagic())) { - MonitorMagicValueBytecodeType(cx, script, pc, rval); - return; - } - - MonitorBytecodeType(cx, script, pc, TypeSet::GetValueType(rval)); -} - -/* static */ -bool JSFunction::setTypeForScriptedFunction(JSContext* cx, HandleFunction fun, - bool singleton /* = false */) { - if (!IsTypeInferenceEnabled()) { - return true; - } - - // Note: Delazifying our parent may fail with a recoverable OOM. This can - // result in the current function being initialized twice. Check if - // group was already initialized. - if (fun->isSingleton() || fun->group()->maybeInterpretedFunction()) { - return true; - } - - if (singleton) { - if (!setSingleton(cx, fun)) { - return false; - } - } else { - RootedObject funProto(cx, fun->staticPrototype()); - Rooted taggedProto(cx, TaggedProto(funProto)); - ObjectGroup* group = ObjectGroupRealm::makeGroup( - cx, fun->realm(), &JSFunction::class_, taggedProto); - if (!group) { - return false; - } - - fun->setGroup(group); - group->setInterpretedFunction(fun); - } - - return true; -} - ///////////////////////////////////////////////////////////////////// // PreliminaryObjectArray ///////////////////////////////////////////////////////////////////// @@ -3807,14 +2023,6 @@ } } - for (const InliningConstraint& constraint : inliningConstraints_) { - if (!AddClearDefiniteFunctionUsesInScript(cx, group, constraint.caller, - constraint.callee)) { - ReportOutOfMemory(cx); - return false; - } - } - return true; } @@ -4535,15 +2743,6 @@ inlinedCompilations.shrinkTo(dest); } - if (IsTypeInferenceEnabled()) { - // Remove constraints and references to dead objects from stack type sets. - unsigned num = numTypeSets(); - StackTypeSet* arr = typeArray(sweep); - for (unsigned i = 0; i < num; i++) { - arr[i].sweep(sweep, zone); - } - } - if (types.hadOOMSweepingTypes()) { // It's possible we OOM'd while copying freeze constraints, so they // need to be regenerated. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/TypeInference.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/TypeInference.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/TypeInference.h 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/TypeInference.h 2020-11-17 19:31:36.000000000 +0000 @@ -158,10 +158,6 @@ JSContext* cx, DPAConstraintInfo& constraintInfo, ObjectGroup* group, HandleId id, bool* added); -bool AddClearDefiniteFunctionUsesInScript(JSContext* cx, ObjectGroup* group, - JSScript* script, - JSScript* calleeScript); - // For groups where only a small number of objects have been allocated, this // structure keeps track of all objects in the group. Once COUNT objects have // been allocated, this structure is cleared and the objects are analyzed, to @@ -247,17 +243,6 @@ // single IonScript doesn't require an allocation. typedef Vector RecompileInfoVector; -// Generate the type constraints for the compilation. Sets |isValidOut| based on -// whether the type constraints still hold. -bool FinishCompilation(JSContext* cx, HandleScript script, - CompilerConstraintList* constraints, - IonCompilationId compilationId, bool* isValidOut); - -// Update the actual types in any scripts queried by constraints with any -// speculative types added during the definite properties analysis. -void FinishDefinitePropertiesAnalysis(JSContext* cx, - CompilerConstraintList* constraints); - struct AutoEnterAnalysis; class TypeZone { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/TypeInference-inl.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/TypeInference-inl.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/TypeInference-inl.h 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/TypeInference-inl.h 2020-11-17 19:31:37.000000000 +0000 @@ -333,11 +333,6 @@ #endif } -TemporaryTypeSet::TemporaryTypeSet(LifoAlloc* alloc, jit::MIRType type) - : TemporaryTypeSet(alloc, PrimitiveOrAnyObjectType(type)) { - MOZ_ASSERT(type != jit::MIRType::Value); -} - // New script properties analyses overview. // // When constructing objects using 'new' on a script, we attempt to determine @@ -558,24 +553,6 @@ // Interface functions ///////////////////////////////////////////////////////////////////// -void TypeMonitorCallSlow(JSContext* cx, JSObject* callee, const CallArgs& args, - bool constructing); - -/* - * Monitor a javascript call, either on entry to the interpreter or made - * from within the interpreter. - */ -inline void TypeMonitorCall(JSContext* cx, const js::CallArgs& args, - bool constructing) { - if (args.callee().is()) { - JSFunction* fun = &args.callee().as(); - if (fun->isInterpreted() && fun->nonLazyScript()->hasJitScript() && - IsTypeInferenceEnabled()) { - TypeMonitorCallSlow(cx, &args.callee(), args, constructing); - } - } -} - MOZ_ALWAYS_INLINE bool TrackPropertyTypes(JSObject* obj, jsid id) { if (obj->hasLazyGroup() || obj->group()->unknownPropertiesDontCheckGeneration()) { @@ -736,127 +713,6 @@ } } -/* static */ inline void jit::JitScript::MonitorBytecodeType( - JSContext* cx, JSScript* script, jsbytecode* pc, StackTypeSet* types, - const js::Value& rval) { - if (!IsTypeInferenceEnabled()) { - return; - } - if (MOZ_UNLIKELY(rval.isMagic())) { - MonitorMagicValueBytecodeType(cx, script, pc, rval); - return; - } - - TypeSet::Type type = TypeSet::GetValueType(rval); - if (!types->hasType(type)) { - MonitorBytecodeTypeSlow(cx, script, pc, types, type); - } -} - -/* static */ inline void jit::JitScript::MonitorAssign(JSContext* cx, - HandleObject obj, - jsid id) { - if (!obj->isSingleton()) { - /* - * Mark as unknown any object which has had dynamic assignments to - * non-integer properties at SETELEM opcodes. This avoids making large - * numbers of type properties for hashmap-style objects. We don't need - * to do this for objects with singleton type, because type properties - * are only constructed for them when analyzed scripts depend on those - * specific properties. - */ - uint32_t i; - if (IdIsIndex(id, &i)) { - return; - } - - // But if we don't have too many properties yet, don't do anything. The - // idea here is that normal object initialization should not trigger - // deoptimization in most cases, while actual usage as a hashmap should. - ObjectGroup* group = obj->group(); - if (group->basePropertyCountDontCheckGeneration() < 128) { - return; - } - MarkObjectGroupUnknownProperties(cx, group); - } -} - -/* static */ inline void jit::JitScript::MonitorThisType(JSContext* cx, - JSScript* script, - TypeSet::Type type) { - if (!IsTypeInferenceEnabled()) { - return; - } - cx->check(script, type); - - JitScript* jitScript = script->maybeJitScript(); - if (!jitScript) { - return; - } - - AutoSweepJitScript sweep(script); - StackTypeSet* types = jitScript->thisTypes(sweep, script); - - if (!types->hasType(type)) { - AutoEnterAnalysis enter(cx); - - InferSpew(ISpewOps, "externalType: setThis %p: %s", script, - TypeSet::TypeString(type).get()); - types->addType(sweep, cx, type); - } -} - -/* static */ inline void jit::JitScript::MonitorThisType( - JSContext* cx, JSScript* script, const js::Value& value) { - if (!IsTypeInferenceEnabled()) { - return; - } - // Bound functions or class constructors can use the magic TDZ value as - // |this| argument. See CreateThis. - if (MOZ_UNLIKELY(value.isMagic())) { - MOZ_ASSERT(value.whyMagic() == JS_UNINITIALIZED_LEXICAL); - MOZ_ASSERT(script->function()); - MonitorThisType(cx, script, TypeSet::UnknownType()); - return; - } - - MonitorThisType(cx, script, TypeSet::GetValueType(value)); -} - -/* static */ inline void jit::JitScript::MonitorArgType(JSContext* cx, - JSScript* script, - unsigned arg, - TypeSet::Type type) { - if (!IsTypeInferenceEnabled()) { - return; - } - cx->check(script->compartment(), type); - - JitScript* jitScript = script->maybeJitScript(); - if (!jitScript) { - return; - } - - AutoSweepJitScript sweep(script); - StackTypeSet* types = jitScript->argTypes(sweep, script, arg); - - if (!types->hasType(type)) { - AutoEnterAnalysis enter(cx); - - InferSpew(ISpewOps, "externalType: setArg %p %u: %s", script, arg, - TypeSet::TypeString(type).get()); - types->addType(sweep, cx, type); - } -} - -/* static */ inline void jit::JitScript::MonitorArgType( - JSContext* cx, JSScript* script, unsigned arg, const js::Value& value) { - if (!IsTypeInferenceEnabled()) { - return; - } - MonitorArgType(cx, script, arg, TypeSet::GetValueType(value)); -} - ///////////////////////////////////////////////////////////////////// // TypeHashSet ///////////////////////////////////////////////////////////////////// diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/TypeSet.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/TypeSet.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/vm/TypeSet.h 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/vm/TypeSet.h 2020-11-17 19:31:37.000000000 +0000 @@ -223,9 +223,7 @@ }; using ObjectGroupFlags = uint32_t; -class StackTypeSet; class HeapTypeSet; -class TemporaryTypeSet; /* * [SMDOC] Type-Inference TypeSet @@ -296,7 +294,6 @@ bool hasFlags(CompilerConstraintList* constraints, ObjectGroupFlags flags); bool hasStableClassAndProto(CompilerConstraintList* constraints); void watchStateChangeForTypedArrayData(CompilerConstraintList* constraints); - HeapTypeSetKey property(jsid id); void ensureTrackedProperty(JSContext* cx, jsid id); ObjectGroup* maybeGroup(); @@ -437,23 +434,6 @@ return (flags >> TYPE_FLAG_DEFINITE_SHIFT) - 1; } - // Join two type sets into a new set. The result should not be modified - // further. - static TemporaryTypeSet* unionSets(TypeSet* a, TypeSet* b, LifoAlloc* alloc); - - // Return the intersection of the 2 TypeSets. The result should not be - // modified further. - static TemporaryTypeSet* intersectSets(TemporaryTypeSet* a, - TemporaryTypeSet* b, LifoAlloc* alloc); - - /* - * Returns a copy of TypeSet a excluding/removing the types in TypeSet b. - * TypeSet b can only contain primitives or be any object. No support for - * specific objects. The result should not be modified further. - */ - static TemporaryTypeSet* removeSet(TemporaryTypeSet* a, TemporaryTypeSet* b, - LifoAlloc* alloc); - /* Add a type to this set using the specified allocator. */ void addType(Type type, LifoAlloc* alloc); @@ -526,21 +506,6 @@ /* Forward all types in this set to the specified constraint. */ bool addTypesToConstraint(JSContext* cx, TypeConstraint* constraint); - // Clone a type set into an arbitrary allocator. - TemporaryTypeSet* clone(LifoAlloc* alloc) const; - - // |*result| is not even partly initialized when this function is called: - // this function placement-new's its contents into existence. - bool cloneIntoUninitialized(LifoAlloc* alloc, TemporaryTypeSet* result) const; - - // Create a new TemporaryTypeSet where undefined and/or null has been filtered - // out. - TemporaryTypeSet* filter(LifoAlloc* alloc, bool filterUndefined, - bool filterNull) const; - // Create a new TemporaryTypeSet where the type has been set to object. - TemporaryTypeSet* cloneObjectsOnly(LifoAlloc* alloc); - TemporaryTypeSet* cloneWithoutObjects(LifoAlloc* alloc); - JS::Compartment* maybeCompartment(); // Trigger a read barrier on all the contents of a type set. @@ -711,10 +676,6 @@ inline void trace(JS::Zone* zone, JSTracer* trc); }; -class StackTypeSet : public ConstraintTypeSet { - public: -}; - class HeapTypeSet : public ConstraintTypeSet { inline void newPropertyState(const AutoSweepObjectGroup& sweep, JSContext* cx); @@ -740,194 +701,6 @@ enum class DOMObjectKind : uint8_t { Proxy, Native, Unknown }; -class TemporaryTypeSet : public TypeSet { - public: - TemporaryTypeSet() { MOZ_ASSERT(!jit::JitOptions.warpBuilder); } - TemporaryTypeSet(LifoAlloc* alloc, Type type); - - TemporaryTypeSet(uint32_t flags, ObjectKey** objectSet) { - MOZ_ASSERT(!jit::JitOptions.warpBuilder); - this->flags = flags; - this->objectSet = objectSet; - } - - inline TemporaryTypeSet(LifoAlloc* alloc, jit::MIRType type); - - /* - * Constraints for JIT compilation. - * - * Methods for JIT compilation. These must be used when a script is - * currently being compiled (see AutoEnterCompilation) and will add - * constraints ensuring that if the return value change in the future due - * to new type information, the script's jitcode will be discarded. - */ - - /* Get any type tag which all values in this set must have. */ - jit::MIRType getKnownMIRType(); - - /* Whether this value may be an object. */ - bool maybeObject() { return unknownObject() || baseObjectCount() > 0; } - - /* - * Whether this typeset represents a potentially sentineled object value: - * the value may be an object or null or undefined. - * Returns false if the value cannot ever be an object. - */ - bool objectOrSentinel() { - TypeFlags flags = - TYPE_FLAG_UNDEFINED | TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT; - if (baseFlags() & (~flags & TYPE_FLAG_BASE_MASK)) { - return false; - } - - return hasAnyFlag(TYPE_FLAG_ANYOBJECT) || baseObjectCount() > 0; - } - - /* Whether the type set contains objects with any of a set of flags. */ - bool hasObjectFlags(CompilerConstraintList* constraints, - ObjectGroupFlags flags); - - /* Get the class shared by all objects in this set, or nullptr. */ - const JSClass* getKnownClass(CompilerConstraintList* constraints); - - /* - * Get the realm shared by all objects in this set, or nullptr. Returns - * nullptr if the set contains proxies (because cross-compartment wrappers - * don't have a single realm associated with them). - */ - JS::Realm* getKnownRealm(CompilerConstraintList* constraints); - - /* Result returned from forAllClasses */ - enum ForAllResult { - EMPTY = 1, // Set empty - ALL_TRUE, // Set not empty and predicate returned true for all classes - ALL_FALSE, // Set not empty and predicate returned false for all classes - MIXED, // Set not empty and predicate returned false for some classes - // and true for others, or set contains an unknown or non-object - // type - }; - - /* Apply func to the members of the set and return an appropriate result. - * The iteration may end early if the result becomes known early. - */ - ForAllResult forAllClasses(CompilerConstraintList* constraints, - bool (*func)(const JSClass* clasp)); - - /* - * Returns true if all objects in this set have the same prototype, and - * assigns this object to *proto. The proto can be nullptr. - */ - bool getCommonPrototype(CompilerConstraintList* constraints, - JSObject** proto); - - /* Whether the buffer mapped by a TypedArray is shared memory or not */ - enum TypedArraySharedness { - UnknownSharedness = 1, // We can't determine sharedness - KnownShared, // We know for sure the buffer is shared - KnownUnshared // We know for sure the buffer is unshared - }; - - /* - * Get the typed array type of all objects in this set, or - * Scalar::MaxTypedArrayViewType. If there is such a common type and - * sharedness is not nullptr then *sharedness is set to what we know about the - * sharedness of the memory. - */ - Scalar::Type getTypedArrayType(CompilerConstraintList* constraints, - TypedArraySharedness* sharedness = nullptr); - - // Whether all objects have JSCLASS_IS_DOMJSCLASS set. - bool isDOMClass(CompilerConstraintList* constraints, DOMObjectKind* kind); - - // Whether clasp->isCallable() is true for one or more objects in this set. - bool maybeCallable(CompilerConstraintList* constraints); - - // Whether clasp->emulatesUndefined() is true for one or more objects in - // this set. - bool maybeEmulatesUndefined(CompilerConstraintList* constraints); - - // Get the single value which can appear in this type set, otherwise - // nullptr. - JSObject* maybeSingleton(); - ObjectKey* maybeSingleObject(); - - // Whether any objects in the type set needs a barrier on id. - bool propertyNeedsBarrier(CompilerConstraintList* constraints, jsid id); - - // Whether this set contains all types in other, except (possibly) the - // specified type. - bool filtersType(const TemporaryTypeSet* other, Type type) const; - - enum DoubleConversion { - /* All types in the set should use eager double conversion. */ - AlwaysConvertToDoubles, - - /* Some types in the set should use eager double conversion. */ - MaybeConvertToDoubles, - - /* No types should use eager double conversion. */ - DontConvertToDoubles, - - /* Some types should use eager double conversion, others cannot. */ - AmbiguousDoubleConversion - }; - - /* - * Whether known double optimizations are possible for element accesses on - * objects in this type set. - */ - DoubleConversion convertDoubleElements(CompilerConstraintList* constraints); - - private: - void getTypedArraySharedness(CompilerConstraintList* constraints, - TypedArraySharedness* sharedness); -}; - -// Representation of a heap type property which may or may not be instantiated. -// Heap properties for singleton types are instantiated lazily as they are used -// by the compiler, but this is only done on the main thread. If we are -// compiling off thread and use a property which has not yet been instantiated, -// it will be treated as empty and non-configured and will be instantiated when -// rejoining to the main thread. If it is in fact not empty, the compilation -// will fail; to avoid this, we try to instantiate singleton property types -// during generation of baseline caches. -class HeapTypeSetKey { - friend class TypeSet::ObjectKey; - - // Object and property being accessed. - TypeSet::ObjectKey* object_; - jsid id_; - - // If instantiated, the underlying heap type set. - HeapTypeSet* maybeTypes_; - - public: - HeapTypeSetKey() : object_(nullptr), id_(JSID_EMPTY), maybeTypes_(nullptr) {} - - TypeSet::ObjectKey* object() const { return object_; } - jsid id() const { return id_; } - - HeapTypeSet* maybeTypes() const { - if (maybeTypes_) { - maybeTypes_->checkMagic(); - } - return maybeTypes_; - } - - bool instantiate(JSContext* cx); - - void freeze(CompilerConstraintList* constraints); - jit::MIRType knownMIRType(CompilerConstraintList* constraints); - bool nonData(CompilerConstraintList* constraints); - bool nonWritable(CompilerConstraintList* constraints); - bool isOwnProperty(CompilerConstraintList* constraints, - bool allowEmptyTypesForGlobal = false); - JSObject* singleton(CompilerConstraintList* constraints); - bool needsBarrier(CompilerConstraintList* constraints); - bool constant(CompilerConstraintList* constraints, Value* valOut); - bool couldBeConstant(CompilerConstraintList* constraints); -}; - } /* namespace js */ #endif /* vm_TypeSet_h */ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/AsmJS.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/AsmJS.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/AsmJS.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/AsmJS.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -1386,13 +1386,13 @@ auto AddMathFunction = [this](const char* name, AsmJSMathBuiltinFunction func) { - auto mbAtom = parserAtoms_.internAscii(cx_, name, strlen(name)); - if (mbAtom.isErr()) { + const ParserAtom* atom = + parserAtoms_.internAscii(cx_, name, strlen(name)); + if (!atom) { return false; } MathBuiltin builtin(func); - return this->standardLibraryMathNames_.putNew(mbAtom.unwrap()->asName(), - builtin); + return this->standardLibraryMathNames_.putNew(atom->asName(), builtin); }; for (const auto& info : functions) { @@ -1416,13 +1416,13 @@ }; auto AddMathConstant = [this](const char* name, double cst) { - auto mbAtom = parserAtoms_.internAscii(cx_, name, strlen(name)); - if (mbAtom.isErr()) { + const ParserAtom* atom = + parserAtoms_.internAscii(cx_, name, strlen(name)); + if (!atom) { return false; } MathBuiltin builtin(cst); - return this->standardLibraryMathNames_.putNew(mbAtom.unwrap()->asName(), - builtin); + return this->standardLibraryMathNames_.putNew(atom->asName(), builtin); }; for (const auto& info : constants) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/WasmInstance.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/WasmInstance.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/WasmInstance.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/WasmInstance.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -136,68 +136,96 @@ }; template -static bool ToWebAssemblyValue_i32(JSContext* cx, HandleValue val, - int32_t* loc) { +static bool ToWebAssemblyValue_i32(JSContext* cx, HandleValue val, int32_t* loc, + bool mustWrite64) { bool ok = ToInt32(cx, val, loc); + if (ok && mustWrite64) { +#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) + loc[1] = loc[0] >> 31; +#else + loc[1] = 0; +#endif + } Debug::print(*loc); return ok; } template -static bool ToWebAssemblyValue_i64(JSContext* cx, HandleValue val, - int64_t* loc) { +static bool ToWebAssemblyValue_i64(JSContext* cx, HandleValue val, int64_t* loc, + bool mustWrite64) { + MOZ_ASSERT(mustWrite64); JS_TRY_VAR_OR_RETURN_FALSE(cx, *loc, ToBigInt64(cx, val)); Debug::print(*loc); return true; } template -static bool ToWebAssemblyValue_f32(JSContext* cx, HandleValue val, float* loc) { +static bool ToWebAssemblyValue_f32(JSContext* cx, HandleValue val, float* loc, + bool mustWrite64) { bool ok = RoundFloat32(cx, val, loc); + if (ok && mustWrite64) { + loc[1] = 0.0; + } Debug::print(*loc); return ok; } template -static bool ToWebAssemblyValue_f64(JSContext* cx, HandleValue val, - double* loc) { +static bool ToWebAssemblyValue_f64(JSContext* cx, HandleValue val, double* loc, + bool mustWrite64) { + MOZ_ASSERT(mustWrite64); bool ok = ToNumber(cx, val, loc); Debug::print(*loc); return ok; } template static bool ToWebAssemblyValue_externref(JSContext* cx, HandleValue val, - void** loc) { + void** loc, bool mustWrite64) { RootedAnyRef result(cx, AnyRef::null()); if (!BoxAnyRef(cx, val, &result)) { return false; } *loc = result.get().forCompiledCode(); +#ifndef JS_64BIT + if (mustWrite64) { + loc[1] = nullptr; + } +#endif Debug::print(*loc); return true; } template -static bool ToWebAssemblyValue_eqref(JSContext* cx, HandleValue val, - void** loc) { +static bool ToWebAssemblyValue_eqref(JSContext* cx, HandleValue val, void** loc, + bool mustWrite64) { RootedAnyRef result(cx, AnyRef::null()); if (!CheckEqRefValue(cx, val, &result)) { return false; } *loc = result.get().forCompiledCode(); +#ifndef JS_64BIT + if (mustWrite64) { + loc[1] = nullptr; + } +#endif Debug::print(*loc); return true; } template static bool ToWebAssemblyValue_funcref(JSContext* cx, HandleValue val, - void** loc) { + void** loc, bool mustWrite64) { RootedFunction fun(cx); if (!CheckFuncRefValue(cx, val, &fun)) { return false; } *loc = fun; +#ifndef JS_64BIT + if (mustWrite64) { + loc[1] = nullptr; + } +#endif Debug::print(*loc); return true; } template static bool ToWebAssemblyValue_typeref(JSContext* cx, HandleValue val, - void** loc) { + void** loc, bool mustWrite64) { JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_WASM_TYPEREF_FROM_JS); return false; @@ -205,16 +233,16 @@ template static bool ToWebAssemblyValue(JSContext* cx, HandleValue val, ValType type, - void* loc) { + void* loc, bool mustWrite64) { switch (type.kind()) { case ValType::I32: - return ToWebAssemblyValue_i32(cx, val, (int32_t*)loc); + return ToWebAssemblyValue_i32(cx, val, (int32_t*)loc, mustWrite64); case ValType::I64: - return ToWebAssemblyValue_i64(cx, val, (int64_t*)loc); + return ToWebAssemblyValue_i64(cx, val, (int64_t*)loc, mustWrite64); case ValType::F32: - return ToWebAssemblyValue_f32(cx, val, (float*)loc); + return ToWebAssemblyValue_f32(cx, val, (float*)loc, mustWrite64); case ValType::F64: - return ToWebAssemblyValue_f64(cx, val, (double*)loc); + return ToWebAssemblyValue_f64(cx, val, (double*)loc, mustWrite64); case ValType::V128: MOZ_CRASH("unexpected v128 in ToWebAssemblyValue"); case ValType::Ref: @@ -229,13 +257,17 @@ #endif switch (type.refTypeKind()) { case RefType::Func: - return ToWebAssemblyValue_funcref(cx, val, (void**)loc); + return ToWebAssemblyValue_funcref(cx, val, (void**)loc, + mustWrite64); case RefType::Extern: - return ToWebAssemblyValue_externref(cx, val, (void**)loc); + return ToWebAssemblyValue_externref(cx, val, (void**)loc, + mustWrite64); case RefType::Eq: - return ToWebAssemblyValue_eqref(cx, val, (void**)loc); + return ToWebAssemblyValue_eqref(cx, val, (void**)loc, + mustWrite64); case RefType::TypeIndex: - return ToWebAssemblyValue_typeref(cx, val, (void**)loc); + return ToWebAssemblyValue_typeref(cx, val, (void**)loc, + mustWrite64); } } MOZ_CRASH("unreachable"); @@ -391,7 +423,7 @@ // Result is either one scalar value to unpack to a wasm value, or // an ignored value for a zero-valued function. if (resultTypes.length() == 1) { - return ToWebAssemblyValue(cx, rval, resultTypes[0], argv); + return ToWebAssemblyValue(cx, rval, resultTypes[0], argv, true); } return true; } @@ -412,6 +444,8 @@ return false; } + DebugOnly previousOffset = ~(uint64_t)0; + ABIResultIter iter(ResultType::Vector(resultTypes)); // The values are converted in the order they are pushed on the // abstract WebAssembly stack; switch to iterate in push order. @@ -432,14 +466,25 @@ // and set `argv[0]` set to the extracted result, to be returned by // register in the stub. The register result follows any stack // results, so this preserves conversion order. - if (!ToWebAssemblyValue(cx, rval, result.type(), argv)) { + if (!ToWebAssemblyValue(cx, rval, result.type(), argv, true)) { return false; } seenRegisterResult = true; continue; } + uint32_t result_size = result.size(); + MOZ_ASSERT(result_size == 4 || result_size == 8); +#ifdef DEBUG + if (previousOffset == ~(uint64_t)0) { + previousOffset = (uint64_t)result.stackOffset(); + } else { + MOZ_ASSERT(previousOffset - (uint64_t)result_size == + (uint64_t)result.stackOffset()); + previousOffset -= (uint64_t)result_size; + } +#endif char* loc = stackResultsArea.value() + result.stackOffset(); - if (!ToWebAssemblyValue(cx, rval, result.type(), loc)) { + if (!ToWebAssemblyValue(cx, rval, result.type(), loc, result_size == 8)) { return false; } } @@ -541,91 +586,9 @@ return true; } - JitScript* jitScript = script->jitScript(); - - // Ensure the argument types are included in the argument TypeSets stored in - // the JitScript. This is necessary for Ion, because the import will use - // the skip-arg-checks entry point. When the JitScript is discarded the import - // is patched back. - if (IsTypeInferenceEnabled()) { - AutoSweepJitScript sweep(script); - - StackTypeSet* thisTypes = jitScript->thisTypes(sweep, script); - if (!thisTypes->hasType(TypeSet::UndefinedType())) { - return true; - } - - const ValTypeVector& importArgs = fi.funcType().args(); - - size_t numKnownArgs = std::min(importArgs.length(), importFun->nargs()); - for (uint32_t i = 0; i < numKnownArgs; i++) { - StackTypeSet* argTypes = jitScript->argTypes(sweep, script, i); - switch (importArgs[i].kind()) { - case ValType::I32: - if (!argTypes->hasType(TypeSet::Int32Type())) { - return true; - } - break; - case ValType::I64: - if (!argTypes->hasType(TypeSet::BigIntType())) { - return true; - } - break; - case ValType::V128: - MOZ_CRASH("Not needed per spec"); - case ValType::F32: - if (!argTypes->hasType(TypeSet::DoubleType())) { - return true; - } - break; - case ValType::F64: - if (!argTypes->hasType(TypeSet::DoubleType())) { - return true; - } - break; - case ValType::Ref: - switch (importArgs[i].refTypeKind()) { - case RefType::Extern: - // We don't know what type the value will be, so we can't really - // check whether the callee will accept it. It doesn't make much - // sense to see if the callee accepts all of the types an AnyRef - // might represent because most callees will not have been exposed - // to all those types and so we'll never pass the test. Instead, - // we must use the callee's arg-type-checking entry point, and not - // check anything here. See FuncType::jitExitRequiresArgCheck(). - break; - case RefType::Func: - // We handle FuncRef as we do AnyRef: by checking the type - // dynamically in the callee. Code in the stubs layer must box up - // the FuncRef as a Value. - break; - case RefType::Eq: - case RefType::TypeIndex: - // Guarded by temporarilyUnsupportedReftypeForExit() - MOZ_CRASH("case guarded above"); - } - break; - } - } - - // These arguments will be filled with undefined at runtime by the - // arguments rectifier: check that the imported function can handle - // undefined there. - for (uint32_t i = importArgs.length(); i < importFun->nargs(); i++) { - StackTypeSet* argTypes = jitScript->argTypes(sweep, script, i); - if (!argTypes->hasType(TypeSet::UndefinedType())) { - return true; - } - } - } - // Let's optimize it! - if (!jitScript->addDependentWasmImport(cx, *this, funcImportIndex)) { - return false; - } import.code = jitExitCode; - import.jitScript = jitScript; return true; } @@ -1465,17 +1428,14 @@ import.realm = f->realm(); import.code = calleeInstance.codeBase(calleeTier) + codeRange.funcUncheckedCallEntry(); - import.jitScript = nullptr; } else if (void* thunk = MaybeGetBuiltinThunk(f, fi.funcType())) { import.tls = tlsData(); import.realm = f->realm(); import.code = thunk; - import.jitScript = nullptr; } else { import.tls = tlsData(); import.realm = f->realm(); import.code = codeBase(callerTier) + fi.interpExitCodeOffset(); - import.jitScript = nullptr; } } @@ -1606,16 +1566,6 @@ Instance::~Instance() { realm_->wasm.unregisterInstance(*this); - const FuncImportVector& funcImports = - metadata(code().stableTier()).funcImports; - - for (unsigned i = 0; i < funcImports.length(); i++) { - FuncImportTls& import = funcImportTls(funcImports[i]); - if (import.jitScript) { - import.jitScript->removeDependentWasmImport(*this, i); - } - } - if (!metadata().funcTypeIds.empty()) { ExclusiveData::Guard lockedFuncTypeIdSet = funcTypeIdSet.lock(); @@ -2125,7 +2075,7 @@ size_t naturalIdx = argTypes.naturalIndex(i); v = naturalIdx < args.length() ? args[naturalIdx] : UndefinedValue(); ValType type = funcType->arg(naturalIdx); - if (!ToWebAssemblyValue(cx, v, type, rawArgLoc)) { + if (!ToWebAssemblyValue(cx, v, type, rawArgLoc, true)) { return false; } if (type.isReference()) { @@ -2263,14 +2213,6 @@ } } -void Instance::deoptimizeImportExit(uint32_t funcImportIndex) { - Tier t = code().bestTier(); - const FuncImport& fi = metadata(t).funcImports[funcImportIndex]; - FuncImportTls& import = funcImportTls(fi); - import.code = codeBase(t) + fi.interpExitCodeOffset(); - import.jitScript = nullptr; -} - JSString* Instance::createDisplayURL(JSContext* cx) { // In the best case, we simply have a URL, from a streaming compilation of a // fetched Response. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/WasmInstance.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/WasmInstance.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/WasmInstance.h 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/WasmInstance.h 2020-11-17 19:31:37.000000000 +0000 @@ -145,14 +145,6 @@ JSAtom* getFuncDisplayAtom(JSContext* cx, uint32_t funcIndex) const; void ensureProfilingLabels(bool profilingEnabled) const; - // Initially, calls to imports in wasm code call out through the generic - // callImport method. If the imported callee gets JIT compiled and the types - // match up, callImport will patch the code to instead call through a thunk - // directly into the JIT code. If the JIT code is released, the Instance must - // be notified so it can go back to the generic callImport. - - void deoptimizeImportExit(uint32_t funcImportIndex); - // Called by Wasm(Memory|Table)Object when a moving resize occurs: void onMovingGrowMemory(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/WasmStubs.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/WasmStubs.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/WasmStubs.cpp 2020-11-15 14:38:05.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/WasmStubs.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -2317,16 +2317,7 @@ // 7. If we haven't rectified arguments, load callee executable entry point. - if (fi.funcType().jitExitRequiresArgCheck()) { - masm.loadJitCodeRaw(callee, callee); - } else { - // This is equivalent to masm.loadJitCodeNoArgCheck(callee, callee) but uses - // two loads instead of three. - masm.loadWasmGlobalPtr( - fi.tlsDataOffset() + offsetof(FuncImportTls, jitScript), callee); - masm.loadPtr(Address(callee, JitScript::offsetOfJitCodeSkipArgCheck()), - callee); - } + masm.loadJitCodeRaw(callee, callee); Label rejoinBeforeCall; masm.bind(&rejoinBeforeCall); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/WasmTypes.h firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/WasmTypes.h --- firefox-trunk-84.0~a1~hg20201115r557261/js/src/wasm/WasmTypes.h 2020-11-15 14:38:06.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/src/wasm/WasmTypes.h 2020-11-17 19:31:37.000000000 +0000 @@ -48,7 +48,6 @@ namespace js { namespace jit { -class JitScript; enum class RoundingMode; template class ABIArgIterBase; @@ -1262,14 +1261,6 @@ } return false; } - bool jitExitRequiresArgCheck() const { - for (ValType arg : args()) { - if (arg.isEncodedAsJSValueOnEscape()) { - return true; - } - } - return false; - } #ifdef WASM_PRIVATE_REFTYPES bool exposesTypeIndex() const { for (const ValType& arg : args()) { @@ -2946,10 +2937,6 @@ // The callee function's realm. JS::Realm* realm; - // If 'code' points into a JIT code thunk, the JitScript of the callee, for - // bidirectional registration purposes. - jit::JitScript* jitScript; - // A GC pointer which keeps the callee alive and is used to recover import // values for lazy table initialization. GCPtrFunction fun; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/js/xpconnect/src/XPCJSContext.cpp firefox-trunk-85.0~a1~hg20201117r557492/js/xpconnect/src/XPCJSContext.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/js/xpconnect/src/XPCJSContext.cpp 2020-11-15 14:38:06.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/js/xpconnect/src/XPCJSContext.cpp 2020-11-17 19:31:37.000000000 +0000 @@ -842,7 +842,6 @@ bool useBaselineInterp = Preferences::GetBool(JS_OPTIONS_DOT_STR "blinterp"); bool useBaselineJit = Preferences::GetBool(JS_OPTIONS_DOT_STR "baselinejit"); bool useIon = Preferences::GetBool(JS_OPTIONS_DOT_STR "ion"); - bool useWarp = Preferences::GetBool(JS_OPTIONS_DOT_STR "warp"); bool useJitForTrustedPrincipals = Preferences::GetBool(JS_OPTIONS_DOT_STR "jit_trustedprincipals"); bool useNativeRegExp = @@ -906,7 +905,6 @@ JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_BASELINE_ENABLE, useBaselineJit); JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_ION_ENABLE, useIon); - JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_WARP_ENABLE, useWarp); JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_JIT_TRUSTEDPRINCIPALS_ENABLE, useJitForTrustedPrincipals); JS_SetGlobalJitCompilerOption(cx, JSJITCOMPILER_NATIVE_REGEXP_ENABLE, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/browser.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/browser.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -23,7 +23,7 @@ # there is no content title: # # "default" - "Mozilla Firefox" -# "private" - "Mozilla Firefox - (Private Browsing)" +# "private" - "Mozilla Firefox — (Private Browsing)" # # The last two are for use when there *is* a content title. # Do not use the brand name in the last two attributes, as we do on non-macOS. @@ -109,6 +109,9 @@ urlbar-search-tips-onboard = Escriviu menys i trobeu més: Cerqueu amb { $engineName } directament des de la barra d'adreces. urlbar-search-tips-redirect-2 = Comenceu la vostra cerca en la barra d'adreces per veure suggeriments de { $engineName } i del vostre historial de navegació. +# Prompts users to use the Urlbar when they are typing in the domain of a +# search engine, e.g. google.com or amazon.com. +urlbar-tabtosearch-onboard = Seleccioneu aquesta drecera per trobar el que necessiteu més ràpidament. ## Local search mode indicator labels in the urlbar @@ -293,11 +296,13 @@ .label = Desactivat identity-https-only-dropdown-off-temporarily = .label = Desactivat temporalment -identity-https-only-info-turn-on = Activeu-ho si voleu que el { -brand-short-name } canviï a una connexió segura quan sigui possible. -identity-https-only-info-turn-off = Si sembla que el lloc no funciona bé, podeu provar de desactivar el mode només HTTPS per tornar-lo a carregar amb HTTP insegur. +identity-https-only-info-turn-on2 = Activeu el mode només HTTPS per a aquest lloc si voleu que el { -brand-short-name } canviï a una connexió segura quan sigui possible. +identity-https-only-info-turn-off2 = Si sembla que la pàgina no funciona bé, podeu provar de desactivar el mode només HTTPS per a aquest lloc per tornar-lo a carregar amb HTTP insegur. identity-https-only-info-no-upgrade = No s'ha pogut actualitzar la connexió des d'HTTP. identity-permissions = .value = Permisos +identity-permissions-storage-access-header = Galetes entre llocs +identity-permissions-storage-access-hint = Aquests subjectes poden utilitzar galetes entre llocs i dades del lloc mentre esteu en aquest lloc. identity-permissions-reload-hint = Potser cal que actualitzeu la pàgina per aplicar els canvis. identity-permissions-empty = No heu donat cap permís especial a aquest lloc. identity-clear-site-data = @@ -341,6 +346,13 @@ browser-window-close-button = .tooltiptext = Tanca +## Bookmarks toolbar items + +browser-import-button2 = + .label = Importa les adreces d'interès… + .tooltiptext = Importa les adreces d'interès d'un altre navegador al { -brand-short-name }. +bookmarks-toolbar-empty-message = Col·loqueu les adreces d'interès aquí, a la barra de les adreces d'interès, per accedir-hi ràpidament. Gestiona les adreces d'interès… + ## WebRTC Pop-up notifications popup-select-camera = @@ -444,16 +456,21 @@ # Variables # $engine (String): the name of a search engine urlbar-result-action-search-w-engine = Cerca amb { $engine } +urlbar-result-action-sponsored = Patrocinat urlbar-result-action-switch-tab = Canvia a la pestanya urlbar-result-action-visit = Visita - -## Action text shown in urlbar results, usually appended after the search -## string or the url, like "result value - action text". -## In these actions "Search" is a verb, followed by where the search is performed. - -urlbar-result-action-search-bookmarks = Cerca en les adreces d'interès -urlbar-result-action-search-history = Cerca en l'historial -urlbar-result-action-search-tabs = Cerca en les pestanyes +# Directs a user to press the Tab key to perform a search with the specified +# engine. +# Variables +# $engine (String): the name of a search engine that searches the entire Web +# (e.g. Google). +urlbar-result-action-before-tabtosearch-web = Premeu Tab per cercar amb { $engine } +# Directs a user to press the Tab key to perform a search with the specified +# engine. +# Variables +# $engine (String): the name of a search engine that searches a specific site +# (e.g. Amazon). +urlbar-result-action-before-tabtosearch-other = Premeu Tab per cercar en { $engine } # Variables # $engine (String): the name of a search engine that searches the entire Web # (e.g. Google). @@ -463,6 +480,14 @@ # (e.g. Amazon). urlbar-result-action-tabtosearch-other-engine = Cerca en { $engine } directament des de la barra d'adreces +## Action text shown in urlbar results, usually appended after the search +## string or the url, like "result value - action text". +## In these actions "Search" is a verb, followed by where the search is performed. + +urlbar-result-action-search-bookmarks = Cerca en les adreces d'interès +urlbar-result-action-search-history = Cerca en l'historial +urlbar-result-action-search-tabs = Cerca en les pestanyes + ## Full Screen and Pointer Lock UI # Please ensure that the domain stays in the `` markup. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/newtab/asrouter.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/newtab/asrouter.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/newtab/asrouter.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/newtab/asrouter.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -265,3 +265,4 @@ ## What's new: Media controls message cfr-whatsnew-media-keys-header = Més controls multimèdia +cfr-whatsnew-media-keys-button = Vegeu com fer-ho diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/newtab/newtab.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/newtab/newtab.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/newtab/newtab.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/newtab/newtab.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -15,7 +15,6 @@ newtab-search-box-search-button = .title = Cerca .aria-label = Cerca - newtab-search-box-search-the-web-text = Cerca al web newtab-search-box-search-the-web-input = .placeholder = Cerca al web @@ -30,12 +29,10 @@ newtab-topsites-title-label = Títol newtab-topsites-title-input = .placeholder = Escriviu el títol - newtab-topsites-url-label = URL newtab-topsites-url-input = .placeholder = Escriviu o enganxeu un URL newtab-topsites-url-validation = Es necessita un URL vàlid - newtab-topsites-image-url-label = URL d'imatge personalitzada newtab-topsites-use-image-link = Utilitza una imatge personalitzada… newtab-topsites-image-validation = S'ha produït un error en carregar la imatge. Proveu un altre URL. @@ -54,18 +51,20 @@ # "This action" refers to deleting a page from history. newtab-confirm-delete-history-p2 = Aquesta acció no es pot desfer. +## Top Sites - Sponsored label + +newtab-topsite-sponsored = Patrocinat + ## Context Menu - Action Tooltips. # General tooltip for context menus. newtab-menu-section-tooltip = .title = Obre el menú .aria-label = Obre el menú - # Tooltip for dismiss button newtab-dismiss-button-tooltip = .title = Elimina .aria-label = Elimina - # This tooltip is for the context menu of Pocket cards or Topsites # Variables: # $title (String): The label or hostname of the site. This is for screen readers when the context menu button is focused/active. @@ -138,12 +137,10 @@ newtab-label-recommended = Tendència newtab-label-saved = Desat al { -pocket-brand-name } newtab-label-download = Baixat - # This string is used in the story cards to indicate sponsored content # Variables: # $sponsorOrSource (String): This is the name of a company or their domain newtab-label-sponsored = { $sponsorOrSource } · Patrocinat - # This string is used at the bottom of story cards to indicate sponsored content # Variables: # $sponsor (String): This is the name of a sponsor @@ -181,13 +178,11 @@ ## Empty Section States: These show when there are no more items in a section. Ex. When there are no more Pocket story recommendations, in the space where there would have been stories, this is shown instead. newtab-empty-section-highlights = Comenceu a navegar i aquí us mostrarem els millors articles, vídeos i altres pàgines que hàgiu visitat o afegit a les adreces d'interès recentment. - # Ex. When there are no more Pocket story recommendations, in the space where there would have been stories, this is shown instead. # Variables: # $provider (String): Name of the content provider for this section, e.g "Pocket". newtab-empty-section-topstories = Ja esteu al dia. Torneu més tard per veure més articles populars de { $provider }. No podeu esperar? Trieu un tema popular per descobrir els articles més interessants de tot el web. - ## Empty Section (Content Discovery Experience). These show when there are no more stories or when some stories fail to load. newtab-discovery-empty-section-topstories-header = Ja esteu al dia. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/newtab/onboarding.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/newtab/onboarding.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/newtab/onboarding.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/newtab/onboarding.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -17,6 +17,14 @@ ## Welcome modal dialog strings + +### UI strings for the simplified onboarding / multistage about:welcome +### Various strings use a non-breaking space to avoid a single dangling / +### widowed word, so test on various window sizes if you also want this. + + +## Welcome page strings + onboarding-welcome-header = Us donem la benvinguda al { -brand-short-name } onboarding-welcome-body = Ja teniu el navegador.
Ara descobriu la resta del { -brand-product-name }. onboarding-welcome-learn-more = Més informació sobre els beneficis. @@ -36,10 +44,59 @@ # Text for link to submit the sign in form onboarding-join-form-signin = Inicia la sessió onboarding-start-browsing-button-label = Comença a navegar +onboarding-not-now-button-label = Ara no onboarding-cards-dismiss = .title = Descarta .aria-label = Descarta +## Welcome full page string + +onboarding-fullpage-welcome-subheader = Descobriu tot allò que podeu fer. +onboarding-fullpage-form-email = + .placeholder = La vostra adreça electrònica… + +## Firefox Sync modal dialog strings. + +onboarding-sync-welcome-header = El vostre { -brand-product-name }, a tot arreu +onboarding-sync-welcome-content = Accediu a les vostres adreces d'interès, historial, contrasenyes i preferències en tots els vostres dispositius. +onboarding-sync-welcome-learn-more-link = Més informació sobre els Comptes del Firefox +onboarding-sync-form-input = + .placeholder = Adreça electrònica +onboarding-sync-form-continue-button = Continua +onboarding-sync-form-skip-login-button = Omet aquest pas + +## This is part of the line "Enter your email to continue to Firefox Sync" + +onboarding-sync-form-header = Introduïu la vostra adreça electrònica +onboarding-sync-form-sub-header = per continuar al { -sync-brand-name }. + +## These are individual benefit messages shown with an image, title and +## description. + +onboarding-benefit-products-text = Milloreu la productivitat amb una família d'eines que respecten la vostra privadesa en tots els dispositius. +# "Personal Data Promise" is a concept that should be translated consistently +# across the product. It refers to a concept shown elsewhere to the user: "The +# Firefox Personal Data Promise is the way we honor your data in everything we +# make and do. We take less data. We keep it safe. And we make sure that we are +# transparent about how we use it." +onboarding-benefit-privacy-text = Tot el que fem respecta la nostra «Promesa sobre les dades personals»: recollir menys dades, mantenir-les segures i sense secrets. +onboarding-benefit-sync-title = { -sync-brand-short-name } +onboarding-benefit-sync-text = Accediu a les adreces d'interès, les contrasenyes, l'historial i molt més a tot arreu on utilitzeu el { -brand-product-name }. +onboarding-benefit-monitor-title = { -monitor-brand-short-name } +onboarding-benefit-monitor-text = Rebeu notificacions si la vostra informació personal apareix en alguna filtració de dades coneguda. +onboarding-benefit-lockwise-title = { -lockwise-brand-short-name } +onboarding-benefit-lockwise-text = Gestioneu les contrasenyes de forma segura i portàtil. + +## Custom Return To AMO onboarding strings + +return-to-amo-subtitle = Molt bé, teniu el { -brand-short-name } +# will be replaced with the icon belonging to the extension +# +# Variables: +# $addon-name (String) - Name of the add-on +return-to-amo-addon-title = Ara, instal·leu l'extensió complement { $addon-name }. +return-to-amo-add-extension-label = Afegeix l'extensió + ## Multistage 3-screen onboarding flow strings (about:welcome pages) # The in this string allows a "zap" underline style to be @@ -72,8 +129,6 @@ onboarding-multistage-theme-secondary-button-label = Ara no # Automatic theme uses operating system color settings onboarding-multistage-theme-label-automatic = Automàtic -# System refers to the operating system -onboarding-multistage-theme-description-automatic = Utilitza el tema del sistema onboarding-multistage-theme-label-light = Clar onboarding-multistage-theme-label-dark = Fosc # "Firefox Alpenglow" here is the name of the theme, and should be kept in English. @@ -85,30 +140,6 @@ ## tooltip. # Tooltip displayed on hover of automatic theme -onboarding-multistage-theme-tooltip-automatic = - .title = - Hereta l'aparença del sistema operatiu - per als botons, menús i finestres. - .aria-label = { onboarding-multistage-theme-tooltip-automatic.title } -# Tooltip displayed on hover of light theme -onboarding-multistage-theme-tooltip-light = - .title = - Utilitza una aparença clara per als - botons, menús i finestres. - .aria-label = { onboarding-multistage-theme-tooltip-light.title } -# Tooltip displayed on hover of dark theme -onboarding-multistage-theme-tooltip-dark = - .title = - Utilitza una aparença fosca per als - botons, menús i finestres. - .aria-label = { onboarding-multistage-theme-tooltip-dark.title } -# Tooltip displayed on hover of Alpenglow theme -onboarding-multistage-theme-tooltip-alpenglow = - .title = - Utilitza una aparença acolorida per als - botons, menús i finestres. - .aria-label = { onboarding-multistage-theme-tooltip-alpenglow.title } -# Tooltip displayed on hover of automatic theme onboarding-multistage-theme-tooltip-automatic-2 = .title = Hereta l'aparença del sistema operatiu @@ -149,44 +180,6 @@ Utilitza una aparença acolorida per als botons, menús i finestres. -## Welcome full page string - -onboarding-fullpage-welcome-subheader = Descobriu tot allò que podeu fer. -onboarding-fullpage-form-email = - .placeholder = La vostra adreça electrònica… - -## Firefox Sync modal dialog strings. - -onboarding-sync-welcome-header = El vostre { -brand-product-name }, a tot arreu -onboarding-sync-welcome-content = Accediu a les vostres adreces d'interès, historial, contrasenyes i preferències en tots els vostres dispositius. -onboarding-sync-welcome-learn-more-link = Més informació sobre els Comptes del Firefox -onboarding-sync-form-input = - .placeholder = Adreça electrònica -onboarding-sync-form-continue-button = Continua -onboarding-sync-form-skip-login-button = Omet aquest pas - -## This is part of the line "Enter your email to continue to Firefox Sync" - -onboarding-sync-form-header = Introduïu la vostra adreça electrònica -onboarding-sync-form-sub-header = per continuar al { -sync-brand-name }. - -## These are individual benefit messages shown with an image, title and -## description. - -onboarding-benefit-products-text = Milloreu la productivitat amb una família d'eines que respecten la vostra privadesa en tots els dispositius. -# "Personal Data Promise" is a concept that should be translated consistently -# across the product. It refers to a concept shown elsewhere to the user: "The -# Firefox Personal Data Promise is the way we honor your data in everything we -# make and do. We take less data. We keep it safe. And we make sure that we are -# transparent about how we use it." -onboarding-benefit-privacy-text = Tot el que fem respecta la nostra «Promesa sobre les dades personals»: recollir menys dades, mantenir-les segures i sense secrets. -onboarding-benefit-sync-title = { -sync-brand-short-name } -onboarding-benefit-sync-text = Accediu a les adreces d'interès, les contrasenyes, l'historial i molt més a tot arreu on utilitzeu el { -brand-product-name }. -onboarding-benefit-monitor-title = { -monitor-brand-short-name } -onboarding-benefit-monitor-text = Rebeu notificacions si la vostra informació personal apareix en alguna filtració de dades coneguda. -onboarding-benefit-lockwise-title = { -lockwise-brand-short-name } -onboarding-benefit-lockwise-text = Gestioneu les contrasenyes de forma segura i portàtil. - ## These strings belong to the individual onboarding messages. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/places.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/places.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/places.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/places.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -17,7 +17,6 @@ places-open-private-window = .label = Obre en una finestra privada nova .accesskey = p - places-new-bookmark = .label = Afegeix una adreça d'interès… .accesskey = d @@ -30,7 +29,6 @@ places-new-separator = .label = Afegeix un separador .accesskey = s - places-view = .label = Visualitza .accesskey = V @@ -49,12 +47,10 @@ places-by-day-and-site = .label = Per data i lloc .accesskey = t - places-history-search = .placeholder = Cerca en l'historial places-bookmarks-search = .placeholder = Cerca en les adreces d'interès - places-delete-domain-data = .label = Oblida aquest lloc .accesskey = O @@ -64,3 +60,9 @@ places-properties = .label = Propietats .accesskey = i +# Managed bookmarks are created by an administrator and cannot be changed by the user. +managed-bookmarks = + .label = Adreces d'interès gestionades +# This label is used when a managed bookmarks folder doesn't have a name. +managed-bookmarks-subfolder = + .label = Subcarpeta diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/preferences/addEngine.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/preferences/addEngine.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/preferences/addEngine.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/preferences/addEngine.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -2,9 +2,15 @@ # 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/. +add-engine-window = + .title = Afegeix un motor de cerca + .style = width: 32em; add-engine-button = Afegeix un motor personalitzat add-engine-name = Nom del motor de cerca add-engine-alias = Àlies -add-engine-cancel = - .label = Cancel·la - .accesskey = C +add-engine-url = URL del motor. Utilitzeu %s en lloc del terme de cerca +add-engine-dialog = + .buttonlabelaccept = Afegeix el motor + .buttonaccesskeyaccept = A +engine-name-exists = Ja existeix un motor amb aquest nom. +engine-alias-exists = Ja existeix un motor amb aquest àlies. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/preferences/fxaPairDevice.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/preferences/fxaPairDevice.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/preferences/fxaPairDevice.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/preferences/fxaPairDevice.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -5,11 +5,11 @@ fxa-pair-device-dialog = .title = Connecta un altre dispositiu .style = width: 26em; min-height: 35em; - fxa-qrcode-heading-phase1 = 1. Si encara no ho heu fet, instal·leu el Firefox en el vostre dispositiu mòbil. - fxa-qrcode-heading-phase2 = 2. A continuació, inicieu la sessió al { -sync-brand-short-name } o, en l'Android, escanegeu el codi d'aparellament des dels paràmetres del { -sync-brand-short-name }. - +fxa-qrcode-heading-step1 = 1. Si encara no ho heu fet, instal·leu el Firefox en el vostre dispositiu mòbil. +fxa-qrcode-heading-step2 = 2. Obriu el Firefox en el dispositiu mòbil. +fxa-qrcode-heading-step3 = 3. Obriu el menú ( o ), toqueu Paràmetres i trieu Activa la sincronització +fxa-qrcode-heading-step4 = 4. Escanegeu aquest codi: fxa-qrcode-error-title = Aparellament incorrecte. - fxa-qrcode-error-body = Torneu-ho a provar. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/preferences/preferences.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/preferences/preferences.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -29,6 +29,8 @@ *[other] Cerca en les preferències } managed-notice = El navegador està gestionat per la vostra organització. +category-list = + .aria-label = Categories pane-general-title = General category-general = .tooltiptext = { pane-general-title } @@ -50,6 +52,9 @@ pane-experimental-subtitle = Aneu amb compte pane-experimental-search-results-header = Experiments del { -brand-short-name }: Aneu amb compte pane-experimental-description = La modificació de les preferències avançades de configuració pot afectar el rendiment o la seguretat del { -brand-short-name }. +pane-experimental-reset = + .label = Restaura els valors per defecte + .accesskey = R help-button-label = Assistència del { -brand-short-name } addons-button-label = Extensions i temes focus-search = @@ -426,6 +431,7 @@ .label = Activa els controls de vídeo d'imatge sobre imatge .accesskey = A browsing-picture-in-picture-learn-more = Més informació +browsing-media-control-learn-more = Més informació browsing-cfr-recommendations = .label = Recomana extensions durant la navegació .accesskey = R @@ -489,6 +495,8 @@ home-prefs-topsites-header = .label = Llocs principals home-prefs-topsites-description = Els llocs que visiteu més sovint +home-prefs-topsites-by-option-sponsored = + .label = Llocs principals patrocinats ## Variables: ## $provider (String): Name of the corresponding content provider, e.g "Pocket". @@ -560,6 +568,7 @@ suggestions-addressbar-settings-generic = Canvia les preferències d'altres suggeriments de la barra d'adreces search-suggestions-cant-show = No es mostraran suggeriments de cerca als resultats de la barra d'ubicació perquè heu configurat el { -brand-short-name } per tal que no recordi mai l'historial. search-one-click-header = Motors de cerca amb un sol clic +search-one-click-header2 = Dreceres de cerca search-one-click-desc = Trieu els motors de cerca alternatius que es mostraran sota la barra d'adreces i de cerca en començar a escriure una paraula. search-choose-engine-column = .label = Motor de cerca @@ -571,6 +580,9 @@ search-remove-engine = .label = Elimina .accesskey = E +search-add-engine = + .label = Afegeix + .accesskey = A search-find-more-link = Afegiu més motors de cerca # This warning is displayed when the chosen keyword is already in use # ('Duplicate' is an adjective) @@ -869,6 +881,10 @@ .label = Elements de seguiment entre llocs sitedata-option-block-cross-site-and-social-media-trackers = .label = Elements de seguiment de xarxes socials i entre llocs +sitedata-option-block-cross-site-tracking-cookies-including-social-media = + .label = Galetes de seguiment entre llocs (inclou les galetes de xarxes socials) +sitedata-option-block-cross-site-cookies-including-social-media = + .label = Galetes entre llocs (inclou les galetes de xarxes socials) sitedata-option-block-cross-site-and-social-media-trackers-plus-isolate = .label = Elements de seguiment de xarxes socials i entre llocs, i aïlla les galetes restants sitedata-option-block-unvisited = @@ -934,6 +950,7 @@ content-blocking-etp-strict-desc = Més protecció, però pot fer que alguns llocs o algun contingut no funcionin correctament. content-blocking-etp-custom-desc = Trieu quins elements de seguiment i scripts cal blocar. content-blocking-private-windows = Contingut que fa seguiment en finestres privades +content-blocking-cross-site-cookies = Galetes entre llocs content-blocking-cross-site-tracking-cookies = Galetes de seguiment entre llocs content-blocking-cross-site-tracking-cookies-plus-isolate = Galetes de seguiment entre llocs, i aïlla les galetes restants content-blocking-social-media-trackers = Elements de seguiment de xarxes socials @@ -945,6 +962,7 @@ content-blocking-fingerprinters = Generadors d'empremtes digitals content-blocking-warning-title = Atenció! content-blocking-and-isolating-etp-warning-description = El bloqueig d'elements de seguiment i l'aïllament de galetes pot afectar la funcionalitat d'alguns llocs. Torneu a carregar la pàgina amb els elements de seguiment per carregar-ne tot el contingut. +content-blocking-and-isolating-etp-warning-description-2 = Aquest paràmetre pot fer que alguns llocs web no mostrin part del contingut o que no funcionin correctament. Si sembla que un lloc no funciona bé, podeu provar de desactivar la protecció contra el seguiment perquè aquest lloc carregui tot el contingut. content-blocking-warning-learn-how = Vegeu com fer-ho content-blocking-reload-description = Cal tornar a carregar les pestanyes per aplicar aquests canvis. content-blocking-reload-tabs-button = diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/safebrowsing/blockedSite.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/safebrowsing/blockedSite.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/safebrowsing/blockedSite.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/safebrowsing/blockedSite.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -19,6 +19,8 @@ safeb-blocked-malware-page-error-desc-override = S'ha informat que { $sitename } conté programari maliciós. Podeu informar d'un error en la detecció o ignorar el risc i visitar aquest lloc insegur. safeb-blocked-malware-page-error-desc-no-override = S'ha informat que { $sitename } conté programari maliciós. Podeu informar d'un error en la detecció. safeb-blocked-malware-page-learn-more = Per obtenir més informació sobre el contingut web perillós, inclosos els virus i altre programari maliciós, i sobre com protegir el vostre ordinador, visiteu StopBadware.org. Per obtenir més informació sobre la protecció contra la pesca electrònica i el programari maliciós del { -brand-short-name }, visiteu support.mozilla.org. +safeb-blocked-malware-page-error-desc-override-sumo = S'ha informat que { $sitename } conté programari maliciós. Podeu ignorar el risc i visitar aquest lloc insegur. +safeb-blocked-malware-page-error-desc-no-override-sumo = S'ha informat que { $sitename } conté programari maliciós. safeb-blocked-malware-page-learn-more-sumo = Per obtenir més informació sobre la protecció contra la pesca electrònica i el programari maliciós del { -brand-short-name }, visiteu support.mozilla.org. safeb-blocked-unwanted-page-error-desc-override = S'ha informat que { $sitename } conté programari perillós. Podeu ignorar el risc i visitar aquest lloc insegur. safeb-blocked-unwanted-page-error-desc-no-override = S'ha informat que { $sitename } conté programari perillós. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/toolbarContextMenu.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/toolbarContextMenu.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/toolbarContextMenu.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/toolbarContextMenu.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -24,21 +24,18 @@ *[other] Desfés el tancament de les pestanyes } .accesskey = f - toolbar-context-menu-manage-extension = .label = Gestiona l'extensió .accesskey = e toolbar-context-menu-remove-extension = .label = Elimina l'extensió .accesskey = l - # This label is used in the extensions toolbar buttons context menus, # a user can use this command to submit to Mozilla an abuse report # related to that extension. "Report" is a verb. toolbar-context-menu-report-extension = .label = Informa sobre l'extensió .accesskey = o - # Can appear on the same context menu as menubarCmd ("Menu Bar") and # personalbarCmd ("Bookmarks Toolbar"), so they should have different # access keys. @@ -54,3 +51,12 @@ toolbar-context-menu-view-customize-toolbar = .label = Personalitza… .accesskey = P +toolbar-context-menu-bookmarks-toolbar-always-show = + .label = Sempre + .accesskey = S +toolbar-context-menu-bookmarks-toolbar-never-show = + .label = Mai + .accesskey = M +toolbar-context-menu-bookmarks-toolbar-on-new-tab = + .label = Només en una pestanya nova + .accesskey = N diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/webrtcIndicator.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/webrtcIndicator.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/browser/webrtcIndicator.ftl 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/browser/webrtcIndicator.ftl 2020-11-17 19:32:43.000000000 +0000 @@ -11,7 +11,6 @@ # This string is used so that the window has a title in tools that enumerate/look for window # titles. It is not normally visible anywhere. webrtc-indicator-title = { -brand-short-name } - Indicador de compartició - webrtc-sharing-window = Esteu compartint una altra finestra d'aplicació. webrtc-sharing-browser-window = Esteu compartint el { -brand-short-name }. webrtc-sharing-screen = Esteu compartint la pantalla sencera. @@ -20,5 +19,22 @@ .title = Esteu compartint el micròfon. Feu clic aquí per controlar què voleu compartir. webrtc-camera-button = .title = Esteu compartint la càmera. Feu clic aquí per controlar què voleu compartir. +webrtc-microphone-unmuted = + .title = Desactiva el micròfon +webrtc-microphone-muted = + .title = Activa el micròfon +webrtc-camera-unmuted = + .title = Desactiva la càmera +webrtc-camera-muted = + .title = Activa la càmera webrtc-minimize = .title = Minimitza l'indicador +# This string will display as a tooltip on supported systems where we show +# device sharing state in the OS notification area. We do not use these strings +# on macOS, as global menu bar items do not have native tooltips. +webrtc-camera-system-menu = + .label = Esteu compartint la càmera. Feu clic aquí per controlar què voleu compartir. +webrtc-microphone-system-menu = + .label = Esteu compartint el micròfon. Feu clic aquí per controlar què voleu compartir. +webrtc-screen-system-menu = + .label = Esteu compartint una finestra o una pantalla. Feu clic aquí per controlar què voleu compartir. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/chrome/browser/accounts.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/chrome/browser/accounts.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/chrome/browser/accounts.properties 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/chrome/browser/accounts.properties 2020-11-17 19:32:43.000000000 +0000 @@ -41,6 +41,10 @@ # Displayed in the Send Tab/Page/Link to Device context menu when right clicking a tab, a page or a link. sendToAllDevices.menuitem = Envia a tots els dispositius +# LOCALIZATION NOTE (manageDevices.menuitem) +# Displayed in the Send Tab/Page/Link to Device context menu when right clicking a tab, a page or a link. +manageDevices.menuitem = Gestiona els dispositius… + # LOCALIZATION NOTE (sendTabToDevice.unconfigured, sendTabToDevice.unconfigured.label2) # Displayed in the Send Tabs context menu when right clicking a tab, a page or a link # and the Sync account is unconfigured. Redirects to a marketing page. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/chrome/browser/app-extension-fields.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/chrome/browser/app-extension-fields.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/chrome/browser/app-extension-fields.properties 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/chrome/browser/app-extension-fields.properties 2020-11-17 19:32:43.000000000 +0000 @@ -10,3 +10,6 @@ extension.firefox-compact-dark@mozilla.org.name=Fosc extension.firefox-compact-dark@mozilla.org.description=Un tema amb colors foscos. +# LOCALIZATION NOTE (extension.firefox-alpenglow@mozilla.org.name): This is displayed in about:addons -> Appearance +extension.firefox-alpenglow@mozilla.org.name=Firefox Alpenglow +extension.firefox-alpenglow@mozilla.org.description=Utilitza una aparença acolorida per als botons, menús i finestres. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/chrome/browser/browser.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/chrome/browser/browser.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ca/browser/chrome/browser/browser.properties 2020-11-15 14:39:54.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ca/browser/chrome/browser/browser.properties 2020-11-17 19:32:43.000000000 +0000 @@ -15,7 +15,6 @@ # %2$S is the selection string. contextMenuSearch=Cerca «%2$S» a %1$S contextMenuSearch.accesskey=C - contextMenuPrivateSearch=Cerca en una finestra privada contextMenuPrivateSearch.accesskey=f # LOCALIZATION NOTE (contextMenuPrivateSearchOtherEngine): %S is the search @@ -57,7 +56,6 @@ # %2$S is replaced by the ID of add-on. %3$S is a custom message that # the administration can add to the message. addonInstallBlockedByPolicy=L'administrador del sistema ha blocat %1$S (%2$S).%3$S - addonInstallFullScreenBlocked=No es permet instal·lar cap complement mentre estigueu en el mode de pantalla completa, o abans d'entrar-hi. # LOCALIZATION NOTE (webextPerms.header) @@ -289,6 +287,9 @@ # LOCALIZATION NOTE (geolocationLastAccessIndicatorText): %S is the relative time of the most recent geolocation access (e.g. 5 min. ago) geolocationLastAccessIndicatorText=Últim accés %S +# LOCALIZATION NOTE (openProtocolHandlerPermissionEntryLabel): %S is the scheme of the protocol the site may open an application for. For example: mailto +openProtocolHandlerPermissionEntryLabel=Enllaços %S:// + crashedpluginsMessage.title=El connector %S ha fallat. crashedpluginsMessage.reloadButton.label=Torna a carregar la pàgina crashedpluginsMessage.reloadButton.accesskey=r @@ -409,7 +410,6 @@ # LOCALIZATION NOTE (newTabButton.tooltip): # %S is the keyboard shortcut for "New Tab" newTabButton.tooltip=Obre una pestanya nova (%S) - newTabContainer.tooltip=Obre una pestanya nova (%S)\nManteniu premut per obrir una pestanya de contenidor nova newTabAlwaysContainer.tooltip=Selecciona un contenidor per obrir una pestanya nova @@ -461,14 +461,12 @@ identity.identified.verifier=Verificat per: %S identity.identified.verified_by_you=Heu afegit una excepció de seguretat per a aquest lloc web. identity.identified.state_and_country=%S, %S - identity.ev.contentOwner2=Certificat emès per a: %S # LOCALIZATION NOTE (identity.notSecure.label): # Keep this string as short as possible, this is displayed in the URL bar # use a synonym for "safe" or "private" if "secure" is too long. identity.notSecure.label=Insegur - identity.notSecure.tooltip=La connexió no és segura identity.extension.label=Extensió (%S) @@ -1032,7 +1030,6 @@ storageAccess.Allow.accesskey = a storageAccess.DontAllow.label = Bloca l'accés storageAccess.DontAllow.accesskey = B - # LOCALIZATION NOTE (storageAccess2.message): # %1$S is the name of the site URL (www.site1.example) trying to track the user's activity. # %2$S is the name of the site URL (www.site2.example) that the user is visiting. This is the same domain name displayed in the address bar. @@ -1052,7 +1049,6 @@ confirmationHint.addSearchEngine.label = S'ha afegit el motor de cerca confirmationHint.pinTab.label = S'ha fixat confirmationHint.pinTab.description = Feu clic amb el botó dret del ratolí per deixar de fixar. - confirmationHint.passwordSaved.label = S'ha desat la contrasenya confirmationHint.loginRemoved.label = S'ha eliminat l'inici de sessió confirmationHint.breakageReport.label = S'ha enviat l'informe. Gràcies! diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/browser/browser/aboutSessionRestore.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/browser/browser/aboutSessionRestore.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/browser/browser/aboutSessionRestore.ftl 2020-11-15 14:40:03.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/browser/browser/aboutSessionRestore.ftl 2020-11-17 19:32:53.000000000 +0000 @@ -3,41 +3,34 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. restore-page-tab-title = Obnovení relace - # The title is intended to be apologetic and disarming, expressing dismay # and regret that we are unable to restore the session for the user restore-page-error-title = Je nám líto, máme nějaké potíže s obnovením vašich stránek. restore-page-problem-desc = Máme nějaké potíže s obnovením vaší předchozí relace prohlížení. Zvolte Obnovit relaci a zkuste to znovu. restore-page-try-this = Pořád se nedaří relaci obnovit? Někdy za to může některý z panelů. Podívejte se na předchozí panely, zrušte označení těch, které nepotřebujete obnovit, a pak pokračujte v obnově. - restore-page-hide-tabs = Skrýt předchozí panely restore-page-show-tabs = Zobrazit předchozí panely - # When tabs are distributed across multiple windows, this message is used as a # header above the group of tabs for each window. # # Variables: # $windowNumber: Progressive number associated to each window restore-page-window-label = Okno #{ $windowNumber } - restore-page-restore-header = .label = Obnovit - restore-page-list-header = .label = Okna a panely - restore-page-try-again-button = .label = Obnovit relaci .accesskey = r - restore-page-close-button = .label = Začít novou relaci .accesskey = n ## The following strings are used in about:welcomeback -welcome-back-tab-title = Úspěch! -welcome-back-page-title = Úspěch! +welcome-back-tab-title = Hotovo! +welcome-back-page-title = Hotovo! welcome-back-page-info = { -brand-short-name.gender -> [masculine] { -brand-short-name } je připravený. @@ -45,13 +38,9 @@ [neuter] { -brand-short-name } je připravené. *[other] Aplikace { -brand-short-name } je připravená. } - welcome-back-restore-button = .label = Pojďme na to! .accesskey = P - welcome-back-restore-all-label = Obnovit všechna okna a panely welcome-back-restore-some-label = Obnovit pouze ty, které chcete - welcome-back-page-info-link = Vaše přizpůsobení a doplňky byly odstraněny a prohlížeč obnoven do výchozího nastavení. Pokud to nevyřeší váš problém, přečtěte si více o tom, co můžete dělat. - diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/browser/browser/preferences/preferences.ftl 2020-11-15 14:40:03.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/browser/browser/preferences/preferences.ftl 2020-11-17 19:32:53.000000000 +0000 @@ -351,13 +351,7 @@ applications-use-app-default = .label = Použít { $app-name } (výchozí) applications-use-os-default = - .label = - Použít výchozí aplikaci - { PLATFORM() -> - [macos] systému macOS - [windows] systému Windows - *[other] operačního systému - } + .label = Použít výchozí systémovou aplikaci applications-use-other = .label = Použít jinou… applications-select-helper = Zvolit pomocnou aplikaci diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/browser/installer/custom.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/browser/installer/custom.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/browser/installer/custom.properties 2020-11-15 14:40:03.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/browser/installer/custom.properties 2020-11-17 19:32:53.000000000 +0000 @@ -36,7 +36,7 @@ SUMMARY_REBOOT_REQUIRED_UNINSTALL=Pro dokončení odinstalace může být vyžadován restart vašeho počítače. SUMMARY_TAKE_DEFAULTS=&Použít aplikaci $BrandShortName jako výchozí prohlížeč SUMMARY_INSTALL_CLICK=Pro pokračování klepněte na Instalovat. -SUMMARY_UPGRADE_CLICK=Pro pokračování klepněte na tlačítko Aktualizovat. +SUMMARY_UPGRADE_CLICK=Pro pokračování klepněte na Aktualizovat. SURVEY_TEXT=&Sdělte nám, co si o aplikaci $BrandShortName myslíte LAUNCH_TEXT=&Spustit $BrandShortName CREATE_ICONS_DESC=Vytvořit zástupce aplikace $BrandShortName: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/chat/imtooltip.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/chat/imtooltip.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/chat/imtooltip.properties 2020-11-15 14:40:04.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/chat/imtooltip.properties 2020-11-17 19:32:53.000000000 +0000 @@ -5,3 +5,6 @@ buddy.username=Uživatelské jméno buddy.account=Účet contact.tags=Štítky + +otr.tag=Stav OTR +message.status=Zpráva je zašifrována diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/toolkit/toolkit/about/aboutConfig.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/toolkit/toolkit/about/aboutConfig.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/toolkit/toolkit/about/aboutConfig.ftl 2020-11-15 14:40:04.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/toolkit/toolkit/about/aboutConfig.ftl 2020-11-17 19:32:53.000000000 +0000 @@ -15,14 +15,11 @@ .label = Beru to na vědomí! config-about-warning-checkbox = .label = Zobrazit příště toto varování - config-search-prefs = .value = Hledat: .accesskey = H - config-focus-search = .key = r - config-focus-search-2 = .key = f @@ -42,7 +39,7 @@ config-pref-column-header = .tooltip = Klepnutím seřadíte config-column-chooser = - .tooltip = Klepnutím vyberte sloupce pro zobrazení + .tooltip = Klepnutím vyberte sloupce, které chcete zobrazit ## These strings are used for the context menu @@ -50,60 +47,45 @@ .key = C .label = Kopírovat .accesskey = K - config-copy-name = .label = Kopírovat název .accesskey = z - config-copy-value = .label = Kopírovat hodnotu .accesskey = K - config-modify = .label = Změnit .accesskey = m - config-toggle = .label = Přepnout .accesskey = t - config-reset = .label = Obnovit .accesskey = O - config-new = .label = Nová předvolba .accesskey = N - config-string = .label = Řetězec .accesskey = t - config-integer = .label = Číslo .accesskey = s - config-boolean = .label = Logická hodnota .accesskey = g - config-default = výchozí config-modified = změněno config-locked = zamknuto - config-property-string = řetězec config-property-int = číslo config-property-bool = logická hodnota - config-new-prompt = Zadejte název pro předvolbu - config-nan-title = Neplatná hodnota config-nan-text = Vložený text není číselná hodnota. - # Variables: # $type (String): type of value (boolean, integer or string) config-new-title = Nová předvolba typu { $type } - # Variables: # $type (String): type of value (boolean, integer or string) config-modify-title = Zadejte předvolbu typu { $type } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/toolkit/toolkit/about/certviewer.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/toolkit/toolkit/about/certviewer.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/cs/toolkit/toolkit/about/certviewer.ftl 2020-11-15 14:40:04.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/cs/toolkit/toolkit/about/certviewer.ftl 2020-11-17 19:32:53.000000000 +0000 @@ -106,6 +106,11 @@ certificate-viewer-export = Exportovat .download = { $fileName }.pem +## + +# Label for a tab where we haven't found a better label: +certificate-viewer-unknown-group-label = (neznámý) + ## Labels for tabs displayed in stand-alone about:certificate page certificate-viewer-tab-mine = Osobní diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/cy/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/cy/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/cy/browser/browser/browser.ftl 2020-11-15 14:40:07.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/cy/browser/browser/browser.ftl 2020-11-17 19:32:56.000000000 +0000 @@ -356,9 +356,10 @@ ## Bookmarks toolbar items -browser-import-button = - .label = Mewnforio nodau tudalen... - .tooltiptext = Copïo nodau tudalen o borwr arall i { -brand-short-name }. +browser-import-button2 = + .label = Mewnforio nodau tudalen… + .tooltiptext = Mewnforio nodau tudalen o borwr arall i { -brand-short-name }. +bookmarks-toolbar-empty-message = I gael mynediad cyflym, rhowch eich nodau tudalen yma ar y bar offer nodau tudalen. Rheoli nodau tudalen… ## WebRTC Pop-up notifications diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/cy/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/cy/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/cy/browser/browser/preferences/preferences.ftl 2020-11-15 14:40:07.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/cy/browser/browser/preferences/preferences.ftl 2020-11-17 19:32:56.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = Gofal! pane-experimental-search-results-header = Arbrofion { -brand-short-name }: Byddwch yn Ofalus pane-experimental-description = Gall newid dewisiadau ffurfweddiad uwch effeithio ar berfformiad neu ddiogelwch { -brand-short-name }. +pane-experimental-reset = + .label = Adfer y Rhagosodiadau + .accesskey = A help-button-label = Cefnogaeth { -brand-short-name } addons-button-label = Estyniadau a Themâu focus-search = @@ -945,6 +948,7 @@ content-blocking-enhanced-tracking-protection = Diogelwch Uwch Rhag Tracio content-blocking-section-top-level-description = Mae tracwyr yn eich dilyn ar-lein i gasglu gwybodaeth am eich arferion pori a'ch diddordebau. Mae { -brand-short-name } yn rhwystro llawer o'r tracwyr hyn a sgriptiau maleisus eraill. content-blocking-learn-more = Dysgu Rhagor +content-blocking-fpi-incompatibility-warning = Rydych yn defnyddio Ynysu Parti Cyntaf (FPI), sy’n gwrthwneud rhai o osodiadau cwci { -brand-short-name } ’. ## These strings are used to define the different levels of ## Enhanced Tracking Protection. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/cy/toolkit/toolkit/featuregates/features.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/cy/toolkit/toolkit/featuregates/features.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/cy/toolkit/toolkit/featuregates/features.ftl 2020-11-15 14:40:07.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/cy/toolkit/toolkit/featuregates/features.ftl 2020-11-17 19:32:56.000000000 +0000 @@ -47,11 +47,6 @@ experimental-features-css-constructable-stylesheets = .label = CSS: Constructable Stylesheets experimental-features-css-constructable-stylesheets-description = Mae ychwanegu adeiladwr at y rhyngwyneb CSSStyleSheet yn ogystal ag amrywiaeth o newidiadau cysylltiedig yn ei gwneud hi'n bosibl creu taflenni arddull newydd yn uniongyrchol heb orfod ychwanegu'r ddalen at yr HTML. Mae hyn yn ei gwneud hi'n llawer haws creu taflenni arddull y mae modd eu hailddefnyddio i'w defnyddio gyda Shadow DOM. Gweler bug 1520690 am fwy o fanylion. -# The title of the experiment should be kept in English as it may be referenced -# by various online articles and is technical in nature. -experimental-features-media-session-api = - .label = Web API: Media Session API -experimental-features-media-session-api-description = Ar hyn o bryd mae gweithrediad cyfan { -brand-short-name } yr Media Session API yn arbrofol. Defnyddir yr API hwn i addasu'r broses o drin hysbysiadau sy'n gysylltiedig â'r cyfryngau, i reoli digwyddiadau a data sy'n ddefnyddiol ar gyfer cyflwyno rhyngwyneb defnyddiwr ar gyfer rheoli chwarae cyfryngau, ac i gael metadata ffeiliau cyfryngau. Gweler bug 1112032 am fwy o fanylion. experimental-features-devtools-color-scheme-simulation = .label = Developer Tools: Color Scheme Simulation experimental-features-devtools-color-scheme-simulation-description = Yn ychwanegu opsiwn i efelychu gwahanol gynlluniau lliw sy'n eich galluogi i brofi @prefers-color-scheme ymholiadau cyfryngau. Mae defnyddio'r ymholiad cyfryngau hwn yn caniatáu i'ch taflen arddull ymateb i p'un a yw'n well gan y defnyddiwr ryngwyneb defnyddiwr ysgafn neu dywyll. Mae'r nodwedd hon yn caniatáu ichi brofi'ch cod heb orfod newid gosodiadau yn eich porwr (neu system weithredu, os yw'r porwr yn dilyn gosodiad cynllun lliw ar draws y system). Gweler bug 1550804 a bug 1137699 am fwy o fanylion. @@ -87,10 +82,6 @@ .label = Developer Tools: Service Worker debugging # "Service Worker" is an API name and is usually not translated. experimental-features-devtools-serviceworker-debugger-support-description = Yn galluogi cefnogaeth arbrofol i Weithwyr Gwasanaeth yn y panel Dadfygiwr. Efallai y bydd y nodwedd hon yn arafu'r Offer Datblygwr ac yn cynyddu'r defnydd o gof. -# Desktop zooming experiment -experimental-features-graphics-desktop-zooming = - .label = Graffeg: Chwyddo Pinsio Llyfn -experimental-features-graphics-desktop-zooming-description = Galluogi cefnogaeth i binsio llyfn chwyddo ar sgriniau cyffwrdd a phadiau cyffwrdd manwl gywir. # WebRTC global mute toggle controls experimental-features-webrtc-global-mute-toggles = .label = Toglau Tewi WebRTC Cyffredinol @@ -103,3 +94,7 @@ experimental-features-fission = .label = Fission (Ynysu Gwefan) experimental-features-fission-description = Mae Fission (ynysu gwefan) yn nodwedd arbrofol yn { -brand-short-name } er mwyn darparu haen ychwanegol o ddiogelwch yn erbyn bygiau diogelwch. Trwy ynysu pob gwefan i broses ar wahân, mae Fission yn ei gwneud hi'n anoddach i wefannau maleisus gael mynediad at wybodaeth o dudalennau eraill rydych chi'n ymweld â nhw. Mae hwn yn newid pensaernïol mawr yn { -brand-short-name } ac rydym yn gwerthfawrogi eich bod yn profi ac yn adrodd am unrhyw faterion y gallech ddod ar eu traws. Am fwy o fanylion, darllenwch y wiki. +# Support for having multiple Picture-in-Picture windows open simultaneously +experimental-features-multi-pip = + .label = Cefnogaeth Llun-mewn-Llun Lluosog +experimental-features-multi-pip-description = Cefnogaeth arbrofol i ganiatáu i nifer o ffenestri Llun-mewn-Llun fod ar agor ar yr un pryd. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/browser/browser.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/browser/browser.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -301,6 +301,7 @@ identity-https-only-info-no-upgrade = Kunne ikke opgradere forbindelsen fra HTTP. identity-permissions = .value = Tilladelser +identity-permissions-storage-access-hint = Disse parter kan anvende webstedsdata og cookies på tværs af websteder, mens du besøger dette websted. identity-permissions-reload-hint = Du skal muligvis genindlæse siden, før at ændringerne slår igennem. identity-permissions-empty = Du har ikke tildelt dette websted nogen særlige tilladelser. identity-clear-site-data = @@ -346,9 +347,10 @@ ## Bookmarks toolbar items -browser-import-button = - .label = Importer bogmærker… - .tooltiptext = Kopier bogmærker fra andre browsere til { -brand-short-name }. +browser-import-button2 = + .label = importer bogmærker… + .tooltiptext = importer bogmærker fra en anden browser til { -brand-short-name }. +bookmarks-toolbar-empty-message = Få hurtig adgang til dine bogmærker ved at placere dem her på bogmærkelinjen. Håndter bogmærker… ## WebRTC Pop-up notifications diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/browser/preferences/preferences.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/browser/preferences/preferences.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = Fortsæt på eget ansvar pane-experimental-search-results-header = { -brand-short-name }-eksperimenter: Fortsæt på eget ansvar pane-experimental-description = Ved at ændre avancerede indstillinger kan du påvirke ydelse eller sikkerhed for { -brand-short-name }. +pane-experimental-reset = + .label = Gendan standarder + .accesskey = G help-button-label = Hjælp til { -brand-short-name } addons-button-label = Udvidelser og temaer focus-search = @@ -877,6 +880,10 @@ .label = Sporings-teknologier på tværs af websteder sitedata-option-block-cross-site-and-social-media-trackers = .label = Sporings-teknologier på tværs af websteder og sociale medier +sitedata-option-block-cross-site-tracking-cookies-including-social-media = + .label = Sporings-cokies på tværs af websteder — herunder cookies fra sociale medier +sitedata-option-block-cross-site-cookies-including-social-media = + .label = Cookies på tværs af websteder — herunder cookies fra sociale medier sitedata-option-block-cross-site-and-social-media-trackers-plus-isolate = .label = Sporings-teknologier på tværs af websteder og sociale medier, isolering af resterende cookies. sitedata-option-block-unvisited = @@ -921,6 +928,7 @@ content-blocking-enhanced-tracking-protection = Udvidet beskyttelse mod sporing content-blocking-section-top-level-description = Sporings-teknologier følger dig rundt på nettet for at indsamle information om dine vaner og interesser. { -brand-short-name } blokerer mange af disse sporings-teknologier og andre ondsindede scripts. content-blocking-learn-more = Læs mere +content-blocking-fpi-incompatibility-warning = Du bruger First Party Isolation (FPI), som tilsidesætter nogle af indstillingerne for cookies i { -brand-short-name }. ## These strings are used to define the different levels of ## Enhanced Tracking Protection. @@ -942,6 +950,7 @@ content-blocking-etp-strict-desc = Bedre beskyttelse, men kan forhindre nogle websteder i at fungere. content-blocking-etp-custom-desc = Vælg selv, hvilke sporings-teknologier og scripts der skal blokeres. content-blocking-private-windows = Sporings-indhold i private vinduer. +content-blocking-cross-site-cookies = Cookies på tværs af websteder content-blocking-cross-site-tracking-cookies = Sporings-cookies på tværs af websteder content-blocking-cross-site-tracking-cookies-plus-isolate = Sporings-cookies på tværs af websteder, isolering af resterende cookies. content-blocking-social-media-trackers = Sporing via sociale medier @@ -953,6 +962,7 @@ content-blocking-fingerprinters = Fingerprinters content-blocking-warning-title = Vigtigt! content-blocking-and-isolating-etp-warning-description = Nogle websteders funktionalitet kan blive påvirket, når du blokerer sporings-teknologier og isolerer cookies. Genindlæs side med sporings-teknologier for at indlæse alt indhold. +content-blocking-and-isolating-etp-warning-description-2 = Denne indstilling kan medføre, at nogle websteder ikke viser indhold eller ikke fungerer som de skal. Hvis et websted ikke ser ud til at fungere korrekt, så prøv at slå beskyttelse mod sporing fra for webstedet for at indlæse alt indhold. content-blocking-warning-learn-how = Læs hvordan content-blocking-reload-description = Du skal genindlæse dine faneblade, før ændringerne slår igennem. content-blocking-reload-tabs-button = diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/browser/safebrowsing/blockedSite.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/browser/safebrowsing/blockedSite.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/browser/safebrowsing/blockedSite.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/browser/safebrowsing/blockedSite.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -19,6 +19,8 @@ safeb-blocked-malware-page-error-desc-override = { $sitename } er blevet rapporteret til at indeholde ondsindet software. Du kan indrapportere, at dette er sket ved en fejl eller ignorere risikoen og fortsætte til det usikre websted. safeb-blocked-malware-page-error-desc-no-override = { $sitename } er blevet rapporteret til at indeholde ondsindet software. Du kan indrapportere, at dette er sket ved en fejl. safeb-blocked-malware-page-learn-more = Læs mere om skadelig indhold på nettet inklusiv vira og anden skadelig software samt hvordan, du kan beskytte din computer på StopBadware.org. Læs mere om beskyttelse mod phishing og skadelig software i { -brand-short-name } på support.mozilla.org. +safeb-blocked-malware-page-error-desc-override-sumo = { $sitename } er blevet rapporteret til at indeholde ondsindet software. Du kan ignorere risikoen og fortsætte til det usikre websted. +safeb-blocked-malware-page-error-desc-no-override-sumo = { $sitename } er blevet rapporteret til at indeholde ondsindet software. safeb-blocked-malware-page-learn-more-sumo = Læs mere om beskyttelse mod phishing og skadelig software i { -brand-short-name } på support.mozilla.org. safeb-blocked-unwanted-page-error-desc-override = { $sitename } er blevet rapporteret til at indeholde skadelig software. Du kan ignorere risikoen og fortsætte til det usikre websted. safeb-blocked-unwanted-page-error-desc-no-override = { $sitename } er blevet er blevet rapporteret til at indeholde skadelig software. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/browser/toolbarContextMenu.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/browser/toolbarContextMenu.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/browser/toolbarContextMenu.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/browser/toolbarContextMenu.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -24,21 +24,18 @@ *[other] Fortryd lukning af faneblade } .accesskey = l - toolbar-context-menu-manage-extension = .label = Håndter udvidelse .accesskey = H toolbar-context-menu-remove-extension = .label = Fjern udvidelse .accesskey = v - # This label is used in the extensions toolbar buttons context menus, # a user can use this command to submit to Mozilla an abuse report # related to that extension. "Report" is a verb. toolbar-context-menu-report-extension = .label = Rapporter udvidelse .accesskey = o - # Can appear on the same context menu as menubarCmd ("Menu Bar") and # personalbarCmd ("Bookmarks Toolbar"), so they should have different # access keys. @@ -54,3 +51,12 @@ toolbar-context-menu-view-customize-toolbar = .label = Tilpas… .accesskey = p +toolbar-context-menu-bookmarks-toolbar-always-show = + .label = Altid + .accesskey = A +toolbar-context-menu-bookmarks-toolbar-never-show = + .label = Aldrig + .accesskey = d +toolbar-context-menu-bookmarks-toolbar-on-new-tab = + .label = Kun i et nyt faneblad + .accesskey = K diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/chrome/browser/browser.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/chrome/browser/browser.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/chrome/browser/browser.properties 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/chrome/browser/browser.properties 2020-11-17 19:33:00.000000000 +0000 @@ -15,7 +15,6 @@ # %2$S is the selection string. contextMenuSearch=Søg efter "%2$S" med %1$S contextMenuSearch.accesskey=S - contextMenuPrivateSearch=Søg i et privat vindue contextMenuPrivateSearch.accesskey=p # LOCALIZATION NOTE (contextMenuPrivateSearchOtherEngine): %S is the search @@ -57,7 +56,6 @@ # %2$S is replaced by the ID of add-on. %3$S is a custom message that # the administration can add to the message. addonInstallBlockedByPolicy=%1$S (%2$S) er blokeret af din system-administrator.%3$S - addonInstallFullScreenBlocked=Installation af tilføjelser er ikke tilladt i fuldskærms-tilstand eller ved aktivering af fuldskærms-tilstand. # LOCALIZATION NOTE (webextPerms.header) @@ -289,6 +287,9 @@ # LOCALIZATION NOTE (geolocationLastAccessIndicatorText): %S is the relative time of the most recent geolocation access (e.g. 5 min. ago) geolocationLastAccessIndicatorText=Senest tilgået %S +# LOCALIZATION NOTE (openProtocolHandlerPermissionEntryLabel): %S is the scheme of the protocol the site may open an application for. For example: mailto +openProtocolHandlerPermissionEntryLabel=%S:// links + crashedpluginsMessage.title=Der opstod en fejl i plugin'et %S. crashedpluginsMessage.reloadButton.label=Genindlæs side crashedpluginsMessage.reloadButton.accesskey=G @@ -409,7 +410,6 @@ # LOCALIZATION NOTE (newTabButton.tooltip): # %S is the keyboard shortcut for "New Tab" newTabButton.tooltip=Åbn et nyt faneblad (%S) - newTabContainer.tooltip=Åbn et nyt faneblad (%S)\nTryk og hold for at åbne et nyt kontekst-faneblad newTabAlwaysContainer.tooltip=Vælg kontekst for at åbne et nyt faneblad @@ -461,14 +461,12 @@ identity.identified.verifier=Bekræftet af: %S identity.identified.verified_by_you=Du har tilføjet en sikkerhedsundtagelse til dette websted identity.identified.state_and_country=%S, %S - identity.ev.contentOwner2=Certifikatet er udstedt til: %S # LOCALIZATION NOTE (identity.notSecure.label): # Keep this string as short as possible, this is displayed in the URL bar # use a synonym for "safe" or "private" if "secure" is too long. identity.notSecure.label=Ikke sikker - identity.notSecure.tooltip=Forbindelsen er ikke sikker identity.extension.label=Udvidelse (%S) @@ -1032,7 +1030,6 @@ storageAccess.Allow.accesskey = T storageAccess.DontAllow.label = Bloker adgang storageAccess.DontAllow.accesskey = B - # LOCALIZATION NOTE (storageAccess2.message): # %1$S is the name of the site URL (www.site1.example) trying to track the user's activity. # %2$S is the name of the site URL (www.site2.example) that the user is visiting. This is the same domain name displayed in the address bar. @@ -1052,7 +1049,6 @@ confirmationHint.addSearchEngine.label = Søgetjeneste tilføjet! confirmationHint.pinTab.label = Fastgjort! confirmationHint.pinTab.description = Højreklik på fanebladet for at frigøre det. - confirmationHint.passwordSaved.label = Adgangskode gemt! confirmationHint.loginRemoved.label = Login fjernet! confirmationHint.breakageReport.label = Rapporten er sendt. Tak! diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/chrome/browser/downloads/downloads.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/chrome/browser/downloads/downloads.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/chrome/browser/downloads/downloads.properties 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/chrome/browser/downloads/downloads.properties 2020-11-17 19:33:00.000000000 +0000 @@ -33,6 +33,7 @@ blockedMalware=Filen indeholder virus eller malware. blockedPotentiallyUnwanted=Filen kan muligvis skade din computer. blockedInsecure = Filen kunne ikke blive hentet på en sikker måde. +blockedPotentiallyInsecure=Fil ikke hentet: Mulig sikkerhedsrisiko. blockedUncommon2=Filen er muligvis ikke sikker at åbne. # LOCALIZATION NOTE (fileMovedOrMissing): @@ -42,7 +43,7 @@ # LOCALIZATION NOTE (unblockHeaderUnblock, unblockHeaderOpen, # unblockTypeMalware, unblockTypePotentiallyUnwanted2, # unblockTypeUncommon2, unblockTip2, unblockButtonOpen, -# unblockButtonUnblock, unblockButtonConfirmBlock): +# unblockButtonUnblock, unblockButtonConfirmBlock, unblockInsecure): # These strings are displayed in the dialog shown when the user asks a blocked # download to be unblocked. The severity of the threat is expressed in # descending order by the unblockType strings, it is higher for files detected @@ -52,6 +53,7 @@ unblockTypeMalware=Filen indeholder virus eller anden malware, der vil skade din computer. unblockTypePotentiallyUnwanted2=Denne fil er forklædt som en brugbar filtype, men den kan muligvis foretage uventede ændringer af dine programmer og indstillinger. unblockTypeUncommon2=Det er ikke normalt at hente filer af denne type. Den er muligvis ikke sikker at åbne og kan indeholde en virus eller foretage uventede ændringer af dine programmer og indstillinger. +unblockInsecure=Filen bruger en usikker forbindelse. Den kan være beskadiget eller være blevet manipuleret med under hentningen. unblockTip2=Du kan prøve at finde et andet sted at hente filen eller prøve at hente den igen senere unblockButtonOpen=Åbn unblockButtonUnblock=Tillad filhentning diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/chrome/browser/sitePermissions.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/chrome/browser/sitePermissions.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/browser/chrome/browser/sitePermissions.properties 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/browser/chrome/browser/sitePermissions.properties 2020-11-17 19:33:00.000000000 +0000 @@ -47,4 +47,6 @@ permission.canvas.label = Ekstrahere canvas-data permission.midi.label = Tilgå MIDI-enheder permission.midi-sysex.label = Tilgå MIDI-enheder med SysEx-understøttelse -permission.https-only-load-insecure.label = Brug usikker HTTP +# LOCALIZATION NOTE (permission.open-protocol-handler.label): +# Open as a verb. "This site may open applications". +permission.open-protocol-handler.label = Åbne programmer diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/devtools/client/accessibility.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/devtools/client/accessibility.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/devtools/client/accessibility.properties 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/devtools/client/accessibility.properties 2020-11-17 19:33:00.000000000 +0000 @@ -298,3 +298,12 @@ # LOCALIZATION NOTE (accessibility.simulation.achromatopsia): This label is shown # in the "Simulate" menu in the accessibility panel and represent the achromatopsia simulation option. accessibility.simulation.achromatopsia=Akromatopsi (ingen farve) + +# LOCALIZATION NOTE (accessibility.toolbar.displayTabbingOrder.label): A title text for a checkbox label +# in the accessibility panel toolbar that turns on/off the overlay of focusable elements in their +# tabbing order. +accessibility.toolbar.displayTabbingOrder.label=Vis tab-rækkefølge + +# LOCALIZATION NOTE (accessibility.toolbar.displayTabbingOrder.tooltip): A title text for a checkbox +# tooltip in the accessibility panel toolbar that turns on/off the overlay of focusable elements in +# their tabbing order. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/devtools/client/netmonitor.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/devtools/client/netmonitor.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/devtools/client/netmonitor.properties 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/devtools/client/netmonitor.properties 2020-11-17 19:33:00.000000000 +0000 @@ -1528,3 +1528,12 @@ # LOCALIZATION NOTE (netmonitor.settings.copyHarTooltip): This is the tooltip that gets displayed # when the HAR copy menu item is hovered netmonitor.settings.copyHarTooltip=Kopier netværksdata til udklipsholder + +# LOCALIZATION NOTE (netmonitor.errorpanel.description): This is the information displayed once the monitor errors out +netmonitor.errorpanel.description=Netværks-panelet er gået ned. + +# LOCALIZATION NOTE (netmonitor.errorpanel.fileBugButton): This is the text that appears in the button to visit the bug filing link. +netmonitor.errorpanel.fileBugButton=Indsend fejlrapport + +# LOCALIZATION NOTE (netmonitor.errorpanel.reloadPanelInfo): This is the text that appears after Network panel errors to instruct the user to reload the panel. +netmonitor.errorpanel.reloadPanelInfo=Luk værktøjskassen og åbn den igen for at rydde fejlen. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/about/aboutAddons.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/about/aboutAddons.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/about/aboutAddons.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/about/aboutAddons.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -392,6 +392,12 @@ addon-badge-verified = .title = Denne udvidelse er gennemgået for sikkerhedsfejl .aria-label = { addon-badge-verified.title } +addon-badge-line2 = + .title = Dette er en officiel udvidelse bygget af udviklerne bag { -brand-product-name } + .aria-label = { addon-badge-line2.title } +addon-badge-verified2 = + .title = Denne udvidelse er blevet tjekket for, om den overholder vores standarder for sikkerhed og ydelse + .aria-label = { addon-badge-verified2.title } ## @@ -400,6 +406,9 @@ release-notes-loading = Indlæser… release-notes-error = Der opstod en fejl under indlæsning af udgivelsesnoterne. addon-permissions-empty = Denne udvidelse kræver ingen tilladelser +addon-permissions-required = Påkrævede tilladelser for kerne-funktionalitet: +addon-permissions-optional = Valgfrie tilladelser for yderligere funktionalitet: +addon-permissions-learnmore = Læs mere om tilladelser recommended-extensions-heading = Anbefalede udvidelser recommended-themes-heading = Anbefalede temaer # A recommendation for the Firefox Color theme shown at the bottom of the theme diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/about/aboutNetworking.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/about/aboutNetworking.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/about/aboutNetworking.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/about/aboutNetworking.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -45,6 +45,7 @@ about-networking-dns-lookup-button = Slå op about-networking-dns-domain = Domæne: about-networking-dns-lookup-table-column = IP-adresser +about-networking-dns-https-rr-lookup-table-column = HTTP RRs about-networking-rcwn = RCWN Stats about-networking-rcwn-status = RCWN Status about-networking-rcwn-cache-won-count = Cache won count diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/about/aboutProcesses.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/about/aboutProcesses.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/about/aboutProcesses.ftl 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/about/aboutProcesses.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -0,0 +1,132 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Page title +about-processes-title = Proces-håndtering +# The Actions column +about-processes-column-action = + .title = Handlinger + +## Tooltips + +about-processes-shutdown-process = + .title = Inaktiver faneblade og afslut proces +about-processes-shutdown-tab = + .title = Luk faneblad + +## Column headers + +about-processes-column-name = Navn +about-processes-column-memory-resident = Hukommelse +about-processes-column-cpu-total = CPU + +## Process names +## Variables: +## $pid (String) The process id of this process, assigned by the OS. +## $origin (String) The domain name for this process. +## $type (String) The raw type for this process. Used for unknown processes. + +about-processes-browser-process-name = { -brand-short-name } (proces { $pid }) +about-processes-web-process-name = Web (proces { $pid }, delt) +about-processes-web-isolated-process-name = Web (proces { $pid }) for { $origin } +about-processes-web-large-allocation = Web (proces { $pid }, stor) for { $origin } +about-processes-with-coop-coep-process-name = Web (proces { $pid }, cross-origin isoleret) for { $origin } +about-processes-file-process-name = Filer (proces { $pid }) +about-processes-extension-process-name = Udvidelser (proces { $pid }) +about-processes-privilegedabout-process-name = Om (proces { $pid }) +about-processes-plugin-process-name = Plugins (proces { $pid }) +about-processes-gmp-plugin-process-name = Gecko media-plugins (proces { $pid }) +about-processes-gpu-process-name = GPU (proces { $pid }) +about-processes-vr-process-name = VR (proces { $pid }) +about-processes-rdd-process-name = Data-afkoder (proces { $pid }) +about-processes-socket-process-name = Netværk (proces { $pid }) +about-processes-remote-sandbox-broker-process-name = Remote Sandbox Broker (proces { $pid }) +about-processes-fork-server-process-name = Fork Server (proces { $pid }) +about-processes-preallocated-process-name = Forhånds-allokeret (proces { $pid }) +about-processes-unknown-process-name = Andet ({ $type }, proces { $pid }) +# Process +# Variables: +# $name (String) The name assigned to the process. +# $pid (String) The process id of this process, assigned by the OS. +about-processes-process-name = Proces { $pid }: { $name } + +## Details within processes + +# Single-line summary of threads +# Variables: +# $number (Number) The number of threads in the process. Typically larger +# than 30. We don't expect to ever have processes with less +# than 5 threads. +about-processes-thread-summary = Tråde ({ $number }) +# Thread details +# Variables: +# $name (String) The name assigned to the thread. +# $tid (String) The thread id of this thread, assigned by the OS. +about-processes-thread-name = Tråd { $tid }: { $name } +# Tab +# Variables: +# $name (String) The name of the tab (typically the title of the page, might be the url while the page is loading). +about-processes-tab-name = Faneblad: { $name } +about-processes-preloaded-tab = Forhåndsindlæst nyt faneblad +# Single subframe +# Variables: +# $url (String) The full url of this subframe. +about-processes-frame-name-one = Subframe: { $url } +# Group of subframes +# Variables: +# $number (Number) The number of subframes in this group. Always ≥ 1. +# $shortUrl (String) The shared prefix for the subframes in the group. +about-processes-frame-name-many = Subframes ({ $number }): { $shortUrl } + +## Displaying CPU (percentage and total) +## Variables: +## $percent (Number) The percentage of CPU used by the process or thread. +## Always > 0, generally <= 200. +## $total (Number) The amount of time used by the process or thread since +## its start. +## $unit (String) The unit in which to display $total. See the definitions +## of `duration-unit-*`. + +# Common case. +about-processes-cpu-user-and-kernel = { NUMBER($percent, maximumSignificantDigits: 2, style: "percent") } ({ NUMBER($total, maximumFractionDigits: 0) }{ $unit }) +# Special case: data is not available yet. +about-processes-cpu-user-and-kernel-not-ready = (måler) +# Special case: process or thread is currently idle. +about-processes-cpu-user-and-kernel-idle = inaktiv ({ NUMBER($total, maximumFractionDigits: 2) }{ $unit }) + +## Displaying Memory (total and delta) +## Variables: +## $total (Number) The amount of memory currently used by the process. +## $totalUnit (String) The unit in which to display $total. See the definitions +## of `memory-unit-*`. +## $delta (Number) The absolute value of the amount of memory added recently. +## $deltaSign (String) Either "+" if the amount of memory has increased +## or "-" if it has decreased. +## $deltaUnit (String) The unit in which to display $delta. See the definitions +## of `memory-unit-*`. + +# Common case. +about-processes-total-memory-size = { NUMBER($total, maximumFractionDigits: 0) }{ $totalUnit } ({ $deltaSign }{ NUMBER($delta, maximumFractionDigits: 0) }{ $deltaUnit }) +# Special case: no change. +about-processes-total-memory-size-no-change = { NUMBER($total, maximumFractionDigits: 0) }{ $totalUnit } + +## Duration units + +duration-unit-ns = ns +duration-unit-us = µs +duration-unit-ms = ms +duration-unit-s = s +duration-unit-m = m +duration-unit-h = t +duration-unit-d = d + +## Memory units + +memory-unit-B = B +memory-unit-KB = KB +memory-unit-MB = MB +memory-unit-GB = GB +memory-unit-TB = TB +memory-unit-PB = PB +memory-unit-EB = EB diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/about/certviewer.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/about/certviewer.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/about/certviewer.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/about/certviewer.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -77,35 +77,39 @@ certificate-viewer-ocsp-stapling = OCSP Stapling certificate-viewer-subject-key-id = Subjektets nøgle-ID certificate-viewer-authority-key-id = Autoritetens nøgle-ID -certificate-viewer-authority-info-aia = Information om autoritet (AIA) +certificate-viewer-authority-info-aia = Information om autoritet (AIA) certificate-viewer-certificate-policies = Certifikatpolitikker certificate-viewer-embedded-scts = Indlejrede SCT'er certificate-viewer-crl-endpoints = Slutpunkter for CRL - -# This message is used as a row header in the Miscellaneous section. +# This message is used as a row header in the Miscellaneous section. # The associated data cell contains links to download the certificate. certificate-viewer-download = Hent # This message is used to replace boolean values (true/false) in several certificate fields, e.g. Certificate Authority # Variables: # $boolean (String) - true/false value for the specific field -certificate-viewer-boolean = { $boolean -> - [true] Ja - *[false] Nej -} +certificate-viewer-boolean = + { $boolean -> + [true] Ja + *[false] Nej + } ## Variables: ## $fileName (String) - The file name to save the PEM data in, derived from the common name from the certificate being displayed. certificate-viewer-download-pem = PEM (cert) - .download = { $fileName }.pem + .download = { $fileName }.pem certificate-viewer-download-pem-chain = PEM (kæde) - .download = { $fileName }-chain.pem - + .download = { $fileName }-chain.pem # The title attribute for Critical Extension icon certificate-viewer-critical-extension = - .title = Denne udvidelse er blevet markeret som kritisk, hvilket betyder at klienter skal afvise certifikatet, hvis de ikke forstår det. + .title = Denne udvidelse er blevet markeret som kritisk, hvilket betyder at klienter skal afvise certifikatet, hvis de ikke forstår det. certificate-viewer-export = Eksporter - .download = { $fileName }.pem + .download = { $fileName }.pem + +## + +# Label for a tab where we haven't found a better label: +certificate-viewer-unknown-group-label = (ukendt) ## Labels for tabs displayed in stand-alone about:certificate page diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/featuregates/features.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/featuregates/features.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/featuregates/features.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/featuregates/features.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -82,10 +82,6 @@ .label = Udviklerværktøj: Debugging af service-workers # "Service Worker" is an API name and is usually not translated. experimental-features-devtools-serviceworker-debugger-support-description = Aktiverer eksperimentel understøttelse af service-workers i Debugger-panelet. Funktion kan gøre udviklerværktøj langsommere og øge hukommelsesforbruget. -# Desktop zooming experiment -experimental-features-graphics-desktop-zooming = - .label = Grafik: Jævn knibe-zoom -experimental-features-graphics-desktop-zooming-description = Understøtter jævn knibe-zoom på touchskærme og præcisions-touchpads. # WebRTC global mute toggle controls experimental-features-webrtc-global-mute-toggles = .label = Slå lyd fra/til globalt for WebRTC @@ -98,3 +94,7 @@ experimental-features-fission = .label = Fission (isolation af websteder) experimental-features-fission-description = Fission (isolation af websteder) er en eksperimentel funktion i { -brand-short-name }, der giver et ekstra lag fa beskyttelse mod sikkerhedsfejl. Ved at isolere hvert websted i en separat proces gør Fission det sværere for ondsindede websteder at få adgang til information fra andre sider, du besøger. Fission udgør en grundlæggende ændring i { -brand-short-name }' arkitektur - og vi sætter stor pris på, at du vil hjælpe os med at teste funktionen og indrapportere eventuelle fejl, du støder på. Læs mere på wiki'en. +# Support for having multiple Picture-in-Picture windows open simultaneously +experimental-features-multi-pip = + .label = Understøttelse af flere billede-i-billede +experimental-features-multi-pip-description = Eksperimentel understøttelse for, at flere videoer kan vises som billede-i-billede på samme tid. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/global/handlerDialog.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/global/handlerDialog.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/global/handlerDialog.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/global/handlerDialog.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -17,11 +17,48 @@ ## $scheme - the type of link that's being opened. ## $appName - Name of the application that will be opened. +permission-dialog-description = Tillad dette websted at åbne { $scheme }-linket? +permission-dialog-description-file = Tillad denne fil at åbne { $scheme }-linket? +permission-dialog-description-host = Tillad { $host } at åbne { $scheme }-linket? +permission-dialog-description-app = Tillad dette websted at åbne { $scheme }-linket med { $appName }? +permission-dialog-description-host-app = Tillad { $host } at åbne { $scheme }-linket med { $appName }? +permission-dialog-description-file-app = Tillad denne fil at åbne { $scheme }-linket med { $appName }? + +## Please keep the emphasis around the hostname and scheme (ie the +## `` HTML tags). Please also keep the hostname as close to the start +## of the sentence as your language's grammar allows. + +permission-dialog-remember = Tillad altid { $host } at åbne { $scheme }-links +permission-dialog-remember-file = Tillad altid denne fil at åbne { $scheme }-links + +## + +permission-dialog-btn-open-link = + .label = Åbn links + .accessKey = b +permission-dialog-btn-choose-app = + .label = Vælg program + .accessKey = p +permission-dialog-unset-description = Du skal vælge et program. +permission-dialog-set-change-app-link = Vælg et andet program. ## Chooser dialog ## Variables: ## $scheme - the type of link that's being opened. +chooser-window = + .title = Vælg program + .style = min-width: 26em; min-height: 26em; +chooser-dialog = + .buttonlabelaccept = Åbn link + .buttonaccesskeyaccept = b +# Please keep the emphasis around the scheme (ie the `` HTML tags). +chooser-dialog-remember = Brug altid dette program til at åbne { $scheme }-links +chooser-dialog-remember-extra = + { PLATFORM() -> + [windows] Dette kan ændres i indstillingerne i { -brand-short-name }. + *[other] Dette kan ændres i indstillingerne i { -brand-short-name }. + } choose-other-app-description = Vælg et andet program choose-app-btn = .label = Vælg… diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/global/videocontrols.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/global/videocontrols.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/global/videocontrols.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/global/videocontrols.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -10,3 +10,5 @@ videocontrols-buffer-bar-label = Indlæser: videocontrols-volume-control = .aria-label = Lydstyrke +videocontrols-closed-caption-button = + .aria-label = Undertekster diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/printing/printUI.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/printing/printUI.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/da/toolkit/toolkit/printing/printUI.ftl 2020-11-15 14:40:10.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/da/toolkit/toolkit/printing/printUI.ftl 2020-11-17 19:33:00.000000000 +0000 @@ -41,6 +41,9 @@ printui-scale-fit-to-page-width = Tilpas til sidens bredde # Label for input control where user can set the scale percentage printui-scale-pcent = Skalér +# Section title (noun) for the two-sided print options +printui-two-sided-printing = Dobbeltsidet udskrift +printui-duplex-checkbox = Udskriv på begge sider # Section title for miscellaneous print options printui-options = Indstillinger printui-headers-footers-checkbox = Print sidehoveder og sidefødder diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/dsb/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/dsb/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/dsb/browser/browser/browser.ftl 2020-11-15 14:40:16.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/dsb/browser/browser/browser.ftl 2020-11-17 19:33:06.000000000 +0000 @@ -352,9 +352,10 @@ ## Bookmarks toolbar items -browser-import-button = +browser-import-button2 = .label = Cytańske znamjenja importěrowaś… - .tooltiptext = Cytańske znamjenja z drugego wobglědowaka do { -brand-short-name } kopěrowaś. + .tooltiptext = Cytańske znamjenja z drugego wobglědowaka do { -brand-short-name } importěrowaś. +bookmarks-toolbar-empty-message = Wótpołožćo swóje cytańske znamjenja w symbolowej rědce za malsny pśistup. Cytańske znamjenja zastojaś… ## WebRTC Pop-up notifications diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/dsb/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/dsb/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/dsb/browser/browser/preferences/preferences.ftl 2020-11-15 14:40:16.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/dsb/browser/browser/preferences/preferences.ftl 2020-11-17 19:33:06.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = Z glědanim pókšacowaś pane-experimental-search-results-header = Eksperimenty { -brand-short-name }: pókšacujśo z glědanim pane-experimental-description = Gaž nastajenja rozšyrjoneje konfiguracije změnijośo, móžo to wugbaśe abo wěstotu { -brand-short-name } wobwliwowaś. +pane-experimental-reset = + .label = Standard wótnowiś + .accesskey = S help-button-label = Pomoc { -brand-short-name } addons-button-label = Rozšyrjenja a drastwy focus-search = @@ -937,6 +940,7 @@ content-blocking-enhanced-tracking-protection = Pólěpšony slědowański šćit content-blocking-section-top-level-description = Pśeslědowaki wam online slěduju, aby informacije wó wašych pśeglědowańskich zwuconosćach a zajmach gromaźili. { -brand-short-name } wjele z toś tych pśeslědowakow a druge złosne skripty blokěrujo. content-blocking-learn-more = Dalšne informacije +content-blocking-fpi-incompatibility-warning = Wužywaśo rozšyrjenje First Party Isolation (FIP), kótarež někotare cookiejowe nastajenja { -brand-short-name } pśepisujo. ## These strings are used to define the different levels of ## Enhanced Tracking Protection. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/dsb/toolkit/toolkit/featuregates/features.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/dsb/toolkit/toolkit/featuregates/features.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/dsb/toolkit/toolkit/featuregates/features.ftl 2020-11-15 14:40:16.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/dsb/toolkit/toolkit/featuregates/features.ftl 2020-11-17 19:33:06.000000000 +0000 @@ -82,10 +82,6 @@ .label = Wuwijaŕske rědy: Pytanje zmólkow ze service worker # "Service Worker" is an API name and is usually not translated. experimental-features-devtools-serviceworker-debugger-support-description = Zmóžnja eksperimentelnu pódpěru za service worker we woknje Pytanje za zmólkami. Toś ta funkcija móžo wuwijaŕske rědy spómałšyś a pśetrjebu składa pówušyś. -# Desktop zooming experiment -experimental-features-graphics-desktop-zooming = - .label = Grafika: pózlažke dwójopalcowe skalěrowanje -experimental-features-graphics-desktop-zooming-description = Pódpěru za pózlažke dwójopalcowe skalěrowanje na dotyknjeńskich wobrazowkach a preciznostne dótyknjeńske póla zmóžniś. # WebRTC global mute toggle controls experimental-features-webrtc-global-mute-toggles = .label = Globalne wóźenje za wušaltowanje zuka WebRTC @@ -98,3 +94,7 @@ experimental-features-fission = .label = Fission (sedłowa izolacija) experimental-features-fission-description = Fission (izolěrowanje websedłow) jo eksperimentelna funkcija w { -brand-short-name }, aby pśidatnu šćitnu warštwu pśeśiwo wěstotnym zmólkam k dispoziciji stajiła. Pśez izolěrowanje kuždego sedła w separatnem procesu, Fission złosnym websedłam póśěežujo, pśistup k informacijam z drugich bokow dostaś, ku kótarymž se woglědujośo. To jo wjelika architekturna změna w { -brand-short-name } a wjaselimy se, jolic wšykne problemy, na kótarež starcyjośo, testujośo a k wěsće dajośo. Za dalšne drobnostki glejśo wiki. +# Support for having multiple Picture-in-Picture windows open simultaneously +experimental-features-multi-pip = + .label = Wěcejrazowa pódpěra wobraz-we-wobrazu +experimental-features-multi-pip-description = Eksperimentelna pódpěra za rownocasne wócynjanje někotarych woknow wobraz-we-wobrazu. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/menubar.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/menubar.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/menubar.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/menubar.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -50,7 +50,7 @@ .label = Εκτύπωση… .accesskey = κ menu-file-import-from-another-browser = - .label = Εισαγωγή από άλλο πρόγρ. περιήγησης… + .label = Εισαγωγή από άλλο φυλλομετρητή… .accesskey = Ε menu-file-go-offline = .label = Εργασία χωρίς σύνδεση @@ -247,7 +247,7 @@ .label = Ξενάγηση στο { -brand-shorter-name } .accesskey = Ξ menu-help-import-from-another-browser = - .label = Εισαγωγή από άλλο πρόγρ. περιήγησης… + .label = Εισαγωγή από άλλο φυλλομετρητή… .accesskey = Ε menu-help-keyboard-shortcuts = .label = Συντομεύσεις πληκτρολογίου diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/migration.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/migration.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/migration.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/migration.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -56,7 +56,7 @@ import-permissions-page-title = Παρακαλούμε παραχωρήστε στο { -brand-short-name } δικαιώματα # Do not translate "Bookmarks.plist"; the file name is the same everywhere. import-permissions-description = Το macOS απαιτεί τη ρητή έγκρισή σας ώστε το { -brand-short-name } να προσπελάσει τους σελιδοδείκτες του Safari. Κάντε κλικ στο “Συνέχεια” και επιλέξτε το αρχείο “Bookmarks.plist” στο παράθυρο “Άνοιγμα αρχείου”. -import-migrating-page-title = Εισαγωγή... +import-migrating-page-title = Εισαγωγή… import-migrating-description = Γίνεται εισαγωγή των παρακάτω στοιχείων αυτή τη στιγμή… import-select-profile-page-title = Επιλογή προφίλ import-select-profile-description = Τα ακόλουθα προφίλ είναι διαθέσιμα για εισαγωγή από: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/newtab/asrouter.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/newtab/asrouter.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/newtab/asrouter.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/newtab/asrouter.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -73,7 +73,7 @@ cfr-doorhanger-bookmark-fxa-header = Συγχρονίστε παντού τους σελιδοδείκτες σας. cfr-doorhanger-bookmark-fxa-body = Εξαιρετική ανακάλυψη! Μην ξεχάσετε να αποθηκεύσετε αυτό το σελιδοδείκτη στις κινητές συσκευές σας. Ξεκινήστε με ένα { -fxaccount-brand-name }. -cfr-doorhanger-bookmark-fxa-link-text = Συγχρονισμός σελιδοδεικτών τώρα... +cfr-doorhanger-bookmark-fxa-link-text = Συγχρονισμός σελιδοδεικτών τώρα… cfr-doorhanger-bookmark-fxa-close-btn-tooltip = .aria-label = Κουμπί κλεισίματος .title = Κλείσιμο @@ -263,8 +263,6 @@ .accesskey = Τ cfr-doorhanger-fission-secondary-button = Μάθετε περισσότερα .accesskey = Μ -# Deprecated -cfr-doorhanger-fission-body = Το { -brand-short-name } έχει ενεργοποιήσει μια πειραματική λειτουργία, το Fission (απομόνωση ιστοσελίδας) για εσάς. Απομονώνοντας την κάθε σελίδα σε ξεχωριστή διεργασία, το Fission παρέχει ένα επιπλέον επίπεδο ασφαλείας για εσάς και τις ιστοσελίδες που επισκέπτεστε. ## What's new: Cookies message diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/pageInfo.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/pageInfo.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/pageInfo.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/pageInfo.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -4,22 +4,18 @@ page-info-window = .style = width: 530px; min-height: 480px; - copy = .key = C menu-copy = .label = Αντιγραφή .accesskey = γ - select-all = .key = A menu-select-all = .label = Επιλογή όλων .accesskey = λ - close-dialog = .key = w - general-tab = .label = Γενικά .accesskey = Γ @@ -43,7 +39,6 @@ .label = Όνομα general-meta-content = .label = Περιεχόμενο - media-tab = .label = Πολυμέσα .accesskey = μ @@ -66,18 +61,16 @@ media-long-desc = .value = Μακρά περιγραφή: media-save-as = - .label = Αποθήκευση ως... - .accesskey = θ + .label = Αποθήκευση ως… + .accesskey = ω media-save-image-as = - .label = Αποθήκευση ως... - .accesskey = η - + .label = Αποθήκευση ως… + .accesskey = ω perm-tab = .label = Δικαιώματα .accesskey = Δ permissions-for = .value = Δικαιώματα για: - security-tab = .label = Ασφάλεια .accesskey = σ @@ -98,22 +91,17 @@ .value = Λήγει στις: security-view-privacy = .value = Απόρρητο & ιστορικό - security-view-privacy-history-value = Έχω επισκεφθεί αυτή την ιστοσελίδα στο παρελθόν; security-view-privacy-sitedata-value = Αυτή η ιστοσελίδα αποθηκεύει πληροφορίες στον υπολογιστή μου; - security-view-privacy-clearsitedata = .label = Εκκαθάριση cookies και δεδομένων ιστοσελίδων .accesskey = Ε - security-view-privacy-passwords-value = Έχω αποθηκεύσει κωδικούς πρόσβασης για αυτή την ιστοσελίδα; - security-view-privacy-viewpasswords = .label = Προβολή αποθηκευμένων κωδικών πρόσβασης .accesskey = λ security-view-technical = .value = Τεχνικές λεπτομέρειες - help-button = .label = Βοήθεια @@ -125,10 +113,8 @@ security-site-data-cookies = Ναι, cookies και { $value } { $unit } δεδομένων ιστοσελίδων security-site-data-only = Ναι, { $value } { $unit } δεδομένων ιστοσελίδων - security-site-data-cookies-only = Ναι, cookies security-site-data-no = Όχι - image-size-unknown = Άγνωστο page-info-not-specified = .value = Δεν έχει καθοριστεί @@ -147,7 +133,6 @@ media-audio = Ήχος saved-passwords-yes = Ναι saved-passwords-no = Όχι - no-page-title = .value = Σελίδα χωρίς τίτλο: general-quirks-mode = @@ -162,7 +147,6 @@ permissions-use-default = .label = Χρήση προεπιλογής security-no-visits = Όχι - # This string is used to display the number of meta tags # in the General Tab # Variables: @@ -173,7 +157,6 @@ [one] Μεταδεδομένα (1 ετικέτα) *[other] Μεταδεδομένα ({ $tags } ετικέτες) } - # This string is used to display the number of times # the user has visited the website prior # Variables: @@ -184,7 +167,6 @@ [one] Ναι, μια φορά *[other] Ναι, { $visits } φορές } - # This string is used to display the size of a media file # Variables: # $kb (number) - The size of an image in Kilobytes @@ -195,7 +177,6 @@ [one] { $kb } KB ({ $bytes } byte) *[other] { $kb } KB ({ $bytes } bytes) } - # This string is used to display the type and number # of frames of a animated image # Variables: @@ -207,14 +188,12 @@ [one] Εικόνα { $type } (κινούμενη, { $frames } καρέ) *[other] Εικόνα { $type } (κινούμενη, { $frames } καρέ) } - # This string is used to display the type of # an image # Variables: # $type (string) - The type of an image media-image-type = .value = Εικόνα { $type } - # This string is used to display the size of a scaled image # in both scaled and unscaled pixels # Variables: @@ -224,20 +203,17 @@ # $scaledy (number) - The scaled vertical size of an image media-dimensions-scaled = .value = { $dimx }px × { $dimy }px (κλιμακώθηκε σε { $scaledx }px × { $scaledy }px) - # This string is used to display the size of an image in pixels # Variables: # $dimx (number) - The horizontal size of an image # $dimy (number) - The vertical size of an image media-dimensions = .value = { $dimx }px × { $dimy }px - # This string is used to display the size of a media # file in kilobytes # Variables: # $size (number) - The size of the media file in kilobytes media-file-size = { $size } KB - # This string is used to display the website name next to the # "Block Images" checkbox in the media tab # Variables: @@ -245,11 +221,10 @@ media-block-image = .label = Φραγή εικόνων από { $website } .accesskey = α - # This string is used to display the URL of the website on top of the # pageInfo dialog box # Variables: -# $website (string) - The url of the website pageInfo is getting info for +# $website (string) — The url of the website pageInfo is getting info for page-info-page = .title = Πληροφορίες σελίδας - { $website } page-info-frame = diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/places.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/places.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/places.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/places.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -18,14 +18,14 @@ .label = Άνοιγμα σε νέο ιδιωτικό παράθυρο .accesskey = θ places-new-bookmark = - .label = Νέος σελιδοδείκτης... + .label = Νέος σελιδοδείκτης… .accesskey = σ places-new-folder-contextmenu = - .label = Νέος φάκελος... + .label = Νέος φάκελος… .accesskey = φ places-new-folder = - .label = Νέος φάκελος... - .accesskey = Φ + .label = Νέος φάκελος… + .accesskey = φ places-new-separator = .label = Νέο διαχωριστικό .accesskey = χ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/preferences/languages.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/preferences/languages.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/preferences/languages.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/preferences/languages.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -5,34 +5,25 @@ webpage-languages-window = .title = Ρυθμίσεις γλώσσας ιστοσελίδων .style = width: 40em - languages-close-key = .key = w - languages-description = Μερικές φορές, οι ιστοσελίδες προσφέρονται σε περισσότερες από μια γλώσσες. Επιλέξτε τις γλώσσες εμφάνισης αυτών των ιστοσελίδων, σε σειρά προτίμησης - languages-customize-spoof-english = .label = Απαίτηση αγγλικών εκδόσεων ιστοσελίδων για ενισχυμένο απόρρητο - languages-customize-moveup = .label = Μετακίνηση πάνω .accesskey = π - languages-customize-movedown = .label = Μετακίνηση κάτω .accesskey = κ - languages-customize-remove = .label = Αφαίρεση .accesskey = Α - languages-customize-select-language = .placeholder = Επιλέξτε γλώσσα προς προσθήκη… - languages-customize-add = .label = Προσθήκη .accesskey = θ - # The pattern used to generate strings presented to the user in the # locale selection list. # @@ -45,29 +36,20 @@ # $code (String) - Locale code of the locale (for example: "is", "es-CL") languages-code-format = .label = { $locale } [{ $code }] - languages-active-code-format = .value = { languages-code-format.label } - browser-languages-window = .title = Ρυθμίσεις γλώσσας του { -brand-short-name } .style = width: 40em - browser-languages-description = Το { -brand-short-name } θα εμφανίζει την πρώτη γλώσσα ως την προεπιλεγμένη και θα προβάλει εναλλακτικές γλώσσες με τη σειρά που φαίνονται, αν είναι απαραίτητο. - -browser-languages-search = Αναζήτηση περισσότερων γλωσσών... - +browser-languages-search = Αναζήτηση περισσότερων γλωσσών… browser-languages-searching = - .label = Γίνεται αναζήτηση γλωσσών... - + .label = Αναζήτηση γλωσσών… browser-languages-downloading = .label = Γίνεται λήψη… - browser-languages-select-language = .label = Επιλέξτε μια γλώσσα για προσθήκη… .placeholder = Επιλέξτε μια γλώσσα για προσθήκη… - browser-languages-installed-label = Εγκατεστημένες γλώσσες browser-languages-available-label = Διαθέσιμες γλώσσες - browser-languages-error = Το { -brand-short-name } δεν μπορεί να ενημερώσει τις γλώσσες σας αυτή τη στιγμή. Ελέγξτε αν έχετε συνδεθεί στο διαδίκτυο ή δοκιμάστε ξανά. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/browser/preferences/preferences.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/browser/preferences/preferences.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -206,8 +206,8 @@ default-font-size = Μέγεθος .accesskey = Μ advanced-fonts = - .label = Για προχωρημένους... - .accesskey = π + .label = Για προχωρημένους… + .accesskey = Γ colors-settings = .label = Χρώματα... .accesskey = Χ @@ -227,7 +227,7 @@ .accesskey = λ choose-browser-language-description = Επιλέξτε τις γλώσσες εμφάνισης μενού, μηνυμάτων και ειδοποιήσεων από το { -brand-short-name }. manage-browser-languages-button = - .label = Ορισμός εναλλακτικών... + .label = Ορισμός εναλλακτικών… .accesskey = ν confirm-browser-language-change-description = Επανεκκίνηση του { -brand-short-name } για εφαρμογή αλλαγών confirm-browser-language-change-button = Εφαρμογή και επανεκκίνηση @@ -469,7 +469,7 @@ home-mode-choice-default = .label = Αρχική σελίδα Firefox (Προεπιλογή) home-mode-choice-custom = - .label = Προσαρμοσμένα URLs… + .label = Προσαρμοσμένα URL… home-mode-choice-blank = .label = Κενή σελίδα home-homepage-custom-url = @@ -664,7 +664,7 @@ prefs-sync-offer-setup-label = Συγχρονίστε τους σελιδοδείκτες, το ιστορικό, τις καρτέλες, τους κωδικούς πρόσβασης, τα πρόσθετα και τις προτιμήσεις σας με όλες τις συσκευές σας. prefs-sync-now = .labelnotsyncing = Συγχρονισμός τώρα - .accesskeynotsyncing = Τ + .accesskeynotsyncing = τ .labelsyncing = Συγχρονισμός… ## The list of things currently syncing. @@ -692,7 +692,7 @@ .title = Επιλέξτε στοιχεία για συγχρονισμό .style = width: 36em; min-height: 35em; .buttonlabelaccept = Αποθήκευση αλλαγών - .buttonaccesskeyaccept = Π + .buttonaccesskeyaccept = π .buttonlabelextra2 = Αποσύνδεση… .buttonaccesskeyextra2 = Α sync-engine-bookmarks = @@ -860,7 +860,7 @@ ## Privacy Section - Site Data sitedata-header = Cookies και δεδομένα ιστοσελίδων -sitedata-total-size-calculating = Υπολογισμός μεγέθους δεδομένων ιστοσελίδας και προσωρινής μνήμης... +sitedata-total-size-calculating = Υπολογισμός μεγέθους δεδομένων ιστοσελίδας και προσωρινής μνήμης… # Variables: # $value (Number) - Value of the unit (for example: 4.6, 500) # $unit (String) - Name of the unit (for example: "bytes", "KB") @@ -897,8 +897,8 @@ sitedata-option-block-all = .label = Όλα τα cookies (θα προκαλέσει δυσλειτουργία σε ιστοσελίδες) sitedata-clear = - .label = Εκκαθάριση δεδομένων... - .accesskey = κ + .label = Απαλοιφή δεδομένων… + .accesskey = ι sitedata-settings = .label = Διαχείριση δεδομένων… .accesskey = Δ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/chrome/browser/accounts.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/chrome/browser/accounts.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/chrome/browser/accounts.properties 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/chrome/browser/accounts.properties 2020-11-17 19:33:09.000000000 +0000 @@ -71,7 +71,7 @@ # Displayed in the Send Tabs context menu when right clicking a tab, a page or a link # and the Sync account is unverified. Redirects to the Sync preferences page. sendTabToDevice.verify.status = Ο λογαριασμός δεν επαληθεύτηκε -sendTabToDevice.verify = Επαληθεύστε το λογαριασμό σας… +sendTabToDevice.verify = Επαλήθευση λογαριασμού… # LOCALIZATION NOTE (tabArrivingNotification.title, tabArrivingNotificationWithDevice.title, # multipleTabsArrivingNotification.title, unnamedTabsArrivingNotification2.body, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/chrome/browser/browser.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/chrome/browser/browser.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/chrome/browser/browser.properties 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/chrome/browser/browser.properties 2020-11-17 19:33:09.000000000 +0000 @@ -880,7 +880,7 @@ emeNotifications.unknownDRMSoftware = Άγνωστο # LOCALIZATION NOTE - %S is brandShortName -slowStartup.message = Ο %S φαίνεται να… αργεί… να ξεκινήσει. +slowStartup.message = Το %S φαίνεται να… αργεί… να ξεκινήσει. slowStartup.helpButton.label = Μάθετε πως να τον κάνετε πιο γρήγορο slowStartup.helpButton.accesskey = θ slowStartup.disableNotificationButton.label = Να μην εμφανιστεί ξανά αυτή η ειδοποίηση diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/chrome/browser/migration/migration.dtd firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/chrome/browser/migration/migration.dtd --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/chrome/browser/migration/migration.dtd 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/chrome/browser/migration/migration.dtd 2020-11-17 19:33:09.000000000 +0000 @@ -41,7 +41,7 @@ - + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/chrome/browser/places/places.dtd firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/chrome/browser/places/places.dtd --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/browser/chrome/browser/places/places.dtd 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/browser/chrome/browser/places/places.dtd 2020-11-17 19:33:09.000000000 +0000 @@ -31,7 +31,7 @@ - + @@ -60,4 +60,3 @@ - diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/chat/twitter.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/chat/twitter.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/chat/twitter.properties 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/chat/twitter.properties 2020-11-17 19:33:09.000000000 +0000 @@ -63,7 +63,7 @@ # (These will be displayed in account.connection.progress from # accounts.properties, which adds … at the end, so do not include # periods at the end of these messages.) -connection.initAuth=Έναρξη διαδικασίας αυθεντικοποίησης +connection.initAuth=Έναρξη διαδικασίας ταυτοποίησης connection.requestAuth=Αναμονή για την εξουσιοδότησή σας connection.requestAccess=Οριστικοποίηση της ταυτοποίησης connection.requestTimelines=Γίνεται αίτηση για τα χρονολόγια χρηστών diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/netwerk/necko.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/netwerk/necko.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/netwerk/necko.properties 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/netwerk/necko.properties 2020-11-17 19:33:09.000000000 +0000 @@ -8,19 +8,19 @@ #SendingRequestTo=Sending request to #TransferringDataFrom=Transferring data from -3=Αναζήτηση %1$S... -4=Έγινε σύνδεση με %1$S... -5=Αποστολή αίτησης σε %1$S... -6=Μεταφορά δεδομένων από %1$S... -7=Σύνδεση με %1$S... +3=Αναζήτηση %1$S… +4=Έγινε σύνδεση με %1$S… +5=Αποστολή αίτησης σε %1$S… +6=Μεταφορά δεδομένων από %1$S… +7=Σύνδεση με %1$S… 8=Ανάγνωση %1$S 9=έγραψε %1$S -10=Αναμονή για %1$S... +10=Αναμονή για %1$S… 11=Αναζήτηση για %1$S… 12=Εκτέλεση χειραψίας TLS σε %1$S… 13=Η χειραψία TLS ολοκληρώθηκε για το %1$S… -27=Εκκίνηση συναλλαγής FTP... +27=Εκκίνηση συναλλαγής FTP… 28=Ολοκλήρωση συναλλαγής FTP RepostFormData=Αυτή η ιστοσελίδα αναδρομολογείται σε μια νέα τοποθεσία. Θέλετε να ξαναστείλετε τα δεδομένα φόρμας που εισάγατε στη νέα τοποθεσία; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/security/manager/security/certificates/certManager.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/security/manager/security/certificates/certManager.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/security/manager/security/certificates/certManager.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/security/manager/security/certificates/certManager.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -27,7 +27,7 @@ .label = Λεπτομέρειες .accesskey = Λ certmgr-pending-label = - .value = Γίνεται προβολή πιστοποιητικού... + .value = Γίνεται προβολή πιστοποιητικού… certmgr-subject-label = Εκδόθηκε σε certmgr-issuer-label = Εκδόθηκε από certmgr-period-of-validity = Περίοδος Εγκυρότητας diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/chrome/global/printdialog.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/chrome/global/printdialog.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/chrome/global/printdialog.properties 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/chrome/global/printdialog.properties 2020-11-17 19:33:09.000000000 +0000 @@ -38,9 +38,10 @@ headerFooterDate=Ημερομηνία/Ώρα headerFooterPage=Σελίδα # headerFooterPageTotal=Σελίδα # από # -headerFooterCustom=Προσαρμογή... +headerFooterCustom=Προσαρμογή… customHeaderFooterPrompt=Παρακαλώ εισάγετε το προσαρμοσμένο κείμενο κεφαλίδας/υποσέλιδου +# These are for the summary view in the Mac dialog: summarySelectionOnlyTitle=Εκτύπωση επιλογής summaryShrinkToFitTitle=Προσαρμογή στη σελίδα summaryPrintBGColorsTitle=Εκτύπωση χρωμάτων BG diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/toolkit/about/aboutAddons.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/toolkit/about/aboutAddons.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/toolkit/about/aboutAddons.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/toolkit/about/aboutAddons.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -399,7 +399,7 @@ available-updates-heading = Διαθέσιμες ενημερώσεις recent-updates-heading = Πρόσφατες ενημερώσεις -release-notes-loading = Φόρτωση... +release-notes-loading = Φόρτωση… release-notes-error = Λυπούμαστε, αλλά προέκυψε σφάλμα φόρτωσης των σημειώσεων έκδοσης. addon-permissions-empty = Αυτή η επέκταση δεν απαιτεί δικαιώματα addon-permissions-required = Απαιτούμενα δικαιώματα για βασική λειτουργικότητα: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/toolkit/global/handlerDialog.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/toolkit/global/handlerDialog.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/toolkit/global/handlerDialog.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/toolkit/global/handlerDialog.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -64,6 +64,6 @@ choose-app-btn = .label = Επιλογή… .accessKey = Ε -choose-other-app-window-title = Άλλη εφαρμογή... +choose-other-app-window-title = Άλλη εφαρμογή… # Displayed under the name of a protocol handler in the Launch Application dialog. choose-dialog-privatebrowsing-disabled = Ανενεργό σε ιδιωτικά παράθυρα diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/toolkit/printing/printDialogs.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/toolkit/printing/printDialogs.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/toolkit/printing/printDialogs.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/toolkit/printing/printDialogs.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -4,7 +4,7 @@ print-setup = .title = Διαμόρφωση σελίδας -custom-prompt-title = Προσαρμοσμένο... +custom-prompt-title = Προσαρμογή… custom-prompt-prompt = Εισάγετε το προσαρμοσμένο κείμενο επικεφαλίδας/υποσέλιδου basic-tab = .label = Μορφή & επιλογές @@ -90,7 +90,7 @@ hf-page-and-total = .label = Σελίδα # από # hf-custom = - .label = Προσαρμοσμένο... + .label = Προσαρμογή… print-preview-window = .title = Προεπισκόπηση εκτύπωσης print-title = @@ -103,7 +103,6 @@ .title = Εκτύπωση print-complete = .value = Η εκτύπωση ολοκληρώθηκε - # Variables # $percent (integer) - Number of printed percentage print-percent = diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/toolkit/printing/printPreview.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/toolkit/printing/printPreview.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/el/toolkit/toolkit/printing/printPreview.ftl 2020-11-15 14:40:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/el/toolkit/toolkit/printing/printPreview.ftl 2020-11-17 19:33:09.000000000 +0000 @@ -25,7 +25,7 @@ printpreview-shrink-to-fit = .label = Αυτόματη προσαρμογή printpreview-custom = - .label = Προσαρμογή... + .label = Προσαρμογή… printpreview-print = .label = Εκτύπωση… .accesskey = Ε @@ -57,4 +57,3 @@ printpreview-endarrow = .label = { $arrow } .tooltiptext = Τελευταία σελίδα - diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-CL/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-CL/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-CL/browser/browser/browser.ftl 2020-11-15 14:40:37.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-CL/browser/browser/browser.ftl 2020-11-17 19:33:26.000000000 +0000 @@ -348,9 +348,10 @@ ## Bookmarks toolbar items -browser-import-button = +browser-import-button2 = .label = Importar marcadores… - .tooltiptext = Copiar marcadores desde otro navegador a { -brand-short-name }. + .tooltiptext = Importar marcadores desde otro navegador a { -brand-short-name }. +bookmarks-toolbar-empty-message = Para un acceso rápido, coloca tus marcadores aquí en la barra de herramientas de marcadores. Gestionar marcadores… ## WebRTC Pop-up notifications diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-CL/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-CL/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-CL/browser/browser/preferences/preferences.ftl 2020-11-15 14:40:37.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-CL/browser/browser/preferences/preferences.ftl 2020-11-17 19:33:26.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = Proceder con precaución pane-experimental-search-results-header = Experimentos de { -brand-short-name }: proceder con precaución pane-experimental-description = Cambiar las preferencias de configuración avanzada puede afectar el rendimiento o la seguridad de { -brand-short-name }. +pane-experimental-reset = + .label = Restaurar predeterminados + .accesskey = R help-button-label = Soporte de { -brand-short-name } addons-button-label = Extensiones y temas focus-search = @@ -929,6 +932,7 @@ content-blocking-enhanced-tracking-protection = Protección de seguimiento mejorada content-blocking-section-top-level-description = Los rastreadores te siguen en línea para recolectar información sobre tus hábitos de navegación e intereses. { -brand-short-name } bloquea muchos de estos rastreadores y otros scripts maliciosos. content-blocking-learn-more = Aprender más +content-blocking-fpi-incompatibility-warning = Estás usando First Party Isolation (FPI), lo que anula algunas de las configuraciones de cookies de { -brand-short-name }. ## These strings are used to define the different levels of ## Enhanced Tracking Protection. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-CL/toolkit/toolkit/featuregates/features.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-CL/toolkit/toolkit/featuregates/features.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-CL/toolkit/toolkit/featuregates/features.ftl 2020-11-15 14:40:37.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-CL/toolkit/toolkit/featuregates/features.ftl 2020-11-17 19:33:26.000000000 +0000 @@ -47,11 +47,6 @@ experimental-features-css-constructable-stylesheets = .label = CSS: Constructable Stylesheets experimental-features-css-constructable-stylesheets-description = La adición de un constructor a la interfaz CSSStyleSheet así como una variedad de cambios relacionados hace posible crear directamente nuevas hojas de estilo sin tener que agregar la hoja al HTML. Esto hace más fácil crear hojas de estilo reutilizables para usar con Shadow DOM. Consulta el bug 1520690 para obtener más detalles. -# The title of the experiment should be kept in English as it may be referenced -# by various online articles and is technical in nature. -experimental-features-media-session-api = - .label = Web API: Media Session API -experimental-features-media-session-api-description = La implementación completa de { -brand-short-name } de Media Session API es actualmente experimental. Esta API se usa para personalizar el manejo de notificaciones relacionadas con los medios, para manejar eventos y datos útiles para presentar una interfaz de usuario para manejar reproducción de medios y para obtener metadatos de los archivos. Consulta el bug 1112032 para obtener más detalles. experimental-features-devtools-color-scheme-simulation = .label = Herramientas para desarrolladores: simulación de esquemas de color experimental-features-devtools-color-scheme-simulation-description = Añade una opción para simular diferentes esquemas de color que te permiten probar las consultas de medios @prefers-color-scheme. El uso de esta función permite que tu hoja de estilo responda si el usuario prefiere una interfaz de usuario clara u oscura. Esto te permite probar el código sin tener que cambiar la configuración del navegador (o sistema operativo, si el navegador sigue una configuración de esquema de color establecida para todo el sistema). Consulta el bug 1550804 y el bug 1137699 para obtener más detalles. @@ -87,10 +82,6 @@ .label = Herramientas de desarrollado: Depuración de Service Worker # "Service Worker" is an API name and is usually not translated. experimental-features-devtools-serviceworker-debugger-support-description = Activa el soporte experimental para Service Workers en el panel del Depurador. Esta función puede ralentizar las Herramientas de Desarrollo y aumentar el consumo de memoria. -# Desktop zooming experiment -experimental-features-graphics-desktop-zooming = - .label = Graphics: Smooth Pinch Zoom -experimental-features-graphics-desktop-zooming-description = Habilita el soporte para un hacer zoom con suavidad al pellizcar en las pantallas táctiles y los touch pads de precisión con suavidad. # WebRTC global mute toggle controls experimental-features-webrtc-global-mute-toggles = .label = Activar/desactivar WebRTC globalmente @@ -103,3 +94,7 @@ experimental-features-fission = .label = Fission (aislamiento de sitios) experimental-features-fission-description = Fission (aislamiento de sitios) es una característica experimental en { -brand-short-name } para proporcionar una capa adicional de defensa contra los problemas de seguridad. Al aislar cada sitio en un proceso separado, Fission hace que sea más difícil para los sitios web maliciosos tener acceso a información de otras páginas que estás visitando. Éste es un cambio arquitectónico importante en { -brand-short-name } y te agradecemos probar e informar cualquier problema que encuentres. Para obtener más detalles, consulta la wiki. +# Support for having multiple Picture-in-Picture windows open simultaneously +experimental-features-multi-pip = + .label = Soporte para múltiples Picture-in-Picture +experimental-features-multi-pip-description = Soporte experimental para permitir múltiples ventanas Picture-in-Picture abiertas al mismo tiempo. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/browser/browser/browser.ftl 2020-11-15 14:40:40.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/browser/browser/browser.ftl 2020-11-17 19:33:29.000000000 +0000 @@ -301,6 +301,8 @@ identity-https-only-info-no-upgrade = No se puede actualizar la conexión desde HTTP. identity-permissions = .value = Permisos +identity-permissions-storage-access-header = Cookies entre sitios +identity-permissions-storage-access-hint = Estas partes pueden usar cookies de sitios cruzados y datos del sitio mientras está en este sitio. identity-permissions-reload-hint = Puede que necesite recargar la página para que se apliquen los cambios. identity-permissions-empty = No ha concedido ningún permiso especial a este sitio. identity-clear-site-data = @@ -346,9 +348,10 @@ ## Bookmarks toolbar items -browser-import-button = +browser-import-button2 = .label = Importar marcadores… - .tooltiptext = Copiar marcadores desde otro navegador a { -brand-short-name }. + .tooltiptext = Importar marcadores desde otro navegador a { -brand-short-name }. +bookmarks-toolbar-empty-message = Para un acceso rápido, sitúe sus marcadores aquí en la barra de herramientas de marcadores. Administrar marcadores… ## WebRTC Pop-up notifications diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/browser/browser/preferences/preferences.ftl 2020-11-15 14:40:40.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/browser/browser/preferences/preferences.ftl 2020-11-17 19:33:29.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = Continuar con precaución pane-experimental-search-results-header = Experimentos de { -brand-short-name }: Proceder con precaución pane-experimental-description = Cambiar las preferencias de configuración avanzada puede afectar el rendimiento o la seguridad de { -brand-short-name }. +pane-experimental-reset = + .label = Restaurar predeterminados + .accesskey = R help-button-label = { -brand-short-name } Asistencia addons-button-label = Extensiones y temas focus-search = @@ -929,6 +932,7 @@ content-blocking-enhanced-tracking-protection = Protección contra el rastreo mejorada content-blocking-section-top-level-description = Los rastreadores le siguen en línea para recopilar información sobre sus hábitos e intereses de navegación. { -brand-short-name } bloquea muchos de estos rastreadores y otros scripts maliciosos. content-blocking-learn-more = Saber más +content-blocking-fpi-incompatibility-warning = Está usando First Party Isolation (FPI), que anula algunas de las configuraciones de cookies de { -brand-short-name }. ## These strings are used to define the different levels of ## Enhanced Tracking Protection. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/browser/browser/safebrowsing/blockedSite.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/browser/browser/safebrowsing/blockedSite.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/browser/browser/safebrowsing/blockedSite.ftl 2020-11-15 14:40:40.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/browser/browser/safebrowsing/blockedSite.ftl 2020-11-17 19:33:29.000000000 +0000 @@ -19,6 +19,8 @@ safeb-blocked-malware-page-error-desc-override = { $sitename } ha sido identificado por contener software malicioso. Puede informar de un problema en la detección o ignorar el riesgo y visitar este sitio inseguro. safeb-blocked-malware-page-error-desc-no-override = { $sitename } ha sido identificado por contener software malicioso. Puede informar de un problema en la detección. safeb-blocked-malware-page-learn-more = Más información sobre contenido web dañino, incluyendo virus y otro software malicioso, y cómo proteger su equipo en StopBadware.org. Más información sobre la protección contra phishing y software malicioso de { -brand-short-name } en support.mozilla.org. +safeb-blocked-malware-page-error-desc-override-sumo = { $sitename } ha sido reportado por contener software malicioso. Puede ignorar el riesgo e ir a este sitio inseguro. +safeb-blocked-malware-page-error-desc-no-override-sumo = { $sitename } ha sido reportado por contener software malicioso. safeb-blocked-malware-page-learn-more-sumo = Aprenda más sobre la protección contra malware y phishing de { -brand-short-name } en support.mozilla.org. safeb-blocked-unwanted-page-error-desc-override = { $sitename } ha sido identificado por contener software dañino. Puede elegir ignorar el riesgo y visitar este sitio inseguro. safeb-blocked-unwanted-page-error-desc-no-override = { $sitename } ha sido identificado por contener software dañino. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/browser/chrome/browser/downloads/downloads.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/browser/chrome/browser/downloads/downloads.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/browser/chrome/browser/downloads/downloads.properties 2020-11-15 14:40:40.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/browser/chrome/browser/downloads/downloads.properties 2020-11-17 19:33:29.000000000 +0000 @@ -33,6 +33,7 @@ blockedMalware=Este archivo contiene un virus o software malicioso. blockedPotentiallyUnwanted=Este archivo puede dañar su equipo. blockedInsecure = Este archivo no se pudo descargar de forma segura. +blockedPotentiallyInsecure=Archivo no descargado: Riesgo potencial de seguridad. blockedUncommon2=Este archivo no se suele descargar. # LOCALIZATION NOTE (fileMovedOrMissing): @@ -42,7 +43,7 @@ # LOCALIZATION NOTE (unblockHeaderUnblock, unblockHeaderOpen, # unblockTypeMalware, unblockTypePotentiallyUnwanted2, # unblockTypeUncommon2, unblockTip2, unblockButtonOpen, -# unblockButtonUnblock, unblockButtonConfirmBlock): +# unblockButtonUnblock, unblockButtonConfirmBlock, unblockInsecure): # These strings are displayed in the dialog shown when the user asks a blocked # download to be unblocked. The severity of the threat is expressed in # descending order by the unblockType strings, it is higher for files detected @@ -52,6 +53,7 @@ unblockTypeMalware=Este archivo contiene un virus u otro software malicioso que dañará su equipo. unblockTypePotentiallyUnwanted2=Este archivo se hace pasar por una descarga útil, pero puede hacer cambios inesperados a sus programas y configuraciones. unblockTypeUncommon2=Este archivo no se descarga habitualmente y puede no ser seguro abrirlo. Puede contener un virus o hacer cambios inesperados a sus programas y configuraciones. +unblockInsecure=El archivo utiliza una conexión insegura. Puede ser manipulado o corrompido durante el proceso de descarga. unblockTip2=Puede buscar una fuente alternativa de descarga o intentarlo de nuevo más tarde. unblockButtonOpen=Abrir unblockButtonUnblock=Permitir descarga diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/devtools/client/accessibility.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/devtools/client/accessibility.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/devtools/client/accessibility.properties 2020-11-15 14:40:40.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/devtools/client/accessibility.properties 2020-11-17 19:33:29.000000000 +0000 @@ -298,3 +298,13 @@ # LOCALIZATION NOTE (accessibility.simulation.achromatopsia): This label is shown # in the "Simulate" menu in the accessibility panel and represent the achromatopsia simulation option. accessibility.simulation.achromatopsia=Acromatopsia (sin color) + +# LOCALIZATION NOTE (accessibility.toolbar.displayTabbingOrder.label): A title text for a checkbox label +# in the accessibility panel toolbar that turns on/off the overlay of focusable elements in their +# tabbing order. +accessibility.toolbar.displayTabbingOrder.label=Mostrar orden de tabulación + +# LOCALIZATION NOTE (accessibility.toolbar.displayTabbingOrder.tooltip): A title text for a checkbox +# tooltip in the accessibility panel toolbar that turns on/off the overlay of focusable elements in +# their tabbing order. +accessibility.toolbar.displayTabbingOrder.tooltip=Mostrar el orden de tabulación de los elementos y su índice de tabulación. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/toolkit/toolkit/about/aboutProcesses.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/toolkit/toolkit/about/aboutProcesses.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/toolkit/toolkit/about/aboutProcesses.ftl 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/toolkit/toolkit/about/aboutProcesses.ftl 2020-11-17 19:33:30.000000000 +0000 @@ -0,0 +1,133 @@ +# 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/. + +# Page title +about-processes-title = Administrador de procesos +# The Actions column +about-processes-column-action = + .title = Acciones + +## Tooltips + +about-processes-shutdown-process = + .title = Descargar pestañas y matar el proceso +about-processes-shutdown-tab = + .title = Cerrar pestaña + +## Column headers + +about-processes-column-name = Nombre +about-processes-column-memory-resident = Memoria +about-processes-column-cpu-total = CPU + +## Process names +## Variables: +## $pid (String) The process id of this process, assigned by the OS. +## $origin (String) The domain name for this process. +## $type (String) The raw type for this process. Used for unknown processes. + +about-processes-browser-process-name = { -brand-short-name } (proceso { $pid }) +about-processes-web-process-name = Web (proceso { $pid }, compartido) +about-processes-web-isolated-process-name = Web (proceso { $pid }) para { $origin } +about-processes-web-large-allocation = Web (proceso { $pid }, grande) para { $origin } +about-processes-with-coop-coep-process-name = Web (proceso { $pid }, origen cruzado aislado) para { $origin } +about-processes-file-process-name = Archivos (proceso { $pid }) +about-processes-extension-process-name = Extensiones (proceso { $pid }) +about-processes-privilegedabout-process-name = Acerca de (proceso { $pid } ) +about-processes-plugin-process-name = Plugins (proceso { $pid }) +about-processes-privilegedmozilla-process-name = Web (proceso { $pid }) para sitios { -vendor-short-name } +about-processes-gmp-plugin-process-name = Plugins de medios de Gecko (proceso { $pid }) +about-processes-gpu-process-name = GPU (proceso { $pid }) +about-processes-vr-process-name = Realidad Virtual (proceso { $pid }) +about-processes-rdd-process-name = Decodificador de datos (proceso { $pid }) +about-processes-socket-process-name = Red (proceso { $pid }) +about-processes-remote-sandbox-broker-process-name = Remote Sandbox Broker (proceso { $pid }) +about-processes-fork-server-process-name = Fork Server (proceso { $pid }) +about-processes-preallocated-process-name = Preasignado (proceso { $pid }) +about-processes-unknown-process-name = Otro ({ $type }, proceso { $pid }) +# Process +# Variables: +# $name (String) The name assigned to the process. +# $pid (String) The process id of this process, assigned by the OS. +about-processes-process-name = Proceso{ $pid }: { $name } + +## Details within processes + +# Single-line summary of threads +# Variables: +# $number (Number) The number of threads in the process. Typically larger +# than 30. We don't expect to ever have processes with less +# than 5 threads. +about-processes-thread-summary = Hilos ({ $number }) +# Thread details +# Variables: +# $name (String) The name assigned to the thread. +# $tid (String) The thread id of this thread, assigned by the OS. +about-processes-thread-name = Hilo { $tid }: { $name } +# Tab +# Variables: +# $name (String) The name of the tab (typically the title of the page, might be the url while the page is loading). +about-processes-tab-name = Pestaña: { $name } +about-processes-preloaded-tab = Pestaña nueva precargada +# Single subframe +# Variables: +# $url (String) The full url of this subframe. +about-processes-frame-name-one = Submarco: { $url } +# Group of subframes +# Variables: +# $number (Number) The number of subframes in this group. Always ≥ 1. +# $shortUrl (String) The shared prefix for the subframes in the group. +about-processes-frame-name-many = Submarcos ({ $number }): { $shortUrl } + +## Displaying CPU (percentage and total) +## Variables: +## $percent (Number) The percentage of CPU used by the process or thread. +## Always > 0, generally <= 200. +## $total (Number) The amount of time used by the process or thread since +## its start. +## $unit (String) The unit in which to display $total. See the definitions +## of `duration-unit-*`. + +# Common case. +about-processes-cpu-user-and-kernel = { NUMBER($percent, maximumSignificantDigits: 2, style: "percent") } ({ NUMBER($total, maximumFractionDigits: 0) }{ $unit }) +# Special case: data is not available yet. +about-processes-cpu-user-and-kernel-not-ready = (medición en curso) +# Special case: process or thread is currently idle. +about-processes-cpu-user-and-kernel-idle = inactivo ({ NUMBER($total, maximumFractionDigits: 2) }{ $unit }) + +## Displaying Memory (total and delta) +## Variables: +## $total (Number) The amount of memory currently used by the process. +## $totalUnit (String) The unit in which to display $total. See the definitions +## of `memory-unit-*`. +## $delta (Number) The absolute value of the amount of memory added recently. +## $deltaSign (String) Either "+" if the amount of memory has increased +## or "-" if it has decreased. +## $deltaUnit (String) The unit in which to display $delta. See the definitions +## of `memory-unit-*`. + +# Common case. +about-processes-total-memory-size = { NUMBER($total, maximumFractionDigits: 0) }{ $totalUnit } ({ $deltaSign }{ NUMBER($delta, maximumFractionDigits: 0) }{ $deltaUnit }) +# Special case: no change. +about-processes-total-memory-size-no-change = { NUMBER($total, maximumFractionDigits: 0) }{ $totalUnit } + +## Duration units + +duration-unit-ns = ns +duration-unit-us = µs +duration-unit-ms = ms +duration-unit-s = s +duration-unit-m = m +duration-unit-h = h +duration-unit-d = d + +## Memory units + +memory-unit-B = B +memory-unit-KB = KB +memory-unit-MB = MB +memory-unit-GB = GB +memory-unit-TB = TB +memory-unit-PB = PB +memory-unit-EB = EB diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/toolkit/toolkit/featuregates/features.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/toolkit/toolkit/featuregates/features.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/toolkit/toolkit/featuregates/features.ftl 2020-11-15 14:40:40.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/toolkit/toolkit/featuregates/features.ftl 2020-11-17 19:33:30.000000000 +0000 @@ -47,11 +47,6 @@ experimental-features-css-constructable-stylesheets = .label = CSS: Constructable Stylesheets experimental-features-css-constructable-stylesheets-description = La adición de un constructor a la interface CSSStyleSheet así como una variedad de cambios relacionados hace posible crear directamente nuevas hojas de estilo sin tener que agregar la hoja al HTML. Esto hace más fácil crear hojas de estilo reutilizables para usar con Shadow DOM. Ver bug 1520690 para más detalles. -# The title of the experiment should be kept in English as it may be referenced -# by various online articles and is technical in nature. -experimental-features-media-session-api = - .label = Web API: Media Session API -experimental-features-media-session-api-description = La implementación completa de { -brand-short-name } de Media Session API es actualmente experimental. Esta API se usa para personalizar el manejo de notificaciones relacionadas con los medios, para manejar eventos y datos útiles para presentar una interfaz de usuario para manejar reproducción de medios y para obtener metadatos de los archivos. Ver bug 1112032 para más detalles. experimental-features-devtools-color-scheme-simulation = .label = Herramientas para desarrolladores: simulación de esquemas de color experimental-features-devtools-color-scheme-simulation-description = Añade una opción para simular diferentes esquemas de color que le permite probar consultas de medios @prefers-color-schem . El uso de esta función permite que su hoja de estilo responda si el usuario prefiere una interfaz de usuario clara u oscura. Esto le permite probar su código sin tener que cambiar la configuración de su navegador (o sistema operativo, si el navegador sigue una configuración de esquema de color para todo el sistema). Consulte bug 1550804 y bug 1137699 para obtener más detalles. @@ -87,10 +82,6 @@ .label = Herramientas de desarrolladores: Depuración de Service Worker # "Service Worker" is an API name and is usually not translated. experimental-features-devtools-serviceworker-debugger-support-description = Activa el soporte experimental para Service Workers en el panel del Depurador. Esta función puede ralentizar las Herramientas de desarrolladores y aumentar el consumo de memoria. -# Desktop zooming experiment -experimental-features-graphics-desktop-zooming = - .label = Gráficos: Zoom suave con los dedos -experimental-features-graphics-desktop-zooming-description = Activa la compatibilidad para un zoom suave en pantallas táctiles y almohadillas táctiles de precisión. # WebRTC global mute toggle controls experimental-features-webrtc-global-mute-toggles = .label = Activar/desactivar WebRTC globalmente @@ -103,3 +94,7 @@ experimental-features-fission = .label = Fission (aislamiento de sitios) experimental-features-fission-description = Fission (aislamiento de sitios) es una característica experimental en { -brand-short-name } para proporcionar una capa adicional de defensa contra los problemas de seguridad. Al aislar cada sitio en un proceso separado, Fission hace que sea más difícil para los sitios web maliciosos tener acceso a información de otras páginas que está visitando. Éste es un cambio arquitectónico importante en { -brand-short-name } y le agradecemos probar e informar de cualquier problema que encuentre. Para obtener más detalles, consulte el wiki. +# Support for having multiple Picture-in-Picture windows open simultaneously +experimental-features-multi-pip = + .label = Compatibilidad con múltiples Picture-in-Picture +experimental-features-multi-pip-description = Función experimental para permitir que se abran varias ventanas Picture-in-Picture al mismo tiempo. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/toolkit/toolkit/global/handlerDialog.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/toolkit/toolkit/global/handlerDialog.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/toolkit/toolkit/global/handlerDialog.ftl 2020-11-15 14:40:40.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/toolkit/toolkit/global/handlerDialog.ftl 2020-11-17 19:33:30.000000000 +0000 @@ -18,13 +18,21 @@ ## $appName - Name of the application that will be opened. permission-dialog-description = ¿Permitir que este sitio abra el enlace { $scheme }? +permission-dialog-description-file = ¿Permitir que este archivo abra el enlace { $scheme }? permission-dialog-description-host = ¿Permitir que { $host } abra el enlace { $scheme }? permission-dialog-description-app = ¿Permitir que este sitio abra el enlace { $scheme } con { $appName }? permission-dialog-description-host-app = ¿Permitir que { $host } abra el enlace { $scheme } con { $appName }? -# Please keep the emphasis around the hostname and scheme (ie the -# `` HTML tags). Please also keep the hostname as close to the start -# of the sentence as your language's grammar allows. +permission-dialog-description-file-app = ¿Permitir que este archivo abra el enlace { $scheme } con { $appName }? + +## Please keep the emphasis around the hostname and scheme (ie the +## `` HTML tags). Please also keep the hostname as close to the start +## of the sentence as your language's grammar allows. + permission-dialog-remember = Siempre permitir a { $host } abrir enlaces { $scheme } +permission-dialog-remember-file = Siempre permitir que este archivo abra enlaces { $scheme } + +## + permission-dialog-btn-open-link = .label = Abrir enlace .accessKey = A diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/toolkit/toolkit/printing/printUI.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/toolkit/toolkit/printing/printUI.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/es-ES/toolkit/toolkit/printing/printUI.ftl 2020-11-15 14:40:40.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/es-ES/toolkit/toolkit/printing/printUI.ftl 2020-11-17 19:33:30.000000000 +0000 @@ -41,6 +41,9 @@ printui-scale-fit-to-page-width = Ajustar al ancho de la página # Label for input control where user can set the scale percentage printui-scale-pcent = Escala +# Section title (noun) for the two-sided print options +printui-two-sided-printing = Impresión a doble cara +printui-duplex-checkbox = Imprimir en ambos lados # Section title for miscellaneous print options printui-options = Opciones printui-headers-footers-checkbox = Imprimir encabezados y pies de página diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/browser.ftl 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/browser.ftl 2020-11-17 19:33:39.000000000 +0000 @@ -348,9 +348,10 @@ ## Bookmarks toolbar items -browser-import-button = +browser-import-button2 = .label = Inportatu laster-markak… - .tooltiptext = Kopiatu laster-markak beste nabigatzaile batetik { -brand-short-name }(e)ra. + .tooltiptext = Inportatu laster-markak beste nabigatzaile batetik { -brand-short-name }(e)ra. +bookmarks-toolbar-empty-message = Sarbide azkarra izateko, ipin itzazu laster-markak hementxe, laster-marken tresna-barran. Kudeatu laster-markak… ## WebRTC Pop-up notifications diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/newtab/onboarding.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/newtab/onboarding.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/newtab/onboarding.ftl 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/newtab/onboarding.ftl 2020-11-17 19:33:39.000000000 +0000 @@ -133,6 +133,47 @@ ## doesn't become too long. Line breaks will be preserved when displaying the ## tooltip. +# Tooltip displayed on hover of automatic theme +onboarding-multistage-theme-tooltip-automatic-2 = + .title = + Heredatu sistema-eragilearen itxura + + sistemaren botoi, menu eta leihoentzat. +# Input description for automatic theme +onboarding-multistage-theme-description-automatic-2 = + .aria-description = + Heredatu sistema-eragilearen itxura + sistemaren botoi, menu eta leihoentzat. +# Tooltip displayed on hover of light theme +onboarding-multistage-theme-tooltip-light-2 = + .title = + Erabili itxura argia botoi, + menu eta leihoentzat. +# Input description for light theme +onboarding-multistage-theme-description-light = + .aria-description = + Erabili itxura argia botoi, + menu eta leihoentzat. +# Tooltip displayed on hover of dark theme +onboarding-multistage-theme-tooltip-dark-2 = + .title = + Erabili itxura iluna botoi, + menu eta leihoentzat. +# Input description for dark theme +onboarding-multistage-theme-description-dark = + .aria-description = + Erabili itxura iluna botoi, + menu eta leihoentzat. +# Tooltip displayed on hover of Alpenglow theme +onboarding-multistage-theme-tooltip-alpenglow-2 = + .title = + Erabili itxura koloretsua botoi, + menu eta leihoentzat. +# Input description for Alpenglow theme +onboarding-multistage-theme-description-alpenglow = + .aria-description = + Erabili itxura koloretsua botoi, + menu eta leihoentzat. ## These strings belong to the individual onboarding messages. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/places.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/places.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/places.ftl 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/places.ftl 2020-11-17 19:33:39.000000000 +0000 @@ -60,6 +60,9 @@ places-properties = .label = Propietateak .accesskey = i +# Managed bookmarks are created by an administrator and cannot be changed by the user. +managed-bookmarks = + .label = Kudeatutako laster-markak # This label is used when a managed bookmarks folder doesn't have a name. managed-bookmarks-subfolder = .label = Azpikarpeta diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/policies/policies-descriptions.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/policies/policies-descriptions.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/policies/policies-descriptions.ftl 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/policies/policies-descriptions.ftl 2020-11-17 19:33:39.000000000 +0000 @@ -11,179 +11,103 @@ ## in the documentation section in about:policies. policy-3rdparty = Ezarri politikak WebExtension gehigarriek chrome.storage.managed bidez sarbidea izan dezaten. - policy-AppAutoUpdate = Gaitu edo desgaitu aplikazioaren eguneraketa automatikoa. - policy-AppUpdateURL = Ezarri aplikazioa-eguneraketen URL pertsonalizatua - policy-Authentication = Konfiguratu onartzen duten webguneentzat integratutako autentifikazioa. - policy-BlockAboutAddons = Blokeatu gehigarrien kudeatzailerako sarbidea (about:addons). - policy-BlockAboutConfig = Blokeatu about:config orrirako sarbidea. - policy-BlockAboutProfiles = Blokeatu about:profiles orrirako sarbidea. - policy-BlockAboutSupport = Blokeatu about:support orrirako sarbidea. - policy-Bookmarks = Sortu laster-markak laster-marken tresna-barran, menuan edo hauen barneko karpeta batean. - policy-CaptivePortal = Gaitu edo desgaitu atari gatibuen euskarria. - policy-CertificatesDescription = Ziurtagiriak gehitzea edo integratutako ziurtagiriak erabiltzea. - policy-Cookies = Baimendu edo ukatu webguneei cookieak ezartzea. - policy-DisabledCiphers = Desgaitu zifratzeak. - policy-DefaultDownloadDirectory = Ezarri deskarga-direktorio lehenetsia. - policy-DisableAppUpdate = Eragotzi nabigatzailea eguneratzea. - policy-DisableBuiltinPDFViewer = Desgaitu PDF.js, { -brand-short-name }(r)en integratutako PDF ikustailea. - policy-DisableDefaultBrowserAgent = Eragotzi lehenetsitako nabigatzaile agenteak ekintzarik egitea. Windowsen bakarrik; beste plataformek ez dute agentea. - policy-DisableDeveloperTools = Blokeatu garatzaile-tresnetarako sarbidea. - policy-DisableFeedbackCommands = Desgaitu iritzia bidaltzeko komandoak 'Laguntza' menutik ('Bidali iritzia' eta 'Eman gune iruzurtiaren berri'). - policy-DisableFirefoxAccounts = Desgaitu { -fxaccount-brand-name }(r)en oinarritutako zerbitzuak, Sync barne. - # Firefox Screenshots is the name of the feature, and should not be translated. policy-DisableFirefoxScreenshots = Desgaitu Firefoxen pantaila-argazkien eginbidea. - policy-DisableFirefoxStudies = Eragotzi { -brand-short-name }(r)i esperimentuak exekutatzea. - policy-DisableForgetButton = Eragotzi 'Ahaztu' botoirako sarbidea. - policy-DisableFormHistory = Ez gogoratu bilaketa- eta inprimaki-historia. - policy-DisableMasterPasswordCreation = Ezarrita badago, ezingo da pasahitz nagusia sortu. - +policy-DisablePrimaryPasswordCreation = Ezarrita badago, ezingo da pasahitz nagusia sortu. policy-DisablePasswordReveal = Ez baimendu gordetako saio-hasieretan pasahitzak agerraraztea. - policy-DisablePocket = Desgaitu webguneak Pocket zerbitzura gordetzeko eginbidea. - policy-DisablePrivateBrowsing = Desgaitu nabigatze pribatua. - policy-DisableProfileImport = Desgaitu beste nabigatzaile batetik datuak inportatzeko menu-komandoa. - policy-DisableProfileRefresh = Desgaitu 'Biziberritu { -brand-short-name }' botoia about:support orrian. - policy-DisableSafeMode = Desgaitu modu seguruan berrabiarazteko eginbidea. Oharra: modu segurura sartzeko shift tekla sakatzea Windowsen desgai daiteke soilik, talde-gidalerroak erabilita. - policy-DisableSecurityBypass = Eragotzi erabiltzaileak zenbait segurtasun-abisu saihestea. - policy-DisableSetAsDesktopBackground = Desgaitu irudientzat 'Jarri idazmahaiaren atzeko planoan' menu-komandoa. - policy-DisableSystemAddonUpdate = Eragotzi nabigatzaileak sistemaren gehigarriak instalatzea eta eguneratzea. - policy-DisableTelemetry = Desgaitu Telemetry. - policy-DisplayBookmarksToolbar = Bistaratu lehenespenez laster-marken tresna-barra. - policy-DisplayMenuBar = Bistaratu lehenespenez menu-barra. - policy-DNSOverHTTPS = Konfiguratu HTTPS gaineko DNSa. - policy-DontCheckDefaultBrowser = Desgaitu abioan nabigatzaile lehenetsia egiaztatzea. - policy-DownloadDirectory = Ezarri eta blokeatu deskarga-direktorioa. - # “lock” means that the user won’t be able to change this setting policy-EnableTrackingProtection = Gaitu edo desgaitu edukia blokeatzea eta blokeatu ezarpen hau. - # “lock” means that the user won’t be able to change this setting policy-EncryptedMediaExtensions = Gaitu edo desgaitu Encrypted Media Extensions eta aukeran blokeatu ezarpen hau. - # A “locked” extension can’t be disabled or removed by the user. This policy # takes 3 keys (“Install”, ”Uninstall”, ”Locked”), you can either keep them in # English or translate them as verbs. policy-Extensions = Instalatu, desinstalatu edo blokeatu hedapenak. Instalatzeko aukerak URLak edo bide-izenak hartzen ditu parametro gisa. Desinstalatzeko eta blokeatzeko aukerek, berriz, hedapen-IDak. - policy-ExtensionSettings = Kudeatu hedapenen instalazioko arlo guztiak. - policy-ExtensionUpdate = Gaitu edo desgaitu hedapenen eguneraketa automatikoa. - policy-FirefoxHome = Konfiguratu Firefox Home. - policy-FlashPlugin = Baimendu edo ukatu Flash plugina erabiltzea. - policy-Handlers = Konfiguratu aplikazio-maneiatzaile lehenetsiak. - policy-HardwareAcceleration = Ez badago ezarrita, hardware-azelerazioa desgaituko da. - # “lock” means that the user won’t be able to change this setting policy-Homepage = Hasiera-orria ezarri eta ezarpen bidez aldatzea. - policy-InstallAddonsPermission = Baimendu zenbait webgunek gehigarriak instalatzea. - policy-LegacyProfiles = Desgaitu instalazio bakoitzerako profil bereiziak behartzen dituen eginbidea ## Do not translate "SameSite", it's the name of a cookie attribute. policy-LegacySameSiteCookieBehaviorEnabled = Gaitu lehenetsitako SameSite cookie portaera zaharraren ezarpena. - policy-LegacySameSiteCookieBehaviorEnabledForDomainList = Leheneratu SameSite portaera zaharrera zehaztutako guneetako cookientzat. ## policy-LocalFileLinks = Baimendu gune zehatzei fitxategi lokalen loturak egitea. - +policy-ManagedBookmarks = Administratzaileak kudeatutako eta erabiltzaileak aldatu ezin duen laster-marken zerrenda konfiguratzen du. policy-MasterPassword = Behartu edo eragotzi pasahitz nagusia erabiltzea. - +policy-PrimaryPassword = Behartu edo eragotzi pasahitz nagusia erabiltzea. policy-NetworkPrediction = Gaitu edo desgaitu sarearen iragarpena (DNS aurre-eskuratzea). - policy-NewTabPage = Gaitu edo desgaitu fitxa berriaren orria. - policy-NoDefaultBookmarks = Desgaitu { -brand-short-name }(r)ekin datozen laster-marka lehenetsiak eta dinamikoak sortzea (gehien bisitatutakoak, azken etiketak). Oharra: profila lehenengo aldiz erabili aurretik ezartzen bada bakarrik du eragina politika honek. - policy-OfferToSaveLogins = Behartu { -brand-short-name }(e)k gordetako saio-hasierak eta pasahitzak gogoratzea eskaintzeko ezarpena. Ezarrita eta ezarri gabeko balioak onartzen dira. - policy-OfferToSaveLoginsDefault = Ezarri balio lehenetsia { -brand-short-name }(e)k gordetako saio-hasierak eta pasahitzak gogoratzea eskaintzeko. Ezarrita eta ezarri gabeko balioak onartzen dira. - policy-OverrideFirstRunPage = Gainidatzi lehen abioko orria. Utzi zurian politika hau lehen abioko orria desgaitu nahi baduzu. - policy-OverridePostUpdatePage = Gainidatzi eguneraketen ondoko "Nobedadeak" orria. Utzi politika hau zurian eguneraketen ondoko orria desgaitu nahi baduzu. - policy-PasswordManagerEnabled = Gaitu pasahitzak pasahitz-kudeatzailean gordetzea. - # PDF.js and PDF should not be translated policy-PDFjs = Desgaitu edo konfiguratu PDF.js, { -brand-short-name }(r)en integratutako PDF ikustailea. - policy-Permissions2 = Konfiguratu kamera, mikrofonoa, kokapena, jakinarazpenak eta erreprodukzio automatikoa erabiltzeko baimenak. - policy-PictureInPicture = Gaitu edo desgaitu bideo beste leiho batean ikusteko eginbidea. - policy-PopupBlocking = Baimendu zenbait webguneri lehenespenez popup leihoak bistaratzea. - policy-Preferences = Ezarri eta blokeatu hobespen-azpimultzo baten balioak. - policy-PromptForDownloadLocation = Galdetu non gorde deskargatutako fitxategiak. - policy-Proxy = Konfiguratu proxy-ezarpenak. - policy-RequestedLocales = Ezarri aplikazioari eskatuko zaizkion hizkuntza-kodeen zerrenda, hobetsitakoen arabera ordenatuta. - policy-SanitizeOnShutdown2 = Ixtean, garbitu nabigazio-datuak. - policy-SearchBar = Ezarri bilaketa-barraren kokaleku lehenetsia. Erabiltzaileek oraindik ere pertsonalizatu ahal izango dute. - policy-SearchEngines = Konfiguratu bilaketa-motorren ezarpenak. Politika hau Extended Support Release (ESR) bertsiorako dago erabilgarri soilik. - policy-SearchSuggestEnabled = Gaitu edo desgaitu bilaketa-iradokizunak. - # For more information, see https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/PKCS11/Module_Installation policy-SecurityDevices = Instalatu PKCS #11 moduluak. - policy-SSLVersionMax = Ezarri SSL bertsio maximoa. - policy-SSLVersionMin = Ezarri SSL bertsio minimoa. - policy-SupportMenu = Gehitu euskarrirako menu-elementu pertsonalizatua laguntzaren menuan. - policy-UserMessaging = Ez erakutsi zenbait mezu erabiltzaileari. - # “format” refers to the format used for the value of this policy. policy-WebsiteFilter = Blokeatu zenbait webgune bisitatzea. Irakurri dokumentazioa formatuaren gaineko xehetasun gehiagorako. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/preferences/preferences.ftl 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/preferences/preferences.ftl 2020-11-17 19:33:39.000000000 +0000 @@ -51,6 +51,9 @@ .tooltiptext = { -brand-short-name } esperimentuak pane-experimental-subtitle = Kontuz jarraitu pane-experimental-description = Konfigurazio-hobespen aurreratuak aldatzeak { -brand-short-name }(r)en errendimendu edo segurtasunean eragin lezake. +pane-experimental-reset = + .label = Berrezarri lehenespenak + .accesskey = h help-button-label = { -brand-short-name } laguntza addons-button-label = Hedapenak eta itxurak focus-search = @@ -83,6 +86,9 @@ # This string is shown to notify the user that their new tab page # is being controlled by an extension. extension-controlled-new-tab-url = { $name } hedapenak zure fitxa berriaren orria kontrolatzen du. +# This string is shown to notify the user that the password manager setting +# is being controlled by an extension +extension-controlled-password-saving = Hedapen bat, { $name }, ezarpen hau kontrolatzen ari da. # This string is shown to notify the user that their notifications permission # is being controlled by an extension. extension-controlled-web-notifications = Hedapen bat, { $name }, ezarpen hau kontrolatzen ari da. @@ -781,6 +787,7 @@ forms-primary-pw-change = .label = Aldatu pasahitz nagusia… .accesskey = d +forms-primary-pw-fips-title = Une honetan FIPS moduan zaude. FIPS moduak pasahitz nagusia ezartzea eskatzen du. forms-master-pw-fips-desc = Pasahitz aldaketak huts egin du ## OS Authentication dialog @@ -792,6 +799,13 @@ # and includes subtitle of "Enter password for the user "xxx" to allow this." These # notes are only valid for English. Please test in your locale. master-password-os-auth-dialog-message-macosx = sortu pasahitz nagusia +# This message can be seen by trying to add a Primary Password. +primary-password-os-auth-dialog-message-win = Pasahitz nagusi bat sortzeko, sartu zure Windows kredentzialak. Honek zure kontuen segurtasuna babesten laguntzen du. +# This message can be seen by trying to add a Primary Password. +# The macOS strings are preceded by the operating system with "Firefox is trying to " +# and includes subtitle of "Enter password for the user "xxx" to allow this." These +# notes are only valid for English. Please test in your locale. +primary-password-os-auth-dialog-message-macosx = Sortu pasahitz nagusia master-password-os-auth-dialog-caption = { -brand-full-name } ## Privacy Section - History @@ -862,6 +876,10 @@ .label = Guneen arteko jarraipen-elementuak sitedata-option-block-cross-site-and-social-media-trackers = .label = Guneen arteko eta sare sozialetako jarraipen-elementuak +sitedata-option-block-cross-site-tracking-cookies-including-social-media = + .label = Guneen arteko jarraipen cookieak — sare sozialetako cookieak ere baditu +sitedata-option-block-cross-site-cookies-including-social-media = + .label = Guneen arteko cookieak — sare sozialetako cookieak ere baditu sitedata-option-block-cross-site-and-social-media-trackers-plus-isolate = .label = Guneen arteko eta sare sozialetako jarraipen-elementuak; bakartu gainerako cookieak sitedata-option-block-unvisited = @@ -927,6 +945,7 @@ content-blocking-etp-strict-desc = Babes sendoagoa baina zenbait gune edo eduki apurtzea eragin lezake. content-blocking-etp-custom-desc = Aukeratu blokeatu beharreko jarraipen-elementu eta scriptak. content-blocking-private-windows = Edukiaren jarraipena leiho pribatuetan +content-blocking-cross-site-cookies = Guneen arteko cookieak content-blocking-cross-site-tracking-cookies = Guneen arteko cookie jarraipen-egileak content-blocking-cross-site-tracking-cookies-plus-isolate = Guneen arteko jarraipen cookieak; bakartu gainerako cookieak content-blocking-social-media-trackers = Sare sozialetako jarraipen-elementuak @@ -1110,6 +1129,13 @@ ## Privacy Section - HTTPS-Only +httpsonly-learn-more = Argibide gehiago +httpsonly-radio-enabled = + .label = Gaitu HTTPS-Only modua leiho guztietan +httpsonly-radio-enabled-pbm = + .label = Gaitu HTTPS-Only modua leiho pribatuetan soilik +httpsonly-radio-disabled = + .label = Ez gaitu HTTPS-Only modua ## The following strings are used in the Download section of settings diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/safebrowsing/blockedSite.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/safebrowsing/blockedSite.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/browser/safebrowsing/blockedSite.ftl 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/browser/safebrowsing/blockedSite.ftl 2020-11-17 19:33:39.000000000 +0000 @@ -19,6 +19,7 @@ safeb-blocked-malware-page-error-desc-override = { $sitename } gunea software maltzurra izateagatik salatuta dago. Atzemate-arazo baten berri eman edo arriskua ezikusi eta gune ez-segurura joan zaitezke. safeb-blocked-malware-page-error-desc-no-override = { $sitename } gunea software maltzurra izateagatik salatuta dago. Atzemate-arazo baten berri eman dezakezu. safeb-blocked-malware-page-learn-more = StopBadware.org gunean web eduki kaltegarriari buruzko argibide gehiago dituzu, hala nola birus eta malware-ari buruzko eta ordenagailua babesteko informazioa. support.mozilla.org gunean { -brand-short-name }(r)en phishing eta malware babesari buruzko argibide gehiago dituzu. +safeb-blocked-malware-page-learn-more-sumo = support.mozilla.org gunean { -brand-short-name }(r)en phishing eta malware babesari buruzko argibide gehiago dituzu. safeb-blocked-unwanted-page-error-desc-override = { $sitename } gunea software kaltegarria izateagatik salatuta dago. Arriskua ezikusi eta gune ez-segurura joan zaitezke. safeb-blocked-unwanted-page-error-desc-no-override = { $sitename } gunea software kaltegarria izateagatik salatuta dago. safeb-blocked-unwanted-page-learn-more = Eskatu gabeko softwarearen politikan kaltegarria den eta nahi ez den softwareari buruzko argibide gehiago dituzu. support.mozilla.org gunean { -brand-short-name }(r)en phishing eta malware babesari buruzko argibide gehiago dituzu. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/chrome/browser/downloads/downloads.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/chrome/browser/downloads/downloads.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/chrome/browser/downloads/downloads.properties 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/chrome/browser/downloads/downloads.properties 2020-11-17 19:33:39.000000000 +0000 @@ -25,16 +25,15 @@ # languages: # http://windows.microsoft.com/en-US/windows-vista/Set-up-Parental-Controls stateBlockedParentalControls=Guraso-kontrolek blokeatua - # LOCALIZATION NOTE (blockedMalware, blockedPotentiallyUnwanted, # blockedUncommon2): -# These strings are shown in the panel for some types of blocked downloads, and -# are immediately followed by the "Learn More" link, thus they must end with a -# period. You may need to adjust "downloadDetails.width" in "downloads.dtd" if -# this turns out to be longer than the other existing status strings. -# Note: These strings don't exist in the UI yet. See bug 1053890. +# These strings are shown in the panel for some types of blocked downloads. You +# may need to adjust "downloads.width" in "downloads.dtd" if this turns out to +# be longer than the other existing status strings. blockedMalware=Fitxategi honek birusa edo malwarea dauka. blockedPotentiallyUnwanted=Fitxategi honek zure ordenagailua kalte lezake. +blockedInsecure = Ezin izan da fitxategi hau modu seguruan deskargatu. +blockedPotentiallyInsecure=Ez da fitxategia deskargatu: balizko segurtasun-arriskua. blockedUncommon2=Fitxategi hau ez da sarri deskargatzen. # LOCALIZATION NOTE (fileMovedOrMissing): @@ -44,7 +43,7 @@ # LOCALIZATION NOTE (unblockHeaderUnblock, unblockHeaderOpen, # unblockTypeMalware, unblockTypePotentiallyUnwanted2, # unblockTypeUncommon2, unblockTip2, unblockButtonOpen, -# unblockButtonUnblock, unblockButtonConfirmBlock): +# unblockButtonUnblock, unblockButtonConfirmBlock, unblockInsecure): # These strings are displayed in the dialog shown when the user asks a blocked # download to be unblocked. The severity of the threat is expressed in # descending order by the unblockType strings, it is higher for files detected diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/pdfviewer/viewer.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/pdfviewer/viewer.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/browser/pdfviewer/viewer.properties 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/browser/pdfviewer/viewer.properties 2020-11-17 19:33:39.000000000 +0000 @@ -143,11 +143,13 @@ document_outline_label=Dokumentuaren eskema attachments.title=Erakutsi eranskinak attachments_label=Eranskinak +layers_label=Geruzak thumbs.title=Erakutsi koadro txikiak thumbs_label=Koadro txikiak findbar.title=Bilatu dokumentuan findbar_label=Bilatu +additional_layers=Geruza gehigarriak # LOCALIZATION NOTE (page_canvas): "{{page}}" will be replaced by the page number. page_canvas={{page}}. orria # Thumbnails panel item (tooltip and alt text for images) diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/devtools/client/aboutdebugging.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/devtools/client/aboutdebugging.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/devtools/client/aboutdebugging.ftl 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/devtools/client/aboutdebugging.ftl 2020-11-17 19:33:39.000000000 +0000 @@ -10,7 +10,6 @@ # Page title (ie tab title) for the Setup page about-debugging-page-title-setup-page = Arazketa - Konfigurazioa - # Page title (ie tab title) for the Runtime page # { $selectedRuntimeId } is the id of the current runtime, such as "this-firefox", "localhost:6080", ... about-debugging-page-title-runtime-page = Arazketa - Exekuzio-ingurunea / { $selectedRuntimeId } @@ -20,60 +19,45 @@ # Display name of the runtime for the currently running instance of Firefox. Used in the # Sidebar and in the Setup page. about-debugging-this-firefox-runtime-name = { -brand-shorter-name } hau - # Sidebar heading for selecting the currently running instance of Firefox about-debugging-sidebar-this-firefox = .name = { about-debugging-this-firefox-runtime-name } - # Sidebar heading for connecting to some remote source about-debugging-sidebar-setup = .name = Konfigurazioa - # Text displayed in the about:debugging sidebar when USB devices discovery is enabled. about-debugging-sidebar-usb-enabled = USB gaituta - # Text displayed in the about:debugging sidebar when USB devices discovery is disabled # (for instance because the mandatory ADB extension is not installed). about-debugging-sidebar-usb-disabled = USB desgaituta - # Connection status (connected) for runtime items in the sidebar aboutdebugging-sidebar-runtime-connection-status-connected = Konektatuta # Connection status (disconnected) for runtime items in the sidebar aboutdebugging-sidebar-runtime-connection-status-disconnected = Deskonektatuta - # Text displayed in the about:debugging sidebar when no device was found. about-debugging-sidebar-no-devices = Ez da gailurik aurkitu - # Text displayed in buttons found in sidebar items representing remote runtimes. # Clicking on the button will attempt to connect to the runtime. about-debugging-sidebar-item-connect-button = Konektatu - # Text displayed in buttons found in sidebar items when the runtime is connecting. about-debugging-sidebar-item-connect-button-connecting = Konektatzen… - # Text displayed in buttons found in sidebar items when the connection failed. about-debugging-sidebar-item-connect-button-connection-failed = Konexioak huts egin du - # Text displayed in connection warning on sidebar item of the runtime when connecting to # the runtime is taking too much time. about-debugging-sidebar-item-connect-button-connection-not-responding = Konexioa oraindik zain, egiaztatu mezurik dagoen helburuko nabigatzailean - # Text displayed as connection error in sidebar item when the connection has timed out. about-debugging-sidebar-item-connect-button-connection-timeout = Konexioa denboraz kanpo - # Temporary text displayed in sidebar items representing remote runtimes after # successfully connecting to them. Temporary UI, do not localize. about-debugging-sidebar-item-connected-label = Konektatuta - # Text displayed in sidebar items for remote devices where a compatible browser (eg # Firefox) has not been detected yet. Typically, Android phones connected via USB with # USB debugging enabled, but where Firefox is not started. about-debugging-sidebar-runtime-item-waiting-for-browser = Nabigatzailearen zain… - # Text displayed in sidebar items for remote devices that have been disconnected from the # computer. about-debugging-sidebar-runtime-item-unplugged = Desentxufatuta - # Title for runtime sidebar items that are related to a specific device (USB, WiFi). about-debugging-sidebar-runtime-item-name = .title = { $displayName } ({ $deviceName }) @@ -81,16 +65,13 @@ # locations). about-debugging-sidebar-runtime-item-name-no-device = .title = { $displayName } - # Text to show in the footer of the sidebar that links to a help page # (currently: https://developer.mozilla.org/docs/Tools/about:debugging) about-debugging-sidebar-support = Arazketarako laguntza - # Text to show as the ALT attribute of a help icon that accompanies the help about # debugging link in the footer of the sidebar about-debugging-sidebar-support-icon = .alt = Laguntzaren ikonoa - # Text displayed in a sidebar button to refresh the list of USB devices. Clicking on it # will attempt to update the list of devices displayed in the sidebar. about-debugging-refresh-usb-devices-button = Berritu gailuak @@ -99,83 +80,61 @@ # Title of the Setup page. about-debugging-setup-title = Konfigurazioa - # Introduction text in the Setup page to explain how to configure remote debugging. about-debugging-setup-intro = Konfiguratu zure gailua urrunetik arazteko nahi duzun konexio-metodoa. - # Explanatory text in the Setup page about what the 'This Firefox' page is for about-debugging-setup-this-firefox2 = Erabili { about-debugging-this-firefox-runtime-name } { -brand-shorter-name }(r)en bertsio honetan hedapenak eta zerbitzu-langileak arazteko. - # Title of the heading Connect section of the Setup page. about-debugging-setup-connect-heading = Konektatu gailua - # USB section of the Setup page about-debugging-setup-usb-title = USB - # Explanatory text displayed in the Setup page when USB debugging is disabled about-debugging-setup-usb-disabled = Gaituz gero, Android USB arazketarako beharrezkoak diren osagaiak deskargatu eta gehituko dira { -brand-shorter-name }(r)en. - # Text of the button displayed in the USB section of the setup page when USB debugging is disabled. # Clicking on it will download components needed to debug USB Devices remotely. about-debugging-setup-usb-enable-button = Gaitu USB gailuak - # Text of the button displayed in the USB section of the setup page when USB debugging is enabled. about-debugging-setup-usb-disable-button = Desgaitu USB gailuak - # Text of the button displayed in the USB section of the setup page while USB debugging # components are downloaded and installed. about-debugging-setup-usb-updating-button = Eguneratzen… - # USB section of the Setup page (USB status) about-debugging-setup-usb-status-enabled = Gaituta about-debugging-setup-usb-status-disabled = Desgaituta about-debugging-setup-usb-status-updating = Eguneratzen… - # USB section step by step guide about-debugging-setup-usb-step-enable-dev-menu2 = Gaitu garatzaile-menua zure Android gailuan. - # USB section step by step guide about-debugging-setup-usb-step-enable-debug2 = Gaitu USB arazketa Android garatzaile-menuan. - # USB section step by step guide about-debugging-setup-usb-step-enable-debug-firefox2 = Gaitu Firefoxen USB arazketa Android gailuan. - # USB section step by step guide about-debugging-setup-usb-step-plug-device = Konektatu Android gailua zure ordenagailura. - # Text shown in the USB section of the setup page with a link to troubleshoot connection errors. # The link goes to https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_over_USB about-debugging-setup-usb-troubleshoot = Arazoak USB gailura konektatzerakoan? Arazo-konpontzea - # Network section of the Setup page about-debugging-setup-network = .title = Sareko kokalekua - # Text shown in the Network section of the setup page with a link to troubleshoot connection errors. # The link goes to https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Debugging_over_a_network about-debugging-setup-network-troubleshoot = Arazoak sareko kokaleku baten bidez konektatzerakoan? Arazo-konpontzea - # Text of a button displayed after the network locations "Host" input. # Clicking on it will add the new network location to the list. about-debugging-network-locations-add-button = Gehitu - # Text to display when there are no locations to show. about-debugging-network-locations-empty-text = Ez da sareko kokalekurik gehitu oraindik. - # Text of the label for the text input that allows users to add new network locations in # the Connect page. A host is a hostname and a port separated by a colon, as suggested by # the input's placeholder "localhost:6080". about-debugging-network-locations-host-input-label = Ostalaria - # Text of a button displayed next to existing network locations in the Connect page. # Clicking on it removes the network location from the list. about-debugging-network-locations-remove-button = Kendu - # Text used as error message if the format of the input value was invalid in the network locations form of the Setup page. # Variables: # $host-value (string) - The input value submitted by the user in the network locations form about-debugging-network-location-form-invalid = Ostalari baliogabea: "{ $host-value }". Esperotako formatua "ostalari-izena:ataka-zenbakia" da. - # Text used as error message if the input value was already registered in the network locations form of the Setup page. # Variables: # $host-value (string) - The input value submitted by the user in the network locations form @@ -206,26 +165,21 @@ # Title of the processes category. about-debugging-runtime-processes = .name = Prozesuak - # Label of the button opening the performance profiler panel in runtime pages for remote # runtimes. about-debugging-runtime-profile-button2 = Errendimenduaren profila - # This string is displayed in the runtime page if the current configuration of the # target runtime is incompatible with service workers. "Learn more" points to MDN. # https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging#Service_workers_not_compatible about-debugging-runtime-service-workers-not-compatible = Zure nabigatzailearen konfigurazioa ez da zerbitzu-langileekin bateragarria. Argibide gehiago - # This string is displayed in the runtime page if the remote browser version is too old. # "Troubleshooting" link points to https://developer.mozilla.org/docs/Tools/about:debugging#Troubleshooting # { $runtimeVersion } is the version of the remote browser (for instance "67.0a1") # { $minVersion } is the minimum version that is compatible with the current Firefox instance (same format) about-debugging-browser-version-too-old = Konektatutako nabigatzaileak bertsio zaharra dauka ({ $runtimeVersion }). Onartutako bertsio minimoa ({ $minVersion }) da. Euskarririk gabeko konfigurazioa da hau eta garatzaile-tresnek huts egitea eragin lezake. Mesedez eguneratu konektatutako nabigatzailea. Arazo-konpontzea - # Dedicated message for a backward compatibility issue that occurs when connecting: # from Fx 70+ to the old Firefox for Android (aka Fennec) which uses Fx 68. about-debugging-browser-version-too-old-fennec = Firefoxen bertsio honek ezin du Androiderako Firefox (68) araztu. Probak egiteko, Androiderako Firefoxen Nightly bertsioa instalatzea gomendatzen dugu. Xehetasun gehiago - # This string is displayed in the runtime page if the remote browser version is too recent. # "Troubleshooting" link points to https://developer.mozilla.org/docs/Tools/about:debugging#Troubleshooting # { $runtimeID } is the build ID of the remote browser (for instance "20181231", format is yyyyMMdd) @@ -233,27 +187,21 @@ # { $runtimeVersion } is the version of the remote browser (for instance "67.0a1") # { $localVersion } is the version of your current browser (same format) about-debugging-browser-version-too-recent = Konektatutako nabigatzailea berriagoa da ({ $runtimeVersion }, { $runtimeID } eraikitze-IDa) zure { -brand-shorter-name } ({ $localVersion }, { $localID } eraikitze-IDa) baino. Euskarririk gabeko konfigurazioa da hau eta garatzaile-tresnek huts egitea eragin lezake. Mesedez eguneratu Firefox. Arazo-konpontzea - # Displayed for runtime info in runtime pages. # { $name } is brand name such as "Firefox Nightly" # { $version } is version such as "64.0a1" about-debugging-runtime-name = { $name } ({ $version }) - # Text of a button displayed in Runtime pages for remote runtimes. # Clicking on the button will close the connection to the runtime. about-debugging-runtime-disconnect-button = Deskonektatu - # Text of the connection prompt button displayed in Runtime pages, when the preference # "devtools.debugger.prompt-connection" is false on the target runtime. about-debugging-connection-prompt-enable-button = Gaitu konexioaren gonbita - # Text of the connection prompt button displayed in Runtime pages, when the preference # "devtools.debugger.prompt-connection" is true on the target runtime. about-debugging-connection-prompt-disable-button = Desgaitu konexioaren gonbita - # Title of a modal dialog displayed on remote runtime pages after clicking on the Profile Runtime button. about-debugging-profiler-dialog-title2 = Profil sortzailea - # Clicking on the header of a debug target category will expand or collapse the debug # target items in the category. This text is used as ’title’ attribute of the header, # to describe this feature. @@ -264,127 +212,100 @@ # Displayed in the categories of "runtime" pages that don't have any debug target to # show. Debug targets depend on the category (extensions, tabs, workers...). about-debugging-debug-target-list-empty = Ezer ez oraindik. - # Text of a button displayed next to debug targets of "runtime" pages. Clicking on this # button will open a DevTools toolbox that will allow inspecting the target. # A target can be an addon, a tab, a worker... about-debugging-debug-target-inspect-button = Ikuskatu - # Text of a button displayed in the "This Firefox" page, in the Temporary Extension # section. Clicking on the button will open a file picker to load a temporary extension about-debugging-tmp-extension-install-button = Kargatu behin-behineko gehigarria… - # Text displayed when trying to install a temporary extension in the "This Firefox" page. about-debugging-tmp-extension-install-error = Errorea gertatu da behin-behineko gehigarria instalatzean. - # Text of a button displayed for a temporary extension loaded in the "This Firefox" page. # Clicking on the button will reload the extension. about-debugging-tmp-extension-reload-button = Berritu - # Text of a button displayed for a temporary extension loaded in the "This Firefox" page. # Clicking on the button will uninstall the extension and remove it from the page. about-debugging-tmp-extension-remove-button = Kendu - # Message displayed in the file picker that opens to select a temporary extension to load # (triggered by the button using "about-debugging-tmp-extension-install-button") # manifest.json .xpi and .zip should not be localized. # Note: this message is only displayed in Windows and Linux platforms. about-debugging-tmp-extension-install-message = Hautatu manifest.json fitxategia edo .xpi/zip artxiboa - # This string is displayed as a message about the add-on having a temporaryID. about-debugging-tmp-extension-temporary-id = WebExtension honek behin-behineko IDa du. Argibide gehiago - # Text displayed for extensions in "runtime" pages, before displaying a link the extension's # manifest URL. about-debugging-extension-manifest-url = .label = Manifestuaren URLa - # Text displayed for extensions in "runtime" pages, before displaying the extension's uuid. # UUIDs look like b293e463-481e-5148-a487-5aaf7a130429 about-debugging-extension-uuid = .label = Barneko UUIDa - # Text displayed for extensions (temporary extensions only) in "runtime" pages, before # displaying the location of the temporary extension. about-debugging-extension-location = .label = Kokalekua - # Text displayed for extensions in "runtime" pages, before displaying the extension's ID. # For instance "geckoprofiler@mozilla.com" or "{ed26ddcb-5611-4512-a89a-51b8db81cfb2}". about-debugging-extension-id = .label = Hedapenaren IDa - # This string is displayed as a label of the button that pushes a test payload # to a service worker. # Note this relates to the "Push" API, which is normally not localized so it is # probably better to not localize it. about-debugging-worker-action-push2 = Push .disabledTitle = Zerbitzu Langileen 'push' ekintza desgaituta dago une honetan prozesu anitzeko { -brand-shorter-name }(e)rako - # This string is displayed as a label of the button that starts a service worker. about-debugging-worker-action-start2 = Start .disabledTitle = Zerbitzu Langileen 'start' ekintza desgaituta dago une honetan prozesu anitzeko { -brand-shorter-name }(e)rako - # This string is displayed as a label of the button that unregisters a service worker. about-debugging-worker-action-unregister = Utzi erregistratuta egoteari - # Displayed for service workers in runtime pages that listen to Fetch events. about-debugging-worker-fetch-listening = .label = Fetch .value = 'fetch' gertaerak entzuten - # Displayed for service workers in runtime pages that do not listen to Fetch events. about-debugging-worker-fetch-not-listening = .label = Fetch .value = 'fetch' gertaerak ez dira entzuten - # Displayed for service workers in runtime pages that are currently running (service # worker instance is active). about-debugging-worker-status-running = Exekutatzen - # Displayed for service workers in runtime pages that are registered but stopped. about-debugging-worker-status-stopped = Geldituta - # Displayed for service workers in runtime pages that are registering. about-debugging-worker-status-registering = Erregistratzen - # Displayed for service workers in runtime pages, to label the scope of a worker about-debugging-worker-scope = .label = Esparrua - # Displayed for service workers in runtime pages, to label the push service endpoint (url) # of a worker about-debugging-worker-push-service = .label = Push zerbitzua - # Displayed as title of the inspect button when service worker debugging is disabled. about-debugging-worker-inspect-action-disabled = .title = Zerbitzu Langileak ikuskatzea desgaituta dago une honetan prozesu anitzeko { -brand-shorter-name }(e)rako - +# Displayed as title of the inspect button for zombie tabs (e.g. tabs loaded via a session restore). +about-debugging-zombie-tab-inspect-action-disabled = + .title = Fitxa ez da erabat kargatu eta ezin da ikuskatu # Displayed as name for the Main Process debug target in the Processes category. Only for # remote runtimes, if `devtools.aboutdebugging.process-debugging` is true. about-debugging-main-process-name = Prozesu nagusia - # Displayed as description for the Main Process debug target in the Processes category. # Only for remote browsers, if `devtools.aboutdebugging.process-debugging` is true. about-debugging-main-process-description2 = Helburu-nabigatzailearen prozesu nagusia - # Displayed instead of the Main Process debug target when the preference # `devtools.browsertoolbox.fission` is true. about-debugging-multiprocess-toolbox-name = Multiprozesuko tresna-kutxa - # Description for the Multiprocess Toolbox target. about-debugging-multiprocess-toolbox-description = Helburu-nabigatzailearen prozesu nagusia eta eduki-prozesua - # Alt text used for the close icon of message component (warnings, errors and notifications). about-debugging-message-close-icon = .alt = Itxi mezua - # Label text used for the error details of message component. about-debugging-message-details-label-error = Errorearen xehetasunak - # Label text used for the warning details of message component. about-debugging-message-details-label-warning = Abisuaren xehetasunak - # Label text used for default state of details of message component. about-debugging-message-details-label = Xehetasunak diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/devtools/client/application.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/devtools/client/application.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/devtools/client/application.ftl 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/devtools/client/application.ftl 2020-11-17 19:33:39.000000000 +0000 @@ -14,37 +14,35 @@ # Header for the list of Service Workers displayed in the application panel for the current page. serviceworker-list-header = Zerbitzu-langileak - # Text displayed next to the list of Service Workers to encourage users to check out # about:debugging to see all registered Service Workers. serviceworker-list-aboutdebugging = Ireki about:debugging beste domeinuetako zerbitzu-langileak ikusteko - # Text for the button to unregister a Service Worker. Displayed for active Service Workers. serviceworker-worker-unregister = Kendu erregistroa - # Text for the debug link displayed for an already started Service Worker. Clicking on the # link opens a new devtools toolbox for this service worker. The title attribute is only # displayed when the link is disabled. serviceworker-worker-debug = Araztu .title = Exekutatzen ari diren zerbitzu-langileak araztu daitezke soilik - # Text for the debug link displayed for an already started Service Worker, when we # are in multi e10s mode, which effectively disables this link. serviceworker-worker-debug-forbidden = Araztu .title = e10s desgaituta dagoenean soilik araz daitezke zerbitzu-langileak - # Text for the start link displayed for a registered but not running Service Worker. # Clicking on the link will attempt to start the service worker. serviceworker-worker-start2 = Hasi .title = e10s desgaituta dagoenean soilik has daitezke zerbitzu-langileak - +# Alt text for the image icon displayed inside a debug link for a service worker. +serviceworker-worker-inspect-icon = + .alt = Ikuskatu +# Text for the start link displayed for a registered but not running Service Worker. +# Clicking on the link will attempt to start the service worker. +serviceworker-worker-start3 = Hasi # Text displayed for the updated time of the service worker. The

Inportatu zure saio-hasiera { $browser } nabigatzailetik
{ $host } eta beste guneetarako
+autocomplete-import-logins-info = + .tooltiptext = Argibide gehiago ## Variables: ## $host (String) - Host name of the current site. + ## -autocomplete-import-logins-info = - .tooltiptext = Argibide gehiago +autocomplete-import-learn-more = Argibide gehiago diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/toolkit/toolkit/printing/printUI.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/toolkit/toolkit/printing/printUI.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/eu/toolkit/toolkit/printing/printUI.ftl 2020-11-15 14:40:50.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/eu/toolkit/toolkit/printing/printUI.ftl 2020-11-17 19:33:39.000000000 +0000 @@ -19,24 +19,78 @@ .aria-label = Aukeratu orri-barrutia printui-page-custom-range = .aria-label = Idatzi orri-barruti pertsonalizatua +# This label is displayed before the first input field indicating +# the start of the range to print. +printui-range-start = Hemendik +# This label is displayed between the input fields indicating +# the start and end page of the range to print. +printui-range-end = hona # Section title for the number of copies to print printui-copies-label = Kopiak printui-orientation = Orientazioa printui-landscape = Horizontala printui-portrait = Bertikala +# Section title for the printer or destination device to target +printui-destination-label = Helburua printui-destination-pdf-label = Gorde PDF gisa printui-more-settings = Ezarpen gehiago printui-less-settings = Ezarpen gutxiago printui-paper-size-label = Paper-tamaina # Section title (noun) for the print scaling options printui-scale = Eskala +printui-scale-fit-to-page-width = Doitu orriaren zabalerara # Label for input control where user can set the scale percentage printui-scale-pcent = Eskala +# Section title (noun) for the two-sided print options +printui-two-sided-printing = Bi aldeko inprimatzea +printui-duplex-checkbox = Inprimatu bi aldeetan # Section title for miscellaneous print options printui-options = Aukerak +printui-headers-footers-checkbox = Inprimatu goiburu eta oinak +printui-backgrounds-checkbox = Inprimatu atzeko planoa +printui-color-mode-label = Kolorearen modua +printui-color-mode-color = Koloretan +printui-color-mode-bw = Zuri-beltzean +printui-margins = Marjinak +printui-margins-default = Lehenetsia +printui-margins-min = Gutxienekoa +printui-margins-none = Bat ere ez +printui-margins-custom = Pertsonalizatua +printui-margins-custom-top = Goia +printui-margins-custom-bottom = Behea +printui-margins-custom-left = Ezkerra +printui-margins-custom-right = Eskuina +printui-system-dialog-link = Inprimatu sistemaren elkarrizketa-koadroa erabiliz… +printui-primary-button = Inprimatu +printui-primary-button-save = Gorde +printui-cancel-button = Utzi +printui-loading = Aurrebista prestatzen +# Reported by screen readers and other accessibility tools to indicate that +# the print preview has focus. +printui-preview-label = + .aria-label = Inprimatzeko aurrebista ## Paper sizes that may be supported by the Save to PDF destination: +printui-paper-a5 = A5 +printui-paper-a4 = A4 +printui-paper-a3 = A3 +printui-paper-a2 = A2 +printui-paper-a1 = A1 +printui-paper-a0 = A0 +printui-paper-b5 = B5 +printui-paper-b4 = B4 +printui-paper-jis-b5 = JIS-B5 +printui-paper-jis-b4 = JIS-B4 +printui-paper-letter = AEBko gutuna +printui-paper-legal = AEBko legala +printui-paper-tabloid = Tabloidea ## Error messages shown when a user has an invalid input +printui-error-invalid-scale = Eskala 10 eta 200 arteko zenbakia izan behar da. +printui-error-invalid-margin = Sartu baliozko marjina hautatutako paper-tamainarako. +# Variables +# $numPages (integer) - Number of pages +printui-error-invalid-range = Barrutiak 1 eta { $numPages } arteko zenbakia izan behar du. +printui-error-invalid-start-overflow = "Hemendik" orri-zenbakia "hona" orri-zenbakia baino txikiagoa izan behar da. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/fr/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/fr/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/fr/browser/browser/browser.ftl 2020-11-15 14:41:03.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/fr/browser/browser/browser.ftl 2020-11-17 19:33:52.000000000 +0000 @@ -347,9 +347,10 @@ ## Bookmarks toolbar items -browser-import-button = - .label = Importer des marque-pages… - .tooltiptext = Copier les marque-pages depuis un autre navigateur vers { -brand-short-name }. +browser-import-button2 = + .label = Importer les marque-pages… + .tooltiptext = Importer les marque-pages d’un autre navigateur dans { -brand-short-name }. +bookmarks-toolbar-empty-message = Pour un accès rapide, placez vos marque-pages ici, sur la barre personnelle. Gérer vos marque-pages… ## WebRTC Pop-up notifications diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/fr/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/fr/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/fr/browser/browser/preferences/preferences.ftl 2020-11-15 14:41:03.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/fr/browser/browser/preferences/preferences.ftl 2020-11-17 19:33:52.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = Agissez avec précaution pane-experimental-search-results-header = Expériences de { -brand-short-name } : gardez l’œil ouvert pane-experimental-description = Modifier les préférences de configuration avancées peut affecter les performances et la sécurité de { -brand-short-name }. +pane-experimental-reset = + .label = Configuration par défaut + .accesskey = d help-button-label = Assistance de { -brand-short-name } addons-button-label = Extensions et thèmes focus-search = diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/fr/toolkit/toolkit/about/aboutNetworking.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/fr/toolkit/toolkit/about/aboutNetworking.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/fr/toolkit/toolkit/about/aboutNetworking.ftl 2020-11-15 14:41:03.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/fr/toolkit/toolkit/about/aboutNetworking.ftl 2020-11-17 19:33:52.000000000 +0000 @@ -43,6 +43,7 @@ about-networking-dns-lookup-button = Résolution about-networking-dns-domain = Domaine: about-networking-dns-lookup-table-column = Adresses IP +about-networking-dns-https-rr-lookup-table-column = RR HTTP about-networking-rcwn = Statistiques RCWN about-networking-rcwn-status = État RCWN about-networking-rcwn-cache-won-count = Nombre de victoires du cache diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/fr/toolkit/toolkit/about/aboutProcesses.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/fr/toolkit/toolkit/about/aboutProcesses.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/fr/toolkit/toolkit/about/aboutProcesses.ftl 2020-11-15 14:41:03.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/fr/toolkit/toolkit/about/aboutProcesses.ftl 2020-11-17 19:33:52.000000000 +0000 @@ -36,6 +36,7 @@ about-processes-privilegedabout-process-name = À propos (processus { $pid }) about-processes-plugin-process-name = Plugins (processus { $pid }) about-processes-privilegedmozilla-process-name = Web (processus { $pid }) pour les sites de { -vendor-short-name }) +about-processes-gmp-plugin-process-name = Plugins multimédia Gecko (processus { $pid }) about-processes-gpu-process-name = GPU (processus { $pid }) about-processes-vr-process-name = Réalité virtuelle (processus { $pid }) about-processes-rdd-process-name = Décodeur de données (processus { $pid }) diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/gn/toolkit/chrome/global/intl.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/gn/toolkit/chrome/global/intl.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/gn/toolkit/chrome/global/intl.properties 2020-11-15 14:41:19.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/gn/toolkit/chrome/global/intl.properties 2020-11-17 19:34:07.000000000 +0000 @@ -5,7 +5,7 @@ # LOCALIZATION NOTE (intl.accept_languages): # This is a comma-separated list of valid BCP 47 language tags. # -# Begin with the value of 'general.useragent.locale'. Next, include language +# Begin with the language tag of your locale. Next, include language # tags for other languages that you expect most users of your locale to be # able to speak, so that their browsing experience degrades gracefully if # content is not available in their primary language. @@ -20,14 +20,14 @@ # British English in their list, since those languages are commonly spoken in # the same area as Breton: # intl.accept_languages=br, fr-FR, fr, en-GB, en -intl.accept_languages=gn, es, en, en-US +intl.accept_languages=gn, es, en-US, en # LOCALIZATION NOTE (font.language.group): # This preference controls the initial setting of the language drop-down menu -# in the Content > Fonts & Colors > Advanced preference panel. +# in the Fonts and Colors > Advanced preference panel. # # Set it to the value of one of the menuitems in the "selectLangs" menulist in -# http://dxr.mozilla.org/mozilla-central/source/browser/components/preferences/fonts.xul +# http://searchfox.org/mozilla-central/source/browser/components/preferences/dialogs/fonts.xhtml font.language.group=x-western # LOCALIZATION NOTE (intl.charset.detector): diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/hr/browser/browser/newtab/newtab.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/hr/browser/browser/newtab/newtab.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/hr/browser/browser/newtab/newtab.ftl 2020-11-15 14:41:32.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/hr/browser/browser/newtab/newtab.ftl 2020-11-17 19:34:20.000000000 +0000 @@ -149,7 +149,7 @@ ## Section Menu: These strings are displayed in the section context menu and are ## meant as a call to action for the given section. -newtab-section-menu-remove-section = Ukloni odjel +newtab-section-menu-remove-section = Ukloni odjeljak newtab-section-menu-collapse-section = Sklopi odjeljak newtab-section-menu-expand-section = Rasklopi odjeljak newtab-section-menu-manage-section = Upravljaj odjeljkom diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/browser/browser/browser.ftl 2020-11-15 14:41:44.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/browser/browser/browser.ftl 2020-11-17 19:34:33.000000000 +0000 @@ -348,9 +348,10 @@ ## Bookmarks toolbar items -browser-import-button = +browser-import-button2 = .label = Importar marcapaginas… - .tooltiptext = Copia le marcapaginas de un altere navigator a { -brand-short-name }. + .tooltiptext = Importar le marcapaginas de un altere navigator in { -brand-short-name }. +bookmarks-toolbar-empty-message = Pro accesso rapide, placia tu marcapaginas sur iste barra. Gerer marcapaginas… ## WebRTC Pop-up notifications diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/browser/browser/newtab/asrouter.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/browser/browser/newtab/asrouter.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/browser/browser/newtab/asrouter.ftl 2020-11-15 14:41:44.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/browser/browser/newtab/asrouter.ftl 2020-11-17 19:34:33.000000000 +0000 @@ -7,7 +7,7 @@ cfr-doorhanger-extension-heading = Extension recommendate cfr-doorhanger-feature-heading = Function recommendate -cfr-doorhanger-pintab-heading = Prova isto: Fixar scheda +cfr-doorhanger-pintab-heading = Prova isto: Clavar le scheda ## @@ -17,8 +17,8 @@ .accesskey = N cfr-doorhanger-extension-ok-button = Adder ora .accesskey = A -cfr-doorhanger-pintab-ok-button = Fixar iste scheda - .accesskey = F +cfr-doorhanger-pintab-ok-button = Clavar iste scheda + .accesskey = C cfr-doorhanger-extension-manage-settings-button = Gerer le configurationes de recommendation .accesskey = G cfr-doorhanger-extension-never-show-recommendation = Non monstrar me iste recommendation @@ -63,8 +63,8 @@ ## These messages are steps on how to use the feature and are shown together. -cfr-doorhanger-pintab-step1 = Face clic dextre sur le scheda que tu vole fixar. -cfr-doorhanger-pintab-step2 = Elige Fixar scheda in le menu. +cfr-doorhanger-pintab-step1 = Face clic dextre sur le scheda que tu vole clavar. +cfr-doorhanger-pintab-step2 = Elige Clavar le scheda in le menu. cfr-doorhanger-pintab-step3 = Si le sito se actualisa, un puncto blau apparera sur le scheda fixate. cfr-doorhanger-pintab-animation-pause = Pausar cfr-doorhanger-pintab-animation-resume = Reprender @@ -257,8 +257,6 @@ .accesskey = a cfr-doorhanger-fission-secondary-button = Saper plus .accesskey = S -# Deprecated -cfr-doorhanger-fission-body = { -brand-short-name } ha activate un function experimental pro te: Fission (isolamento de sitos). Isolante cata sito in un processo separate, Fission forni un strato additional de securitate pro te e pro le sitos web que tu visita. ## What's new: Cookies message diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/browser/browser/preferences/preferences.ftl 2020-11-15 14:41:44.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/browser/browser/preferences/preferences.ftl 2020-11-17 19:34:33.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = Proceder con cautela pane-experimental-search-results-header = Experimentos { -brand-short-name }: continuar con attention pane-experimental-description = Cambiar le preferentias avantiate de configuration pote haber impacto sur le prestationes e le securitate de { -brand-short-name }. +pane-experimental-reset = + .label = Restaurar predefinitiones + .accesskey = R help-button-label = Assistentia de { -brand-short-name } addons-button-label = Extensiones e themas focus-search = @@ -929,6 +932,7 @@ content-blocking-enhanced-tracking-protection = Protection antitraciamento reinfortiate content-blocking-section-top-level-description = Le traciatores te seque per tote le rete pro colliger informationes sur tu habitos e interesses de navigation. { -brand-short-name } bloca multes de iste traciatores e altere scripts maligne. content-blocking-learn-more = Saper plus +content-blocking-fpi-incompatibility-warning = Tu usa First Party Isolation (FPI) que supplanta alcunes del parametros de cookies de { -brand-short-name }. ## These strings are used to define the different levels of ## Enhanced Tracking Protection. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/browser/browser/tabContextMenu.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/browser/browser/tabContextMenu.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/browser/browser/tabContextMenu.ftl 2020-11-15 14:41:44.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/browser/browser/tabContextMenu.ftl 2020-11-17 19:34:33.000000000 +0000 @@ -30,7 +30,7 @@ .label = Disclavar le scheda .accesskey = v pin-selected-tabs = - .label = Fixar le schedas + .label = Clavar le schedas .accesskey = F unpin-selected-tabs = .label = Liberar le schedas diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/toolkit/toolkit/featuregates/features.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/toolkit/toolkit/featuregates/features.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ia/toolkit/toolkit/featuregates/features.ftl 2020-11-15 14:41:44.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ia/toolkit/toolkit/featuregates/features.ftl 2020-11-17 19:34:33.000000000 +0000 @@ -82,10 +82,6 @@ .label = Utensiles de disveloppator: depuration de obrero de servicio # "Service Worker" is an API name and is usually not translated. experimental-features-devtools-serviceworker-debugger-support-description = Activa supporto experimental pro Service Workers in le quadro Depurator. Iste function pote relentar le Utensiles de disveloppator e augmentar le consumption de memoria. -# Desktop zooming experiment -experimental-features-graphics-desktop-zooming = - .label = Graphica: zoom a prisa lisie -experimental-features-graphics-desktop-zooming-description = Activa le supporto al zoom a prisa lisie sur schermos tactile e placas tactile de precision. # WebRTC global mute toggle controls experimental-features-webrtc-global-mute-toggles = .label = Activar/disactivar audio e video WebRTC globalmente @@ -98,3 +94,7 @@ experimental-features-fission = .label = Fission (Isolation de sitos) experimental-features-fission-description = Fission (isolamento de sitos) es un function experimental in { -brand-short-name } que forni un strato additional de defensa contra defectos de securitate. Isolante cata sito in un processo separate, Fission rende plus difficile pro sitos web maligne acceder a informationes de altere paginas que tu visita. Isto es un grande cambiamento architectural in { -brand-short-name } e nos multo appreciarea tu adjuta a testar isto e reportar omne problemas que tu incontra. Pro plus detalios, vider le wiki. +# Support for having multiple Picture-in-Picture windows open simultaneously +experimental-features-multi-pip = + .label = Plure fenestras imagine-in-imagine +experimental-features-multi-pip-description = Function experimental que permitte aperir plure fenestras imagine-in-imagine al mesme tempore. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ka/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ka/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ka/browser/browser/preferences/preferences.ftl 2020-11-15 14:42:04.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ka/browser/browser/preferences/preferences.ftl 2020-11-17 19:34:53.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = გამოიყენეთ სიფრთხილით pane-experimental-search-results-header = { -brand-short-name } ცდები: გამოიყენეთ სიფრთხილით pane-experimental-description = გაფართოებული პარამეტრების შეცვლით, შესაძლოა დაზიანდეს { -brand-short-name } წარმადობის ან უსაფრთხოების კუთხით. +pane-experimental-reset = + .label = ნაგულისხმევის აღდგენა + .accesskey = უ help-button-label = { -brand-short-name } დახმარება addons-button-label = გაფართოებები და თემები focus-search = @@ -929,6 +932,7 @@ content-blocking-enhanced-tracking-protection = თვალთვალისგან გაძლიერებული დაცვა content-blocking-section-top-level-description = მეთვალყურეები თან დაგყვებათ მთელ ინტერნეტში და აგროვებს ინფორმაციას თქვენი ჩვევებისა და მისწრაფებების შესახებ. { -brand-short-name } ზღუდავს ამ მეთვალყურეების უმეტესობასა და სხვა მავნე კოდებსაც. content-blocking-learn-more = ვრცლად +content-blocking-fpi-incompatibility-warning = თქვენ იყენებთ პირველი მხარის გამიჯვნას (FPI), რომლითაც { -brand-short-name } ანაცვლებს ფუნთუშების ზოგიერთ პარამეტრს. ## These strings are used to define the different levels of ## Enhanced Tracking Protection. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ka/toolkit/toolkit/featuregates/features.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ka/toolkit/toolkit/featuregates/features.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ka/toolkit/toolkit/featuregates/features.ftl 2020-11-15 14:42:04.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ka/toolkit/toolkit/featuregates/features.ftl 2020-11-17 19:34:53.000000000 +0000 @@ -82,10 +82,6 @@ .label = Developer Tools: Service Worker debugging # "Service Worker" is an API name and is usually not translated. experimental-features-devtools-serviceworker-debugger-support-description = ჩართავს საცდელ მხარდაჭერას Service Workers-ისთვის გასამართ არეში. შესაძლოა, ამ შესაძლებლობამ შეანელოს Developer Tools და გაზარდოს მეხსიერების მოხმარება. -# Desktop zooming experiment -experimental-features-graphics-desktop-zooming = - .label = გრაფიკა: Smooth Pinch Zoom -experimental-features-graphics-desktop-zooming-description = ჩართვა თითების ჟესტებით გლუვი მოახლოების, შეხების აღმქმელი ეკრანებისა და დაფებისთვის. # WebRTC global mute toggle controls experimental-features-webrtc-global-mute-toggles = .label = WebRTC Global Mute Toggles @@ -98,3 +94,7 @@ experimental-features-fission = .label = Fission (საიტის გამიჯვნა) experimental-features-fission-description = Fission (საიტის გამიჯვნა) არის ახალი საცდელი შესაძლებლობა, რომლითაც { -brand-short-name } გთავაზობთ დაცვის დამატებით ფენას, უსაფრთხოების სისუსტეების წინააღმდეგ. თითოეული საიტის ცალ-ცალკე პროცესებად გაშვებით, Fission ურთულებს მავნე ვებსაიტებს, სხვა მონახულებულ გვერდებთან წვდომას. ჩვენ და { -brand-short-name } მეტად მოხარულნი ვიქნებით, თუ გამოცდით და მოგვახსენებთ ხარვეზებს, რომელთაც წააწყდებით. ვრცლად, დამატებით იხილეთ ვიკი. +# Support for having multiple Picture-in-Picture windows open simultaneously +experimental-features-multi-pip = + .label = რამდენიმე ეკრანი-ეკრანში მხარდაჭერა +experimental-features-multi-pip-description = საცდელი შესაძლებლობა, რომელიც ეკრანი-ეკრანში რეჟიმით, ერთდროულად რამდენიმე ფანჯრის გამოტანის საშუალებას იძლევა. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/kab/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/kab/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/kab/browser/browser/preferences/preferences.ftl 2020-11-15 14:42:07.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/kab/browser/browser/preferences/preferences.ftl 2020-11-17 19:34:56.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = Kemmel, maca ɣur-k. pane-experimental-search-results-header = { -brand-short-name } Tirma: ddu kan s leεqel pane-experimental-description = Abeddel n yismenyifen n twila leqqayen zemren ad ḥazen tamlellit neɣ taɣellist n { -brand-short-name }. +pane-experimental-reset = + .label = Err-d iɣewwaren imezwer + .accesskey = R help-button-label = { -brand-short-name } Tallelt addons-button-label = Isiɣzaf akked yisental focus-search = diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/ko/browser/browser/toolbarContextMenu.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/ko/browser/browser/toolbarContextMenu.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/ko/browser/browser/toolbarContextMenu.ftl 2020-11-15 14:42:20.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/ko/browser/browser/toolbarContextMenu.ftl 2020-11-17 19:35:08.000000000 +0000 @@ -52,11 +52,11 @@ .label = 사용자 지정… .accesskey = C toolbar-context-menu-bookmarks-toolbar-always-show = - .label = 항상 + .label = 항상 표시 .accesskey = A toolbar-context-menu-bookmarks-toolbar-never-show = - .label = 안 함 + .label = 표시 안 함 .accesskey = N toolbar-context-menu-bookmarks-toolbar-on-new-tab = - .label = 새 탭에서만 + .label = 새 탭에서만 표시 .accesskey = O diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/lv/chat/xmpp.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/lv/chat/xmpp.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/lv/chat/xmpp.properties 2020-11-15 14:42:29.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/lv/chat/xmpp.properties 2020-11-17 19:35:18.000000000 +0000 @@ -252,7 +252,7 @@ # This is displayed inside the accountUsernameInfoWithDescription # string defined in imAccounts.properties when the user is # configuring a Google Talk account. -gtalk.usernameHint=e-pasta adrese +gtalk.usernameHint=epasta adrese # LOCALIZATION NOTE (odnoklassniki.usernameHint): # This is displayed inside the accountUsernameInfoWithDescription diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/my/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/my/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/my/browser/browser/browser.ftl 2020-11-15 14:42:42.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/my/browser/browser/browser.ftl 2020-11-17 19:35:30.000000000 +0000 @@ -23,7 +23,7 @@ # there is no content title: # # "default" - "Mozilla Firefox" -# "private" - "Mozilla Firefox - (Private Browsing)" +# "private" - "Mozilla Firefox — (Private Browsing)" # # The last two are for use when there *is* a content title. # Do not use the brand name in the last two attributes, as we do on non-macOS. @@ -188,7 +188,7 @@ ## Search Engine selection buttons (one-offs) -# This string prompts the user to use the list of one-click search engines in +# This string prompts the user to use the list of search shortcuts in # the Urlbar and searchbar. search-one-offs-with-title = ယခုအကြိမ် ရှာဖွေလိုက်သည်မှာ # This string won't wrap, so if the translated string is longer, @@ -234,6 +234,7 @@ ## Identity Panel identity-connection-not-secure = ချိတ်ဆက်မှုသည် မလုံခြုံပါ +identity-connection-secure = ချိတ်ဆက်မှု လုံခြုံသည် identity-connection-internal = ဒီ စာမျက်နှာ { -brand-short-name } သည် လုံခြုံစိတ်ချရသည်။ identity-connection-file = ဒီစာမျက်နှာကို သင့်ကွန်ပျူတာတွင် သိမ်းထားသည်။ identity-extension-page = ယခုစာမျက်နှာကို တိုးချဲ့ဆော့ဖ်ဝဲထံမှ ဖွင့်ထားသည်။ @@ -242,6 +243,8 @@ identity-active-loaded = ဒီစာမျက်နှာတွင် သင်သည် ကာကွယ်မှုကို ပိတ်ထားသည်။ identity-weak-encryption = ဒီစာမျက်နှာသည် အားနည်းသည့် ဝှက်စာစနစ်ကို သုံးထားသည်။ identity-insecure-login-forms = ဒီစာမျက်နှာကို ဝင်ရောက်ရာတွင် အသုံးပြုသည့် အချက်အလက်များသည် တိုက်ခိုက်ခိုးယူခံရနိုင်သည်။ +identity-https-only-dropdown-on = + .label = ဖွင့် identity-permissions = .value = ခွင့်ပြုချက်များ identity-permissions-reload-hint = ပြောင်းလဲထားသည့် အပြင်အဆင်များ သက်ရောက်မှုရှိစေရန်အတွက် ယခုစာမျက်နှာကို ပြန်လည်ခေါ်ယူရန် လိုအပ်ကောင်း လိုအပ်နိုင်ပါသည်။ @@ -284,6 +287,9 @@ browser-window-close-button = .tooltiptext = ပိတ်ပါ +## Bookmarks toolbar items + + ## WebRTC Pop-up notifications popup-select-camera = diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/nl/browser/browser/browser.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/nl/browser/browser/browser.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/nl/browser/browser/browser.ftl 2020-11-15 14:42:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/nl/browser/browser/browser.ftl 2020-11-17 19:35:40.000000000 +0000 @@ -353,6 +353,7 @@ browser-import-button2 = .label = Bladwijzers importeren… .tooltiptext = Bladwijzers uit een andere browser naar { -brand-short-name } importeren. +bookmarks-toolbar-empty-message = Plaats voor snelle toegang uw bladwijzers hier op de bladwijzerwerkbalk. Bladwijzers beheren… ## WebRTC Pop-up notifications diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/nl/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/nl/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/nl/browser/browser/preferences/preferences.ftl 2020-11-15 14:42:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/nl/browser/browser/preferences/preferences.ftl 2020-11-17 19:35:40.000000000 +0000 @@ -52,6 +52,9 @@ pane-experimental-subtitle = Ga voorzichtig verder pane-experimental-search-results-header = { -brand-short-name }-experimenten: voorzichtigheid geadviseerd pane-experimental-description = Het wijzigen van geavanceerde configuratievoorkeuren kan de prestaties of veiligheid van { -brand-short-name } beïnvloeden. +pane-experimental-reset = + .label = Standaardwaarden herstellen + .accesskey = h help-button-label = { -brand-short-name } Support addons-button-label = Extensies & Thema’s focus-search = @@ -929,6 +932,7 @@ content-blocking-enhanced-tracking-protection = Verbeterde bescherming tegen volgen content-blocking-section-top-level-description = Trackers volgen u online om gegevens over uw surfgedrag en interesses te verzamelen. { -brand-short-name } blokkeert veel van deze trackers en andere kwaadwillende scripts. content-blocking-learn-more = Meer info +content-blocking-fpi-incompatibility-warning = U gebruikt First Party Isolation (FPI), dat een aantal cookie-instellingen van { -brand-short-name } overschrijft. ## These strings are used to define the different levels of ## Enhanced Tracking Protection. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/nl/toolkit/toolkit/featuregates/features.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/nl/toolkit/toolkit/featuregates/features.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/nl/toolkit/toolkit/featuregates/features.ftl 2020-11-15 14:42:52.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/nl/toolkit/toolkit/featuregates/features.ftl 2020-11-17 19:35:40.000000000 +0000 @@ -82,10 +82,6 @@ .label = Developer Tools: Service Worker debugging # "Service Worker" is an API name and is usually not translated. experimental-features-devtools-serviceworker-debugger-support-description = Schakelt in het Debugger-paneel experimentele ondersteuning voor service workers in. Deze functie kan hulpmiddelen voor webontwikkelaars vertragen en het geheugengebruik verhogen. -# Desktop zooming experiment -experimental-features-graphics-desktop-zooming = - .label = Grafisch: Smooth Pinch Zoom -experimental-features-graphics-desktop-zooming-description = Schakel ondersteuning in voor soepel zoomen door knijpen op aanraakschermen en precisie-touchpads. # WebRTC global mute toggle controls experimental-features-webrtc-global-mute-toggles = .label = WebRTC Global Mute-schakelaars @@ -98,3 +94,7 @@ experimental-features-fission = .label = Fission (website-isolatie) experimental-features-fission-description = Fission (website-isolatie) is een experimentele functie in { -brand-short-name } die een extra beschermingslaag biedt tegen beveiligingsbugs. Door elke website in een apart proces te isoleren, maakt Fission het moeilijker voor kwaadwillende websites om toegang te verkrijgen tot informatie van andere door u bezochte pagina’s. Dit is een grote wijziging in de architectuur van { -brand-short-name } en we stellen het op prijs als u het test en alle problemen die u tegenkomt rapporteert. Voor meer details, zie de wiki. +# Support for having multiple Picture-in-Picture windows open simultaneously +experimental-features-multi-pip = + .label = Ondersteuning voor meerdere Picture-in-picture +experimental-features-multi-pip-description = Experimentele ondersteuning voor gelijktijdig openen van meerdere Picture-in-Picturevensters. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/browser/nsserrors.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/browser/nsserrors.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/browser/nsserrors.ftl 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/browser/nsserrors.ftl 2020-11-17 19:35:47.000000000 +0000 @@ -11,7 +11,7 @@ # Variables: # $hostname (String) - Hostname of the website with SSL error. # $errorMessage (String) - Error message corresponding to the type of error we are experiencing. -ssl-connection-error = Una error s'es produita pendent una connexion a { $hostname }. { $errorMessage } +ssl-connection-error = Una error s'es producha pendent una connexion a { $hostname }. { $errorMessage } # Variables: # $error (string) - NSS error code string that specifies type of cert error. e.g. unknown issuer, invalid cert, etc. cert-error-code-prefix = Còdi d’error : { $error } @@ -158,7 +158,7 @@ ssl-error-unsupported-signature-algorithm = Lo par a utilizat una combinason non presa en carga de signatura e d’algoritme de trissatge. ssl-error-missing-extended-master-secret = Lo par a ensajat de tornar sens extension extended_master_secret corrècta. ssl-error-unexpected-extended-master-secret = Lo par a ensajat de tornar amb una extension extended_master_secret imprevista. -sec-error-io = Una error d'entrada/sortida s'es produita pendent l'autorizacion de seguretat. +sec-error-io = Una error d'entrada/sortida s'es producha pendent l'autorizacion de seguretat. sec-error-library-failure = Fracàs de la bibliotèca de seguretat. sec-error-bad-data = Bibliotèca de seguretat : donadas incorrèctas recebudas. sec-error-output-len = Bibliotèca de seguretat : error de longor de las donadas en sortida. @@ -324,10 +324,10 @@ sec-error-bad-ldap-response = Lo servidor a renviat una marrida responsa LDAP sec-error-failed-to-encode-data = Fracàs de l'encodatge de donadas amb l'encodador ASN1 sec-error-bad-info-access-location = Marrida informacion d'emplaçament d'accès dins l'extension de certificat -sec-error-libpkix-internal = Una error intèrna libpkix s'es produita pendent la validacion de certificat. -sec-error-pkcs11-general-error = Un modul PKCS #11 a renviat CKR_GENERAL_ERROR, qu'indica qu'una error irrecuperabla s'es produita. +sec-error-libpkix-internal = Una error intèrna libpkix s'es producha pendent la validacion de certificat. +sec-error-pkcs11-general-error = Un modul PKCS #11 a renviat CKR_GENERAL_ERROR, qu'indica qu'una error irrecuperabla s'es producha. sec-error-pkcs11-function-failed = Un modul PKCS #11 a renviat CKR_FUNCTION_FAILED, qu'indican que la foncion demandada podiá pas èsser realizada. Ensajar tornarmai la meteissa operacion poiriá foncionar. -sec-error-pkcs11-device-error = Un modul PKCS #11 a renviat CKR_DEVICE_ERROR, qu'indica qu'un problèma amb lo geton o lo slot s'es produit. +sec-error-pkcs11-device-error = Un modul PKCS #11 a renviat CKR_DEVICE_ERROR, qu'indica qu'un problèma amb lo geton o lo slot s'es produch. sec-error-bad-info-access-method = Metòde d'accès a l'informacion desconeguda dins l'extension de certificat. sec-error-crl-import-failed = Error al moment de la temptativa d'importacion d'una lista de revocacion de certificat (CRL). sec-error-expired-password = Lo senhal a expirat. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/browser/preferences/preferences.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/browser/preferences/preferences.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/browser/preferences/preferences.ftl 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/browser/preferences/preferences.ftl 2020-11-17 19:35:47.000000000 +0000 @@ -165,7 +165,7 @@ .label = En dobrissent un ligam dins un onglet novèl, i anar sul pic .accesskey = d show-tabs-in-taskbar = - .label = Afichar los apercebuts d'onglets dins la barra dels prètzfaits de Windows + .label = Afichar los apercebuts d'onglets dins la barra dels prètzfaches de Windows .accesskey = c browser-containers-enabled = .label = Activar los onglets de contenidor diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/chrome/browser/browser.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/chrome/browser/browser.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/chrome/browser/browser.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/chrome/browser/browser.properties 2020-11-17 19:35:47.000000000 +0000 @@ -977,10 +977,10 @@ decoder.noPulseAudio.message = Per legir l'àudio, benlèu vos cal installar lo logicial PulseAudio necessari. decoder.unsupportedLibavcodec.message = Lo libavcodec es benlèu vulnerable o non compatible, e deuriatz l'actualizar per legir la vidèo. -decoder.decodeError.message = Una error s'es produita pendent lo descodatge d'una font mèdia. +decoder.decodeError.message = Una error s'es producha pendent lo descodatge d'una font mèdia. decoder.decodeError.button = Reportar lo problèma del site decoder.decodeError.accesskey = R -decoder.decodeWarning.message = Una error corregibla s'es produita pendent lo descodatge d'una font mèdia. +decoder.decodeWarning.message = Una error corregibla s'es producha pendent lo descodatge d'una font mèdia. # LOCALIZATION NOTE (captivePortal.infoMessage3): # Shown in a notification bar when we detect a captive portal is blocking network access diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/chrome/browser/pocket.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/chrome/browser/pocket.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/chrome/browser/pocket.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/chrome/browser/pocket.properties 2020-11-17 19:35:47.000000000 +0000 @@ -4,7 +4,7 @@ addtags = Apondre d'etiquetas alreadyhaveacct = Avètz ja un compte dins Pocket ? -errorgeneric = Una error s'es produita en ensajant d'enregistrar dins Pocket. +errorgeneric = Una error s'es producha en ensajant d'enregistrar dins Pocket. learnmore = Ne saber mai loginnow = Dobrir una session maxtaglength = Las etiquetas an un limit de 25 caractèrs @@ -28,4 +28,3 @@ tryitnow = Ensajatz-lo ara signupfirefox = Se marcar amb Firefox viewlist = Afichar la lista - diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/pdfviewer/viewer.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/pdfviewer/viewer.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/browser/pdfviewer/viewer.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/browser/pdfviewer/viewer.properties 2020-11-17 19:35:47.000000000 +0000 @@ -214,7 +214,7 @@ error_file=Fichièr : {{file}} # LOCALIZATION NOTE (error_line): "{{line}}" will be replaced with a line number error_line=Linha : {{line}} -rendering_error=Una error s'es produita pendent l'afichatge de la pagina. +rendering_error=Una error s'es producha pendent l'afichatge de la pagina. # Predefined zoom values page_scale_width=Largor plena @@ -227,7 +227,7 @@ # Loading indicator messages loading_error_indicator=Error -loading_error=Una error s'es produita pendent lo cargament del fichièr PDF. +loading_error=Una error s'es producha pendent lo cargament del fichièr PDF. invalid_file_error=Fichièr PDF invalid o corromput. missing_file_error=Fichièr PDF mancant. unexpected_response_error=Responsa de servidor imprevista. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/devtools/client/netmonitor.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/devtools/client/netmonitor.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/devtools/client/netmonitor.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/devtools/client/netmonitor.properties 2020-11-17 19:35:47.000000000 +0000 @@ -1131,7 +1131,7 @@ # LOCALIZATION NOTE (netmonitor.security.error): This is the label displayed # in the security tab if a security error prevented the connection. -netmonitor.security.error=Una error s'es produita : +netmonitor.security.error=Una error s'es producha : # LOCALIZATION NOTE (netmonitor.security.protocolVersion): This is the label displayed # in the security tab describing TLS/SSL protocol version. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/dom/dom.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/dom/dom.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/dom/dom.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/dom/dom.properties 2020-11-17 19:35:47.000000000 +0000 @@ -89,11 +89,11 @@ TimeoutSyncXHRWarning=L'utilizacion de l'atribut « timeout » dins XMLHttpRequest es pas mai gerida en mòde sincròn dins lo contèxte de fenèstra. # LOCALIZATION NOTE: Do not translate navigator.sendBeacon, unload, pagehide, or XMLHttpRequest. UseSendBeaconDuringUnloadAndPagehideWarning=L’utilizacion de navigator.sendBeacon allòc de XMLHttpRequest sincrnòm pendent lo descargament e mascatge de la pagina melhora l’experiéncia de l’utilizaire. -JSONCharsetWarning=Una temptativa es estada faita per declarar un encodatge non UTF-8 per de JSON recuperat en utilizant XMLHttpRequest. Sol UTF-8 es gerit pel desencodatge de JSON. +JSONCharsetWarning=Una temptativa es estada facha per declarar un encodatge non UTF-8 per de JSON recuperat en utilizant XMLHttpRequest. Sol UTF-8 es gerit pel desencodatge de JSON. # LOCALIZATION NOTE: Do not translate decodeAudioData. MediaDecodeAudioDataUnknownContentType=Las donadas passadas a decodeAudioData possedisson de contengut de tipe desconegut. # LOCALIZATION NOTE: Do not translate decodeAudioData. -MediaDecodeAudioDataUnknownError=Una error desconeguda s'es produita al moment del tractament de decodeAudioData. +MediaDecodeAudioDataUnknownError=Una error desconeguda s'es producha al moment del tractament de decodeAudioData. # LOCALIZATION NOTE: Do not translate decodeAudioData. MediaDecodeAudioDataInvalidContent=Las donadas passadas a decodeAudioData possedisson de contengut invalid que pòt pas èsser desencodat. # LOCALIZATION NOTE: Do not translate decodeAudioData. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/global-strres.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/global-strres.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/global-strres.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/global-strres.properties 2020-11-17 19:35:47.000000000 +0000 @@ -2,4 +2,4 @@ # 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/. -16389=Una error desconeguda s'es produita (%1$S). +16389=Una error desconeguda s'es producha (%1$S). diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/layout/layout_errors.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/layout/layout_errors.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/layout/layout_errors.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/layout/layout_errors.properties 2020-11-17 19:35:47.000000000 +0000 @@ -8,7 +8,7 @@ ImageMapPolyWrongNumberOfCoords=L'atribut « coords » de la balisa es pas al format « x1,y1,x2,y2 … ». ImageMapPolyOddNumberOfCoords=L'atribut « coords » de la balisa conten pas la darrièra coordenada « y » (lo format corrècte es u00ab x1,y1,x2,y2 … »). -TablePartRelPosWarning=Lo posicionament relatiu de las linhas de tablèu e dels gropes de linhas es d'ara enlà pres en carga. Aqueste site pòt aver besonh d'èsser mes a jorn se repausa sul fait qu'aquesta foncionalitat a pas cap d'efèit. +TablePartRelPosWarning=Lo posicionament relatiu de las linhas de tablèu e dels gropes de linhas es d'ara enlà pres en carga. Aqueste site pòt aver besonh d'èsser mes a jorn se repausa sul facha qu'aquesta foncionalitat a pas cap d'efèit. ScrollLinkedEffectFound2=Sembla qu'aqueste site utiliza un efièch de posicionament ligat al desfialament. Aqueste efièch poiriá foncionar pas coma cal amb lo desfialament asincròn ; veire https://developer.mozilla.org/docs/Mozilla/Performance/ScrollLinkedEffects per saber mai de detalhs o discutir de las aisinas e foncionalitats ligadas ! ## LOCALIZATION NOTE(CompositorAnimationWarningContentTooLargeArea): diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/layout/printing.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/layout/printing.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/layout/printing.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/layout/printing.properties 2020-11-17 19:35:47.000000000 +0000 @@ -4,7 +4,7 @@ # Page number formatting ## @page_number The current page number -#LOCALIZATION NOTE (pageofpages): Do not translate %ld in the following line. +#LOCALIZATION NOTE (pagenumber): Do not translate %ld in the following line. # Place the word %ld where the page number and number of pages should be # The first %ld will receive the the page number pagenumber=%1$d @@ -37,7 +37,7 @@ # printing, and PERR_FAILURE_PP will be used under the same conditions # when print previewing. # -PERR_FAILURE=Una error desconeguda s'es produita pendent l'impression. +PERR_FAILURE=Una error desconeguda s'es producha pendent l'impression. PERR_ABORT=Lo trabalh d'impression es estada arrestada o anullada. PERR_NOT_AVAILABLE=D'unas foncionalitats d'impression son pas disponiblas. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/security/csp.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/security/csp.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/security/csp.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/security/csp.properties 2020-11-17 19:35:47.000000000 +0000 @@ -12,7 +12,7 @@ CSPViolationWithURI = Los paramètres de la pagina an empachat lo cargament d'una ressorsa a %2$S (« %1$S »). # LOCALIZATION NOTE (CSPROViolation): # %1$S is the reason why the resource has not been loaded. -CSPROViolation = S'es produita una violacion d'una politica CSP de tipe «Report-Only» (“%1$S”). S'a permes lo compòrtament e s'es mandat un rapòrt CSP. +CSPROViolation = S'es producha una violacion d'una politica CSP de tipe «Report-Only» (“%1$S”). S'a permes lo compòrtament e s'es mandat un rapòrt CSP. # LOCALIZATION NOTE (CSPROViolationWithURI): # %1$S is the directive that has been violated. # %2$S is the URI of the resource which violated the directive. @@ -74,7 +74,7 @@ # %1$S is the URL of the blocked resource load. blockAllMixedContent = La requèsta non securizada « %1$S » es estat blocada. # LOCALIZATION NOTE (ignoringDirectiveWithNoValues): -# %1$S is the name of a CSP directive that requires additional values +# %1$S is the name of a CSP directive that requires additional values ignoringDirectiveWithNoValues = La directiva « %1$S » es estada ignorada, pr’amor que possedís pas cap de paramètre. # LOCALIZATION NOTE (ignoringReportOnlyDirective): # %1$S is the directive that is ignored in report-only mode. @@ -83,7 +83,6 @@ # %1$S is the name of the src that is ignored. # %2$S is the name of the directive that causes the src to be ignored. IgnoringSrcBecauseOfDirective=« %1$S » ignorat a causa de la directiva « %2$S ». - # LOCALIZATION NOTE (IgnoringSourceWithinDirective): # %1$S is the ignored src # %2$S is the directive which supports src diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/security/security.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/security/security.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/security/security.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/security/security.properties 2020-11-17 19:35:47.000000000 +0000 @@ -26,7 +26,7 @@ CORSMissingAllowHeaderFromPreflight2=Blocatge d'una requèsta multi-originas (Cross-Origin Request) : la politica « Same Origin » permet pas de consultar la ressorsa distanta situada sus %1$S. (Rason : l'entèsta « %2$S » es pas autorizada segon l'entèsta « Access-Control-Allow-Headers » de la responsa de contraròtle en amont CORS.) # LOCALIZATION NOTE: Do not translate "Strict-Transport-Security", "HSTS", "max-age" or "includeSubDomains" -STSUnknownError=Strict-Transport-Security : una error desconeguda s’es produita pendent lo tractament de l’entèsta especificada pel site. +STSUnknownError=Strict-Transport-Security : una error desconeguda s’es producha pendent lo tractament de l’entèsta especificada pel site. STSUntrustworthyConnection=Strict-Transport-Security: la connexion al site es pas digne de fisança, l’entèsta especificada a estat ignorat. STSCouldNotParseHeader=Strict-Transport-Security : lo site a especificat una entèsta qu’a pas pogut èsser analizat coma cal. STSNoMaxAge=Strict-Transport-Security : lo site a especificat un entèsta qu'inclusís pas de directiva « max-age ». @@ -34,7 +34,7 @@ STSInvalidMaxAge=Strict-Transport-Security : lo site a especificat un entèsta que possedís una directiva « max-age » invalida. STSMultipleIncludeSubdomains=Strict-Transport-Security : lo site a especificat un entèsta que possedís mai d'una directiva « includeSubDomains ». STSInvalidIncludeSubdomains=Strict-Transport-Security : lo site a especificat un entèsta que possedís una directiva « includeSubDomains » invalida. -STSCouldNotSaveState=Strict-Transport-Security : una error s’es produita marcant lo site coma òste Strict-Transport-Security. +STSCouldNotSaveState=Strict-Transport-Security : una error s’es producha marcant lo site coma òste Strict-Transport-Security. # LOCALIZATION NOTE: Do not translate "SHA-1" SHA1Sig=Aqueste site utiliza un certificat SHA-1 ; se recomanda d’utilizar de certificats que possedisson d'algoritmes de signatura qu'ajan recors a de foncions de tissatge mai solidas que SHA-1. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/xslt/xslt.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/xslt/xslt.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/dom/chrome/xslt/xslt.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/dom/chrome/xslt/xslt.properties 2020-11-17 19:35:47.000000000 +0000 @@ -4,14 +4,14 @@ 1 = Fracàs de l'analisi d'un fuèlh d'estil XSLT. 2 = Fracàs de l'analisi d'una expression XPath. -3 = +3 = 4 = Fracàs de transformacion XSLT. 5 = Foncion XSLT/XPath invalida. 6 = Lo fuèlh d'estil XSLT conten (probablament) una bocla. 7 = Valor d'atribut illegala en XSLT 1.0. 8 = Un NodeSet èra esperat en retorn d'una expression XPath. 9 = Una transformacion XSLT s'es acabada per . -10 = Una error de ret s'es produita al moment del cargament d'un fuèlh d'estil XSLT : +10 = Una error de ret s'es producha al moment del cargament d'un fuèlh d'estil XSLT : 11 = Un fuèlh d'estil XSLT possedís pas de tipe Mime XML : 12 = Un fuèlh d'estil XSLT s'impòrta o s'inclutz solet, dirèctament o indirèctament : 13 = Un foncion XPath es estada apelada amb un nombre d'arguments marrit. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/security/manager/chrome/pipnss/nsserrors.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/security/manager/chrome/pipnss/nsserrors.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/security/manager/chrome/pipnss/nsserrors.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/security/manager/chrome/pipnss/nsserrors.properties 2020-11-17 19:35:47.000000000 +0000 @@ -138,7 +138,7 @@ SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM=Lo par a utilizat una combinason non presa en carga de signatura e d’algoritme de trissatge. SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET=Lo par a ensajat de tornar sens extension extended_master_secret corrècta. SSL_ERROR_UNEXPECTED_EXTENDED_MASTER_SECRET=Lo par a ensajat de tornar amb una extension extended_master_secret imprevista. -SEC_ERROR_IO=Una error d'entrada/sortida s'es produita pendent l'autorizacion de seguretat. +SEC_ERROR_IO=Una error d'entrada/sortida s'es producha pendent l'autorizacion de seguretat. SEC_ERROR_LIBRARY_FAILURE=Fracàs de la bibliotèca de seguretat. SEC_ERROR_BAD_DATA=Bibliotèca de seguretat : donadas incorrèctas recebudas. SEC_ERROR_OUTPUT_LEN=Bibliotèca de seguretat : error de longor de las donadas en sortida. @@ -304,10 +304,10 @@ SEC_ERROR_BAD_LDAP_RESPONSE=Lo servidor a renviat una marrida responsa LDAP SEC_ERROR_FAILED_TO_ENCODE_DATA=Fracàs de l'encodatge de donadas amb l'encodador ASN1 SEC_ERROR_BAD_INFO_ACCESS_LOCATION=Marrida informacion d'emplaçament d'accès dins l'extension de certificat -SEC_ERROR_LIBPKIX_INTERNAL=Una error intèrna libpkix s'es produita pendent la validacion de certificat. -SEC_ERROR_PKCS11_GENERAL_ERROR=Un modul PKCS #11 a renviat CKR_GENERAL_ERROR, qu'indica qu'una error irrecuperabla s'es produita. +SEC_ERROR_LIBPKIX_INTERNAL=Una error intèrna libpkix s'es producha pendent la validacion de certificat. +SEC_ERROR_PKCS11_GENERAL_ERROR=Un modul PKCS #11 a renviat CKR_GENERAL_ERROR, qu'indica qu'una error irrecuperabla s'es producha. SEC_ERROR_PKCS11_FUNCTION_FAILED=Un modul PKCS #11 a renviat CKR_FUNCTION_FAILED, qu'indican que la foncion demandada podiá pas èsser realizada. Ensajar tornarmai la meteissa operacion poiriá foncionar. -SEC_ERROR_PKCS11_DEVICE_ERROR=Un modul PKCS #11 a renviat CKR_DEVICE_ERROR, qu'indica qu'un problèma amb lo geton o lo slot s'es produit. +SEC_ERROR_PKCS11_DEVICE_ERROR=Un modul PKCS #11 a renviat CKR_DEVICE_ERROR, qu'indica qu'un problèma amb lo geton o lo slot s'es producha. SEC_ERROR_BAD_INFO_ACCESS_METHOD=Metòde d'accès a l'informacion desconeguda dins l'extension de certificat. SEC_ERROR_CRL_IMPORT_FAILED=Error al moment de la temptativa d'importacion d'una lista de revocacion de certificat (CRL). SEC_ERROR_EXPIRED_PASSWORD=Lo senhal a expirat. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/security/manager/chrome/pipnss/pipnss.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/security/manager/chrome/pipnss/pipnss.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/security/manager/chrome/pipnss/pipnss.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/security/manager/chrome/pipnss/pipnss.properties 2020-11-17 19:35:47.000000000 +0000 @@ -258,7 +258,7 @@ PSMERR_HostReusedIssuerSerial=Avètz recebut un certificat invalid. Contactatz l'administrator del servidor o vòstre correspondent de messatjariá e provesissètz-li las entresenhas seguentas :\n\nVòstre certificat conten lo meteis numèro de seria qu'un autre certificat emes per l'autoritat de certificacion. Provesissètz-vos un certificat novèl amb un numèro de seria unic. # LOCALIZATION NOTE (SSLConnectionErrorPrefix2): %1$S is the host string, %2$S is more detailed information (localized as well). -SSLConnectionErrorPrefix2=Una error s'es produita pendent una connexion a %1$S. %2$S\n +SSLConnectionErrorPrefix2=Una error s'es producha pendent una connexion a %1$S. %2$S\n certErrorIntro=%S utiliza un certificat de seguretat invalid. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/chrome/mozapps/downloads/downloads.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/chrome/mozapps/downloads/downloads.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/chrome/mozapps/downloads/downloads.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/chrome/mozapps/downloads/downloads.properties 2020-11-17 19:35:47.000000000 +0000 @@ -23,7 +23,7 @@ shortDays=j;j downloadErrorAlertTitle=Error de telecargament -downloadErrorGeneric=Lo telecargament pòt pas èsser enregistrat perque una error desconeguda s'es produita.\n\nEnsajatz tornarmai. +downloadErrorGeneric=Lo telecargament pòt pas èsser enregistrat perque una error desconeguda s'es producha.\n\nEnsajatz tornarmai. # LOCALIZATION NOTE: we don't have proper plural support in the CPP code; bug 463102 quitCancelDownloadsAlertTitle=Anullar totes los telecargaments ? diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/chrome/mozapps/extensions/extensions.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/chrome/mozapps/extensions/extensions.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/chrome/mozapps/extensions/extensions.properties 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/chrome/mozapps/extensions/extensions.properties 2020-11-17 19:35:47.000000000 +0000 @@ -26,11 +26,11 @@ #LOCALIZATION NOTE (notification.restartless-uninstall) %1$S is the add-on name notification.restartless-uninstall=%1$S sera desinstallat aprèp la tampadura d’aquesta onglet. #LOCALIZATION NOTE (notification.downloadError) %1$S is the add-on name. -notification.downloadError=Una error s'es produita al moment del telecargament de %1$S. +notification.downloadError=Una error s'es producha al moment del telecargament de %1$S. notification.downloadError.retry=Tornar ensajar notification.downloadError.retry.tooltip=Ensajar tornarmai de telecargar aqueste modul complementari #LOCALIZATION NOTE (notification.installError) %1$S is the add-on name. -notification.installError=Una error s'es produita al moment de l'installacion de %1$S. +notification.installError=Una error s'es producha al moment de l'installacion de %1$S. notification.installError.retry=Tornar ensajar notification.installError.retry.tooltip=Ensajar tornarmai de telecargar e installar aqueste modul complementari #LOCALIZATION NOTE (notification.gmpPending) %1$S is the add-on name. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/crashreporter/crashreporter.ini firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/crashreporter/crashreporter.ini --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/crashreporter/crashreporter.ini 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/crashreporter/crashreporter.ini 2020-11-17 19:35:47.000000000 +0000 @@ -19,7 +19,7 @@ CrashReporterSorry=O planhèm # LOCALIZATION NOTE (CrashReporterDescriptionText2): The %s is replaced with the product name. CrashReporterDescriptionText2=%s a rencontrat un problèma imprevist e a plantat.\n\nPer nos ajudar a diagnosticar e corregir aqueste problèma, nos podètz mandar un rapòrt de plantatge. -CrashReporterDefault=Aquesta aplicacion es executada aprèp un plantatge per raportar lo problèma que s'es produit per l'editor de l'aplicacion. Deu pas èsser aviada dirèctament. +CrashReporterDefault=Aquesta aplicacion es executada aprèp un plantatge per raportar lo problèma que s'es producha per l'editor de l'aplicacion. Deu pas èsser aviada dirèctament. Details=Detalhs… ViewReportTitle=Contengut del rapòrt CommentGrayText=Apondre un comentari (los comentaris son visibles publicament) diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/toolkit/about/aboutAddons.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/toolkit/about/aboutAddons.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/toolkit/about/aboutAddons.ftl 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/toolkit/about/aboutAddons.ftl 2020-11-17 19:35:47.000000000 +0000 @@ -402,7 +402,7 @@ available-updates-heading = Mesas a jorn disponiblas recent-updates-heading = Mesas a jorn recentas release-notes-loading = Cargament… -release-notes-error = Una error s'es producha en cargant las nòtas de version. +release-notes-error = Una error s'es produch en cargant las nòtas de version. addon-permissions-empty = Aquesta extension demanda pas cap d'autorizacion addon-permissions-required = Permissions requeridas per las foncionalitats principalas : addon-permissions-optional = Permissions opcionalas per las foncionalitats suplementàrias : diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/toolkit/about/aboutProfiles.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/toolkit/about/aboutProfiles.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/toolkit/about/aboutProfiles.ftl 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/toolkit/about/aboutProfiles.ftl 2020-11-17 19:35:47.000000000 +0000 @@ -2,7 +2,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. - profiles-title = A perpaus dels perfils profiles-subtitle = Aquesta pagina vos ajuda a gerir vòstres perfils. Cada perfil es separat e conten un istoric, de marcapaginas e de moduls pròpris. profiles-create = Crear un perfil novèl @@ -14,13 +13,11 @@ profiles-flush-conflict = { profiles-conflict } profiles-flush-failed = Una error inesperada a empachat l’enregistrament de vòstras modificacions. profiles-flush-restart-button = Reaviar { -brand-short-name } - # Variables: # $name (String) - Name of the profile profiles-name = Perfil : { $name } profiles-is-default = Perfil per defaut profiles-rootdir = Dossièr raiç - # localDir is used to show the directory corresponding to # the main profile directory that exists for the purpose of storing data on the # local filesystem, including cache files or other data files that may not @@ -30,28 +27,22 @@ profiles-localdir = Dossièr local profiles-current-profile = Aqueste es lo perfil que siatz a utilizar e se pòt pas suprimir. profiles-in-use-profile = Una autra aplicacion utiliza aqueste perfil e fa que sa supression es impossibla. - profiles-rename = Renommar profiles-remove = Suprimir profiles-set-as-default = Definir coma perfil per defaut profiles-launch-profile = Lançar lo perfil dins un navegador novèl - profiles-cannot-set-as-default-title = Impossible de definir la valor per defaut profiles-cannot-set-as-default-message = Lo perfil per defaut se pòt pas cambiar per { -brand-short-name }. - profiles-yes = òc profiles-no = non - profiles-rename-profile-title = Renommar lo perfil # Variables: # $name (String) - Name of the profile profiles-rename-profile = Renommar lo perfil { $name } - profiles-invalid-profile-name-title = Nom de perfil invalid # Variables: # $name (String) - Name of the profile profiles-invalid-profile-name = Lo nom de perfil « { $name } » es pas valid. - profiles-delete-profile-title = Suprimir lo perfil # Variables: # $dir (String) - Path to be displayed @@ -61,11 +52,8 @@ Desiratz suprimir los fichièrs de donadas del perfil ? profiles-delete-files = Suprimir los fichièrs profiles-dont-delete-files = Suprimir pas los fichièrs - profiles-delete-profile-failed-title = Error -profiles-delete-profile-failed-message = Una error s’es produita en ensajar de suprimir aqueste perfil. - - +profiles-delete-profile-failed-message = Una error s’es producha en ensajar de suprimir aqueste perfil. profiles-opendir = { PLATFORM() -> [macos] Afichar dins lo Finder diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/toolkit/about/aboutTelemetry.ftl firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/toolkit/about/aboutTelemetry.ftl --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/oc/toolkit/toolkit/about/aboutTelemetry.ftl 2020-11-15 14:42:59.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/oc/toolkit/toolkit/about/aboutTelemetry.ftl 2020-11-17 19:35:47.000000000 +0000 @@ -130,7 +130,7 @@ about-telemetry-late-writes-title = Escritura tardièra n°{ $lateWriteCount } about-telemetry-stack-title = Pila : about-telemetry-memory-map-title = Cartografia memòria : -about-telemetry-error-fetching-symbols = Una error s'es produita al moment de la recuperacion dels simbòls. Verificatz que sètz connectat a Internet e ensajatz tornarmai. +about-telemetry-error-fetching-symbols = Una error s'es producha al moment de la recuperacion dels simbòls. Verificatz que sètz connectat a Internet e ensajatz tornarmai. about-telemetry-time-stamp-header = marca orària about-telemetry-category-header = categoria about-telemetry-method-header = metòde diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/pt-BR/devtools/client/netmonitor.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/pt-BR/devtools/client/netmonitor.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/pt-BR/devtools/client/netmonitor.properties 2020-11-15 14:43:08.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/pt-BR/devtools/client/netmonitor.properties 2020-11-17 19:35:56.000000000 +0000 @@ -547,15 +547,15 @@ # LOCALIZATION NOTE (netmonitor.perfNotice1/2/3): These are the labels displayed # in the network table when empty to start performance analysis. -netmonitor.perfNotice1=• Click on the -netmonitor.perfNotice2=button to start performance analysis. +netmonitor.perfNotice1=• Clique no botão +netmonitor.perfNotice2=para iniciar uma análise de desempenho. netmonitor.perfNotice3=Analyze # LOCALIZATION NOTE (netmonitor.reload1/2/3): These are the labels displayed # in the network table when empty to start logging network requests. -netmonitor.reloadNotice1=• Perform a request or -netmonitor.reloadNotice2=Reload -netmonitor.reloadNotice3=the page to see detailed information about network activity. +netmonitor.reloadNotice1=• Efetue uma requisição ou +netmonitor.reloadNotice2=Recarregue +netmonitor.reloadNotice3=a página para ver informações detalhadas sobre atividade de rede. # LOCALIZATION NOTE (netmonitor.toolbar.status3): This is the label displayed # in the network table toolbar, above the "status" column. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/pt-BR/devtools/client/webconsole.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/pt-BR/devtools/client/webconsole.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/pt-BR/devtools/client/webconsole.properties 2020-11-15 14:43:08.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/pt-BR/devtools/client/webconsole.properties 2020-11-17 19:35:56.000000000 +0000 @@ -7,27 +7,6 @@ # You want to make that choice consistent across the developer tools. # A good criteria is the language in which you'd find the best # documentation on web development on the web. -# LOCALIZATION NOTE (browserConsole.title): shown as the -# title when opening the browser console popup -# 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/. -# LOCALIZATION NOTE -# The correct localization of this file might be to keep it in -# English, or another language commonly spoken among web developers. -# You want to make that choice consistent across the developer tools. -# A good criteria is the language in which you'd find the best -# documentation on web development on the web. - -# 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/. -# LOCALIZATION NOTE -# The correct localization of this file might be to keep it in -# English, or another language commonly spoken among web developers. -# You want to make that choice consistent across the developer tools. -# A good criteria is the language in which you'd find the best -# documentation on web development on the web. # LOCALIZATION NOTE (browserConsole.title): shown as the # title when opening the browser console popup @@ -537,7 +516,7 @@ # text. # Parameters: %1$S is Enter key, %2$S is the shorcut to evaluate the expression ( # Ctrl+Enter or Cmd+Enter on OSX). -webconsole.input.editor.onboarding.label=Iterate on your code faster with the new multi-line editor mode. Use %1$S to add new lines and %2$S to run. +webconsole.input.editor.onboarding.label=Interaja mais rápido com seu código, com o novo modo de editor multi-linhas. Use %1$S para adicionar novas linhas e %2$S para executar. # LOCALIZATION NOTE (webconsole.input.editor.onboarding.dismiss.label): the text that is # displayed in the multiline-input mode onboarding UI to dismiss it. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/l10n/pt-BR/devtools/shared/accessibility.properties firefox-trunk-85.0~a1~hg20201117r557492/l10n/pt-BR/devtools/shared/accessibility.properties --- firefox-trunk-84.0~a1~hg20201115r557261/l10n/pt-BR/devtools/shared/accessibility.properties 2020-11-15 14:43:08.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/l10n/pt-BR/devtools/shared/accessibility.properties 2020-11-17 19:35:56.000000000 +0000 @@ -5,138 +5,138 @@ # LOCALIZATION NOTE (accessibility.contrast.ratio): A title text for the color contrast # ratio description, used by the accessibility highlighter to display the value. %S in the # content will be replaced by the contrast ratio numerical value. -accessibility.contrast.ratio=Contrast: %S +accessibility.contrast.ratio=Contraste: %S # LOCALIZATION NOTE (accessibility.contrast.ratio.error): A title text for the color # contrast ratio, used when the tool is unable to calculate the contrast ratio value. -accessibility.contrast.ratio.error=Unable to calculate +accessibility.contrast.ratio.error=Não foi possível calcular # LOCALIZATION NOTE (accessibility.contrast.ratio.label): A title text for the color # contrast ratio description, used together with the actual values. -accessibility.contrast.ratio.label=Contrast: +accessibility.contrast.ratio.label=Contraste: # LOCALIZATION NOTE (accessibility.contrast.ratio.label.large): A title text for the color # contrast ratio description that also specifies that the color contrast criteria used is # if for large text. -accessibility.contrast.ratio.label.large=Contrast (large text): +accessibility.contrast.ratio.label.large=Contraste (texto grande): # LOCALIZATION NOTE (accessibility.text.label.issue.area): A title text that # describes that currently selected accessible object for an element must have # its name provided via the alt attribute. -accessibility.text.label.issue.area = Use “alt” attribute to label “area” elements that have the “href” attribute. +accessibility.text.label.issue.area = Use o atributo “alt” para rotular elementos “area” que têm o atributo “href”. # LOCALIZATION NOTE (accessibility.text.label.issue.dialog): A title text that # describes that currently selected accessible object for a dialog should have a name # provided. -accessibility.text.label.issue.dialog = Dialogs should be labeled. +accessibility.text.label.issue.dialog = Diálogos devem ser rotulados. # LOCALIZATION NOTE (accessibility.text.label.issue.document.title): A title text that # describes that currently selected accessible object for a document must have a name # provided via title. -accessibility.text.label.issue.document.title = Documents must have a title. +accessibility.text.label.issue.document.title = Documentos devem ter um título. # LOCALIZATION NOTE (accessibility.text.label.issue.embed): A title text that # describes that currently selected accessible object for an must have a name # provided. -accessibility.text.label.issue.embed = Embedded content must be labeled. +accessibility.text.label.issue.embed = Conteúdo incorporado deve ser rotulado. # LOCALIZATION NOTE (accessibility.text.label.issue.figure): A title text that # describes that currently selected accessible object for a figure should have a name # provided. -accessibility.text.label.issue.figure = Figures with optional captions should be labeled. +accessibility.text.label.issue.figure = Figuras com legendas opcionais devem ser rotuladas. # LOCALIZATION NOTE (accessibility.text.label.issue.fieldset): A title text that # describes that currently selected accessible object for a
must have a name # provided. -accessibility.text.label.issue.fieldset = “fieldset” elements must be labeled. +accessibility.text.label.issue.fieldset = Elementos “fieldset” devem ser rotulados. # LOCALIZATION NOTE (accessibility.text.label.issue.fieldset.legend2): A title text that # describes that currently selected accessible object for a
must have a name # provided via element. -accessibility.text.label.issue.fieldset.legend2 = Use a “legend” element to label a “fieldset”. +accessibility.text.label.issue.fieldset.legend2 = Use um elemento “legend” para rotular um “fieldset”. # LOCALIZATION NOTE (accessibility.text.label.issue.form): A title text that # describes that currently selected accessible object for a form element must have a name # provided. -accessibility.text.label.issue.form = Form elements must be labeled. +accessibility.text.label.issue.form = Elementos de formulário devem ser rotulados. # LOCALIZATION NOTE (accessibility.text.label.issue.form.visible): A title text that # describes that currently selected accessible object for a form element should have a name # provided via a visible label/element. -accessibility.text.label.issue.form.visible = Form elements should have a visible text label. +accessibility.text.label.issue.form.visible = Elementos de formulário devem ter um rótulo de texto visível. # LOCALIZATION NOTE (accessibility.text.label.issue.frame): A title text that # describes that currently selected accessible object for a must have a name # provided. -accessibility.text.label.issue.frame = “frame” elements must be labeled. +accessibility.text.label.issue.frame = Elementos “frame” devem ser rotulados. # LOCALIZATION NOTE (accessibility.text.label.issue.glyph): A title text that # describes that currently selected accessible object for a must have a name # provided via alt attribute. -accessibility.text.label.issue.glyph = Use “alt” attribute to label “mglyph” elements. +accessibility.text.label.issue.glyph = Use o atributo “alt” para rotular elementos “mglyph”. # LOCALIZATION NOTE (accessibility.text.label.issue.heading): A title text that # describes that currently selected accessible object for a heading must have a name # provided. -accessibility.text.label.issue.heading = Headings must be labeled. +accessibility.text.label.issue.heading = Cabeçalhos devem ser rotulados. # LOCALIZATION NOTE (accessibility.text.label.issue.heading.content): A title text that # describes that currently selected accessible object for a heading must have visible # content. -accessibility.text.label.issue.heading.content = Headings should have visible text content. +accessibility.text.label.issue.heading.content = Cabeçalhos devem ter conteúdo de texto visível. # LOCALIZATION NOTE (accessibility.text.label.issue.iframe): A title text that # describes that currently selected accessible object for an diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/client-hints/viewport-width-iframe.https.html.headers firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/client-hints/viewport-width-iframe.https.html.headers --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/client-hints/viewport-width-iframe.https.html.headers 2020-11-15 14:38:11.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/client-hints/viewport-width-iframe.https.html.headers 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -Accept-CH: Viewport-Width - diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/client-hints/viewport-width-subresource.https.html firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/client-hints/viewport-width-subresource.https.html --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/client-hints/viewport-width-subresource.https.html 2020-11-15 14:38:12.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/client-hints/viewport-width-subresource.https.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ - - - - - - + + +     Ipsum + + Whitespace + +
+
 
+ +
This isn't rendered
+
This also isn't visible
+ + +     + + Dipsum + + + +

+

+ This text appears at the end of the document +

diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/tools/wpt/wpt.py firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/tools/wpt/wpt.py --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/tools/wpt/wpt.py 2020-11-15 14:38:18.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/tools/wpt/wpt.py 2020-11-17 19:31:51.000000000 +0000 @@ -50,7 +50,10 @@ dest="skip_venv_setup", help="Whether to use the virtualenv as-is. Must set --venv as well") parser.add_argument("--debug", action="store_true", help="Run the debugger in case of an exception") - parser.add_argument("--py3", action="store_true", help="Run with python3") + parser.add_argument("--py3", action="store_true", + help="Run with Python 3 (requires a `python3` binary on the PATH)") + parser.add_argument("--py2", action="store_true", + help="Run with Python 2 (requires a `python2` binary on the PATH)") subparsers = parser.add_subparsers(dest="command") for command, props in iteritems(commands): subparsers.add_parser(command, help=props["help"], add_help=False) diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/tools/wptrunner/wptrunner/update/state.py firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/tools/wptrunner/wptrunner/update/state.py --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/tools/wptrunner/wptrunner/update/state.py 2020-11-15 14:38:19.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/tools/wptrunner/wptrunner/update/state.py 2020-11-17 19:31:50.000000000 +0000 @@ -97,7 +97,7 @@ try: if not os.path.isfile(cls.filename): return None - with open(cls.filename) as f: + with open(cls.filename, "rb") as f: try: rv = pickle.load(f) logger.debug("Loading data %r" % (rv._data,)) @@ -111,7 +111,7 @@ def save(self): """Write the state to disk""" - with open(self.filename, "w") as f: + with open(self.filename, "wb") as f: pickle.dump(self, f) def clear(self): diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/tools/wptserve/wptserve/utils.py firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/tools/wptserve/wptserve/utils.py --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/tools/wptserve/wptserve/utils.py 2020-11-15 14:38:18.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/tools/wptserve/wptserve/utils.py 2020-11-17 19:31:50.000000000 +0000 @@ -120,6 +120,7 @@ 532, # netnews 540, # uucp 548, # afp + 554, # rtsp 556, # remotefs 563, # nntp+ssl 587, # smtp (outgoing) @@ -127,6 +128,8 @@ 636, # ldap+ssl 993, # ldap+ssl 995, # pop3+ssl + 1720, # h323hostcall + 1723, # pptp 2049, # nfs 3659, # apple-sasl 4045, # lockd diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/webrtc/protocol/handover.html firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/webrtc/protocol/handover.html --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/webrtc/protocol/handover.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/webrtc/protocol/handover.html 2020-11-17 19:31:51.000000000 +0000 @@ -0,0 +1,74 @@ + + +RTCPeerConnection Handovers + + + + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/websockets/Create-blocked-port.any.js firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/websockets/Create-blocked-port.any.js --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/websockets/Create-blocked-port.any.js 2020-11-15 14:38:18.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/websockets/Create-blocked-port.any.js 2020-11-17 19:31:50.000000000 +0000 @@ -58,6 +58,7 @@ 532, // netnews 540, // uucp 548, // afp + 554, // rtsp 556, // remotefs 563, // nntp+ssl 587, // smtp (outgoing) @@ -65,6 +66,8 @@ 636, // ldap+ssl 993, // ldap+ssl 995, // pop3+ssl + 1720, // h323hostcall + 1723, // pptp 2049, // nfs 3659, // apple-sasl 4045, // lockd diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/wpt firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/wpt --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/tests/wpt 2020-11-15 14:38:18.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/tests/wpt 2020-11-17 19:31:50.000000000 +0000 @@ -7,7 +7,20 @@ commands = wpt.load_commands() py3only = commands[args.command]["py3only"] - if (args.py3 or py3only) and sys.version_info.major < 3: + if (args.py2) and sys.version_info.major > 2: + if py3only: + sys.stderr.write("This command only works with Python 3\n") + sys.exit(1) + from subprocess import call + try: + sys.exit(call(['python2'] + sys.argv)) + except OSError as e: + if e.errno == 2: + sys.stderr.write("python2 is needed to run this command\n") + sys.exit(1) + else: + raise + elif (args.py3 or py3only) and sys.version_info.major < 3: from subprocess import call try: sys.exit(call(['python3'] + sys.argv)) diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/unittestrunner.py firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/unittestrunner.py --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/unittestrunner.py 2020-11-15 14:38:19.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/unittestrunner.py 2020-11-17 19:31:51.000000000 +0000 @@ -1,3 +1,7 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + import argparse import configparser import os diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/update/upstream.py firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/update/upstream.py --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/update/upstream.py 2020-11-15 14:38:19.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/update/upstream.py 2020-11-17 19:31:51.000000000 +0000 @@ -1,3 +1,7 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + import os import re import subprocess diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/vcs.py firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/vcs.py --- firefox-trunk-84.0~a1~hg20201115r557261/testing/web-platform/vcs.py 2020-11-15 14:38:19.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/web-platform/vcs.py 2020-11-17 19:31:51.000000000 +0000 @@ -1,3 +1,7 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + import os import subprocess diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/xpcshell/moz-http2/moz-http2-child.js firefox-trunk-85.0~a1~hg20201117r557492/testing/xpcshell/moz-http2/moz-http2-child.js --- firefox-trunk-84.0~a1~hg20201115r557261/testing/xpcshell/moz-http2/moz-http2-child.js 2020-11-15 14:38:19.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/xpcshell/moz-http2/moz-http2-child.js 2020-11-17 19:31:50.000000000 +0000 @@ -1,3 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + /* eslint-env node */ function sendBackResponse(evalResult, e) { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/testing/xpcshell/xpcshellcommandline.py firefox-trunk-85.0~a1~hg20201117r557492/testing/xpcshell/xpcshellcommandline.py --- firefox-trunk-84.0~a1~hg20201115r557261/testing/xpcshell/xpcshellcommandline.py 2020-11-15 14:38:19.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/testing/xpcshell/xpcshellcommandline.py 2020-11-17 19:31:51.000000000 +0000 @@ -1,3 +1,7 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + from __future__ import absolute_import import argparse diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/antitracking/test/browser/antitracking_head.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/antitracking/test/browser/antitracking_head.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/antitracking/test/browser/antitracking_head.js 2020-11-15 14:38:21.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/antitracking/test/browser/antitracking_head.js 2020-11-17 19:31:54.000000000 +0000 @@ -797,7 +797,7 @@ doAccessRemovalChecks && options.accessRemoval == "navigate-topframe" ) { - await BrowserTestUtils.loadURI(browser, TEST_4TH_PARTY_PAGE); + BrowserTestUtils.loadURI(browser, TEST_4TH_PARTY_PAGE); await BrowserTestUtils.browserLoaded(browser); let pageshow = BrowserTestUtils.waitForContentEvent( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/browser/nsWebBrowser.cpp firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/browser/nsWebBrowser.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/browser/nsWebBrowser.cpp 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/browser/nsWebBrowser.cpp 2020-11-17 19:31:53.000000000 +0000 @@ -1169,7 +1169,7 @@ printf("nsWebBrowser::NS_ACTIVATE %p %s\n", (void*)this, NS_ConvertUTF16toUTF8(documentURI).get()); #endif - FocusActivate(); + FocusActivate(nsFocusManager::GenerateFocusActionId()); } void nsWebBrowser::WindowDeactivated() { @@ -1180,7 +1180,7 @@ printf("nsWebBrowser::NS_DEACTIVATE %p %s\n", (void*)this, NS_ConvertUTF16toUTF8(documentURI).get()); #endif - FocusDeactivate(); + FocusDeactivate(nsFocusManager::GenerateFocusActionId()); } bool nsWebBrowser::PaintWindow(nsIWidget* aWidget, @@ -1200,19 +1200,19 @@ return true; } -void nsWebBrowser::FocusActivate() { +void nsWebBrowser::FocusActivate(uint64_t aActionId) { nsFocusManager* fm = nsFocusManager::GetFocusManager(); nsCOMPtr window = GetWindow(); if (fm && window) { - fm->WindowRaised(window); + fm->WindowRaised(window, aActionId); } } -void nsWebBrowser::FocusDeactivate() { +void nsWebBrowser::FocusDeactivate(uint64_t aActionId) { nsFocusManager* fm = nsFocusManager::GetFocusManager(); nsCOMPtr window = GetWindow(); if (fm && window) { - fm->WindowLowered(window); + fm->WindowLowered(window, aActionId); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/browser/nsWebBrowser.h firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/browser/nsWebBrowser.h --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/browser/nsWebBrowser.h 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/browser/nsWebBrowser.h 2020-11-17 19:31:54.000000000 +0000 @@ -102,8 +102,8 @@ NS_DECL_NSIWEBPROGRESSLISTENER void SetAllowDNSPrefetch(bool aAllowPrefetch); - void FocusActivate(); - void FocusDeactivate(); + void FocusActivate(uint64_t aActionId); + void FocusDeactivate(uint64_t aActionId); void SetWillChangeProcess(); static already_AddRefed Create( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/captivedetect/CaptiveDetect.jsm firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/captivedetect/CaptiveDetect.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/captivedetect/CaptiveDetect.jsm 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/captivedetect/CaptiveDetect.jsm 2020-11-17 19:31:54.000000000 +0000 @@ -45,6 +45,11 @@ // We don't want to follow _any_ redirects xhr.channel.QueryInterface(Ci.nsIHttpChannel).redirectionLimit = 0; + // bug 1666072 - firefox.com returns a HSTS header triggering a https upgrade + // but the upgrade triggers an internal redirect causing an incorrect locked + // portal notification. We exclude CP detection from STS. + xhr.channel.QueryInterface(Ci.nsIHttpChannel).allowSTS = false; + // The Cache-Control header is only interpreted by proxies and the // final destination. It does not help if a resource is already // cached locally. diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/ConduitsChild.jsm firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/ConduitsChild.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/ConduitsChild.jsm 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/ConduitsChild.jsm 2020-11-17 19:31:53.000000000 +0000 @@ -129,6 +129,16 @@ } catch (ex) {} } } + this.closeCallback?.(); + this.closeCallback = null; + } + + /** + * Set the callback to be called when the conduit is closed. + * @param {function} callback + */ + setCloseCallback(callback) { + this.closeCallback = callback; } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/ext-browser-content.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/ext-browser-content.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/ext-browser-content.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/ext-browser-content.js 2020-11-17 19:31:54.000000000 +0000 @@ -10,7 +10,6 @@ XPCOMUtils.defineLazyModuleGetters(this, { BrowserUtils: "resource://gre/modules/BrowserUtils.jsm", clearTimeout: "resource://gre/modules/Timer.jsm", - E10SUtils: "resource://gre/modules/E10SUtils.jsm", ExtensionCommon: "resource://gre/modules/ExtensionCommon.jsm", setTimeout: "resource://gre/modules/Timer.jsm", }); @@ -336,9 +335,7 @@ }, shouldLoadURIInThisProcess(URI) { - let remoteSubframes = docShell.QueryInterface(Ci.nsILoadContext) - .useRemoteSubframes; - return E10SUtils.shouldLoadURIInThisProcess(URI, remoteSubframes); + return true; }, }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/ExtensionCommon.jsm firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/ExtensionCommon.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/ExtensionCommon.jsm 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/ExtensionCommon.jsm 2020-11-17 19:31:53.000000000 +0000 @@ -504,6 +504,9 @@ ...address, }); this.callOnClose(conduit); + conduit.setCloseCallback(() => { + this.forgetOnClose(conduit); + }); return conduit; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/test/xpcshell/test_ext_runtime_ports_gc.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/test/xpcshell/test_ext_runtime_ports_gc.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/test/xpcshell/test_ext_runtime_ports_gc.js 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/test/xpcshell/test_ext_runtime_ports_gc.js 2020-11-17 19:31:54.000000000 +0000 @@ -0,0 +1,168 @@ +"use strict"; + +let gcExperimentAPIs = { + gcHelper: { + schema: "schema.json", + child: { + scopes: ["addon_child"], + script: "child.js", + paths: [["gcHelper"]], + }, + }, +}; + +let gcExperimentFiles = { + "schema.json": JSON.stringify([ + { + namespace: "gcHelper", + functions: [ + { + name: "forceGarbageCollect", + type: "function", + parameters: [], + async: true, + }, + { + name: "registerWitness", + type: "function", + parameters: [ + { + name: "obj", + // Expected type is "object", but using "any" here to ensure that + // the parameter is untouched (not normalized). + type: "any", + }, + ], + returns: { type: "number" }, + }, + { + name: "isGarbageCollected", + type: "function", + parameters: [ + { + name: "witnessId", + description: "return value of registerWitness", + type: "number", + }, + ], + returns: { type: "boolean" }, + }, + ], + }, + ]), + "child.js": () => { + let { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm"); + /* globals ExtensionAPI */ + this.gcHelper = class extends ExtensionAPI { + getAPI(context) { + let witnesses = new Map(); + return { + gcHelper: { + async forceGarbageCollect() { + // Logic copied from test_ext_contexts_gc.js + for (let i = 0; i < 3; ++i) { + Cu.forceShrinkingGC(); + Cu.forceCC(); + Cu.forceGC(); + await new Promise(resolve => setTimeout(resolve, 0)); + } + }, + registerWitness(obj) { + let witnessId = witnesses.size; + witnesses.set(witnessId, Cu.getWeakReference(obj)); + return witnessId; + }, + isGarbageCollected(witnessId) { + return witnesses.get(witnessId).get() === null; + }, + }, + }; + } + }; + }, +}; + +// Verify that the experiment is working as intended before using it in tests. +add_task(async function test_gc_experiment() { + let extension = ExtensionTestUtils.loadExtension({ + isPrivileged: true, + manifest: { + experiment_apis: gcExperimentAPIs, + }, + files: gcExperimentFiles, + async background() { + let obj1 = {}; + let obj2 = {}; + let witness1 = browser.gcHelper.registerWitness(obj1); + let witness2 = browser.gcHelper.registerWitness(obj2); + obj1 = null; + await browser.gcHelper.forceGarbageCollect(); + browser.test.assertTrue( + browser.gcHelper.isGarbageCollected(witness1), + "obj1 should have been garbage-collected" + ); + browser.test.assertFalse( + browser.gcHelper.isGarbageCollected(witness2), + "obj2 should not have been garbage-collected" + ); + + browser.test.sendMessage("done"); + }, + }); + + await extension.startup(); + await extension.awaitMessage("done"); + await extension.unload(); +}); + +add_task(async function test_port_gc() { + let extension = ExtensionTestUtils.loadExtension({ + isPrivileged: true, + manifest: { + experiment_apis: gcExperimentAPIs, + }, + files: gcExperimentFiles, + async background() { + let witnessPortSender; + let witnessPortReceiver; + + browser.runtime.onConnect.addListener(port => { + browser.test.assertEq("daName", port.name, "expected port"); + witnessPortReceiver = browser.gcHelper.registerWitness(port); + port.disconnect(); + }); + + // runtime.connect() only triggers onConnect for different contexts, + // so create a frame to have a different context. + // A blank frame in a moz-extension:-document will have access to the + // extension APIs. + let frameWindow = await new Promise(resolve => { + let f = document.createElement("iframe"); + f.onload = () => resolve(f.contentWindow); + document.body.append(f); + }); + await new Promise(resolve => { + let port = frameWindow.browser.runtime.connect({ name: "daName" }); + witnessPortSender = browser.gcHelper.registerWitness(port); + port.onDisconnect.addListener(() => resolve()); + }); + + await browser.gcHelper.forceGarbageCollect(); + + browser.test.assertTrue( + browser.gcHelper.isGarbageCollected(witnessPortSender), + "runtime.connect() port should have been garbage-collected" + ); + browser.test.assertTrue( + browser.gcHelper.isGarbageCollected(witnessPortReceiver), + "runtime.onConnect port should have been garbage-collected" + ); + + browser.test.sendMessage("done"); + }, + }); + + await extension.startup(); + await extension.awaitMessage("done"); + await extension.unload(); +}); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/extensions/test/xpcshell/xpcshell-common.ini 2020-11-17 19:31:54.000000000 +0000 @@ -138,6 +138,7 @@ [test_ext_runtime_messaging_self.js] [test_ext_runtime_onInstalled_and_onStartup.js] [test_ext_runtime_ports.js] +[test_ext_runtime_ports_gc.js] [test_ext_runtime_sendMessage.js] [test_ext_runtime_sendMessage_errors.js] [test_ext_runtime_sendMessage_multiple.js] diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/featuregates/Features.toml firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/featuregates/Features.toml --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/featuregates/Features.toml 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/featuregates/Features.toml 2020-11-17 19:31:54.000000000 +0000 @@ -177,15 +177,6 @@ bug-numbers = [1643027] is-public = true -[js-warp] -title = "experimental-features-js-warp" -description = "experimental-features-js-warp-description" -restart-required = true -preference = "javascript.options.warp" -type = "boolean" -bug-numbers = [1613592] -is-public = true - [fission] title = "experimental-features-fission" description = "experimental-features-fission-description" diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/experiments/ExperimentAPI.jsm firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/experiments/ExperimentAPI.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/experiments/ExperimentAPI.jsm 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/experiments/ExperimentAPI.jsm 2020-11-17 19:31:54.000000000 +0000 @@ -39,41 +39,98 @@ /** * Returns an experiment, including all its metadata + * Sends exposure ping * * @param {{slug?: string, featureId?: string}} options slug = An experiment identifier * or feature = a stable identifier for a type of experiment - * @returns {Enrollment|undefined} A matching experiment if one is found. + * @returns {{slug: string, active: bool, exposurePingSent: bool}} A matching experiment if one is found. */ - getExperiment({ slug, featureId } = {}) { + getExperiment({ slug, featureId, sendExposurePing } = {}) { + if (!slug && !featureId) { + throw new Error( + "getExperiment(options) must include a slug or a feature." + ); + } + let experimentData; + if (slug) { + experimentData = this._store.get(slug); + } else if (featureId) { + experimentData = this._store.getExperimentForFeature(featureId); + } + if (experimentData) { + return { + slug: experimentData.slug, + active: experimentData.active, + exposurePingSent: experimentData.exposurePingSent, + branch: this.getFeatureBranch({ featureId, sendExposurePing }), + }; + } + + return null; + }, + + /** + * Return experiment slug its status and the enrolled branch slug + * Does NOT send exposure ping because you only have access to the slugs + */ + getExperimentMetaData({ slug, featureId }) { + if (!slug && !featureId) { + throw new Error( + "getExperiment(options) must include a slug or a feature." + ); + } + + let experimentData; if (slug) { - return this._store.get(slug); + experimentData = this._store.get(slug); } else if (featureId) { - return this._store.getExperimentForFeature(featureId); + experimentData = this._store.getExperimentForFeature(featureId); + } + if (experimentData) { + return { + slug: experimentData.slug, + active: experimentData.active, + exposurePingSent: experimentData.exposurePingSent, + branch: { slug: experimentData.branch.slug }, + }; } - throw new Error("getExperiment(options) must include a slug or a feature."); + + return null; }, /** * Lookup feature in active experiments and return status. + * Sends exposure ping * @param {string} featureId Feature to lookup * @param {boolean} defaultValue * @returns {boolean} */ isFeatureEnabled(featureId, defaultValue) { - const featureConfig = this._store.getFeature(featureId); - if (featureConfig && featureConfig.enabled !== undefined) { - return featureConfig.enabled; + const branch = this.getFeatureBranch({ featureId }); + if (branch?.feature.enabled !== undefined) { + return branch.feature.enabled; } return defaultValue; }, /** * Lookup feature in active experiments and return value. - * @param {string} featureId Feature name to lookup - * @returns {FeatureConfig.value} + * By default, this will send an exposure event. + * @param {{featureId: string, sendExposurePing: boolean}} options + * @returns {obj} The feature value + */ + getFeatureValue(options) { + return this._store.activateBranch(options)?.feature.value; + }, + + /** + * Lookup feature in active experiments and returns the entire branch. + * By default, this will send an exposure event. + * @param {{featureId: string, sendExposurePing: boolean}} options + * @returns {Branch} */ - getFeatureValue(featureId) { - return this._store.getFeature(featureId)?.value; + getFeatureBranch(options) { + return this._store.activateBranch(options); }, /** @@ -172,6 +229,25 @@ const recipe = await this.getRecipe(slug); return recipe?.branches; }, + + recordExposureEvent(name, { sent, experimentSlug, branchSlug }) { + if (!IS_MAIN_PROCESS) { + Cu.reportError("Need to call from Parent process"); + return false; + } + if (sent) { + return false; + } + + // Notify listener to record that the ping was sent + this._store._emitExperimentExposure({ + featureId: name, + experimentSlug, + branchSlug, + }); + + return true; + }, }; XPCOMUtils.defineLazyGetter(ExperimentAPI, "_store", function() { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/experiments/ExperimentManager.jsm firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/experiments/ExperimentManager.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/experiments/ExperimentManager.jsm 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/experiments/ExperimentManager.jsm 2020-11-17 19:31:54.000000000 +0000 @@ -26,6 +26,7 @@ TelemetryEvents: "resource://normandy/lib/TelemetryEvents.jsm", TelemetryEnvironment: "resource://gre/modules/TelemetryEnvironment.jsm", FirstStartup: "resource://gre/modules/FirstStartup.jsm", + Services: "resource://gre/modules/Services.jsm", }); XPCOMUtils.defineLazyGetter(this, "log", () => { @@ -43,6 +44,8 @@ // Also included in telemetry const DEFAULT_EXPERIMENT_TYPE = "messaging_experiment"; const STUDIES_OPT_OUT_PREF = "app.shield.optoutstudies.enabled"; +const EXPOSURE_EVENT_CATEGORY = "normandy"; +const EXPOSURE_EVENT_METHOD = "expose"; /** * A module for processes Experiment recipes, choosing and storing enrollment state, @@ -53,7 +56,7 @@ this.id = id; this.store = store || new ExperimentStore(); this.sessions = new Map(); - + this._onExposureEvent = this._onExposureEvent.bind(this); Services.prefs.addObserver(STUDIES_OPT_OUT_PREF, this); } @@ -85,6 +88,7 @@ */ async onStartup() { await this.store.init(); + this.store.on("exposure", this._onExposureEvent); const restoredExperiments = this.store.getAllActive(); for (const experiment of restoredExperiments) { @@ -224,6 +228,8 @@ slug, branch, active: true, + // Sent first time feature value is used + exposurePingSent: false, enrollmentId, experimentType, source, @@ -337,6 +343,32 @@ }); } + async _onExposureEvent(event, experimentData) { + await this.store.ready(); + this.store.updateExperiment(experimentData.experimentSlug, { + exposurePingSent: true, + }); + // featureId is not validated and might be rejected by recordEvent if not + // properly defined in Events.yaml. Saving experiment state regardless of + // the result, no use retrying. + try { + Services.telemetry.recordEvent( + EXPOSURE_EVENT_CATEGORY, + EXPOSURE_EVENT_METHOD, + "feature_study", + experimentData.experimentSlug, + { + branchSlug: experimentData.branchSlug, + featureId: experimentData.featureId, + } + ); + } catch (e) { + Cu.reportError(e); + } + + log.debug(`Experiment exposure: ${experimentData.experimentSlug}`); + } + /** * Sets Telemetry when activating an experiment. * diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/experiments/ExperimentStore.jsm firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/experiments/ExperimentStore.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/experiments/ExperimentStore.jsm 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/experiments/ExperimentStore.jsm 2020-11-17 19:31:54.000000000 +0000 @@ -38,13 +38,25 @@ /** * Return FeatureConfig from first active experiment where it can be found - * @param {string} featureId Feature to lookup - * @returns {FeatureConfig | null} + * @param {{slug: string, featureId: string, sendExposurePing: bool}} + * @returns {Branch | null} */ - getFeature(featureId) { - for (let { branch } of this.getAllActive()) { - if (branch.feature?.featureId === featureId) { - return branch.feature; + activateBranch({ slug, featureId, sendExposurePing = true }) { + for (let experiment of this.getAllActive()) { + if ( + experiment?.branch.feature.featureId === featureId || + experiment.slug === slug + ) { + if (sendExposurePing) { + this._emitExperimentExposure({ + experimentSlug: experiment.slug, + branchSlug: experiment.branch.slug, + featureId, + }); + } + // Default to null for feature-less experiments where we're only + // interested in exposure. + return experiment?.branch || null; } } @@ -62,10 +74,8 @@ if (!featureId) { return false; } - for (const { branch } of this.getAllActive()) { - if (branch.feature?.featureId === featureId) { - return true; - } + if (this.activateBranch({ featureId })?.feature.featureId === featureId) { + return true; } return false; } @@ -94,6 +104,13 @@ } /** + * @param {{featureId: string, experimentSlug: string, branchSlug: string}} experimentData + */ + _emitExperimentExposure(experimentData) { + this.emit("exposure", experimentData); + } + + /** * Add an experiment. Short form for .set(slug, experiment) * @param {Enrollment} experiment */ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_configure_homepage.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_configure_homepage.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_configure_homepage.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/schemas/SpecialMessageActionSchemas/test/browser/browser_sma_configure_homepage.js 2020-11-17 19:31:54.000000000 +0000 @@ -126,7 +126,7 @@ let browser = gBrowser.selectedBrowser; // Wait for any other navigation events from previous tests await BrowserTestUtils.browserLoaded(browser, false, "about:home"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:config"); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:config"); await BrowserTestUtils.browserLoaded(browser, false, "about:config"); await SMATestUtils.executeAndValidateAction(action); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/schemas/TriggerActionSchemas/test/browser/browser_asrouter_trigger_listeners.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/schemas/TriggerActionSchemas/test/browser/browser_asrouter_trigger_listeners.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/schemas/TriggerActionSchemas/test/browser/browser_asrouter_trigger_listeners.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/schemas/TriggerActionSchemas/test/browser/browser_asrouter_trigger_listeners.js 2020-11-17 19:31:54.000000000 +0000 @@ -16,7 +16,7 @@ async function openURLInWindow(window, url) { const { selectedBrowser } = window.gBrowser; - await BrowserTestUtils.loadURI(selectedBrowser, url); + BrowserTestUtils.loadURI(selectedBrowser, url); await BrowserTestUtils.browserLoaded(selectedBrowser, false, url); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/test/unit/test_ExperimentAPI.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/test/unit/test_ExperimentAPI.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/test/unit/test_ExperimentAPI.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/test/unit/test_ExperimentAPI.js 2020-11-17 19:31:54.000000000 +0000 @@ -13,7 +13,7 @@ /** * #getExperiment */ -add_task(async function test_getExperiment_slug() { +add_task(async function test_getExperiment_fromChild_slug() { const sandbox = sinon.createSandbox(); const manager = ExperimentFakes.manager(); const expected = ExperimentFakes.experiment("foo"); @@ -30,15 +30,62 @@ "Wait for child to sync" ); - Assert.deepEqual( - ExperimentAPI.getExperiment({ slug: "foo" }), - expected, + Assert.equal( + ExperimentAPI.getExperiment({ slug: "foo" }).slug, + expected.slug, + "should return an experiment by slug" + ); + + sandbox.restore(); +}); + +add_task(async function test_getExperiment_fromParent_slug() { + const sandbox = sinon.createSandbox(); + const manager = ExperimentFakes.manager(); + const expected = ExperimentFakes.experiment("foo"); + + await manager.onStartup(); + sandbox.stub(ExperimentAPI, "_store").get(() => manager.store); + await ExperimentAPI.ready(); + + manager.store.addExperiment(expected); + + Assert.equal( + ExperimentAPI.getExperiment({ slug: "foo" }).slug, + expected.slug, "should return an experiment by slug" ); sandbox.restore(); }); +add_task(async function test_getExperimentMetaData() { + const sandbox = sinon.createSandbox(); + const manager = ExperimentFakes.manager(); + const expected = ExperimentFakes.experiment("foo"); + + await manager.onStartup(); + sandbox.stub(ExperimentAPI, "_store").get(() => manager.store); + await ExperimentAPI.ready(); + + manager.store.addExperiment(expected); + + let metadata = ExperimentAPI.getExperimentMetaData({ slug: expected.slug }); + + Assert.equal( + Object.keys(metadata.branch).length, + 1, + "Should only expose one property" + ); + Assert.equal( + metadata.branch.slug, + expected.branch.slug, + "Should have the slug prop" + ); + + sandbox.restore(); +}); + add_task(async function test_getExperiment_feature() { const sandbox = sinon.createSandbox(); const manager = ExperimentFakes.manager(); @@ -62,10 +109,10 @@ "Wait for child to sync" ); - Assert.deepEqual( - ExperimentAPI.getExperiment({ featureId: "cfr" }), - expected, - "should return an experiment by slug" + Assert.equal( + ExperimentAPI.getExperiment({ featureId: "cfr" }).slug, + expected.slug, + "should return an experiment by featureId" ); sandbox.restore(); @@ -98,13 +145,19 @@ ); Assert.deepEqual( - ExperimentAPI.getFeatureValue("aboutwelcome"), + ExperimentAPI.getFeatureValue({ featureId: "aboutwelcome" }), feature.value, - "should return an experiment value by slug" + "should return a Branch by feature" + ); + + Assert.deepEqual( + ExperimentAPI.getFeatureBranch({ featureId: "aboutwelcome" }), + expected.branch, + "should return an experiment branch by feature" ); Assert.equal( - ExperimentAPI.getFeatureValue("doesnotexist"), + ExperimentAPI.getFeatureBranch({ featureId: "doesnotexist" }), undefined, "should return undefined if the experiment is not found" ); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/test/unit/test_ExperimentManager_lifecycle.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/test/unit/test_ExperimentManager_lifecycle.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/test/unit/test_ExperimentManager_lifecycle.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/test/unit/test_ExperimentManager_lifecycle.js 2020-11-17 19:31:54.000000000 +0000 @@ -12,6 +12,9 @@ const { Sampling } = ChromeUtils.import( "resource://gre/modules/components-utils/Sampling.jsm" ); +const { TelemetryTestUtils } = ChromeUtils.import( + "resource://testing-common/TelemetryTestUtils.jsm" +); /** * onStartup() @@ -216,3 +219,36 @@ "should clear sessions[test]" ); }); + +add_task(async function test_onExposureEvent() { + const manager = ExperimentFakes.manager(); + const fooExperiment = ExperimentFakes.experiment("foo"); + + await manager.onStartup(); + manager.store.addExperiment(fooExperiment); + + let updateEv = new Promise(resolve => + manager.store.on(`update:${fooExperiment.slug}`, resolve) + ); + + manager.store._emitExperimentExposure({ + branchSlug: fooExperiment.branch.slug, + experimentSlug: fooExperiment.slug, + featureId: "cfr", + }); + + await updateEv; + + Assert.equal( + manager.store.get(fooExperiment.slug).exposurePingSent, + true, + "Experiment state updated" + ); + const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true); + TelemetryTestUtils.assertKeyedScalar( + scalars, + "telemetry.event_counts", + "normandy#expose#feature_study", + 1 + ); +}); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/test/unit/test_ExperimentStore.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/test/unit/test_ExperimentStore.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/messaging-system/test/unit/test_ExperimentStore.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/messaging-system/test/unit/test_ExperimentStore.js 2020-11-17 19:31:54.000000000 +0000 @@ -90,7 +90,33 @@ ); }); -add_task(async function test_getFeature() { +add_task(async function test_recordExposureEvent() { + const manager = ExperimentFakes.manager(); + const experiment = ExperimentFakes.experiment("foo"); + const experimentData = { + experimentSlug: experiment.slug, + branchSlug: experiment.branch.slug, + featureId: experiment.branch.feature.featureId, + }; + await manager.onStartup(); + + let exposureEvEmit = new Promise(resolve => + manager.store.on("exposure", (ev, data) => resolve(data)) + ); + + manager.store.addExperiment(experiment); + manager.store._emitExperimentExposure(experimentData); + + let result = await exposureEvEmit; + + Assert.deepEqual( + result, + experimentData, + "should return the same data as sent" + ); +}); + +add_task(async function test_activateBranch() { const store = ExperimentFakes.store(); const experiment = ExperimentFakes.experiment("foo", { branch: { @@ -102,13 +128,84 @@ await store.init(); store.addExperiment(experiment); - Assert.equal( - store.getFeature("green"), - experiment.branch.feature, + Assert.deepEqual( + store.activateBranch({ featureId: "green" }), + experiment.branch, "Should return feature of active experiment" ); }); +add_task(async function test_activateBranch_activationEvent() { + const store = ExperimentFakes.store(); + const sandbox = sinon.createSandbox(); + const experiment = ExperimentFakes.experiment("foo", { + branch: { + slug: "variant", + feature: { featureId: "green", enabled: true }, + }, + }); + + await store.init(); + store.addExperiment(experiment); + // Adding stub later because `addExperiment` emits update events + const stub = sandbox.stub(store, "emit"); + // Call activateBranch to trigger an activation event + store.activateBranch({ featureId: "green" }); + + Assert.equal(stub.callCount, 1, "Called by doing activateBranch"); + Assert.equal(stub.firstCall.args[0], "exposure", "Has correct event name"); + Assert.equal( + stub.firstCall.args[1].experimentSlug, + experiment.slug, + "Has correct payload" + ); +}); + +add_task(async function test_activateBranch_storeFailure() { + const store = ExperimentFakes.store(); + const sandbox = sinon.createSandbox(); + const experiment = ExperimentFakes.experiment("foo", { + branch: { + slug: "variant", + feature: { featureId: "green", enabled: true }, + }, + }); + + await store.init(); + store.addExperiment(experiment); + // Adding stub later because `addExperiment` emits update events + const stub = sandbox.stub(store, "emit"); + // Call activateBranch to trigger an activation event + sandbox.stub(store, "getAllActive").throws(); + try { + store.activateBranch({ featureId: "green" }); + } catch (e) { + /* This is expected */ + } + + Assert.equal(stub.callCount, 0, "Not called if store somehow fails"); +}); + +add_task(async function test_activateBranch_noActivationEvent() { + const store = ExperimentFakes.store(); + const sandbox = sinon.createSandbox(); + const experiment = ExperimentFakes.experiment("foo", { + branch: { + slug: "variant", + feature: { featureId: "green", enabled: true }, + }, + }); + + await store.init(); + store.addExperiment(experiment); + // Adding stub later because `addExperiment` emits update events + const stub = sandbox.stub(store, "emit"); + // Call activateBranch to trigger an activation event + store.activateBranch({ featureId: "green", sendExposurePing: false }); + + Assert.equal(stub.callCount, 0, "Not called: sendExposurePing is false"); +}); + add_task(async function test_hasExperimentForFeature() { const store = ExperimentFakes.store(); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/passwordmgr/test/browser/browser_autofill_hidden_document.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/passwordmgr/test/browser/browser_autofill_hidden_document.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/passwordmgr/test/browser/browser_autofill_hidden_document.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/passwordmgr/test/browser/browser_autofill_hidden_document.js 2020-11-17 19:31:54.000000000 +0000 @@ -67,7 +67,7 @@ is(tab1Visibility, "visible", "The first tab should be foreground"); let formProcessedPromise = listenForTestNotification("FormProcessed"); - await BrowserTestUtils.loadURI(tab1.linkedBrowser, FORM_URL); + BrowserTestUtils.loadURI(tab1.linkedBrowser, FORM_URL); await formProcessedPromise; gBrowser.removeTab(tab1); }); @@ -95,7 +95,7 @@ listenForTestNotification("FormProcessed").then(() => { formFilled = true; }); - await BrowserTestUtils.loadURI(tab1.linkedBrowser, testUrl); + BrowserTestUtils.loadURI(tab1.linkedBrowser, testUrl); await TestUtils.waitForCondition(() => { let windowGlobal = tab1.linkedBrowser.browsingContext.currentWindowGlobal; @@ -192,7 +192,7 @@ // In this case we will try to autofill while hidden, so look for the passwordmgr-processed-form // to be observed let formProcessedPromise = listenForTestNotification("FormProcessed"); - await BrowserTestUtils.loadURI(tab1.linkedBrowser, FORM_URL); + BrowserTestUtils.loadURI(tab1.linkedBrowser, FORM_URL); await Promise.all([formProcessedPromise, dialogObserved]); let wasProcessed = await formProcessedPromise; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/passwordmgr/test/browser/browser_private_window.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/passwordmgr/test/browser/browser_private_window.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/passwordmgr/test/browser/browser_private_window.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/passwordmgr/test/browser/browser_private_window.js 2020-11-17 19:31:54.000000000 +0000 @@ -569,7 +569,7 @@ // Add the observer before loading the form page let formFilled = listenForTestNotification("FormProcessed"); await SimpleTest.promiseFocus(browser.ownerGlobal); - await BrowserTestUtils.loadURI(browser, form1Url); + BrowserTestUtils.loadURI(browser, form1Url); await formFilled; // the form should have been autofilled, so submit without updating field values diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/pdfjs/test/browser_pdfjs_notification_close_on_navigation.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/pdfjs/test/browser_pdfjs_notification_close_on_navigation.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/pdfjs/test/browser_pdfjs_notification_close_on_navigation.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/pdfjs/test/browser_pdfjs_notification_close_on_navigation.js 2020-11-17 19:31:53.000000000 +0000 @@ -32,7 +32,7 @@ "Notification should be pdfjs-fallback" ); - await BrowserTestUtils.loadURI(browser, "https://example.com"); + BrowserTestUtils.loadURI(browser, "https://example.com"); await TestUtils.waitForCondition( () => !notification.parentNode, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/places/tests/browser/browser_visituri_privatebrowsing_perwindowpb.js 2020-11-17 19:31:55.000000000 +0000 @@ -58,6 +58,6 @@ let loadedPromise = BrowserTestUtils.browserLoaded( win.gBrowser.selectedBrowser ); - await BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url); + BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url); await loadedPromise; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/printing/tests/browser_modal_print.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/printing/tests/browser_modal_print.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/printing/tests/browser_modal_print.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/printing/tests/browser_modal_print.js 2020-11-17 19:31:53.000000000 +0000 @@ -183,7 +183,7 @@ }); let win = await BrowserTestUtils.openNewBrowserWindow(); let browser = win.gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, PrintHelper.defaultTestPageUrl); + BrowserTestUtils.loadURI(browser, PrintHelper.defaultTestPageUrl); await BrowserTestUtils.browserLoaded( browser, true, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/moz.build firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/moz.build --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/moz.build 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/moz.build 2020-11-17 19:31:55.000000000 +0000 @@ -17,6 +17,10 @@ "nsIProcessToolsService.idl", ] +EXPORTS.mozilla += [ + "ProcInfo.h", +] + EXPORTS += [ "ProcessToolsService.h", ] @@ -28,3 +32,15 @@ FINAL_LIBRARY = "xul" XPCSHELL_TESTS_MANIFESTS += ["tests/xpcshell/xpcshell.ini"] +BROWSER_CHROME_MANIFESTS += ["tests/browser/browser.ini"] + +# Platform-specific implementations of `ProcInfo`. +toolkit = CONFIG["MOZ_WIDGET_TOOLKIT"] +if toolkit == "gtk" or toolkit == "android": + UNIFIED_SOURCES += ["ProcInfo_linux.cpp"] +elif toolkit == "windows": + UNIFIED_SOURCES += ["ProcInfo_win.cpp"] +elif toolkit == "cocoa": + UNIFIED_SOURCES += ["ProcInfo.mm"] + +include("/ipc/chromium/chromium-config.mozbuild") diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/ProcInfo.h firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/ProcInfo.h --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/ProcInfo.h 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/ProcInfo.h 2020-11-17 19:31:54.000000000 +0000 @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 8; 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/. */ + +#ifndef __mozilla_ProcInfo_h +#define __mozilla_ProcInfo_h + +#include +#include +#include "mozilla/dom/ipc/IdType.h" +#include "mozilla/HashTable.h" +#include "mozilla/MozPromise.h" + +namespace mozilla { + +namespace ipc { +class GeckoChildProcessHost; +} + +// Process types. When updating this enum, please make sure to update +// WebIDLProcType, ChromeUtils::RequestProcInfo and ProcTypeToWebIDL to +// mirror the changes. +enum class ProcType { + // These must match the ones in ContentParent.h, and E10SUtils.jsm + Web, + WebIsolated, + File, + Extension, + PrivilegedAbout, + PrivilegedMozilla, + WebLargeAllocation, + WebCOOPCOEP, + // the rest matches GeckoProcessTypes.h + Browser, // Default is named Browser here + Plugin, + IPDLUnitTest, + GMPlugin, + GPU, + VR, + RDD, + Socket, + RemoteSandboxBroker, +#ifdef MOZ_ENABLE_FORKSERVER + ForkServer, +#endif + Preallocated, + // Unknown type of process + Unknown, + Max = Unknown, +}; + +struct ThreadInfo { + // Thread Id. + base::ProcessId tid = 0; + // Thread name, if any. + nsString name; + // User time in ns. + uint64_t cpuUser = 0; + // System time in ns. + uint64_t cpuKernel = 0; +}; + +// Info on a DOM window. +struct WindowInfo { + explicit WindowInfo() + : outerWindowId(0), + documentURI(nullptr), + documentTitle(u""_ns), + isProcessRoot(false), + isInProcess(false) {} + WindowInfo(uint64_t aOuterWindowId, nsIURI* aDocumentURI, + nsAString&& aDocumentTitle, bool aIsProcessRoot, bool aIsInProcess) + : outerWindowId(aOuterWindowId), + documentURI(aDocumentURI), + documentTitle(std::move(aDocumentTitle)), + isProcessRoot(aIsProcessRoot), + isInProcess(aIsInProcess) {} + + // Internal window id. + const uint64_t outerWindowId; + + // URI of the document. + const nsCOMPtr documentURI; + + // Title of the document. + const nsString documentTitle; + + // True if this is the toplevel window of the process. + // Note that this may be an iframe from another process. + const bool isProcessRoot; + + const bool isInProcess; +}; + +struct ProcInfo { + // Process Id + base::ProcessId pid = 0; + // Child Id as defined by Firefox when a child process is created. + dom::ContentParentId childId; + // Process type + ProcType type; + // Origin, if any + nsCString origin; + // Process filename (without the path name). + nsString filename; + // RSS in bytes. + int64_t residentSetSize = 0; + // Unshared resident size in bytes. + int64_t residentUniqueSize = 0; + // User time in ns. + uint64_t cpuUser = 0; + // System time in ns. + uint64_t cpuKernel = 0; + // Threads owned by this process. + CopyableTArray threads; + // DOM windows represented by this process. + CopyableTArray windows; +}; + +typedef MozPromise, nsresult, true> + ProcInfoPromise; + +/** + * Data we need to request process info (e.g. CPU usage, memory usage) + * from the operating system and populate the resulting `ProcInfo`. + * + * Note that this structure contains a mix of: + * - low-level handles that we need to request low-level process info + * (`aChildTask` on macOS, `aPid` on other platforms); and + * - high-level data that we already acquired while looking for + * `aPid`/`aChildTask` and that we will need further down the road. + */ +struct ProcInfoRequest { + ProcInfoRequest(base::ProcessId aPid, ProcType aProcessType, + const nsACString& aOrigin, nsTArray&& aWindowInfo, + uint32_t aChildId = 0 +#ifdef XP_MACOSX + , + mach_port_t aChildTask = 0 +#endif // XP_MACOSX + ) + : pid(aPid), + processType(aProcessType), + origin(aOrigin), + windowInfo(std::move(aWindowInfo)), + childId(aChildId) +#ifdef XP_MACOSX + , + childTask(aChildTask) +#endif // XP_MACOSX + { + } + const base::ProcessId pid; + const ProcType processType; + const nsCString origin; + const nsTArray windowInfo; + // If the process is a child, its child id, otherwise `0`. + const int32_t childId; +#ifdef XP_MACOSX + const mach_port_t childTask; +#endif // XP_MACOSX +}; + +/** + * Batch a request for low-level information on Gecko processes. + * + * # Request + * + * Argument `aRequests` is a list of processes, along with high-level data + * we have already obtained on them and that we need to populate the + * resulting array of `ProcInfo`. + * + * # Result + * + * This call succeeds (possibly with missing data, see below) unless we + * cannot allocate memory. + * + * # Performance + * + * - This call is always executed on a background thread. + * - This call does NOT wake up children processes. + * - This function is sometimes observably slow to resolve, in particular + * under Windows. + * + * # Error-handling and race conditions + * + * Requesting low-level information on a process and its threads is inherently + * subject to race conditions. Typically, if a process or a thread is killed + * while we're preparing to fetch information, we can easily end up with + * system/lib calls that return failures. + * + * For this reason, this API assumes that errors when placing a system/lib call + * are likely and normal. When some information cannot be obtained, the API will + * simply skip over said information. + * + * Note that due to different choices by OSes, the exact information we skip may + * vary across platforms. For instance, under Unix, failing to access the + * threads of a process will cause us to skip all data on the process, while + * under Windows, process information will be returned without thread + * information. + */ +RefPtr GetProcInfo(nsTArray&& aRequests); + +/** + * Utility function: copy data from a `ProcInfo` and into either a + * `ParentProcInfoDictionary` or a `ChildProcInfoDictionary`. + */ +template +nsresult CopySysProcInfoToDOM(const ProcInfo& source, T* dest) { + // Copy system info. + dest->mPid = source.pid; + dest->mFilename.Assign(source.filename); + dest->mResidentSetSize = source.residentSetSize; + dest->mResidentUniqueSize = source.residentUniqueSize; + dest->mCpuUser = source.cpuUser; + dest->mCpuKernel = source.cpuKernel; + + // Copy thread info. + mozilla::dom::Sequence threads; + for (const ThreadInfo& entry : source.threads) { + mozilla::dom::ThreadInfoDictionary* thread = + threads.AppendElement(fallible); + if (NS_WARN_IF(!thread)) { + return NS_ERROR_OUT_OF_MEMORY; + } + thread->mCpuUser = entry.cpuUser; + thread->mCpuKernel = entry.cpuKernel; + thread->mTid = entry.tid; + thread->mName.Assign(entry.name); + } + dest->mThreads = std::move(threads); + return NS_OK; +} + +} // namespace mozilla +#endif // ProcInfo_h diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/ProcInfo_linux.cpp firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/ProcInfo_linux.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/ProcInfo_linux.cpp 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/ProcInfo_linux.cpp 2020-11-17 19:31:55.000000000 +0000 @@ -0,0 +1,297 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ProcInfo.h" +#include "mozilla/Sprintf.h" +#include "mozilla/Logging.h" +#include "mozilla/ipc/GeckoChildProcessHost.h" +#include "nsLocalFile.h" +#include "nsMemoryReporterManager.h" +#include "nsNetCID.h" +#include "nsWhitespaceTokenizer.h" + +#include +#include +#include +#include + +#define NANOPERSEC 1000000000. + +namespace mozilla { + +// StatReader can parse and tokenize a POSIX stat file. +// see http://man7.org/linux/man-pages/man5/proc.5.html +// +// Its usage is quite simple: +// +// StatReader reader(pid); +// ProcInfo info; +// rv = reader.ParseProc(info); +// if (NS_FAILED(rv)) { +// // the reading of the file or its parsing failed. +// } +// +class StatReader { + public: + explicit StatReader(const base::ProcessId aPid) + : mPid(aPid), mMaxIndex(53), mTicksPerSec(sysconf(_SC_CLK_TCK)) { + mFilepath.AppendPrintf("/proc/%u/stat", mPid); + } + + nsresult ParseProc(ProcInfo& aInfo) { + nsAutoString fileContent; + nsresult rv = ReadFile(fileContent); + NS_ENSURE_SUCCESS(rv, rv); + // We first extract the filename + int32_t startPos = fileContent.RFindChar('('); + if (startPos == -1) { + return NS_ERROR_FAILURE; + } + int32_t endPos = fileContent.RFindChar(')'); + if (endPos == -1) { + return NS_ERROR_FAILURE; + } + int32_t len = endPos - (startPos + 1); + aInfo.filename.Assign(Substring(fileContent, startPos + 1, len)); + + // now we can use the tokenizer for the rest of the file + nsWhitespaceTokenizer tokenizer(Substring(fileContent, endPos + 2)); + int32_t index = 2; // starting at third field + while (tokenizer.hasMoreTokens() && index < mMaxIndex) { + const nsAString& token = tokenizer.nextToken(); + rv = UseToken(index, token, aInfo); + NS_ENSURE_SUCCESS(rv, rv); + index++; + } + return NS_OK; + } + + protected: + // Called for each token found in the stat file. + nsresult UseToken(int32_t aIndex, const nsAString& aToken, ProcInfo& aInfo) { + // We're using a subset of what stat has to offer for now. + nsresult rv = NS_OK; + // see the proc documentation for fields index references. + switch (aIndex) { + case 13: + // Amount of time that this process has been scheduled + // in user mode, measured in clock ticks + aInfo.cpuUser = GetCPUTime(aToken, &rv); + NS_ENSURE_SUCCESS(rv, rv); + break; + case 14: + // Amount of time that this process has been scheduled + // in kernel mode, measured in clock ticks + aInfo.cpuKernel = GetCPUTime(aToken, &rv); + NS_ENSURE_SUCCESS(rv, rv); + break; + case 23: + // Resident Set Size: number of pages the process has + // in real memory. + uint64_t pageCount = Get64Value(aToken, &rv); + NS_ENSURE_SUCCESS(rv, rv); + uint64_t pageSize = sysconf(_SC_PAGESIZE); + aInfo.residentSetSize = pageCount * pageSize; + break; + } + return rv; + } + + // Converts a token into a int64_t + uint64_t Get64Value(const nsAString& aToken, nsresult* aRv) { + // We can't use aToken.ToInteger64() since it returns a signed 64. + // and that can result into an overflow. + nsresult rv = NS_OK; + uint64_t out = 0; + if (sscanf(NS_ConvertUTF16toUTF8(aToken).get(), "%" PRIu64, &out) == 0) { + rv = NS_ERROR_FAILURE; + } + *aRv = rv; + return out; + } + + // Converts a token into CPU time in nanoseconds. + uint64_t GetCPUTime(const nsAString& aToken, nsresult* aRv) { + nsresult rv; + uint64_t value = Get64Value(aToken, &rv); + *aRv = rv; + if (NS_FAILED(rv)) { + return 0; + } + if (value) { + value = (value * NANOPERSEC) / mTicksPerSec; + } + return value; + } + + base::ProcessId mPid; + int32_t mMaxIndex; + nsCString mFilepath; + ProcInfo mProcInfo; + + private: + // Reads the stat file and puts its content in a nsString. + nsresult ReadFile(nsAutoString& aFileContent) { + RefPtr file = new nsLocalFile(mFilepath); + bool exists; + nsresult rv = file->Exists(&exists); + NS_ENSURE_SUCCESS(rv, rv); + if (!exists) { + return NS_ERROR_FAILURE; + } + // /proc is a virtual file system and all files are + // of size 0, so GetFileSize() and related functions will + // return 0 - so the way to read the file is to fill a buffer + // of an arbitrary big size and look for the end of line char. + FILE* fstat; + if (NS_FAILED(file->OpenANSIFileDesc("r", &fstat)) || !fstat) { + return NS_ERROR_FAILURE; + } + char buffer[2048]; + char* end; + char* start = fgets(buffer, 2048, fstat); + fclose(fstat); + if (start == nullptr) { + return NS_ERROR_FAILURE; + } + // let's find the end + end = strchr(buffer, '\n'); + if (!end) { + return NS_ERROR_FAILURE; + } + aFileContent.AssignASCII(buffer, size_t(end - start)); + return NS_OK; + } + + int64_t mTicksPerSec; +}; + +// Threads have the same stat file. The only difference is its path +// and we're getting less info in the ThreadInfo structure. +class ThreadInfoReader final : public StatReader { + public: + ThreadInfoReader(const base::ProcessId aPid, const base::ProcessId aTid) + : StatReader(aPid), mTid(aTid) { + // Adding the thread path + mFilepath.Truncate(); + mFilepath.AppendPrintf("/proc/%u/task/%u/stat", aPid, mTid); + mMaxIndex = 17; + } + + nsresult ParseThread(ThreadInfo& aInfo) { + ProcInfo info; + nsresult rv = StatReader::ParseProc(info); + NS_ENSURE_SUCCESS(rv, rv); + + aInfo.tid = mTid; + // Copying over the data we got from StatReader::ParseProc() + aInfo.cpuKernel = info.cpuKernel; + aInfo.cpuUser = info.cpuUser; + aInfo.name.Assign(info.filename); + return NS_OK; + } + + private: + base::ProcessId mTid; +}; + +RefPtr GetProcInfo(nsTArray&& aRequests) { + auto holder = MakeUnique>(); + RefPtr promise = holder->Ensure(__func__); + nsresult rv = NS_OK; + nsCOMPtr target = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to get stream transport service"); + holder->Reject(rv, __func__); + return promise; + } + + RefPtr r = NS_NewRunnableFunction( + __func__, + [holder = std::move(holder), requests = std::move(aRequests)]() { + HashMap gathered; + if (!gathered.reserve(requests.Length())) { + holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); + return; + } + for (const auto& request : requests) { + // opening the stat file and reading its content + StatReader reader(request.pid); + ProcInfo info; + nsresult rv = reader.ParseProc(info); + if (NS_FAILED(rv)) { + // Can't read data for this proc. + // Probably either a sandboxing issue or a race condition, e.g. + // the process has been just been killed. Regardless, skip process. + continue; + } + // Computing the resident unique size is somewhat tricky, + // so we use about:memory's implementation. This implementation + // reopens `/proc/[pid]`, so there is the risk of an additional + // race condition. In that case, the result is `0`. + info.residentUniqueSize = + nsMemoryReporterManager::ResidentUnique(request.pid); + + // Extra info + info.pid = request.pid; + info.childId = request.childId; + info.type = request.processType; + info.origin = request.origin; + info.windows = std::move(request.windowInfo); + + // Let's look at the threads + nsCString taskPath; + taskPath.AppendPrintf("/proc/%u/task", request.pid); + DIR* dirHandle = opendir(taskPath.get()); + if (!dirHandle) { + // For some reason, we have no data on the threads for this process. + // Most likely reason is that we have just lost a race condition and + // the process is dead. + // Let's stop here and ignore the entire process. + continue; + } + auto cleanup = mozilla::MakeScopeExit([&] { closedir(dirHandle); }); + + // If we can't read some thread info, we ignore that thread. + dirent* entry; + while ((entry = readdir(dirHandle)) != nullptr) { + if (entry->d_name[0] == '.') { + continue; + } + // Threads have a stat file, like processes. + nsAutoCString entryName(entry->d_name); + int32_t tid = entryName.ToInteger(&rv); + if (NS_FAILED(rv)) { + continue; + } + ThreadInfoReader reader(request.pid, tid); + ThreadInfo threadInfo; + rv = reader.ParseThread(threadInfo); + if (NS_FAILED(rv)) { + continue; + } + info.threads.AppendElement(threadInfo); + } + + if (!gathered.put(request.pid, std::move(info))) { + holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); + return; + } + } + + // ... and we're done! + holder->Resolve(std::move(gathered), __func__); + }); + + rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch the LoadDataRunnable."); + } + return promise; +} + +} // namespace mozilla diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/ProcInfo.mm firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/ProcInfo.mm --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/ProcInfo.mm 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/ProcInfo.mm 2020-11-17 19:31:54.000000000 +0000 @@ -0,0 +1,164 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ProcInfo.h" +#include "mozilla/ScopeExit.h" +#include "mozilla/ipc/GeckoChildProcessHost.h" + +#include "nsMemoryReporterManager.h" +#include "nsNetCID.h" + +#include +#include +#include + +#include +#include +#include + +namespace mozilla { + +RefPtr GetProcInfo(nsTArray&& aRequests) { + auto holder = MakeUnique>(); + RefPtr promise = holder->Ensure(__func__); + nsresult rv = NS_OK; + nsCOMPtr target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to get stream transport service"); + holder->Reject(rv, __func__); + return promise; + } + + RefPtr r = NS_NewRunnableFunction( + __func__, [holder = std::move(holder), requests = std::move(aRequests)]() { + HashMap gathered; + if (!gathered.reserve(requests.Length())) { + holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); + return; + } + for (const auto& request : requests) { + ProcInfo info; + info.pid = request.pid; + info.childId = request.childId; + info.type = request.processType; + info.origin = std::move(request.origin); + info.windows = std::move(request.windowInfo); + struct proc_bsdinfo proc; + if ((unsigned long)proc_pidinfo(request.pid, PROC_PIDTBSDINFO, 0, &proc, + PROC_PIDTBSDINFO_SIZE) < PROC_PIDTBSDINFO_SIZE) { + // Can't read data for this proc. + // Probably either a sandboxing issue or a race condition, e.g. + // the process has been just been killed. Regardless, skip process. + continue; + } + + struct proc_taskinfo pti; + if ((unsigned long)proc_pidinfo(request.pid, PROC_PIDTASKINFO, 0, &pti, + PROC_PIDTASKINFO_SIZE) < PROC_PIDTASKINFO_SIZE) { + continue; + } + + // copying all the info to the ProcInfo struct + info.filename.AssignASCII(proc.pbi_name); + info.residentSetSize = pti.pti_resident_size; + info.cpuUser = pti.pti_total_user; + info.cpuKernel = pti.pti_total_system; + + mach_port_t selectedTask; + // If we did not get a task from a child process, we use mach_task_self() + if (request.childTask == MACH_PORT_NULL) { + selectedTask = mach_task_self(); + } else { + selectedTask = request.childTask; + } + // Computing the resident unique size is somewhat tricky, + // so we use about:memory's implementation. This implementation + // uses the `task` so, in theory, should be no additional + // race condition. However, in case of error, the result is `0`. + info.residentUniqueSize = nsMemoryReporterManager::ResidentUnique(selectedTask); + + // Now getting threads info + + // task_threads() gives us a snapshot of the process threads + // but those threads can go away. All the code below makes + // the assumption that thread_info() calls may fail, and + // these errors will be ignored. + thread_act_port_array_t threadList; + mach_msg_type_number_t threadCount; + kern_return_t kret = task_threads(selectedTask, &threadList, &threadCount); + if (kret != KERN_SUCCESS) { + // For some reason, we have no data on the threads for this process. + // Most likely reason is that we have just lost a race condition and + // the process is dead. + // Let's stop here and ignore the entire process. + continue; + } + + // Deallocate the thread list. + // Note that this deallocation is entirely undocumented, so the following code is based + // on guesswork and random examples found on the web. + auto guardThreadCount = MakeScopeExit([&] { + if (threadList == nullptr) { + return; + } + // Free each thread to avoid leaks. + for (mach_msg_type_number_t i = 0; i < threadCount; i++) { + mach_port_deallocate(mach_task_self(), threadList[i]); + } + vm_deallocate(mach_task_self(), /* address */ (vm_address_t)threadList, + /* size */ sizeof(thread_t) * threadCount); + }); + + mach_msg_type_number_t count; + + for (mach_msg_type_number_t i = 0; i < threadCount; i++) { + // Basic thread info. + thread_extended_info_data_t threadInfoData; + count = THREAD_EXTENDED_INFO_COUNT; + kret = thread_info(threadList[i], THREAD_EXTENDED_INFO, (thread_info_t)&threadInfoData, + &count); + if (kret != KERN_SUCCESS) { + continue; + } + + // Getting the thread id. + thread_identifier_info identifierInfo; + count = THREAD_IDENTIFIER_INFO_COUNT; + kret = thread_info(threadList[i], THREAD_IDENTIFIER_INFO, + (thread_info_t)&identifierInfo, &count); + if (kret != KERN_SUCCESS) { + continue; + } + + // The two system calls were successful, let's add that thread + ThreadInfo* thread = info.threads.AppendElement(fallible); + if (!thread) { + holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); + return; + } + thread->cpuUser = threadInfoData.pth_user_time; + thread->cpuKernel = threadInfoData.pth_system_time; + thread->name.AssignASCII(threadInfoData.pth_name); + thread->tid = identifierInfo.thread_id; + } + + if (!gathered.put(request.pid, std::move(info))) { + holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); + return; + } + } + // ... and we're done! + holder->Resolve(std::move(gathered), __func__); + }); + + rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch the LoadDataRunnable."); + } + return promise; +} + +} // namespace mozilla diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/ProcInfo_win.cpp firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/ProcInfo_win.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/ProcInfo_win.cpp 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/ProcInfo_win.cpp 2020-11-17 19:31:54.000000000 +0000 @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/ProcInfo.h" +#include "mozilla/ipc/GeckoChildProcessHost.h" +#include "nsMemoryReporterManager.h" +#include "nsNetCID.h" +#include "nsWindowsHelpers.h" +#include +#include +#include + +typedef HRESULT(WINAPI* GETTHREADDESCRIPTION)(HANDLE hThread, + PWSTR* threadDescription); + +namespace mozilla { + +uint64_t ToNanoSeconds(const FILETIME& aFileTime) { + // FILETIME values are 100-nanoseconds units, converting + ULARGE_INTEGER usec = {{aFileTime.dwLowDateTime, aFileTime.dwHighDateTime}}; + return usec.QuadPart * 100; +} + +RefPtr GetProcInfo(nsTArray&& aRequests) { + auto holder = MakeUnique>(); + RefPtr promise = holder->Ensure(__func__); + + nsresult rv = NS_OK; + nsCOMPtr target = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to get stream transport service"); + holder->Reject(rv, __func__); + return promise; + } + + RefPtr r = NS_NewRunnableFunction( + __func__, + [holder = std::move(holder), requests = std::move(aRequests)]() -> void { + HashMap gathered; + if (!gathered.reserve(requests.Length())) { + holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); + return; + } + + // ---- Copying data on processes (minus threads). + + for (const auto& request : requests) { + nsAutoHandle handle(OpenProcess( + PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, request.pid)); + + if (!handle) { + // Ignore process, it may have died. + continue; + } + + wchar_t filename[MAX_PATH]; + if (GetProcessImageFileNameW(handle.get(), filename, MAX_PATH) == 0) { + // Ignore process, it may have died. + continue; + } + FILETIME createTime, exitTime, kernelTime, userTime; + if (!GetProcessTimes(handle.get(), &createTime, &exitTime, + &kernelTime, &userTime)) { + // Ignore process, it may have died. + continue; + } + PROCESS_MEMORY_COUNTERS memoryCounters; + if (!GetProcessMemoryInfo(handle.get(), + (PPROCESS_MEMORY_COUNTERS)&memoryCounters, + sizeof(memoryCounters))) { + // Ignore process, it may have died. + continue; + } + + // Assumption: values of `pid` are distinct between processes, + // regardless of any race condition we might have stumbled upon. Even + // if it somehow could happen, in the worst case scenario, we might + // end up overwriting one process info and we might end up with too + // many threads attached to a process, as the data is not crucial, we + // do not need to defend against that (unlikely) scenario. + ProcInfo info; + info.pid = request.pid; + info.childId = request.childId; + info.type = request.processType; + info.origin = request.origin; + info.windows = std::move(request.windowInfo); + info.filename.Assign(filename); + info.cpuKernel = ToNanoSeconds(kernelTime); + info.cpuUser = ToNanoSeconds(userTime); + info.residentSetSize = memoryCounters.WorkingSetSize; + + // Computing the resident unique size is somewhat tricky, + // so we use about:memory's implementation. This implementation + // uses the `HANDLE` so, in theory, should be no additional + // race condition. However, in case of error, the result is `0`. + info.residentUniqueSize = + nsMemoryReporterManager::ResidentUnique(handle.get()); + + if (!gathered.put(request.pid, std::move(info))) { + holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); + return; + } + } + + // ---- Add thread data to already-copied processes. + + // First, we need to capture a snapshot of all the threads on this + // system. + nsAutoHandle hThreadSnap(CreateToolhelp32Snapshot( + /* dwFlags */ TH32CS_SNAPTHREAD, /* ignored */ 0)); + if (!hThreadSnap) { + holder->Reject(NS_ERROR_UNEXPECTED, __func__); + return; + } + + // `GetThreadDescription` is available as of Windows 10. + // We attempt to import it dynamically, knowing that it + // may be `nullptr`. + auto getThreadDescription = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleW(L"Kernel32.dll"), "GetThreadDescription")); + + THREADENTRY32 te32; + te32.dwSize = sizeof(THREADENTRY32); + + // Now, walk through the threads. + for (auto success = Thread32First(hThreadSnap.get(), &te32); success; + success = Thread32Next(hThreadSnap.get(), &te32)) { + auto processLookup = gathered.lookup(te32.th32OwnerProcessID); + if (!processLookup) { + // Not one of the processes we're interested in. + continue; + } + ThreadInfo* threadInfo = + processLookup->value().threads.AppendElement(fallible); + if (!threadInfo) { + holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); + return; + } + + nsAutoHandle hThread( + OpenThread(/* dwDesiredAccess = */ THREAD_QUERY_INFORMATION, + /* bInheritHandle = */ FALSE, + /* dwThreadId = */ te32.th32ThreadID)); + if (!hThread) { + // Cannot open thread. Not sure why, but let's erase this thread + // and attempt to find data on other threads. + processLookup->value().threads.RemoveLastElement(); + continue; + } + + threadInfo->tid = te32.th32ThreadID; + + // Attempt to get thread times. + // If we fail, continue without this piece of information. + FILETIME createTime, exitTime, kernelTime, userTime; + if (GetThreadTimes(hThread.get(), &createTime, &exitTime, &kernelTime, + &userTime)) { + threadInfo->cpuKernel = ToNanoSeconds(kernelTime); + threadInfo->cpuUser = ToNanoSeconds(userTime); + } + + // Attempt to get thread name. + // If we fail, continue without this piece of information. + if (getThreadDescription) { + PWSTR threadName = nullptr; + if (getThreadDescription(hThread.get(), &threadName) && + threadName) { + threadInfo->name = threadName; + } + if (threadName) { + LocalFree(threadName); + } + } + } + + // ----- We're ready to return. + holder->Resolve(std::move(gathered), __func__); + }); + + rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch the LoadDataRunnable."); + } + + return promise; +} + +} // namespace mozilla diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/tests/browser/browser.ini firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/tests/browser/browser.ini --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/tests/browser/browser.ini 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/tests/browser/browser.ini 2020-11-17 19:31:55.000000000 +0000 @@ -0,0 +1,9 @@ +[DEFAULT] +prefs= + media.rdd-process.enabled=true + +support-files = + dummy.html + +[browser_test_procinfo.js] +skip-if = (ccov && os == "linux") # https://bugzilla.mozilla.org/show_bug.cgi?id=1608080 diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/tests/browser/browser_test_procinfo.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/tests/browser/browser_test_procinfo.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/tests/browser/browser_test_procinfo.js 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/tests/browser/browser_test_procinfo.js 2020-11-17 19:31:54.000000000 +0000 @@ -0,0 +1,173 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +const DUMMY_URL = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" + ) + "/dummy.html"; + +const { AppConstants } = ChromeUtils.import( + "resource://gre/modules/AppConstants.jsm" +); +const MAC = AppConstants.platform == "macosx"; +const HAS_THREAD_NAMES = + AppConstants.platform != "win" || + AppConstants.isPlatformAndVersionAtLeast("win", 10); +const isFissionEnabled = SpecialPowers.useRemoteSubframes; + +const SAMPLE_SIZE = 10; + +add_task(async function test_proc_info() { + console.log("YORIC", "Test starts"); + // Open a few `about:home` tabs, they'll end up in `privilegedabout`. + let tabsAboutHome = []; + for (let i = 0; i < 5; ++i) { + let tab = BrowserTestUtils.addTab(gBrowser, "about:home"); + tabsAboutHome.push(tab); + gBrowser.selectedTab = tab; + await BrowserTestUtils.browserLoaded(tab.linkedBrowser); + } + + await BrowserTestUtils.withNewTab( + { gBrowser, url: DUMMY_URL }, + async function(browser) { + let cpuThreads = 0; + let cpuUser = 0; + + // We test `SAMPLE_SIZE` times to increase a tad the chance of encountering race conditions. + for (let z = 0; z < SAMPLE_SIZE; z++) { + let parentProc = await ChromeUtils.requestProcInfo(); + cpuUser += parentProc.cpuUser; + + Assert.equal( + parentProc.type, + "browser", + "Parent proc type should be browser" + ); + + for (var x = 0; x < parentProc.threads.length; x++) { + cpuThreads += parentProc.threads[x].cpuUser; + } + + // Under Windows, thread names appeared with Windows 10. + if (HAS_THREAD_NAMES) { + Assert.ok( + parentProc.threads.some(thread => thread.name), + "At least one of the threads of the parent process is named" + ); + } + + Assert.ok( + parentProc.residentUniqueSize > 0, + "Resident-unique-size was set" + ); + Assert.ok( + parentProc.residentUniqueSize <= parentProc.residentSetSize, + `Resident-unique-size should be bounded by resident-set-size ${parentProc.residentUniqueSize} <= ${parentProc.residentSetSize}` + ); + + // While it's very unlikely that the parent will disappear while we're running + // tests, some children can easily vanish. So we go twice through the list of + // children. Once to test stuff that all process data respects the invariants + // that don't care whether we have a race condition and once to test that at + // least one well-known process that should not be able to vanish during + // the test respects all the invariants. + for (var i = 0; i < parentProc.children.length; i++) { + let childProc = parentProc.children[i]; + Assert.notEqual( + childProc.type, + "browser", + "Child proc type should not be browser" + ); + + // We set the `childID` for child processes that have a `ContentParent`/`ContentChild` + // actor hierarchy. + if (childProc.type.startsWith("web")) { + Assert.notEqual( + childProc.childID, + 0, + "Child proc should have been set" + ); + } + Assert.notEqual( + childProc.type, + "unknown", + "Child proc type should be known" + ); + if (childProc.type == "webIsolated") { + Assert.notEqual( + childProc.origin || "", + "", + "Child process should have an origin" + ); + } + + for (var y = 0; y < childProc.threads.length; y++) { + cpuThreads += childProc.threads[y].cpuUser; + } + cpuUser += childProc.cpuUser; + } + + // We only check other properties on the `privilegedabout` subprocess, which + // as of this writing is always active and available. + var hasPrivilegedAbout = false; + var numberOfAboutTabs = 0; + for (i = 0; i < parentProc.children.length; i++) { + let childProc = parentProc.children[i]; + if (childProc.type != "privilegedabout") { + continue; + } + hasPrivilegedAbout = true; + Assert.ok( + childProc.residentUniqueSize > 0, + "Resident-unique-size was set" + ); + Assert.ok( + childProc.residentUniqueSize <= childProc.residentSetSize, + `Resident-unique-size should be bounded by resident-set-size ${childProc.residentUniqueSize} <= ${childProc.residentSetSize}` + ); + + for (var win of childProc.windows) { + if (win.documentURI.spec != "about:home") { + // We're only interested in about:home for this test. + continue; + } + numberOfAboutTabs++; + Assert.ok( + win.outerWindowId > 0, + `ContentParentID should be > 0 ${win.outerWindowId}` + ); + if (win.documentTitle) { + // Unfortunately, we sometimes reach this point before the document is fully loaded, so + // `win.documentTitle` may still be empty. + Assert.equal(win.documentTitle, "New Tab"); + } + } + Assert.ok( + numberOfAboutTabs >= tabsAboutHome.length, + "We have found at least as many about:home tabs as we opened" + ); + + // Once we have verified the privileged about process, bailout. + break; + } + + Assert.ok( + hasPrivilegedAbout, + "We have found the privileged about process" + ); + } + // see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023 + if (!MAC) { + Assert.greater(cpuThreads, 0, "Got some cpu time in the threads"); + } + Assert.greater(cpuUser, 0, "Got some cpu time"); + + for (let tab of tabsAboutHome) { + BrowserTestUtils.removeTab(tab); + } + } + ); +}); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/tests/browser/dummy.html firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/tests/browser/dummy.html --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/processtools/tests/browser/dummy.html 1970-01-01 00:00:00.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/processtools/tests/browser/dummy.html 2020-11-17 19:31:53.000000000 +0000 @@ -0,0 +1,20 @@ + + + +Dummy test page + + + +

Dummy test page

+
Holder
+ + + diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/remotebrowserutils/tests/browser/browser_documentChannel.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/remotebrowserutils/tests/browser/browser_documentChannel.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/remotebrowserutils/tests/browser/browser_documentChannel.js 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/remotebrowserutils/tests/browser/browser_documentChannel.js 2020-11-17 19:31:54.000000000 +0000 @@ -140,21 +140,15 @@ ); } -async function loadAndGetProcessID(browser, target, expectedProcessSwitch) { +async function loadAndGetProcessID(browser, target) { info(`Performing GET load: ${target}`); await performLoad( browser, { maybeErrorPage: true, }, - async () => { + () => { BrowserTestUtils.loadURI(browser, target); - if (expectedProcessSwitch) { - await BrowserTestUtils.waitForEvent( - gBrowser.getTabForBrowser(browser), - "SSTabRestored" - ); - } } ); @@ -187,11 +181,7 @@ info(`firstProcessID: ${firstProcessID}`); - let secondProcessID = await loadAndGetProcessID( - browser, - target, - expectedProcessSwitch - ); + let secondProcessID = await loadAndGetProcessID(browser, target); info(`secondProcessID: ${secondProcessID}`); Assert.equal(firstProcessID != secondProcessID, expectedProcessSwitch); @@ -200,11 +190,7 @@ return; } - let thirdProcessID = await loadAndGetProcessID( - browser, - add307(target), - expectedProcessSwitch - ); + let thirdProcessID = await loadAndGetProcessID(browser, add307(target)); info(`thirdProcessID: ${thirdProcessID}`); Assert.equal(firstProcessID != thirdProcessID, expectedProcessSwitch); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/remotebrowserutils/tests/browser/browser.ini firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/remotebrowserutils/tests/browser/browser.ini --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/remotebrowserutils/tests/browser/browser.ini 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/remotebrowserutils/tests/browser/browser.ini 2020-11-17 19:31:55.000000000 +0000 @@ -11,7 +11,6 @@ [browser_RemoteWebNavigation.js] skip-if = fission [browser_documentChannel.js] -skip-if = fission [browser_httpCrossOriginOpenerPolicy.js] [browser_httpToFileHistory.js] [browser_oopProcessSwap.js] diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/telemetry/Events.yaml firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/telemetry/Events.yaml --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/telemetry/Events.yaml 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/telemetry/Events.yaml 2020-11-17 19:31:54.000000000 +0000 @@ -726,6 +726,28 @@ extra_keys: enrollmentId: A unique ID for this enrollment that will be included in all related Telemetry. + expose: + objects: [ + "feature_study", + ] + methods: ["expose"] + release_channel_collection: opt-out + products: + - "firefox" + record_in_processes: ["main"] + description: > + This records an event at the moment the user is exposed to an experiment + treatment. The event is triggered either by the code checking that a + certain experiment feature is enabled or when that feature value is used. + This is different from enrollment or experiment activation because it + registers when a user actually gets exposed to the experiment feature. + bug_numbers: [1675104] + notification_emails: ["ujet@mozilla.com"] + expiry_version: "never" + extra_keys: + branchSlug: The slug for the branch the user is enrolled in. + featureId: The type of experiment variant the user was enrolled into. + pwmgr: open_management: objects: ["aboutprotections", "autocomplete", "capturedoorhanger", "contextmenu", "direct", "fxamenu", "mainmenu", "pageinfo", "preferences", "snippet"] diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/url-classifier/tests/mochitest/test_advisory_link.html firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/url-classifier/tests/mochitest/test_advisory_link.html --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/url-classifier/tests/mochitest/test_advisory_link.html 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/url-classifier/tests/mochitest/test_advisory_link.html 2020-11-17 19:31:54.000000000 +0000 @@ -75,7 +75,7 @@ subject => subject == win); let browser = win.gBrowser.selectedBrowser; - await BrowserTestUtils.loadURI(browser, aTestData.url); + BrowserTestUtils.loadURI(browser, aTestData.url); await BrowserTestUtils.waitForContentEvent(browser, "DOMContentLoaded"); let doc = win.gBrowser.contentDocument; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/url-classifier/tests/mochitest/test_reporturl.html firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/url-classifier/tests/mochitest/test_reporturl.html --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/url-classifier/tests/mochitest/test_reporturl.html 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/url-classifier/tests/mochitest/test_reporturl.html 2020-11-17 19:31:54.000000000 +0000 @@ -95,7 +95,7 @@ var createBlockedIframe = function(aWindow, aBrowser, aTopUrl, aUrl) { (async function() { - await BrowserTestUtils.loadURI(aBrowser, aTopUrl); + BrowserTestUtils.loadURI(aBrowser, aTopUrl); await BrowserTestUtils.browserLoaded(aBrowser); await SpecialPowers.spawn(aBrowser, [aUrl], async function(url) { @@ -119,7 +119,7 @@ var createBlockedPage = function(aWindow, aBrowser, aTopUrl, aUrl) { (async function() { - await BrowserTestUtils.loadURI(aBrowser, aTopUrl); + BrowserTestUtils.loadURI(aBrowser, aTopUrl); await BrowserTestUtils.waitForContentEvent(aBrowser, "DOMContentLoaded"); let doc = aWindow.gBrowser.contentDocument; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/url-classifier/tests/mochitest/test_threathit_report.html 2020-11-17 19:31:54.000000000 +0000 @@ -200,7 +200,7 @@ }; win.gBrowser.addProgressListener(progressListener, Ci.nsIWebProgress.NOTIFY_CONTENT_BLOCKING); - await BrowserTestUtils.loadURI(browser, aTestData.url); + BrowserTestUtils.loadURI(browser, aTestData.url); await BrowserTestUtils.browserLoaded( browser, false, diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/windowwatcher/test/browser_non_popup_from_popup.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/windowwatcher/test/browser_non_popup_from_popup.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/windowwatcher/test/browser_non_popup_from_popup.js 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/windowwatcher/test/browser_non_popup_from_popup.js 2020-11-17 19:31:54.000000000 +0000 @@ -36,7 +36,7 @@ const newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, OPEN_PAGE); // Open a new tab that opens a popup with NON_POPUP_OPENER. - await BrowserTestUtils.loadURI(gBrowser, POPUP_OPENER); + BrowserTestUtils.loadURI(gBrowser, POPUP_OPENER); let win = await newPopupPromise; Assert.ok(true, "popup is opened"); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/windowwatcher/test/browser_popup_condition.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/windowwatcher/test/browser_popup_condition.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/components/windowwatcher/test/browser_popup_condition.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/components/windowwatcher/test/browser_popup_condition.js 2020-11-17 19:31:55.000000000 +0000 @@ -205,7 +205,7 @@ }, async function(browser) { const newWinPromise = BrowserTestUtils.waitForNewWindow(); - await BrowserTestUtils.loadURI(gBrowser, SCRIPT_PAGE); + BrowserTestUtils.loadURI(gBrowser, SCRIPT_PAGE); const win = await newWinPromise; const parentChromeFlags = getParentChromeFlags(win); @@ -242,7 +242,7 @@ gBrowser, OPEN_PAGE ); - await BrowserTestUtils.loadURI(gBrowser, SCRIPT_PAGE); + BrowserTestUtils.loadURI(gBrowser, SCRIPT_PAGE); let tab = await newTabPromise; BrowserTestUtils.removeTab(tab); @@ -262,7 +262,7 @@ false, OPEN_PAGE ); - await BrowserTestUtils.loadURI(gBrowser, SCRIPT_PAGE); + BrowserTestUtils.loadURI(gBrowser, SCRIPT_PAGE); await pagePromise; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/content/tests/browser/browser_bug1170531.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/content/tests/browser/browser_bug1170531.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/content/tests/browser/browser_bug1170531.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/content/tests/browser/browser_bug1170531.js 2020-11-17 19:31:55.000000000 +0000 @@ -54,10 +54,7 @@ async function(browser) { let menu_cut_disabled, menu_copy_disabled; - await BrowserTestUtils.loadURI( - browser, - "data:text/html,
hello!
" - ); + BrowserTestUtils.loadURI(browser, "data:text/html,
hello!
"); await BrowserTestUtils.browserLoaded(browser); browser.focus(); await new Promise(resolve => waitForFocus(resolve, window)); @@ -74,7 +71,7 @@ is(menu_copy_disabled, false, "menu_copy should be enabled"); await new Promise(closeMenu); - await BrowserTestUtils.loadURI( + BrowserTestUtils.loadURI( browser, "data:text/html,
hello!
" ); @@ -94,7 +91,7 @@ is(menu_copy_disabled, false, "menu_copy should be enabled"); await new Promise(closeMenu); - await BrowserTestUtils.loadURI(browser, "about:preferences"); + BrowserTestUtils.loadURI(browser, "about:preferences"); await BrowserTestUtils.browserLoaded(browser); browser.focus(); await new Promise(resolve => waitForFocus(resolve, window)); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/content/tests/browser/browser_bug982298.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/content/tests/browser/browser_bug982298.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/content/tests/browser/browser_bug982298.js 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/content/tests/browser/browser_bug982298.js 2020-11-17 19:31:54.000000000 +0000 @@ -34,7 +34,7 @@ let textarea = content.document.getElementById("textarea1"); textarea.scrollTop = textarea.scrollHeight; }); - await BrowserTestUtils.loadURI(browser, "about:blank"); + BrowserTestUtils.loadURI(browser, "about:blank"); await BrowserTestUtils.browserLoaded(browser); ok( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/library/rust/shared/build.rs firefox-trunk-85.0~a1~hg20201117r557492/toolkit/library/rust/shared/build.rs --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/library/rust/shared/build.rs 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/library/rust/shared/build.rs 2020-11-17 19:31:54.000000000 +0000 @@ -9,7 +9,7 @@ fn main() { let ver = version().unwrap(); let mut bootstrap = false; - let max_oom_hook_version = Version::parse("1.50.0-alpha").unwrap(); + let max_oom_hook_version = Version::parse("1.51.0-alpha").unwrap(); if ver >= Version::parse("1.28.0-alpha").unwrap() && ver < max_oom_hook_version { println!("cargo:rustc-cfg=feature=\"oom_with_hook\""); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/modules/E10SUtils.jsm firefox-trunk-85.0~a1~hg20201117r557492/toolkit/modules/E10SUtils.jsm --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/modules/E10SUtils.jsm 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/modules/E10SUtils.jsm 2020-11-17 19:31:54.000000000 +0000 @@ -11,12 +11,6 @@ "resource://gre/modules/XPCOMUtils.jsm" ); -ChromeUtils.defineModuleGetter( - this, - "PrivateBrowsingUtils", - "resource://gre/modules/PrivateBrowsingUtils.jsm" -); - XPCOMUtils.defineLazyPreferenceGetter( this, "useSeparateFileUriProcess", @@ -122,17 +116,6 @@ "xmpp", ]; -const kDocumentChannelDeniedSchemes = ["javascript"]; -const kDocumentChannelDeniedURIs = ["about:crashcontent", "about:printpreview"]; - -// Changes here should also be made in URIUsesDocChannel in DocumentChannel.cpp. -function documentChannelPermittedForURI(aURI) { - return ( - !kDocumentChannelDeniedSchemes.includes(aURI.scheme) && - !kDocumentChannelDeniedURIs.includes(aURI.spec) - ); -} - // Note that even if the scheme fits the criteria for a web-handled scheme // (ie it is compatible with the checks registerProtocolHandler uses), it may // not be web-handled - it could still be handled via the OS by another app. @@ -858,247 +841,6 @@ return deserialized; }, - /** - * Returns whether or not a URI is supposed to load in a particular - * browser given its current remote type. - * - * @param browser () - * The browser to check. - * @param uri (String) - * The URI that will be checked to see if it can load in the - * browser. - * @param multiProcess (boolean, optional) - * Whether or not multi-process tabs are enabled. Defaults to true. - * @param remoteSubframes (boolean, optional) - * Whether or not multi-process subframes are enabled. Defaults to - * false. - * @param flags (Number, optional) - * nsIWebNavigation flags used to clean up the URL in the event that - * it needs fixing ia the URI fixup service. Defaults to - * nsIWebNavigation.LOAD_FLAGS_NONE. - * - * @return (Object) - * An object with the following properties: - * - * uriObject (nsIURI) - * The fixed-up URI that was generated for the check. - * - * requiredRemoteType (String) - * The remoteType that was computed for the browser that - * is required to load the URI. - * - * mustChangeProcess (boolean) - * Whether or not the front-end will be required to flip - * the process in order to view the URI. - * - * NOTE: - * mustChangeProcess might be false even if a process - * flip will occur. In this case, DocumentChannel is taking - * care of the process flip for us rather than the front-end - * code. - * - * newFrameloader (boolean) - * Whether or not a new frameloader will need to be created - * in order to browse to this URI. For non-Fission, this is - * important if we're transition from a web content process - * to another web content process, but want to force the - * creation of a _new_ web content process. - */ - shouldLoadURIInBrowser( - browser, - uri, - multiProcess = true, - remoteSubframes = false, - flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE - ) { - let currentRemoteType = browser.remoteType; - let requiredRemoteType; - let uriObject; - try { - let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_NONE; - if (flags & Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) { - fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP; - } - if (flags & Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS) { - fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS; - } - if (PrivateBrowsingUtils.isBrowserPrivate(browser)) { - fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_PRIVATE_CONTEXT; - } - - uriObject = Services.uriFixup.getFixupURIInfo(uri, fixupFlags) - .preferredURI; - // Note that I had thought that we could set uri = uriObject.spec here, to - // save on fixup later on, but that changes behavior and breaks tests. - requiredRemoteType = this.getRemoteTypeForURIObject( - uriObject, - multiProcess, - remoteSubframes, - currentRemoteType, - browser.currentURI - ); - } catch (e) { - // createFixupURI throws if it can't create a URI. If that's the case then - // we still need to pass down the uri because docshell handles this case. - requiredRemoteType = multiProcess ? DEFAULT_REMOTE_TYPE : NOT_REMOTE; - } - - let mustChangeProcess = requiredRemoteType != currentRemoteType; - - let newFrameloader = false; - if ( - browser.getAttribute("preloadedState") === "consumed" && - uri != "about:newtab" - ) { - // Leaving about:newtab from a used to be preloaded browser should run the process - // selecting algorithm again. - mustChangeProcess = true; - newFrameloader = true; - } - - // If we already have a content process, and the load will be - // handled using DocumentChannel, then we can skip switching - // for now, and let DocumentChannel do it during the response. - if (uriObject && documentChannelPermittedForURI(uriObject)) { - mustChangeProcess = false; - newFrameloader = false; - } - - return { - uriObject, - requiredRemoteType, - mustChangeProcess, - newFrameloader, - }; - }, - - shouldLoadURIInThisProcess(aURI, aRemoteSubframes) { - let remoteType = Services.appinfo.remoteType; - let wantRemoteType = this.getRemoteTypeForURIObject( - aURI, - /* remote */ true, - aRemoteSubframes, - remoteType - ); - this.log().info( - `shouldLoadURIInThisProcess: have ${remoteType} want ${wantRemoteType}` - ); - - if (documentChannelPermittedForURI(aURI)) { - // We can switch later with documentchannel. - return true; - } - - return remoteType == wantRemoteType; - }, - - shouldLoadURI(aDocShell, aURI, aHasPostData) { - let { useRemoteSubframes } = aDocShell; - this.log().debug(`shouldLoadURI(${this._uriStr(aURI)})`); - - let remoteType = Services.appinfo.remoteType; - - if (aDocShell.browsingContext.parent) { - return true; - } - - let webNav = aDocShell.QueryInterface(Ci.nsIWebNavigation); - let sessionHistory = webNav.sessionHistory; - let wantRemoteType = this.getRemoteTypeForURIObject( - aURI, - true, - useRemoteSubframes, - remoteType, - webNav.currentURI - ); - - // If we are using DocumentChannel or remote subframes (fission), we - // can start the load in the current process, and then perform the - // switch later-on using the DocumentLoadListener mechanism. - if (documentChannelPermittedForURI(aURI)) { - return true; - } - - if ( - !aHasPostData && - remoteType == WEB_REMOTE_TYPE && - sessionHistory.count == 1 && - webNav.currentURI.spec == "about:newtab" - ) { - // This is possibly a preloaded browser and we're about to navigate away for - // the first time. On the child side there is no way to tell for sure if that - // is the case, so let's redirect this request to the parent to decide if a new - // process is needed. But we don't currently properly handle POST data in - // redirects (bug 1457520), so if there is POST data, don't return false here. - return false; - } - - // Allow history load if loaded in this process before. - if (!Services.appinfo.sessionHistoryInParent) { - let requestedIndex = sessionHistory.legacySHistory.requestedIndex; - if (requestedIndex >= 0) { - this.log().debug("Checking history case\n"); - if ( - sessionHistory.legacySHistory.getEntryAtIndex(requestedIndex) - .loadedInThisProcess - ) { - this.log().info("History entry loaded in this process"); - return true; - } - - // If not originally loaded in this process allow it if the URI would - // normally be allowed to load in this process by default. - this.log().debug( - `Checking remote type, got: ${remoteType} want: ${wantRemoteType}\n` - ); - return remoteType == wantRemoteType; - } - } - - // If the URI can be loaded in the current process then continue - return remoteType == wantRemoteType; - }, - - redirectLoad( - aDocShell, - aURI, - aReferrerInfo, - aTriggeringPrincipal, - aFlags, - aCsp - ) { - const actor = aDocShell.domWindow.windowGlobalChild.getActor("BrowserTab"); - - let loadOptions = { - uri: aURI.spec, - flags: aFlags || Ci.nsIWebNavigation.LOAD_FLAGS_NONE, - referrerInfo: this.serializeReferrerInfo(aReferrerInfo), - triggeringPrincipal: this.serializePrincipal( - aTriggeringPrincipal || - Services.scriptSecurityManager.createNullPrincipal({}) - ), - csp: aCsp ? this.serializeCSP(aCsp) : null, - }; - // Retarget the load to the correct process - if (!Services.appinfo.sessionHistoryInParent) { - let sessionHistory = aDocShell.QueryInterface(Ci.nsIWebNavigation) - .sessionHistory; - actor.sendAsyncMessage("Browser:LoadURI", { - loadOptions, - historyIndex: sessionHistory.legacySHistory.requestedIndex, - }); - } else { - // If we can't access legacySHistory, session history in the - // parent is enabled. Browser:LoadURI knows about this and will - // act accordingly. - actor.sendAsyncMessage("Browser:LoadURI", { - loadOptions, - }); - } - - return false; - }, - wrapHandlingUserInput(aWindow, aIsHandling, aCallback) { var handlingUserInput; try { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/modules/tests/browser/browser_FinderHighlighter.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/modules/tests/browser/browser_FinderHighlighter.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/modules/tests/browser/browser_FinderHighlighter.js 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/modules/tests/browser/browser_FinderHighlighter.js 2020-11-17 19:31:54.000000000 +0000 @@ -300,7 +300,7 @@ insertCalls: [0, 0], removeCalls: [1, 2], }); - await BrowserTestUtils.loadURI(browser, url); + BrowserTestUtils.loadURI(browser, url); await promise; BrowserTestUtils.removeTab(tab); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/mozapps/extensions/content/extensions.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/mozapps/extensions/content/extensions.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/mozapps/extensions/content/extensions.js 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/mozapps/extensions/content/extensions.js 2020-11-17 19:31:55.000000000 +0000 @@ -94,19 +94,13 @@ addon = await AddonManager.getAddonByID(id); } - AMTelemetry.recordViewEvent({ view: getCurrentViewName(), addon, type }); -} - -function getCurrentViewName() { - let view = gViewController.currentViewObj; - let entries = Object.entries(gViewController.viewObjects); - let viewIndex = entries.findIndex(([name, viewObj]) => { - return viewObj == view; + let { currentViewId } = gViewController; + let viewType = gViewController.parseViewId(currentViewId)?.type; + AMTelemetry.recordViewEvent({ + view: viewType || "other", + addon, + type, }); - if (viewIndex != -1) { - return entries[viewIndex][0]; - } - return "other"; } // Used by external callers to load a specific view into the manager diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/mozapps/extensions/test/browser/browser_history_navigation.js firefox-trunk-85.0~a1~hg20201117r557492/toolkit/mozapps/extensions/test/browser/browser_history_navigation.js --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/mozapps/extensions/test/browser/browser_history_navigation.js 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/mozapps/extensions/test/browser/browser_history_navigation.js 2020-11-17 19:31:55.000000000 +0000 @@ -199,7 +199,7 @@ ok(!gBrowser.canGoBack, "Should not be able to go back"); ok(!gBrowser.canGoForward, "Should not be able to go forward"); - await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:addons"); + BrowserTestUtils.loadURI(gBrowser.selectedBrowser, "about:addons"); await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); let manager = await wait_for_manager_load(gBrowser.contentWindow); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/toolkit/xre/glxtest.cpp firefox-trunk-85.0~a1~hg20201117r557492/toolkit/xre/glxtest.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/toolkit/xre/glxtest.cpp 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/toolkit/xre/glxtest.cpp 2020-11-17 19:31:54.000000000 +0000 @@ -132,6 +132,88 @@ // care about leaking memory extern "C" { +#define PCI_FILL_IDENT 0x0001 +#define PCI_FILL_CLASS 0x0020 +#define PCI_BASE_CLASS_DISPLAY 0x03 + +static int get_pci_status(char* buf, int bufsize) { + void* libpci = dlopen("libpci.so.3", RTLD_LAZY); + if (!libpci) { + libpci = dlopen("libpci.so", RTLD_LAZY); + } + if (!libpci) { + return 0; + } + + typedef struct pci_dev { + struct pci_dev* next; + uint16_t domain_16; + uint8_t bus, dev, func; + unsigned int known_fields; + uint16_t vendor_id, device_id; + uint16_t device_class; + } pci_dev; + + typedef struct pci_access { + unsigned int method; + int writeable; + int buscentric; + char* id_file_name; + int free_id_name; + int numeric_ids; + unsigned int id_lookup_mode; + int debugging; + void* error; + void* warning; + void* debug; + pci_dev* devices; + } pci_access; + + typedef pci_access* (*PCIALLOC)(void); + PCIALLOC pci_alloc = cast(dlsym(libpci, "pci_alloc")); + + typedef void (*PCIINIT)(pci_access*); + PCIINIT pci_init = cast(dlsym(libpci, "pci_init")); + + typedef void (*PCICLEANUP)(pci_access*); + PCICLEANUP pci_cleanup = cast(dlsym(libpci, "pci_cleanup")); + + typedef void (*PCISCANBUS)(pci_access*); + PCISCANBUS pci_scan_bus = cast(dlsym(libpci, "pci_scan_bus")); + + typedef void (*PCIFILLINFO)(pci_dev*, int); + PCIFILLINFO pci_fill_info = cast(dlsym(libpci, "pci_fill_info")); + + if (!pci_alloc || !pci_cleanup || !pci_scan_bus || !pci_fill_info) { + dlclose(libpci); + return 0; + } + + pci_access* pacc = pci_alloc(); + if (!pacc) { + dlclose(libpci); + return 0; + } + + pci_init(pacc); + pci_scan_bus(pacc); + + int length = 0; + for (pci_dev* dev = pacc->devices; dev; dev = dev->next) { + pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS); + if (dev->device_class >> 8 == PCI_BASE_CLASS_DISPLAY && dev->vendor_id && + dev->device_id) { + length += snprintf(buf + length, bufsize - length, + "PCI_VENDOR_ID\n0x%04x\nPCI_DEVICE_ID\n0x%04x\n", + dev->vendor_id, dev->device_id); + } + } + + pci_cleanup(pacc); + dlclose(libpci); + return length; +} + typedef void* EGLNativeDisplayType; static int get_egl_status(char* buf, int bufsize, @@ -311,6 +393,12 @@ fatal_error("GL strings length too large for buffer size"); } + // Get a list of all GPUs from the PCI bus. + length += get_pci_status(buf + length, bufsize - length); + if (length >= bufsize) { + fatal_error("PCI strings length too large for buffer size"); + } + ///// Finally write data to the pipe mozilla::Unused << write(write_end_of_the_pipe, buf, length); @@ -526,6 +614,12 @@ } } + // Get a list of all GPUs from the PCI bus. + length += get_pci_status(buf + length, bufsize - length); + if (length >= bufsize) { + fatal_error("PCI strings length too large for buffer size"); + } + ///// Finally write data to the pipe mozilla::Unused << write(write_end_of_the_pipe, buf, length); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/tools/lint/license/__init__.py firefox-trunk-85.0~a1~hg20201117r557492/tools/lint/license/__init__.py --- firefox-trunk-84.0~a1~hg20201115r557261/tools/lint/license/__init__.py 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/tools/lint/license/__init__.py 2020-11-17 19:31:55.000000000 +0000 @@ -84,7 +84,9 @@ # For the unit tests return False return ( - "/test" in f + "/tests/" in f + or "/test/" in f + or "/test_" in f or "/gtest" in f or "/crashtest" in f or "/mochitest" in f diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/tools/lint/license/valid-licenses.txt firefox-trunk-85.0~a1~hg20201117r557492/tools/lint/license/valid-licenses.txt --- firefox-trunk-84.0~a1~hg20201115r557261/tools/lint/license/valid-licenses.txt 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/tools/lint/license/valid-licenses.txt 2020-11-17 19:31:55.000000000 +0000 @@ -1,7 +1,7 @@ mozilla.org/MPL/ Licensed under the Apache License, Version 2.0 copyright is dedicated to the Public Domain. -Licensed under the MIT License +under the MIT Redistributions of source code must retain the above copyright Use of this source code is governed by a BSD-style license The author disclaims copyright to this source code. @@ -10,9 +10,7 @@ author grants irrevocable permission to anyone to use, modify, THIS FILE IS AUTO-GENERATED Permission is hereby granted, free of charge, to any person obtaining -Permission to use, copy, modify, distribute, and sell this software -Permission to use, copy, modify, distribute and sell this software -This file is dual licensed under the MIT +Permission to use, copy, modify, License: Public domain. You are free to use this code however you You are granted a license to use, reproduce and create derivative works GENERATED FILE, DO NOT EDIT diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/tools/lint/license.yml firefox-trunk-85.0~a1~hg20201117r557492/tools/lint/license.yml --- firefox-trunk-84.0~a1~hg20201115r557261/tools/lint/license.yml 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/tools/lint/license.yml 2020-11-17 19:31:55.000000000 +0000 @@ -26,6 +26,8 @@ - gradle.properties # might not work with license - gradle/wrapper/gradle-wrapper.properties + # tests + - js/src/devtools/rootAnalysis/t/ - mobile/android/components/extensions - mobile/android/geckoview/src/main/AndroidManifest.xml - mobile/android/geckoview/src/main/res/drawable/ic_generic_file.xml @@ -48,6 +50,7 @@ - security/mac/hardenedruntime/production.entitlements.xml - servo/components/hashglobe/src/alloc.rs - servo/components/hashglobe/src/shim.rs + - testing/marionette/harness/marionette_harness/www/ - toolkit/components/reputationservice/chromium/chrome/common/safe_browsing/csd.pb.cc - toolkit/components/reputationservice/chromium/chrome/common/safe_browsing/csd.pb.h - toolkit/mozapps/update/updater/crctable.h diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/android/moz.build firefox-trunk-85.0~a1~hg20201117r557492/widget/android/moz.build --- firefox-trunk-84.0~a1~hg20201115r557261/widget/android/moz.build 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/android/moz.build 2020-11-17 19:31:55.000000000 +0000 @@ -143,7 +143,6 @@ "nsUserIdleServiceAndroid.cpp", "nsWidgetFactory.cpp", "nsWindow.cpp", - "ProcInfo.cpp", "ScreenHelperAndroid.cpp", "WebExecutorSupport.cpp", ] diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/android/ProcInfo.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/android/ProcInfo.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/android/ProcInfo.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/android/ProcInfo.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,17 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/ProcInfo.h" -#include "mozilla/ipc/GeckoChildProcessHost.h" - -namespace mozilla { - -RefPtr GetProcInfo(nsTArray&& aRequests) { - // Not implemented on Android. - return ProcInfoPromise::CreateAndReject(NS_ERROR_NOT_IMPLEMENTED, __func__); -} - -} // namespace mozilla diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/BasicEvents.h firefox-trunk-85.0~a1~hg20201117r557492/widget/BasicEvents.h --- firefox-trunk-84.0~a1~hg20201115r557261/widget/BasicEvents.h 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/BasicEvents.h 2020-11-17 19:31:55.000000000 +0000 @@ -480,7 +480,8 @@ break; default: if (mMessage == eResize || mMessage == eMozVisualResize || - mMessage == eMozVisualScroll || mMessage == eEditorInput) { + mMessage == eMozVisualScroll || mMessage == eEditorInput || + mMessage == eFormSelect) { mFlags.mCancelable = false; } else { mFlags.mCancelable = true; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/cocoa/moz.build firefox-trunk-85.0~a1~hg20201117r557492/widget/cocoa/moz.build --- firefox-trunk-84.0~a1~hg20201115r557261/widget/cocoa/moz.build 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/cocoa/moz.build 2020-11-17 19:31:55.000000000 +0000 @@ -73,7 +73,6 @@ "nsWidgetFactory.mm", "nsWindowMap.mm", "OSXNotificationCenter.mm", - "ProcInfo.mm", "ScreenHelperCocoa.mm", "SwipeTracker.mm", "TextInputHandler.mm", diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/cocoa/nsCocoaFeatures.mm firefox-trunk-85.0~a1~hg20201117r557492/widget/cocoa/nsCocoaFeatures.mm --- firefox-trunk-84.0~a1~hg20201115r557261/widget/cocoa/nsCocoaFeatures.mm 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/cocoa/nsCocoaFeatures.mm 2020-11-17 19:31:55.000000000 +0000 @@ -31,6 +31,7 @@ #include "nsObjCExceptions.h" #import +#include /*static*/ int32_t nsCocoaFeatures::mOSVersion = 0; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/cocoa/nsLookAndFeel.mm firefox-trunk-85.0~a1~hg20201117r557492/widget/cocoa/nsLookAndFeel.mm --- firefox-trunk-84.0~a1~hg20201115r557261/widget/cocoa/nsLookAndFeel.mm 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/cocoa/nsLookAndFeel.mm 2020-11-17 19:31:55.000000000 +0000 @@ -514,8 +514,8 @@ case IntID::MacGraphiteTheme: aResult = [NSColor currentControlTint] == NSGraphiteControlTint; break; - case IntID::MacYosemiteTheme: - aResult = 1; + case IntID::MacBigSurTheme: + aResult = nsCocoaFeatures::OnBigSurOrLater(); break; case IntID::AlertNotificationOrigin: aResult = NS_ALERT_TOP; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/cocoa/ProcInfo.mm firefox-trunk-85.0~a1~hg20201117r557492/widget/cocoa/ProcInfo.mm --- firefox-trunk-84.0~a1~hg20201115r557261/widget/cocoa/ProcInfo.mm 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/cocoa/ProcInfo.mm 1970-01-01 00:00:00.000000000 +0000 @@ -1,164 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/ProcInfo.h" -#include "mozilla/ScopeExit.h" -#include "mozilla/ipc/GeckoChildProcessHost.h" - -#include "nsMemoryReporterManager.h" -#include "nsNetCID.h" - -#include -#include -#include - -#include -#include -#include - -namespace mozilla { - -RefPtr GetProcInfo(nsTArray&& aRequests) { - auto holder = MakeUnique>(); - RefPtr promise = holder->Ensure(__func__); - nsresult rv = NS_OK; - nsCOMPtr target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to get stream transport service"); - holder->Reject(rv, __func__); - return promise; - } - - RefPtr r = NS_NewRunnableFunction( - __func__, [holder = std::move(holder), requests = std::move(aRequests)]() { - HashMap gathered; - if (!gathered.reserve(requests.Length())) { - holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); - return; - } - for (const auto& request : requests) { - ProcInfo info; - info.pid = request.pid; - info.childId = request.childId; - info.type = request.processType; - info.origin = std::move(request.origin); - info.windows = std::move(request.windowInfo); - struct proc_bsdinfo proc; - if ((unsigned long)proc_pidinfo(request.pid, PROC_PIDTBSDINFO, 0, &proc, - PROC_PIDTBSDINFO_SIZE) < PROC_PIDTBSDINFO_SIZE) { - // Can't read data for this proc. - // Probably either a sandboxing issue or a race condition, e.g. - // the process has been just been killed. Regardless, skip process. - continue; - } - - struct proc_taskinfo pti; - if ((unsigned long)proc_pidinfo(request.pid, PROC_PIDTASKINFO, 0, &pti, - PROC_PIDTASKINFO_SIZE) < PROC_PIDTASKINFO_SIZE) { - continue; - } - - // copying all the info to the ProcInfo struct - info.filename.AssignASCII(proc.pbi_name); - info.residentSetSize = pti.pti_resident_size; - info.cpuUser = pti.pti_total_user; - info.cpuKernel = pti.pti_total_system; - - mach_port_t selectedTask; - // If we did not get a task from a child process, we use mach_task_self() - if (request.childTask == MACH_PORT_NULL) { - selectedTask = mach_task_self(); - } else { - selectedTask = request.childTask; - } - // Computing the resident unique size is somewhat tricky, - // so we use about:memory's implementation. This implementation - // uses the `task` so, in theory, should be no additional - // race condition. However, in case of error, the result is `0`. - info.residentUniqueSize = nsMemoryReporterManager::ResidentUnique(selectedTask); - - // Now getting threads info - - // task_threads() gives us a snapshot of the process threads - // but those threads can go away. All the code below makes - // the assumption that thread_info() calls may fail, and - // these errors will be ignored. - thread_act_port_array_t threadList; - mach_msg_type_number_t threadCount; - kern_return_t kret = task_threads(selectedTask, &threadList, &threadCount); - if (kret != KERN_SUCCESS) { - // For some reason, we have no data on the threads for this process. - // Most likely reason is that we have just lost a race condition and - // the process is dead. - // Let's stop here and ignore the entire process. - continue; - } - - // Deallocate the thread list. - // Note that this deallocation is entirely undocumented, so the following code is based - // on guesswork and random examples found on the web. - auto guardThreadCount = MakeScopeExit([&] { - if (threadList == nullptr) { - return; - } - // Free each thread to avoid leaks. - for (mach_msg_type_number_t i = 0; i < threadCount; i++) { - mach_port_deallocate(mach_task_self(), threadList[i]); - } - vm_deallocate(mach_task_self(), /* address */ (vm_address_t)threadList, - /* size */ sizeof(thread_t) * threadCount); - }); - - mach_msg_type_number_t count; - - for (mach_msg_type_number_t i = 0; i < threadCount; i++) { - // Basic thread info. - thread_extended_info_data_t threadInfoData; - count = THREAD_EXTENDED_INFO_COUNT; - kret = thread_info(threadList[i], THREAD_EXTENDED_INFO, (thread_info_t)&threadInfoData, - &count); - if (kret != KERN_SUCCESS) { - continue; - } - - // Getting the thread id. - thread_identifier_info identifierInfo; - count = THREAD_IDENTIFIER_INFO_COUNT; - kret = thread_info(threadList[i], THREAD_IDENTIFIER_INFO, - (thread_info_t)&identifierInfo, &count); - if (kret != KERN_SUCCESS) { - continue; - } - - // The two system calls were successful, let's add that thread - ThreadInfo* thread = info.threads.AppendElement(fallible); - if (!thread) { - holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); - return; - } - thread->cpuUser = threadInfoData.pth_user_time; - thread->cpuKernel = threadInfoData.pth_system_time; - thread->name.AssignASCII(threadInfoData.pth_name); - thread->tid = identifierInfo.thread_id; - } - - if (!gathered.put(request.pid, std::move(info))) { - holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); - return; - } - } - // ... and we're done! - holder->Resolve(std::move(gathered), __func__); - }); - - rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch the LoadDataRunnable."); - } - return promise; -} - -} // namespace mozilla diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/GfxInfoX11.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/GfxInfoX11.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/GfxInfoX11.cpp 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/GfxInfoX11.cpp 2020-11-17 19:31:55.000000000 +0000 @@ -50,6 +50,7 @@ mIsWayland = false; mIsWaylandDRM = false; mIsXWayland = false; + mHasMultipleGPUs = false; return GfxInfoBase::Init(); } @@ -68,6 +69,18 @@ mIsWaylandDRM); CrashReporter::AnnotateCrashReport( CrashReporter::Annotation::DesktopEnvironment, mDesktopEnvironment); + + if (mHasMultipleGPUs) { + nsAutoCString note; + note.AppendLiteral("Has dual GPUs."); + if (!mSecondaryVendorId.IsEmpty()) { + note.AppendLiteral(" GPU #2: AdapterVendorID2: "); + note.Append(mSecondaryVendorId); + note.AppendLiteral(", AdapterDeviceID2: "); + note.Append(mSecondaryDeviceId); + } + CrashReporter::AppendAppNotesToCrashReport(note); + } } void GfxInfo::GetData() { @@ -141,6 +154,9 @@ nsCString screenInfo; nsCString adapterRam; + AutoTArray pciVendors; + AutoTArray pciDevices; + nsCString* stringToFill = nullptr; char* bufptr = buf; @@ -151,29 +167,40 @@ if (stringToFill) { stringToFill->Assign(line); stringToFill = nullptr; - } else if (!strcmp(line, "VENDOR")) + } else if (!strcmp(line, "VENDOR")) { stringToFill = &glVendor; - else if (!strcmp(line, "RENDERER")) + } else if (!strcmp(line, "RENDERER")) { stringToFill = &glRenderer; - else if (!strcmp(line, "VERSION")) + } else if (!strcmp(line, "VERSION")) { stringToFill = &glVersion; - else if (!strcmp(line, "TFP")) + } else if (!strcmp(line, "TFP")) { stringToFill = &textureFromPixmap; - else if (!strcmp(line, "MESA_VENDOR_ID")) + } else if (!strcmp(line, "MESA_VENDOR_ID")) { stringToFill = &mesaVendor; - else if (!strcmp(line, "MESA_DEVICE_ID")) + } else if (!strcmp(line, "MESA_DEVICE_ID")) { stringToFill = &mesaDevice; - else if (!strcmp(line, "MESA_ACCELERATED")) + } else if (!strcmp(line, "MESA_ACCELERATED")) { stringToFill = &mesaAccelerated; - else if (!strcmp(line, "MESA_VRAM")) + } else if (!strcmp(line, "MESA_VRAM")) { stringToFill = &adapterRam; - else if (!strcmp(line, "DRI_DRIVER")) + } else if (!strcmp(line, "DRI_DRIVER")) { stringToFill = &driDriver; - else if (!strcmp(line, "SCREEN_INFO")) + } else if (!strcmp(line, "SCREEN_INFO")) { stringToFill = &screenInfo; + } else if (!strcmp(line, "PCI_VENDOR_ID")) { + stringToFill = pciVendors.AppendElement(); + } else if (!strcmp(line, "PCI_DEVICE_ID")) { + stringToFill = pciDevices.AppendElement(); + } } } + MOZ_ASSERT(pciDevices.Length() == pciVendors.Length(), + "Missing PCI vendors/devices"); + + size_t pciLen = std::min(pciVendors.Length(), pciDevices.Length()); + mHasMultipleGPUs = pciLen > 1; + if (!strcmp(textureFromPixmap.get(), "TRUE")) mHasTextureFromPixmap = true; // only useful for Linux kernel version check for FGLRX driver. @@ -328,6 +355,94 @@ mAdapterRAM = (uint32_t)atoi(adapterRam.get()); } + // If we have the DRI driver, we can derive the vendor ID from that if needed. + if (mVendorId.IsEmpty() && !driDriver.IsEmpty()) { + const char* nvidiaDrivers[] = {"nouveau", "tegra", nullptr}; + for (size_t i = 0; nvidiaDrivers[i]; ++i) { + if (driDriver.Equals(nvidiaDrivers[i])) { + CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::NVIDIA), + mVendorId); + break; + } + } + + if (mVendorId.IsEmpty()) { + const char* intelDrivers[] = {"iris", "i915", "i965", + "i810", "intel", nullptr}; + for (size_t i = 0; intelDrivers[i]; ++i) { + if (driDriver.Equals(intelDrivers[i])) { + CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::Intel), + mVendorId); + break; + } + } + } + + if (mVendorId.IsEmpty()) { + const char* amdDrivers[] = {"r600", "r200", "r100", + "radeon", "radeonsi", nullptr}; + for (size_t i = 0; amdDrivers[i]; ++i) { + if (driDriver.Equals(amdDrivers[i])) { + CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::ATI), + mVendorId); + break; + } + } + } + + if (mVendorId.IsEmpty()) { + if (driDriver.EqualsLiteral("freedreno")) { + CopyUTF16toUTF8(GfxDriverInfo::GetDeviceVendor(DeviceVendor::Qualcomm), + mVendorId); + } + } + } + + // If we still don't have a vendor ID, we can try the PCI vendor list. + if (mVendorId.IsEmpty()) { + if (pciVendors.Length() == 1) { + mVendorId = pciVendors[0]; + } else if (pciVendors.IsEmpty()) { + NS_WARNING("No GPUs detected via PCI"); + } else { + NS_WARNING("More than 1 GPU detected via PCI, cannot deduce vendor"); + } + } + + // If we know the vendor ID, but didn't get a device ID, we can guess from the + // PCI device list. + if (mDeviceId.IsEmpty() && !mVendorId.IsEmpty()) { + for (size_t i = 0; i < pciLen; ++i) { + if (mVendorId.Equals(pciVendors[i])) { + if (mDeviceId.IsEmpty()) { + mDeviceId = pciDevices[i]; + } else { + NS_WARNING( + "More than 1 GPU from same vendor detected via PCI, cannot " + "deduce device"); + mDeviceId.Truncate(); + break; + } + } + } + } + + // Assuming we know the vendor, we should check for a secondary card. + if (!mVendorId.IsEmpty()) { + if (pciLen > 2) { + NS_WARNING( + "More than 2 GPUs detected via PCI, secondary GPU is arbitrary"); + } + for (size_t i = 0; i < pciLen; ++i) { + if (!mVendorId.Equals(pciVendors[i]) || + (!mDeviceId.IsEmpty() && !mDeviceId.Equals(pciDevices[i]))) { + mSecondaryVendorId = pciVendors[i]; + mSecondaryDeviceId = pciDevices[i]; + break; + } + } + } + // Fallback to GL_VENDOR and GL_RENDERER. if (mVendorId.IsEmpty()) { mVendorId.Assign(glVendor.get()); @@ -830,7 +945,9 @@ NS_IMETHODIMP GfxInfo::GetAdapterVendorID2(nsAString& aAdapterVendorID) { - return NS_ERROR_FAILURE; + GetData(); + CopyUTF8toUTF16(mSecondaryVendorId, aAdapterVendorID); + return NS_OK; } NS_IMETHODIMP @@ -842,7 +959,9 @@ NS_IMETHODIMP GfxInfo::GetAdapterDeviceID2(nsAString& aAdapterDeviceID) { - return NS_ERROR_FAILURE; + GetData(); + CopyUTF8toUTF16(mSecondaryDeviceId, aAdapterDeviceID); + return NS_OK; } NS_IMETHODIMP @@ -886,7 +1005,11 @@ } NS_IMETHODIMP -GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { return NS_ERROR_FAILURE; } +GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) { + // This is never the case, as the active GPU should be the primary GPU. + *aIsGPU2Active = false; + return NS_OK; +} #ifdef DEBUG diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/GfxInfoX11.h firefox-trunk-85.0~a1~hg20201117r557492/widget/GfxInfoX11.h --- firefox-trunk-84.0~a1~hg20201115r557261/widget/GfxInfoX11.h 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/GfxInfoX11.h 2020-11-17 19:31:55.000000000 +0000 @@ -89,6 +89,9 @@ nsCString mOSRelease; nsAutoCStringN<16> mDesktopEnvironment; + nsCString mSecondaryVendorId; + nsCString mSecondaryDeviceId; + struct ScreenInfo { uint32_t mWidth; uint32_t mHeight; @@ -103,6 +106,7 @@ bool mIsWayland; bool mIsWaylandDRM; bool mIsXWayland; + bool mHasMultipleGPUs; void AddCrashReportAnnotations(); }; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/gtk/moz.build firefox-trunk-85.0~a1~hg20201117r557492/widget/gtk/moz.build --- firefox-trunk-84.0~a1~hg20201115r557261/widget/gtk/moz.build 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/gtk/moz.build 2020-11-17 19:31:55.000000000 +0000 @@ -50,7 +50,6 @@ "nsSound.cpp", "nsToolkit.cpp", "nsWidgetFactory.cpp", - "ProcInfo.cpp", "ScreenHelperGTK.cpp", "TaskbarProgress.cpp", "WakeLockListener.cpp", diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/gtk/ProcInfo.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/gtk/ProcInfo.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/gtk/ProcInfo.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/gtk/ProcInfo.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,297 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/ProcInfo.h" -#include "mozilla/Sprintf.h" -#include "mozilla/Logging.h" -#include "mozilla/ipc/GeckoChildProcessHost.h" -#include "nsLocalFile.h" -#include "nsMemoryReporterManager.h" -#include "nsNetCID.h" -#include "nsWhitespaceTokenizer.h" - -#include -#include -#include -#include - -#define NANOPERSEC 1000000000. - -namespace mozilla { - -// StatReader can parse and tokenize a POSIX stat file. -// see http://man7.org/linux/man-pages/man5/proc.5.html -// -// Its usage is quite simple: -// -// StatReader reader(pid); -// ProcInfo info; -// rv = reader.ParseProc(info); -// if (NS_FAILED(rv)) { -// // the reading of the file or its parsing failed. -// } -// -class StatReader { - public: - explicit StatReader(const base::ProcessId aPid) - : mPid(aPid), mMaxIndex(53), mTicksPerSec(sysconf(_SC_CLK_TCK)) { - mFilepath.AppendPrintf("/proc/%u/stat", mPid); - } - - nsresult ParseProc(ProcInfo& aInfo) { - nsAutoString fileContent; - nsresult rv = ReadFile(fileContent); - NS_ENSURE_SUCCESS(rv, rv); - // We first extract the filename - int32_t startPos = fileContent.RFindChar('('); - if (startPos == -1) { - return NS_ERROR_FAILURE; - } - int32_t endPos = fileContent.RFindChar(')'); - if (endPos == -1) { - return NS_ERROR_FAILURE; - } - int32_t len = endPos - (startPos + 1); - aInfo.filename.Assign(Substring(fileContent, startPos + 1, len)); - - // now we can use the tokenizer for the rest of the file - nsWhitespaceTokenizer tokenizer(Substring(fileContent, endPos + 2)); - int32_t index = 2; // starting at third field - while (tokenizer.hasMoreTokens() && index < mMaxIndex) { - const nsAString& token = tokenizer.nextToken(); - rv = UseToken(index, token, aInfo); - NS_ENSURE_SUCCESS(rv, rv); - index++; - } - return NS_OK; - } - - protected: - // Called for each token found in the stat file. - nsresult UseToken(int32_t aIndex, const nsAString& aToken, ProcInfo& aInfo) { - // We're using a subset of what stat has to offer for now. - nsresult rv = NS_OK; - // see the proc documentation for fields index references. - switch (aIndex) { - case 13: - // Amount of time that this process has been scheduled - // in user mode, measured in clock ticks - aInfo.cpuUser = GetCPUTime(aToken, &rv); - NS_ENSURE_SUCCESS(rv, rv); - break; - case 14: - // Amount of time that this process has been scheduled - // in kernel mode, measured in clock ticks - aInfo.cpuKernel = GetCPUTime(aToken, &rv); - NS_ENSURE_SUCCESS(rv, rv); - break; - case 23: - // Resident Set Size: number of pages the process has - // in real memory. - uint64_t pageCount = Get64Value(aToken, &rv); - NS_ENSURE_SUCCESS(rv, rv); - uint64_t pageSize = sysconf(_SC_PAGESIZE); - aInfo.residentSetSize = pageCount * pageSize; - break; - } - return rv; - } - - // Converts a token into a int64_t - uint64_t Get64Value(const nsAString& aToken, nsresult* aRv) { - // We can't use aToken.ToInteger64() since it returns a signed 64. - // and that can result into an overflow. - nsresult rv = NS_OK; - uint64_t out = 0; - if (sscanf(NS_ConvertUTF16toUTF8(aToken).get(), "%" PRIu64, &out) == 0) { - rv = NS_ERROR_FAILURE; - } - *aRv = rv; - return out; - } - - // Converts a token into CPU time in nanoseconds. - uint64_t GetCPUTime(const nsAString& aToken, nsresult* aRv) { - nsresult rv; - uint64_t value = Get64Value(aToken, &rv); - *aRv = rv; - if (NS_FAILED(rv)) { - return 0; - } - if (value) { - value = (value * NANOPERSEC) / mTicksPerSec; - } - return value; - } - - base::ProcessId mPid; - int32_t mMaxIndex; - nsCString mFilepath; - ProcInfo mProcInfo; - - private: - // Reads the stat file and puts its content in a nsString. - nsresult ReadFile(nsAutoString& aFileContent) { - RefPtr file = new nsLocalFile(mFilepath); - bool exists; - nsresult rv = file->Exists(&exists); - NS_ENSURE_SUCCESS(rv, rv); - if (!exists) { - return NS_ERROR_FAILURE; - } - // /proc is a virtual file system and all files are - // of size 0, so GetFileSize() and related functions will - // return 0 - so the way to read the file is to fill a buffer - // of an arbitrary big size and look for the end of line char. - FILE* fstat; - if (NS_FAILED(file->OpenANSIFileDesc("r", &fstat)) || !fstat) { - return NS_ERROR_FAILURE; - } - char buffer[2048]; - char* end; - char* start = fgets(buffer, 2048, fstat); - fclose(fstat); - if (start == nullptr) { - return NS_ERROR_FAILURE; - } - // let's find the end - end = strchr(buffer, '\n'); - if (!end) { - return NS_ERROR_FAILURE; - } - aFileContent.AssignASCII(buffer, size_t(end - start)); - return NS_OK; - } - - int64_t mTicksPerSec; -}; - -// Threads have the same stat file. The only difference is its path -// and we're getting less info in the ThreadInfo structure. -class ThreadInfoReader final : public StatReader { - public: - ThreadInfoReader(const base::ProcessId aPid, const base::ProcessId aTid) - : StatReader(aPid), mTid(aTid) { - // Adding the thread path - mFilepath.Truncate(); - mFilepath.AppendPrintf("/proc/%u/task/%u/stat", aPid, mTid); - mMaxIndex = 17; - } - - nsresult ParseThread(ThreadInfo& aInfo) { - ProcInfo info; - nsresult rv = StatReader::ParseProc(info); - NS_ENSURE_SUCCESS(rv, rv); - - aInfo.tid = mTid; - // Copying over the data we got from StatReader::ParseProc() - aInfo.cpuKernel = info.cpuKernel; - aInfo.cpuUser = info.cpuUser; - aInfo.name.Assign(info.filename); - return NS_OK; - } - - private: - base::ProcessId mTid; -}; - -RefPtr GetProcInfo(nsTArray&& aRequests) { - auto holder = MakeUnique>(); - RefPtr promise = holder->Ensure(__func__); - nsresult rv = NS_OK; - nsCOMPtr target = - do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to get stream transport service"); - holder->Reject(rv, __func__); - return promise; - } - - RefPtr r = NS_NewRunnableFunction( - __func__, - [holder = std::move(holder), requests = std::move(aRequests)]() { - HashMap gathered; - if (!gathered.reserve(requests.Length())) { - holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); - return; - } - for (const auto& request : requests) { - // opening the stat file and reading its content - StatReader reader(request.pid); - ProcInfo info; - nsresult rv = reader.ParseProc(info); - if (NS_FAILED(rv)) { - // Can't read data for this proc. - // Probably either a sandboxing issue or a race condition, e.g. - // the process has been just been killed. Regardless, skip process. - continue; - } - // Computing the resident unique size is somewhat tricky, - // so we use about:memory's implementation. This implementation - // reopens `/proc/[pid]`, so there is the risk of an additional - // race condition. In that case, the result is `0`. - info.residentUniqueSize = - nsMemoryReporterManager::ResidentUnique(request.pid); - - // Extra info - info.pid = request.pid; - info.childId = request.childId; - info.type = request.processType; - info.origin = request.origin; - info.windows = std::move(request.windowInfo); - - // Let's look at the threads - nsCString taskPath; - taskPath.AppendPrintf("/proc/%u/task", request.pid); - DIR* dirHandle = opendir(taskPath.get()); - if (!dirHandle) { - // For some reason, we have no data on the threads for this process. - // Most likely reason is that we have just lost a race condition and - // the process is dead. - // Let's stop here and ignore the entire process. - continue; - } - auto cleanup = mozilla::MakeScopeExit([&] { closedir(dirHandle); }); - - // If we can't read some thread info, we ignore that thread. - dirent* entry; - while ((entry = readdir(dirHandle)) != nullptr) { - if (entry->d_name[0] == '.') { - continue; - } - // Threads have a stat file, like processes. - nsAutoCString entryName(entry->d_name); - int32_t tid = entryName.ToInteger(&rv); - if (NS_FAILED(rv)) { - continue; - } - ThreadInfoReader reader(request.pid, tid); - ThreadInfo threadInfo; - rv = reader.ParseThread(threadInfo); - if (NS_FAILED(rv)) { - continue; - } - info.threads.AppendElement(threadInfo); - } - - if (!gathered.put(request.pid, std::move(info))) { - holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); - return; - } - } - - // ... and we're done! - holder->Resolve(std::move(gathered), __func__); - }); - - rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch the LoadDataRunnable."); - } - return promise; -} - -} // namespace mozilla diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/gtk/ScreenHelperGTK.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/gtk/ScreenHelperGTK.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/gtk/ScreenHelperGTK.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/gtk/ScreenHelperGTK.cpp 2020-11-17 19:31:55.000000000 +0000 @@ -32,8 +32,7 @@ self->RefreshScreens(); } -static void screen_resolution_changed(GdkScreen* aScreen, - GParamSpec* aPspec, +static void screen_resolution_changed(GdkScreen* aScreen, GParamSpec* aPspec, ScreenHelperGTK* self) { self->RefreshScreens(); } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/headless/HeadlessLookAndFeelGTK.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/headless/HeadlessLookAndFeelGTK.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/headless/HeadlessLookAndFeelGTK.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/headless/HeadlessLookAndFeelGTK.cpp 2020-11-17 19:31:55.000000000 +0000 @@ -219,7 +219,7 @@ break; case IntID::TouchEnabled: case IntID::MacGraphiteTheme: - case IntID::MacYosemiteTheme: + case IntID::MacBigSurTheme: aResult = 0; res = NS_ERROR_NOT_IMPLEMENTED; break; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/LookAndFeel.h firefox-trunk-85.0~a1~hg20201117r557492/widget/LookAndFeel.h --- firefox-trunk-84.0~a1~hg20201115r557261/widget/LookAndFeel.h 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/LookAndFeel.h 2020-11-17 19:31:54.000000000 +0000 @@ -150,14 +150,14 @@ MacGraphiteTheme, /* - * A Boolean value to determine whether the Mac OS X Yosemite-specific + * A Boolean value to determine whether the macOS Big Sur-specific * theming should be used. * * The value of this metric is not used on non-Mac platforms. These * platforms should return NS_ERROR_NOT_IMPLEMENTED when queried for this * metric. */ - MacYosemiteTheme, + MacBigSurTheme, /* * AlertNotificationOrigin indicates from which corner of the diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/moz.build firefox-trunk-85.0~a1~hg20201117r557492/widget/moz.build --- firefox-trunk-84.0~a1~hg20201115r557261/widget/moz.build 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/moz.build 2020-11-17 19:31:54.000000000 +0000 @@ -161,7 +161,6 @@ "LookAndFeel.h", "MiscEvents.h", "MouseEvents.h", - "ProcInfo.h", "TextEventDispatcher.h", "TextEventDispatcherListener.h", "TextEvents.h", diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/nsNativeBasicTheme.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/nsNativeBasicTheme.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/nsNativeBasicTheme.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/nsNativeBasicTheme.cpp 2020-11-17 19:31:55.000000000 +0000 @@ -143,6 +143,8 @@ uint32_t aDpiRatio, CSSCoord aRadius, CSSCoord aOffset) { + // NOTE(emilio): If the widths or offsets here change, make sure to tweak the + // GetWidgetOverflow path for FocusOutline. Rect focusRect(aRect); RefPtr roundedRect; CSSCoord offset = aOffset * aDpiRatio; @@ -1275,6 +1277,9 @@ case StyleAppearance::Button: PaintButton(aFrame, dt, devPxRect, eventState, dpiRatio); break; + case StyleAppearance::FocusOutline: + PaintRoundedFocusRect(dt, devPxRect, dpiRatio, 0.0f, 0.0f); + break; default: MOZ_ASSERT_UNREACHABLE( "Should not get here with a widget type we don't support."); @@ -1386,10 +1391,12 @@ nsIFrame* aFrame, StyleAppearance aAppearance, nsRect* aOverflowRect) { - // TODO(bug 1620360): This should return non-zero for - // StyleAppearance::FocusOutline, if we implement outline-style: auto. nsIntMargin overflow; switch (aAppearance) { + case StyleAppearance::FocusOutline: + // 2px * each of the segments + 1 px for the separation between them. + overflow.SizeTo(5, 5, 5, 5); + break; case StyleAppearance::Radio: case StyleAppearance::Checkbox: case StyleAppearance::Range: @@ -1534,6 +1541,7 @@ switch (aAppearance) { case StyleAppearance::Radio: case StyleAppearance::Checkbox: + case StyleAppearance::FocusOutline: case StyleAppearance::Textarea: case StyleAppearance::Textfield: case StyleAppearance::Range: diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/nsPrinterCUPS.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/nsPrinterCUPS.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/nsPrinterCUPS.cpp 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/nsPrinterCUPS.cpp 2020-11-17 19:31:54.000000000 +0000 @@ -115,8 +115,7 @@ cups_size_t& aMedia) const { // The returned string is owned by mPrinterInfo. // https://www.cups.org/doc/cupspm.html#cupsLocalizeDestMedia - auto printerInfoLock = mPrinterInfoMutex.Lock(); - TryEnsurePrinterInfo(*printerInfoLock); + auto printerInfoLock = TryEnsurePrinterInfo(); cups_dinfo_t* const printerInfo = printerInfoLock->mPrinterInfo; return mShim.cupsLocalizeDestMedia(&aConnection, mPrinter, printerInfo, CUPS_MEDIA_FLAGS_DEFAULT, &aMedia); @@ -164,8 +163,7 @@ } bool nsPrinterCUPS::Supports(const char* aOption, const char* aValue) const { - auto printerInfoLock = mPrinterInfoMutex.Lock(); - TryEnsurePrinterInfo(*printerInfoLock); + auto printerInfoLock = TryEnsurePrinterInfo(); cups_dinfo_t* const printerInfo = printerInfoLock->mPrinterInfo; return mShim.cupsCheckDestSupported(CUPS_HTTP_DEFAULT, mPrinter, printerInfo, aOption, aValue); @@ -174,8 +172,7 @@ bool nsPrinterCUPS::IsCUPSVersionAtLeast(uint64_t aCUPSMajor, uint64_t aCUPSMinor, uint64_t aCUPSPatch) const { - auto printerInfoLock = mPrinterInfoMutex.Lock(); - TryEnsurePrinterInfo(*printerInfoLock); + auto printerInfoLock = TryEnsurePrinterInfo(); // Compare major version. if (printerInfoLock->mCUPSMajor > aCUPSMajor) { return true; @@ -226,8 +223,7 @@ Connection& aConnection) const { nsString printerName; GetPrinterName(printerName); - auto printerInfoLock = mPrinterInfoMutex.Lock(); - TryEnsurePrinterInfo(*printerInfoLock); + auto printerInfoLock = TryEnsurePrinterInfo(); cups_dinfo_t* const printerInfo = printerInfoLock->mPrinterInfo; cups_size_t media; @@ -286,8 +282,7 @@ nsTArray nsPrinterCUPS::PaperList( Connection& aConnection) const { http_t* const connection = aConnection.GetConnection(mPrinter); - auto printerInfoLock = mPrinterInfoMutex.Lock(); - TryEnsurePrinterInfo(*printerInfoLock, connection); + auto printerInfoLock = TryEnsurePrinterInfo(connection); cups_dinfo_t* const printerInfo = printerInfoLock->mPrinterInfo; if (!printerInfo) { @@ -326,35 +321,31 @@ return paperList; } -void nsPrinterCUPS::TryEnsurePrinterInfo(CUPSPrinterInfo& aInOutPrinterInfo, - http_t* const aConnection) const { - if (aInOutPrinterInfo.mPrinterInfo) { - return; +nsPrinterCUPS::PrinterInfoLock nsPrinterCUPS::TryEnsurePrinterInfo( + http_t* const aConnection) const { + PrinterInfoLock lock = mPrinterInfoMutex.Lock(); + if (lock->mPrinterInfo || + (aConnection == CUPS_HTTP_DEFAULT ? lock->mTriedInitWithDefault + : lock->mTriedInitWithConnection)) { + return lock; } if (aConnection == CUPS_HTTP_DEFAULT) { - if (aInOutPrinterInfo.mTriedInitWithDefault) { - return; - } - aInOutPrinterInfo.mTriedInitWithDefault = true; + lock->mTriedInitWithDefault = true; } else { - if (aInOutPrinterInfo.mTriedInitWithConnection) { - return; - } - aInOutPrinterInfo.mTriedInitWithConnection = true; + lock->mTriedInitWithConnection = true; } // All CUPS calls that take the printer info do null-checks internally, so we // can fetch this info and only worry about the result of the later CUPS // functions. - aInOutPrinterInfo.mPrinterInfo = - mShim.cupsCopyDestInfo(aConnection, mPrinter); + lock->mPrinterInfo = mShim.cupsCopyDestInfo(aConnection, mPrinter); // Even if we failed to fetch printer info, it is still possible we can talk // to the print server and get its CUPS version. - FetchCUPSVersionForPrinter(mShim, mPrinter, aInOutPrinterInfo.mCUPSMajor, - aInOutPrinterInfo.mCUPSMinor, - aInOutPrinterInfo.mCUPSPatch); + FetchCUPSVersionForPrinter(mShim, mPrinter, lock->mCUPSMajor, + lock->mCUPSMinor, lock->mCUPSPatch); + return lock; } void nsPrinterCUPS::ForEachExtraMonochromeSetting( diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/nsPrinterCUPS.h firefox-trunk-85.0~a1~hg20201117r557492/widget/nsPrinterCUPS.h --- firefox-trunk-84.0~a1~hg20201115r557261/widget/nsPrinterCUPS.h 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/nsPrinterCUPS.h 2020-11-17 19:31:55.000000000 +0000 @@ -67,6 +67,8 @@ using PrinterInfoMutex = mozilla::DataMutexBase; + using PrinterInfoLock = PrinterInfoMutex::AutoLock; + ~nsPrinterCUPS(); /** @@ -107,8 +109,7 @@ * but has been known to require an established connection * on older versions of Ubuntu (18 and below). */ - void TryEnsurePrinterInfo( - CUPSPrinterInfo& aInOutPrinterInfo, + PrinterInfoLock TryEnsurePrinterInfo( http_t* const aConnection = CUPS_HTTP_DEFAULT) const; const nsCUPSShim& mShim; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/ProcInfo.h firefox-trunk-85.0~a1~hg20201117r557492/widget/ProcInfo.h --- firefox-trunk-84.0~a1~hg20201115r557261/widget/ProcInfo.h 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/ProcInfo.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,237 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; 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/. */ - -#ifndef __mozilla_ProcInfo_h -#define __mozilla_ProcInfo_h - -#include -#include -#include "mozilla/dom/ipc/IdType.h" -#include "mozilla/HashTable.h" -#include "mozilla/MozPromise.h" - -namespace mozilla { - -namespace ipc { -class GeckoChildProcessHost; -} - -// Process types. When updating this enum, please make sure to update -// WebIDLProcType, ChromeUtils::RequestProcInfo and ProcTypeToWebIDL to -// mirror the changes. -enum class ProcType { - // These must match the ones in ContentParent.h, and E10SUtils.jsm - Web, - WebIsolated, - File, - Extension, - PrivilegedAbout, - PrivilegedMozilla, - WebLargeAllocation, - WebCOOPCOEP, - // the rest matches GeckoProcessTypes.h - Browser, // Default is named Browser here - Plugin, - IPDLUnitTest, - GMPlugin, - GPU, - VR, - RDD, - Socket, - RemoteSandboxBroker, -#ifdef MOZ_ENABLE_FORKSERVER - ForkServer, -#endif - Preallocated, - // Unknown type of process - Unknown, - Max = Unknown, -}; - -struct ThreadInfo { - // Thread Id. - base::ProcessId tid = 0; - // Thread name, if any. - nsString name; - // User time in ns. - uint64_t cpuUser = 0; - // System time in ns. - uint64_t cpuKernel = 0; -}; - -// Info on a DOM window. -struct WindowInfo { - explicit WindowInfo() - : outerWindowId(0), - documentURI(nullptr), - documentTitle(u""_ns), - isProcessRoot(false), - isInProcess(false) {} - WindowInfo(uint64_t aOuterWindowId, nsIURI* aDocumentURI, - nsAString&& aDocumentTitle, bool aIsProcessRoot, bool aIsInProcess) - : outerWindowId(aOuterWindowId), - documentURI(aDocumentURI), - documentTitle(std::move(aDocumentTitle)), - isProcessRoot(aIsProcessRoot), - isInProcess(aIsInProcess) {} - - // Internal window id. - const uint64_t outerWindowId; - - // URI of the document. - const nsCOMPtr documentURI; - - // Title of the document. - const nsString documentTitle; - - // True if this is the toplevel window of the process. - // Note that this may be an iframe from another process. - const bool isProcessRoot; - - const bool isInProcess; -}; - -struct ProcInfo { - // Process Id - base::ProcessId pid = 0; - // Child Id as defined by Firefox when a child process is created. - dom::ContentParentId childId; - // Process type - ProcType type; - // Origin, if any - nsCString origin; - // Process filename (without the path name). - nsString filename; - // RSS in bytes. - int64_t residentSetSize = 0; - // Unshared resident size in bytes. - int64_t residentUniqueSize = 0; - // User time in ns. - uint64_t cpuUser = 0; - // System time in ns. - uint64_t cpuKernel = 0; - // Threads owned by this process. - CopyableTArray threads; - // DOM windows represented by this process. - CopyableTArray windows; -}; - -typedef MozPromise, nsresult, true> - ProcInfoPromise; - -/** - * Data we need to request process info (e.g. CPU usage, memory usage) - * from the operating system and populate the resulting `ProcInfo`. - * - * Note that this structure contains a mix of: - * - low-level handles that we need to request low-level process info - * (`aChildTask` on macOS, `aPid` on other platforms); and - * - high-level data that we already acquired while looking for - * `aPid`/`aChildTask` and that we will need further down the road. - */ -struct ProcInfoRequest { - ProcInfoRequest(base::ProcessId aPid, ProcType aProcessType, - const nsACString& aOrigin, nsTArray&& aWindowInfo, - uint32_t aChildId = 0 -#ifdef XP_MACOSX - , - mach_port_t aChildTask = 0 -#endif // XP_MACOSX - ) - : pid(aPid), - processType(aProcessType), - origin(aOrigin), - windowInfo(std::move(aWindowInfo)), - childId(aChildId) -#ifdef XP_MACOSX - , - childTask(aChildTask) -#endif // XP_MACOSX - { - } - const base::ProcessId pid; - const ProcType processType; - const nsCString origin; - const nsTArray windowInfo; - // If the process is a child, its child id, otherwise `0`. - const int32_t childId; -#ifdef XP_MACOSX - const mach_port_t childTask; -#endif // XP_MACOSX -}; - -/** - * Batch a request for low-level information on Gecko processes. - * - * # Request - * - * Argument `aRequests` is a list of processes, along with high-level data - * we have already obtained on them and that we need to populate the - * resulting array of `ProcInfo`. - * - * # Result - * - * This call succeeds (possibly with missing data, see below) unless we - * cannot allocate memory. - * - * # Performance - * - * - This call is always executed on a background thread. - * - This call does NOT wake up children processes. - * - This function is sometimes observably slow to resolve, in particular - * under Windows. - * - * # Error-handling and race conditions - * - * Requesting low-level information on a process and its threads is inherently - * subject to race conditions. Typically, if a process or a thread is killed - * while we're preparing to fetch information, we can easily end up with - * system/lib calls that return failures. - * - * For this reason, this API assumes that errors when placing a system/lib call - * are likely and normal. When some information cannot be obtained, the API will - * simply skip over said information. - * - * Note that due to different choices by OSes, the exact information we skip may - * vary across platforms. For instance, under Unix, failing to access the - * threads of a process will cause us to skip all data on the process, while - * under Windows, process information will be returned without thread - * information. - */ -RefPtr GetProcInfo(nsTArray&& aRequests); - -/** - * Utility function: copy data from a `ProcInfo` and into either a - * `ParentProcInfoDictionary` or a `ChildProcInfoDictionary`. - */ -template -nsresult CopySysProcInfoToDOM(const ProcInfo& source, T* dest) { - // Copy system info. - dest->mPid = source.pid; - dest->mFilename.Assign(source.filename); - dest->mResidentSetSize = source.residentSetSize; - dest->mResidentUniqueSize = source.residentUniqueSize; - dest->mCpuUser = source.cpuUser; - dest->mCpuKernel = source.cpuKernel; - - // Copy thread info. - mozilla::dom::Sequence threads; - for (const ThreadInfo& entry : source.threads) { - mozilla::dom::ThreadInfoDictionary* thread = - threads.AppendElement(fallible); - if (NS_WARN_IF(!thread)) { - return NS_ERROR_OUT_OF_MEMORY; - } - thread->mCpuUser = entry.cpuUser; - thread->mCpuKernel = entry.cpuKernel; - thread->mTid = entry.tid; - thread->mName.Assign(entry.name); - } - dest->mThreads = std::move(threads); - return NS_OK; -} - -} // namespace mozilla -#endif // ProcInfo_h diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/tests/browser/browser.ini firefox-trunk-85.0~a1~hg20201117r557492/widget/tests/browser/browser.ini --- firefox-trunk-84.0~a1~hg20201115r557261/widget/tests/browser/browser.ini 2020-11-15 14:38:22.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/tests/browser/browser.ini 2020-11-17 19:31:54.000000000 +0000 @@ -1,11 +1,2 @@ -[DEFAULT] -prefs= - media.rdd-process.enabled=true - -support-files = - dummy.html - [browser_test_clipboardcache.js] skip-if = os == 'android' || (os == 'linux' && ccov) # Bug 1613516, the test consistently timeouts on Linux coverage builds. -[browser_test_procinfo.js] -skip-if = os == "android" || (ccov && os == "linux") # https://bugzilla.mozilla.org/show_bug.cgi?id=1608080 diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/tests/browser/browser_test_procinfo.js firefox-trunk-85.0~a1~hg20201117r557492/widget/tests/browser/browser_test_procinfo.js --- firefox-trunk-84.0~a1~hg20201115r557261/widget/tests/browser/browser_test_procinfo.js 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/tests/browser/browser_test_procinfo.js 1970-01-01 00:00:00.000000000 +0000 @@ -1,169 +0,0 @@ -/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ -/* vim: set sts=2 sw=2 et tw=80: */ -"use strict"; - -const ROOT_URL = "http://example.com/browser/widget/tests/browser"; -const DUMMY_URL = ROOT_URL + "/dummy.html"; -const { AppConstants } = ChromeUtils.import( - "resource://gre/modules/AppConstants.jsm" -); -const MAC = AppConstants.platform == "macosx"; -const HAS_THREAD_NAMES = - AppConstants.platform != "win" || - AppConstants.isPlatformAndVersionAtLeast("win", 10); -const isFissionEnabled = SpecialPowers.useRemoteSubframes; - -const SAMPLE_SIZE = 10; - -add_task(async function test_proc_info() { - console.log("YORIC", "Test starts"); - // Open a few `about:home` tabs, they'll end up in `privilegedabout`. - let tabsAboutHome = []; - for (let i = 0; i < 5; ++i) { - let tab = BrowserTestUtils.addTab(gBrowser, "about:home"); - tabsAboutHome.push(tab); - gBrowser.selectedTab = tab; - await BrowserTestUtils.browserLoaded(tab.linkedBrowser); - } - - await BrowserTestUtils.withNewTab( - { gBrowser, url: DUMMY_URL }, - async function(browser) { - let cpuThreads = 0; - let cpuUser = 0; - - // We test `SAMPLE_SIZE` times to increase a tad the chance of encountering race conditions. - for (let z = 0; z < SAMPLE_SIZE; z++) { - let parentProc = await ChromeUtils.requestProcInfo(); - cpuUser += parentProc.cpuUser; - - Assert.equal( - parentProc.type, - "browser", - "Parent proc type should be browser" - ); - - for (var x = 0; x < parentProc.threads.length; x++) { - cpuThreads += parentProc.threads[x].cpuUser; - } - - // Under Windows, thread names appeared with Windows 10. - if (HAS_THREAD_NAMES) { - Assert.ok( - parentProc.threads.some(thread => thread.name), - "At least one of the threads of the parent process is named" - ); - } - - Assert.ok( - parentProc.residentUniqueSize > 0, - "Resident-unique-size was set" - ); - Assert.ok( - parentProc.residentUniqueSize <= parentProc.residentSetSize, - `Resident-unique-size should be bounded by resident-set-size ${parentProc.residentUniqueSize} <= ${parentProc.residentSetSize}` - ); - - // While it's very unlikely that the parent will disappear while we're running - // tests, some children can easily vanish. So we go twice through the list of - // children. Once to test stuff that all process data respects the invariants - // that don't care whether we have a race condition and once to test that at - // least one well-known process that should not be able to vanish during - // the test respects all the invariants. - for (var i = 0; i < parentProc.children.length; i++) { - let childProc = parentProc.children[i]; - Assert.notEqual( - childProc.type, - "browser", - "Child proc type should not be browser" - ); - - // We set the `childID` for child processes that have a `ContentParent`/`ContentChild` - // actor hierarchy. - if (childProc.type.startsWith("web")) { - Assert.notEqual( - childProc.childID, - 0, - "Child proc should have been set" - ); - } - Assert.notEqual( - childProc.type, - "unknown", - "Child proc type should be known" - ); - if (childProc.type == "webIsolated") { - Assert.notEqual( - childProc.origin || "", - "", - "Child process should have an origin" - ); - } - - for (var y = 0; y < childProc.threads.length; y++) { - cpuThreads += childProc.threads[y].cpuUser; - } - cpuUser += childProc.cpuUser; - } - - // We only check other properties on the `privilegedabout` subprocess, which - // as of this writing is always active and available. - var hasPrivilegedAbout = false; - var numberOfAboutTabs = 0; - for (i = 0; i < parentProc.children.length; i++) { - let childProc = parentProc.children[i]; - if (childProc.type != "privilegedabout") { - continue; - } - hasPrivilegedAbout = true; - Assert.ok( - childProc.residentUniqueSize > 0, - "Resident-unique-size was set" - ); - Assert.ok( - childProc.residentUniqueSize <= childProc.residentSetSize, - `Resident-unique-size should be bounded by resident-set-size ${childProc.residentUniqueSize} <= ${childProc.residentSetSize}` - ); - - for (var win of childProc.windows) { - if (win.documentURI.spec != "about:home") { - // We're only interested in about:home for this test. - continue; - } - numberOfAboutTabs++; - Assert.ok( - win.outerWindowId > 0, - `ContentParentID should be > 0 ${win.outerWindowId}` - ); - if (win.documentTitle) { - // Unfortunately, we sometimes reach this point before the document is fully loaded, so - // `win.documentTitle` may still be empty. - Assert.equal(win.documentTitle, "New Tab"); - } - } - Assert.ok( - numberOfAboutTabs >= tabsAboutHome.length, - "We have found at least as many about:home tabs as we opened" - ); - - // Once we have verified the privileged about process, bailout. - break; - } - - Assert.ok( - hasPrivilegedAbout, - "We have found the privileged about process" - ); - } - // see https://bugzilla.mozilla.org/show_bug.cgi?id=1529023 - if (!MAC) { - Assert.greater(cpuThreads, 0, "Got some cpu time in the threads"); - } - Assert.greater(cpuUser, 0, "Got some cpu time"); - - for (let tab of tabsAboutHome) { - BrowserTestUtils.removeTab(tab); - } - } - ); -}); diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/tests/browser/dummy.html firefox-trunk-85.0~a1~hg20201117r557492/widget/tests/browser/dummy.html --- firefox-trunk-84.0~a1~hg20201115r557261/widget/tests/browser/dummy.html 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/tests/browser/dummy.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ - - - -Dummy test page - - - -

Dummy test page

-
Holder
- - - diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/moz.build firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/moz.build --- firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/moz.build 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/moz.build 2020-11-17 19:31:55.000000000 +0000 @@ -87,7 +87,6 @@ "nsWindowDbg.cpp", "nsWindowGfx.cpp", "nsWinGesture.cpp", - "ProcInfo.cpp", "RemoteBackbuffer.cpp", "ScreenHelperWin.cpp", "SystemStatusBar.cpp", diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/nsFilePicker.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/nsFilePicker.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/nsFilePicker.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/nsFilePicker.cpp 2020-11-17 19:31:55.000000000 +0000 @@ -29,11 +29,11 @@ using mozilla::MakeUnique; using mozilla::UniquePtr; using mozilla::mscom::EnsureMTA; -using namespace mozilla::widget; -char16_t* nsFilePicker::mLastUsedUnicodeDirectory; +using namespace mozilla::widget; -static const unsigned long kDialogTimerTimeout = 300; +UniquePtr + nsFilePicker::sLastUsedUnicodeDirectory; #define MAX_EXTENSION_LENGTH 10 #define FILE_BUFFER_SIZE 4096 @@ -43,29 +43,6 @@ /////////////////////////////////////////////////////////////////////////////// // Helper classes -// Manages the current working path. -class AutoRestoreWorkingPath { - public: - AutoRestoreWorkingPath() { - DWORD bufferLength = GetCurrentDirectoryW(0, nullptr); - mWorkingPath = MakeUnique(bufferLength); - if (GetCurrentDirectoryW(bufferLength, mWorkingPath.get()) == 0) { - mWorkingPath = nullptr; - } - } - - ~AutoRestoreWorkingPath() { - if (HasWorkingPath()) { - ::SetCurrentDirectoryW(mWorkingPath.get()); - } - } - - inline bool HasWorkingPath() const { return mWorkingPath != nullptr; } - - private: - UniquePtr mWorkingPath; -}; - // Manages NS_NATIVE_TMP_WINDOW child windows. NS_NATIVE_TMP_WINDOWs are // temporary child windows of mParentWidget created to address RTL issues // in picker dialogs. We are responsible for destroying these. @@ -105,49 +82,10 @@ RefPtr mWindow; }; -// Manages a simple callback timer -class AutoTimerCallbackCancel { - public: - AutoTimerCallbackCancel(nsFilePicker* aTarget, - nsTimerCallbackFunc aCallbackFunc, - const char* aName) { - Init(aTarget, aCallbackFunc, aName); - } - - ~AutoTimerCallbackCancel() { - if (mPickerCallbackTimer) { - mPickerCallbackTimer->Cancel(); - } - } - - private: - void Init(nsFilePicker* aTarget, nsTimerCallbackFunc aCallbackFunc, - const char* aName) { - NS_NewTimerWithFuncCallback(getter_AddRefs(mPickerCallbackTimer), - aCallbackFunc, aTarget, kDialogTimerTimeout, - nsITimer::TYPE_REPEATING_SLACK, aName); - if (!mPickerCallbackTimer) { - NS_WARNING("do_CreateInstance for timer failed??"); - } - } - nsCOMPtr mPickerCallbackTimer; -}; - /////////////////////////////////////////////////////////////////////////////// // nsIFilePicker -nsFilePicker::nsFilePicker() - : mSelectedType(1), mDlgWnd(nullptr), mFDECookie(0) { - CoInitialize(nullptr); -} - -nsFilePicker::~nsFilePicker() { - if (mLastUsedUnicodeDirectory) { - free(mLastUsedUnicodeDirectory); - mLastUsedUnicodeDirectory = nullptr; - } - CoUninitialize(); -} +nsFilePicker::nsFilePicker() : mSelectedType(1) {} NS_IMPL_ISUPPORTS(nsFilePicker, nsIFilePicker) @@ -160,102 +98,6 @@ return nsBaseFilePicker::Init(aParent, aTitle, aMode); } -STDMETHODIMP nsFilePicker::QueryInterface(REFIID refiid, void** ppvResult) { - *ppvResult = nullptr; - if (IID_IUnknown == refiid || refiid == IID_IFileDialogEvents) { - *ppvResult = this; - } - - if (nullptr != *ppvResult) { - ((LPUNKNOWN)*ppvResult)->AddRef(); - return S_OK; - } - - return E_NOINTERFACE; -} - -/* - * Vista+ callbacks - */ - -HRESULT -nsFilePicker::OnFileOk(IFileDialog* pfd) { return S_OK; } - -HRESULT -nsFilePicker::OnFolderChanging(IFileDialog* pfd, IShellItem* psiFolder) { - return S_OK; -} - -HRESULT -nsFilePicker::OnFolderChange(IFileDialog* pfd) { return S_OK; } - -HRESULT -nsFilePicker::OnSelectionChange(IFileDialog* pfd) { return S_OK; } - -HRESULT -nsFilePicker::OnShareViolation(IFileDialog* pfd, IShellItem* psi, - FDE_SHAREVIOLATION_RESPONSE* pResponse) { - return S_OK; -} - -HRESULT -nsFilePicker::OnTypeChange(IFileDialog* pfd) { - // Failures here result in errors due to security concerns. - RefPtr win; - pfd->QueryInterface(IID_IOleWindow, getter_AddRefs(win)); - if (!win) { - NS_ERROR("Could not retrieve the IOleWindow interface for IFileDialog."); - return S_OK; - } - HWND hwnd = nullptr; - win->GetWindow(&hwnd); - if (!hwnd) { - NS_ERROR("Could not retrieve the HWND for IFileDialog."); - return S_OK; - } - - SetDialogHandle(hwnd); - return S_OK; -} - -HRESULT -nsFilePicker::OnOverwrite(IFileDialog* pfd, IShellItem* psi, - FDE_OVERWRITE_RESPONSE* pResponse) { - return S_OK; -} - -/* - * Close on parent close logic - */ - -bool nsFilePicker::ClosePickerIfNeeded() { - if (!mParentWidget || !mDlgWnd) return false; - - nsWindow* win = static_cast(mParentWidget.get()); - if (IsWindow(mDlgWnd) && IsWindowVisible(mDlgWnd) && win->DestroyCalled()) { - wchar_t className[64]; - // Make sure we have the right window - if (GetClassNameW(mDlgWnd, className, mozilla::ArrayLength(className)) && - !wcscmp(className, L"#32770") && DestroyWindow(mDlgWnd)) { - mDlgWnd = nullptr; - return true; - } - } - return false; -} - -void nsFilePicker::PickerCallbackTimerFunc(nsITimer* aTimer, void* aCtx) { - nsFilePicker* picker = (nsFilePicker*)aCtx; - if (picker->ClosePickerIfNeeded()) { - aTimer->Cancel(); - } -} - -void nsFilePicker::SetDialogHandle(HWND aWnd) { - if (!aWnd || mDlgWnd) return; - mDlgWnd = aWnd; -} - /* * Folder picker invocation */ @@ -278,23 +120,30 @@ } RefPtr dialog; - if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC, - IID_IFileOpenDialog, getter_AddRefs(dialog)))) { + if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr, + CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, + getter_AddRefs(dialog)))) { return false; } - // hook up event callbacks - dialog->Advise(this, &mFDECookie); - // options FILEOPENDIALOGOPTIONS fos = FOS_PICKFOLDERS; - dialog->SetOptions(fos); + HRESULT hr = dialog->SetOptions(fos); + if (FAILED(hr)) { + return false; + } // initial strings - dialog->SetTitle(mTitle.get()); + hr = dialog->SetTitle(mTitle.get()); + if (FAILED(hr)) { + return false; + } if (!mOkButtonLabel.IsEmpty()) { - dialog->SetOkButtonLabel(mOkButtonLabel.get()); + hr = dialog->SetOkButtonLabel(mOkButtonLabel.get()); + if (FAILED(hr)) { + return false; + } } if (!aInitialDir.IsEmpty()) { @@ -302,7 +151,10 @@ if (SUCCEEDED(SHCreateItemFromParsingName(aInitialDir.get(), nullptr, IID_IShellItem, getter_AddRefs(folder)))) { - dialog->SetFolder(folder); + hr = dialog->SetFolder(folder); + if (FAILED(hr)) { + return false; + } } } @@ -315,10 +167,8 @@ RefPtr item; if (FAILED(dialog->Show(adtw.get())) || FAILED(dialog->GetResult(getter_AddRefs(item))) || !item) { - dialog->Unadvise(mFDECookie); return false; } - dialog->Unadvise(mFDECookie); // results @@ -326,8 +176,11 @@ // default save folder. RefPtr folderPath; RefPtr shellLib; - CoCreateInstance(CLSID_ShellLibrary, nullptr, CLSCTX_INPROC, - IID_IShellLibrary, getter_AddRefs(shellLib)); + if (FAILED(CoCreateInstance(CLSID_ShellLibrary, nullptr, CLSCTX_INPROC_SERVER, + IID_IShellLibrary, getter_AddRefs(shellLib)))) { + return false; + } + if (shellLib && SUCCEEDED(shellLib->LoadLibraryFromItem(item, STGM_READ)) && SUCCEEDED(shellLib->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, getter_AddRefs(folderPath)))) { @@ -363,20 +216,19 @@ RefPtr dialog; if (mMode != modeSave) { - if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC, - IID_IFileOpenDialog, getter_AddRefs(dialog)))) { + if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr, + CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, + getter_AddRefs(dialog)))) { return false; } } else { - if (FAILED(CoCreateInstance(CLSID_FileSaveDialog, nullptr, CLSCTX_INPROC, - IID_IFileSaveDialog, getter_AddRefs(dialog)))) { + if (FAILED(CoCreateInstance(CLSID_FileSaveDialog, nullptr, + CLSCTX_INPROC_SERVER, IID_IFileSaveDialog, + getter_AddRefs(dialog)))) { return false; } } - // hook up event callbacks - dialog->Advise(this, &mFDECookie); - // options FILEOPENDIALOGOPTIONS fos = 0; @@ -387,10 +239,6 @@ fos |= FOS_DONTADDTORECENT; } - // Msdn claims FOS_NOCHANGEDIR is not needed. We'll add this - // just in case. - AutoRestoreWorkingPath arw; - // mode specific switch (mMode) { case modeOpen: @@ -409,23 +257,38 @@ break; } - dialog->SetOptions(fos); + HRESULT hr = dialog->SetOptions(fos); + if (FAILED(hr)) { + return false; + } // initial strings // title - dialog->SetTitle(mTitle.get()); + hr = dialog->SetTitle(mTitle.get()); + if (FAILED(hr)) { + return false; + } // default filename if (!mDefaultFilename.IsEmpty()) { - dialog->SetFileName(mDefaultFilename.get()); + hr = dialog->SetFileName(mDefaultFilename.get()); + if (FAILED(hr)) { + return false; + } } // default extension to append to new files if (!mDefaultExtension.IsEmpty()) { - dialog->SetDefaultExtension(mDefaultExtension.get()); + hr = dialog->SetDefaultExtension(mDefaultExtension.get()); + if (FAILED(hr)) { + return false; + } } else if (IsDefaultPathHtml()) { - dialog->SetDefaultExtension(L"html"); + hr = dialog->SetDefaultExtension(L"html"); + if (FAILED(hr)) { + return false; + } } // initial location @@ -434,14 +297,24 @@ if (SUCCEEDED(SHCreateItemFromParsingName(aInitialDir.get(), nullptr, IID_IShellItem, getter_AddRefs(folder)))) { - dialog->SetFolder(folder); + hr = dialog->SetFolder(folder); + if (FAILED(hr)) { + return false; + } } } // filter types and the default index if (!mComFilterList.IsEmpty()) { - dialog->SetFileTypes(mComFilterList.Length(), mComFilterList.get()); - dialog->SetFileTypeIndex(mSelectedType); + hr = dialog->SetFileTypes(mComFilterList.Length(), mComFilterList.get()); + if (FAILED(hr)) { + return false; + } + + hr = dialog->SetFileTypeIndex(mSelectedType); + if (FAILED(hr)) { + return false; + } } // display @@ -450,16 +323,12 @@ AutoDestroyTmpWindow adtw((HWND)( mParentWidget.get() ? mParentWidget->GetNativeData(NS_NATIVE_TMP_WINDOW) : nullptr)); - AutoTimerCallbackCancel atcc(this, PickerCallbackTimerFunc, - "nsFilePicker::PickerCallbackTimerFunc"); AutoWidgetPickerState awps(mParentWidget); mozilla::BackgroundHangMonitor().NotifyWait(); if (FAILED(dialog->Show(adtw.get()))) { - dialog->Unadvise(mFDECookie); return false; } - dialog->Unadvise(mFDECookie); } // results @@ -497,9 +366,10 @@ nsAutoString str; if (SUCCEEDED(items->GetItemAt(idx, getter_AddRefs(item)))) { if (!WinUtils::GetShellItemPath(item, str)) continue; - nsCOMPtr file = do_CreateInstance("@mozilla.org/file/local;1"); - if (file && NS_SUCCEEDED(file->InitWithPath(str))) + nsCOMPtr file; + if (NS_SUCCEEDED(NS_NewLocalFile(str, false, getter_AddRefs(file)))) { mFiles.AppendObject(file); + } } } return true; @@ -519,7 +389,7 @@ // If no display directory, re-use the last one. if (initialDir.IsEmpty()) { // Allocate copy of last used dir. - initialDir = mLastUsedUnicodeDirectory; + initialDir = sLastUsedUnicodeDirectory.get(); } // Clear previous file selections @@ -546,10 +416,11 @@ if (mMode == modeSave) { // Windows does not return resultReplace, we must check if file // already exists. - nsCOMPtr file(do_CreateInstance("@mozilla.org/file/local;1")); + nsCOMPtr file; + nsresult rv = NS_NewLocalFile(mUnicodeFile, false, getter_AddRefs(file)); + bool flag = false; - if (file && NS_SUCCEEDED(file->InitWithPath(mUnicodeFile)) && - NS_SUCCEEDED(file->Exists(&flag)) && flag) { + if (NS_SUCCEEDED(rv) && NS_SUCCEEDED(file->Exists(&flag)) && flag) { retValue = returnReplace; } } @@ -567,14 +438,13 @@ if (mUnicodeFile.IsEmpty()) return NS_OK; - nsCOMPtr file(do_CreateInstance("@mozilla.org/file/local;1")); - - NS_ENSURE_TRUE(file, NS_ERROR_FAILURE); - - file->InitWithPath(mUnicodeFile); - - NS_ADDREF(*aFile = file); + nsCOMPtr file; + nsresult rv = NS_NewLocalFile(mUnicodeFile, false, getter_AddRefs(file)); + if (NS_FAILED(rv)) { + return rv; + } + file.forget(aFile); return NS_OK; } @@ -673,8 +543,13 @@ } void nsFilePicker::RememberLastUsedDirectory() { - nsCOMPtr file(do_CreateInstance("@mozilla.org/file/local;1")); - if (!file || NS_FAILED(file->InitWithPath(mUnicodeFile))) { + if (IsPrivacyModeEnabled()) { + // Don't remember the directory if private browsing was in effect + return; + } + + nsCOMPtr file; + if (NS_FAILED(NS_NewLocalFile(mUnicodeFile, false, getter_AddRefs(file)))) { NS_WARNING("RememberLastUsedDirectory failed to init file path."); return; } @@ -688,11 +563,7 @@ return; } - if (mLastUsedUnicodeDirectory) { - free(mLastUsedUnicodeDirectory); - mLastUsedUnicodeDirectory = nullptr; - } - mLastUsedUnicodeDirectory = ToNewUnicode(newDir); + sLastUsedUnicodeDirectory.reset(ToNewUnicode(newDir)); } bool nsFilePicker::IsPrivacyModeEnabled() { diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/nsFilePicker.h firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/nsFilePicker.h --- firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/nsFilePicker.h 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/nsFilePicker.h 2020-11-17 19:31:55.000000000 +0000 @@ -10,7 +10,6 @@ #include #include "nsIFile.h" -#include "nsITimer.h" #include "nsISimpleEnumerator.h" #include "nsCOMArray.h" #include "nsBaseFilePicker.h" @@ -39,8 +38,8 @@ * Native Windows FileSelector wrapper */ -class nsFilePicker : public IFileDialogEvents, public nsBaseWinFilePicker { - virtual ~nsFilePicker(); +class nsFilePicker : public nsBaseWinFilePicker { + virtual ~nsFilePicker() = default; public: nsFilePicker(); @@ -50,9 +49,6 @@ NS_DECL_ISUPPORTS - // IUnknown's QueryInterface - STDMETHODIMP QueryInterface(REFIID refiid, void** ppvResult); - // nsIFilePicker (less what's in nsBaseFilePicker and nsBaseWinFilePicker) NS_IMETHOD GetFilterIndex(int32_t* aFilterIndex) override; NS_IMETHOD SetFilterIndex(int32_t aFilterIndex) override; @@ -62,19 +58,6 @@ NS_IMETHOD AppendFilter(const nsAString& aTitle, const nsAString& aFilter) override; - // IFileDialogEvents - HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog* pfd); - HRESULT STDMETHODCALLTYPE OnFolderChanging(IFileDialog* pfd, - IShellItem* psiFolder); - HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialog* pfd); - HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialog* pfd); - HRESULT STDMETHODCALLTYPE - OnShareViolation(IFileDialog* pfd, IShellItem* psi, - FDE_SHAREVIOLATION_RESPONSE* pResponse); - HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialog* pfd); - HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialog* pfd, IShellItem* psi, - FDE_OVERWRITE_RESPONSE* pResponse); - protected: /* method from nsBaseFilePicker */ virtual void InitNative(nsIWidget* aParent, const nsAString& aTitle) override; @@ -87,9 +70,6 @@ bool IsPrivacyModeEnabled(); bool IsDefaultPathLink(); bool IsDefaultPathHtml(); - void SetDialogHandle(HWND aWnd); - bool ClosePickerIfNeeded(); - static void PickerCallbackTimerFunc(nsITimer* aTimer, void* aPicker); nsCOMPtr mLoadContext; nsCOMPtr mParentWidget; @@ -99,8 +79,11 @@ int16_t mSelectedType; nsCOMArray mFiles; nsString mUnicodeFile; - static char16_t* mLastUsedUnicodeDirectory; - HWND mDlgWnd; + + struct FreeDeleter { + void operator()(void* aPtr) { ::free(aPtr); } + }; + static mozilla::UniquePtr sLastUsedUnicodeDirectory; class ComDlgFilterSpec { public: @@ -121,7 +104,6 @@ }; ComDlgFilterSpec mComFilterList; - DWORD mFDECookie; }; #endif // nsFilePicker_h__ diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/nsNativeThemeWin.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/nsNativeThemeWin.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/nsNativeThemeWin.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/nsNativeThemeWin.cpp 2020-11-17 19:31:54.000000000 +0000 @@ -2596,7 +2596,7 @@ ui->mScrollbarColor.AsColors().track.MaybeTransparent()) { return eTransparent; } - // DrawCustomScrollbarPart doesn't draw the track background for + // MayDrawCustomScrollbarPart doesn't draw the track background for // widgets on it, and these widgets are thinner than the track, // so we need to return transparent for them. switch (aAppearance) { @@ -4042,12 +4042,11 @@ gfxContextAutoSaveRestore autoSave(aContext); RefPtr ctx = aContext; + DrawTarget* dt = ctx->GetDrawTarget(); gfxFloat p2a = gfxFloat(aFrame->PresContext()->AppUnitsPerDevPixel()); - gfxRect clipRect = ThebesRect( - LayoutDevicePixel::FromAppUnits(aClipRect, p2a).ToUnknownRect()); + gfxRect rect = ThebesRect(NSRectToSnappedRect(aRect, p2a, *dt)); + gfxRect clipRect = ThebesRect(NSRectToSnappedRect(aClipRect, p2a, *dt)); ctx->Clip(clipRect); - gfxRect rect = - ThebesRect(LayoutDevicePixel::FromAppUnits(aRect, p2a).ToUnknownRect()); const nsStyleUI* ui = style->StyleUI(); auto* customColors = diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/ProcInfo.cpp firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/ProcInfo.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/widget/windows/ProcInfo.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/widget/windows/ProcInfo.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,191 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/ProcInfo.h" -#include "mozilla/ipc/GeckoChildProcessHost.h" -#include "nsMemoryReporterManager.h" -#include -#include -#include - -typedef HRESULT(WINAPI* GETTHREADDESCRIPTION)(HANDLE hThread, - PWSTR* threadDescription); - -namespace mozilla { - -uint64_t ToNanoSeconds(const FILETIME& aFileTime) { - // FILETIME values are 100-nanoseconds units, converting - ULARGE_INTEGER usec = {{aFileTime.dwLowDateTime, aFileTime.dwHighDateTime}}; - return usec.QuadPart * 100; -} - -RefPtr GetProcInfo(nsTArray&& aRequests) { - auto holder = MakeUnique>(); - RefPtr promise = holder->Ensure(__func__); - - nsresult rv = NS_OK; - nsCOMPtr target = - do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to get stream transport service"); - holder->Reject(rv, __func__); - return promise; - } - - RefPtr r = NS_NewRunnableFunction( - __func__, - [holder = std::move(holder), requests = std::move(aRequests)]() -> void { - HashMap gathered; - if (!gathered.reserve(requests.Length())) { - holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); - return; - } - - // ---- Copying data on processes (minus threads). - - for (const auto& request : requests) { - nsAutoHandle handle(OpenProcess( - PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, request.pid)); - - if (!handle) { - // Ignore process, it may have died. - continue; - } - - wchar_t filename[MAX_PATH]; - if (GetProcessImageFileNameW(handle.get(), filename, MAX_PATH) == 0) { - // Ignore process, it may have died. - continue; - } - FILETIME createTime, exitTime, kernelTime, userTime; - if (!GetProcessTimes(handle.get(), &createTime, &exitTime, - &kernelTime, &userTime)) { - // Ignore process, it may have died. - continue; - } - PROCESS_MEMORY_COUNTERS memoryCounters; - if (!GetProcessMemoryInfo(handle.get(), - (PPROCESS_MEMORY_COUNTERS)&memoryCounters, - sizeof(memoryCounters))) { - // Ignore process, it may have died. - continue; - } - - // Assumption: values of `pid` are distinct between processes, - // regardless of any race condition we might have stumbled upon. Even - // if it somehow could happen, in the worst case scenario, we might - // end up overwriting one process info and we might end up with too - // many threads attached to a process, as the data is not crucial, we - // do not need to defend against that (unlikely) scenario. - ProcInfo info; - info.pid = request.pid; - info.childId = request.childId; - info.type = request.processType; - info.origin = request.origin; - info.windows = std::move(request.windowInfo); - info.filename.Assign(filename); - info.cpuKernel = ToNanoSeconds(kernelTime); - info.cpuUser = ToNanoSeconds(userTime); - info.residentSetSize = memoryCounters.WorkingSetSize; - - // Computing the resident unique size is somewhat tricky, - // so we use about:memory's implementation. This implementation - // uses the `HANDLE` so, in theory, should be no additional - // race condition. However, in case of error, the result is `0`. - info.residentUniqueSize = - nsMemoryReporterManager::ResidentUnique(handle.get()); - - if (!gathered.put(request.pid, std::move(info))) { - holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); - return; - } - } - - // ---- Add thread data to already-copied processes. - - // First, we need to capture a snapshot of all the threads on this - // system. - nsAutoHandle hThreadSnap(CreateToolhelp32Snapshot( - /* dwFlags */ TH32CS_SNAPTHREAD, /* ignored */ 0)); - if (!hThreadSnap) { - holder->Reject(NS_ERROR_UNEXPECTED, __func__); - return; - } - - // `GetThreadDescription` is available as of Windows 10. - // We attempt to import it dynamically, knowing that it - // may be `nullptr`. - auto getThreadDescription = - reinterpret_cast(::GetProcAddress( - ::GetModuleHandleW(L"Kernel32.dll"), "GetThreadDescription")); - - THREADENTRY32 te32; - te32.dwSize = sizeof(THREADENTRY32); - - // Now, walk through the threads. - for (auto success = Thread32First(hThreadSnap.get(), &te32); success; - success = Thread32Next(hThreadSnap.get(), &te32)) { - auto processLookup = gathered.lookup(te32.th32OwnerProcessID); - if (!processLookup) { - // Not one of the processes we're interested in. - continue; - } - ThreadInfo* threadInfo = - processLookup->value().threads.AppendElement(fallible); - if (!threadInfo) { - holder->Reject(NS_ERROR_OUT_OF_MEMORY, __func__); - return; - } - - nsAutoHandle hThread( - OpenThread(/* dwDesiredAccess = */ THREAD_QUERY_INFORMATION, - /* bInheritHandle = */ FALSE, - /* dwThreadId = */ te32.th32ThreadID)); - if (!hThread) { - // Cannot open thread. Not sure why, but let's erase this thread - // and attempt to find data on other threads. - processLookup->value().threads.RemoveLastElement(); - continue; - } - - threadInfo->tid = te32.th32ThreadID; - - // Attempt to get thread times. - // If we fail, continue without this piece of information. - FILETIME createTime, exitTime, kernelTime, userTime; - if (GetThreadTimes(hThread.get(), &createTime, &exitTime, &kernelTime, - &userTime)) { - threadInfo->cpuKernel = ToNanoSeconds(kernelTime); - threadInfo->cpuUser = ToNanoSeconds(userTime); - } - - // Attempt to get thread name. - // If we fail, continue without this piece of information. - if (getThreadDescription) { - PWSTR threadName = nullptr; - if (getThreadDescription(hThread.get(), &threadName) && - threadName) { - threadInfo->name = threadName; - } - if (threadName) { - LocalFree(threadName); - } - } - } - - // ----- We're ready to return. - holder->Resolve(std::move(gathered), __func__); - }); - - rv = target->Dispatch(r.forget(), NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch the LoadDataRunnable."); - } - - return promise; -} - -} // namespace mozilla diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/xpcom/base/ErrorList.py firefox-trunk-85.0~a1~hg20201117r557492/xpcom/base/ErrorList.py --- firefox-trunk-84.0~a1~hg20201115r557261/xpcom/base/ErrorList.py 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/xpcom/base/ErrorList.py 2020-11-17 19:31:55.000000000 +0000 @@ -1086,7 +1086,6 @@ with modules["DOM_FILE"]: errors["NS_ERROR_DOM_FILE_NOT_FOUND_ERR"] = FAILURE(0) errors["NS_ERROR_DOM_FILE_NOT_READABLE_ERR"] = FAILURE(1) - errors["NS_ERROR_DOM_FILE_ABORT_ERR"] = FAILURE(2) # ======================================================================= diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/xpcom/base/nsMacUtilsImpl.cpp firefox-trunk-85.0~a1~hg20201117r557492/xpcom/base/nsMacUtilsImpl.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/xpcom/base/nsMacUtilsImpl.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/xpcom/base/nsMacUtilsImpl.cpp 2020-11-17 19:31:55.000000000 +0000 @@ -24,6 +24,9 @@ #include #include +#if defined(__aarch64__) +# include +#endif #include NS_IMPL_ISUPPORTS(nsMacUtilsImpl, nsIMacUtils) @@ -38,6 +41,10 @@ std::atomic nsMacUtilsImpl::sBundleArchMaskAtomic = 0; +#if defined(__aarch64__) +std::atomic nsMacUtilsImpl::sIsXULTranslated = false; +#endif + // Info.plist key associated with the developer repo path #define MAC_DEV_REPO_KEY "MozillaDeveloperRepoPath" // Info.plist key associated with the developer repo object directory @@ -521,3 +528,90 @@ return NS_OK; } + +#if defined(__aarch64__) +// Pre-translate XUL so that x64 child processes launched after this +// translation will not incur the translation overhead delaying startup. +// Returns 1 if translation is in progress, -1 on an error encountered before +// translation, and otherwise returns the result of rosetta_translate_binaries. +/* static */ +int nsMacUtilsImpl::PreTranslateXUL() { + bool expected = false; + if (!sIsXULTranslated.compare_exchange_strong(expected, true)) { + // Translation is already done or in progress. + return 1; + } + + // Get the path to XUL by first getting the + // outer .app path and appending the path to XUL. + nsCString xulPath; + if (!GetAppPath(xulPath)) { + return -1; + } + xulPath.Append("/Contents/MacOS/XUL"); + + return PreTranslateBinary(xulPath); +} + +// Use Chromium's method to pre-translate the provided binary using the +// undocumented function "rosetta_translate_binaries" from libRosetta.dylib. +// Re-translating the same binary does not cause translation to occur again. +// Returns -1 on an error encountered before translation, otherwise returns +// the rosetta_translate_binaries result. This method is partly copied from +// Chromium code. +/* static */ +int nsMacUtilsImpl::PreTranslateBinary(nsCString aBinaryPath) { + // Do not attempt to use this in child processes. Child + // processes executing should already be translated and + // sandboxing may interfere with translation. + MOZ_ASSERT(XRE_IsParentProcess()); + if (!XRE_IsParentProcess()) { + return -1; + } + + // Translation can take several seconds and therefore + // should not be done on the main thread. + MOZ_ASSERT(!NS_IsMainThread()); + if (NS_IsMainThread()) { + return -1; + } + + // @available() is not available for macOS 11 at this time so use + // -Wunguarded-availability-new to avoid compiler warnings caused + // by an earlier minimum SDK. ARM64 builds require the 11.0 SDK and + // can not be run on earlier OS versions so this is not a concern. +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunguarded-availability-new" + // If Rosetta is not installed, do not proceed. + if (!CFBundleIsArchitectureLoadable(CPU_TYPE_X86_64)) { + return -1; + } +# pragma clang diagnostic pop + + if (aBinaryPath.IsEmpty()) { + return -1; + } + + // int rosetta_translate_binaries(const char*[] paths, int npaths) + using rosetta_translate_binaries_t = int (*)(const char*[], int); + + static auto rosetta_translate_binaries = []() { + void* libRosetta = + dlopen("/usr/lib/libRosetta.dylib", RTLD_LAZY | RTLD_LOCAL); + if (!libRosetta) { + return static_cast(nullptr); + } + + return reinterpret_cast( + dlsym(libRosetta, "rosetta_translate_binaries")); + }(); + + if (!rosetta_translate_binaries) { + return -1; + } + + const char* pathPtr = aBinaryPath.get(); + return rosetta_translate_binaries(&pathPtr, 1); +} + +#endif diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/xpcom/base/nsMacUtilsImpl.h firefox-trunk-85.0~a1~hg20201117r557492/xpcom/base/nsMacUtilsImpl.h --- firefox-trunk-84.0~a1~hg20201115r557261/xpcom/base/nsMacUtilsImpl.h 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/xpcom/base/nsMacUtilsImpl.h 2020-11-17 19:31:55.000000000 +0000 @@ -47,6 +47,15 @@ static nsresult GetArchitecturesForBinary(const char* aPath, uint32_t* aArchMask); +#if defined(__aarch64__) + // Pre-translate binaries to avoid translation delays when launching + // x64 child process instances for the first time. i.e. on first launch + // after installation or after an update. Translations are cached so + // repeated launches of the binaries do not encounter delays. + static int PreTranslateXUL(); + static int PreTranslateBinary(nsCString aBinaryPath); +#endif + private: ~nsMacUtilsImpl() {} @@ -69,6 +78,11 @@ // be multiple architectures for universal binaries. static std::atomic sBundleArchMaskAtomic; +#if defined(__aarch64__) + // Limit XUL translation to one attempt + static std::atomic sIsXULTranslated; +#endif + enum TCSMStatus { TCSM_Unknown = 0, TCSM_Available, TCSM_Unavailable }; static mozilla::Atomic sTCSMStatus; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/xpcom/components/Module.h firefox-trunk-85.0~a1~hg20201117r557492/xpcom/components/Module.h --- firefox-trunk-84.0~a1~hg20201115r557261/xpcom/components/Module.h 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/xpcom/components/Module.h 2020-11-17 19:31:55.000000000 +0000 @@ -21,7 +21,7 @@ * via a module loader. */ struct Module { - static const unsigned int kVersion = 84; + static const unsigned int kVersion = 85; struct CIDEntry; diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/xpcom/ds/StaticAtoms.py firefox-trunk-85.0~a1~hg20201117r557492/xpcom/ds/StaticAtoms.py --- firefox-trunk-84.0~a1~hg20201115r557261/xpcom/ds/StaticAtoms.py 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/xpcom/ds/StaticAtoms.py 2020-11-17 19:31:55.000000000 +0000 @@ -2231,7 +2231,7 @@ ), Atom("_moz_windows_default_theme", "-moz-windows-default-theme"), Atom("_moz_mac_graphite_theme", "-moz-mac-graphite-theme"), - Atom("_moz_mac_yosemite_theme", "-moz-mac-yosemite-theme"), + Atom("_moz_mac_big_sur_theme", "-moz-mac-big-sur-theme"), Atom("_moz_windows_compositor", "-moz-windows-compositor"), Atom("_moz_windows_classic", "-moz-windows-classic"), Atom("_moz_windows_glass", "-moz-windows-glass"), @@ -2294,6 +2294,7 @@ Atom("aria_rowindextext", "aria-rowindextext"), Atom("aria_rowspan", "aria-rowspan"), Atom("aria_valuetext", "aria-valuetext"), + Atom("assertive", "assertive"), Atom("auto_generated", "auto-generated"), Atom("banner", "banner"), Atom("checkable", "checkable"), diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/xpcom/threads/DataMutex.h firefox-trunk-85.0~a1~hg20201117r557492/xpcom/threads/DataMutex.h --- firefox-trunk-84.0~a1~hg20201115r557261/xpcom/threads/DataMutex.h 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/xpcom/threads/DataMutex.h 2020-11-17 19:31:55.000000000 +0000 @@ -37,7 +37,7 @@ // template class DataMutexBase { - private: + public: class MOZ_STACK_CLASS AutoLock { public: T* operator->() const& { return &ref(); } @@ -84,7 +84,6 @@ DataMutexBase* mOwner; }; - public: explicit DataMutexBase(const char* aName) : mMutex(aName) {} DataMutexBase(T&& aValue, const char* aName) diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/xpfe/appshell/AppWindow.cpp firefox-trunk-85.0~a1~hg20201117r557492/xpfe/appshell/AppWindow.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/xpfe/appshell/AppWindow.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/xpfe/appshell/AppWindow.cpp 2020-11-17 19:31:55.000000000 +0000 @@ -2931,7 +2931,7 @@ mDocShell ? mDocShell->GetWindow() : nullptr; nsFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm && window) { - fm->WindowRaised(window); + fm->WindowRaised(window, nsFocusManager::GenerateFocusActionId()); } if (mChromeLoaded) { @@ -2947,7 +2947,7 @@ mDocShell ? mDocShell->GetWindow() : nullptr; nsFocusManager* fm = nsFocusManager::GetFocusManager(); if (fm && window && !fm->IsTestMode()) { - fm->WindowLowered(window); + fm->WindowLowered(window, nsFocusManager::GenerateFocusActionId()); } } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/xpfe/appshell/nsContentTreeOwner.cpp firefox-trunk-85.0~a1~hg20201117r557492/xpfe/appshell/nsContentTreeOwner.cpp --- firefox-trunk-84.0~a1~hg20201115r557261/xpfe/appshell/nsContentTreeOwner.cpp 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/xpfe/appshell/nsContentTreeOwner.cpp 2020-11-17 19:31:55.000000000 +0000 @@ -386,16 +386,6 @@ nsIDocShell* aDocShell, nsIURI* aURI, nsIReferrerInfo* aReferrerInfo, bool aHasPostData, nsIPrincipal* aTriggeringPrincipal, nsIContentSecurityPolicy* aCsp, bool* _retval) { - NS_ENSURE_STATE(mAppWindow); - - nsCOMPtr xulBrowserWindow; - mAppWindow->GetXULBrowserWindow(getter_AddRefs(xulBrowserWindow)); - - if (xulBrowserWindow) - return xulBrowserWindow->ShouldLoadURI(aDocShell, aURI, aReferrerInfo, - aHasPostData, aTriggeringPrincipal, - aCsp, _retval); - *_retval = true; return NS_OK; } diff -Nru firefox-trunk-84.0~a1~hg20201115r557261/xpfe/appshell/nsIXULBrowserWindow.idl firefox-trunk-85.0~a1~hg20201117r557492/xpfe/appshell/nsIXULBrowserWindow.idl --- firefox-trunk-84.0~a1~hg20201115r557261/xpfe/appshell/nsIXULBrowserWindow.idl 2020-11-15 14:38:23.000000000 +0000 +++ firefox-trunk-85.0~a1~hg20201117r557492/xpfe/appshell/nsIXULBrowserWindow.idl 2020-11-17 19:31:55.000000000 +0000 @@ -43,31 +43,6 @@ in boolean isAppTab); /** - * Determines whether a load should continue. - * - * @param aDocShell - * The docshell performing the load. - * @param aURI - * The URI being loaded. - * @param aReferrerInfo - * The referrerInfo of the load. - * @param aHasPostData - * True if the load which is being asked about has associated post data - * which would be discarded if the load was redirected across process - * boundaries. - * @param aTriggeringPrincipal - * The principal that initiated the load of aURI. - * @param aCsp - * The CSP to be used for that load. That is the CSP that e.g. upgrades - * the load to HTTPS in case upgrade-insecure-requests is set - */ - bool shouldLoadURI(in nsIDocShell aDocShell, - in nsIURI aURI, - in nsIReferrerInfo aReferrerInfo, - in boolean aHasPostData, - in nsIPrincipal aTriggeringPrincipal, - in nsIContentSecurityPolicy aCsp); - /** * Show/hide a tooltip (when the user mouses over a link, say). */ void showTooltip(in long x, in long y, in AString tooltip, in AString direction,