diff --git a/accessible/base/TextAttrs.cpp b/accessible/base/TextAttrs.cpp index cb66d1380b9c..f6e6d8519972 100644 --- a/accessible/base/TextAttrs.cpp +++ b/accessible/base/TextAttrs.cpp @@ -18,10 +18,6 @@ #include "mozilla/AppUnits.h" #include "mozilla/gfx/2D.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - using namespace mozilla; using namespace mozilla::a11y; @@ -652,28 +648,14 @@ TextAttrsMgr::FontWeightTextAttr:: if (font->IsSyntheticBold()) return 700; - bool useFontEntryWeight = true; - - // Under Linux, when gfxPangoFontGroup code is used, - // font->GetStyle()->weight will give the absolute weight requested of the - // font face. The gfxPangoFontGroup code uses the gfxFontEntry constructor - // which doesn't initialize the weight field. -#if defined(MOZ_WIDGET_GTK) - useFontEntryWeight = gfxPlatformGtk::UseFcFontList(); -#endif - - if (useFontEntryWeight) { - // On Windows, font->GetStyle()->weight will give the same weight as - // fontEntry->Weight(), the weight of the first font in the font group, - // which may not be the weight of the font face used to render the - // characters. On Mac, font->GetStyle()->weight will just give the same - // number as getComputedStyle(). fontEntry->Weight() will give the weight - // of the font face used. - gfxFontEntry *fontEntry = font->GetFontEntry(); - return fontEntry->Weight(); - } else { - return font->GetStyle()->weight; - } + // On Windows, font->GetStyle()->weight will give the same weight as + // fontEntry->Weight(), the weight of the first font in the font group, + // which may not be the weight of the font face used to render the + // characters. On Mac, font->GetStyle()->weight will just give the same + // number as getComputedStyle(). fontEntry->Weight() will give the weight + // of the font face used. + gfxFontEntry *fontEntry = font->GetFontEntry(); + return fontEntry->Weight(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp index 31eeb4f47ae1..fa7d89002097 100644 --- a/accessible/base/nsAccessibilityService.cpp +++ b/accessible/base/nsAccessibilityService.cpp @@ -595,6 +595,7 @@ nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell, } if (child) { + MOZ_DIAGNOSTIC_ASSERT(child->Parent(), "Unattached accessible from tree"); document->ContentRemoved(child->Parent(), aChildNode); #ifdef A11Y_LOG if (logging::IsEnabled(logging::eTree)) diff --git a/browser/base/content/pageinfo/permissions.js b/browser/base/content/pageinfo/permissions.js index 16a0af7318db..7b8487c0df3e 100644 --- a/browser/base/content/pageinfo/permissions.js +++ b/browser/base/content/pageinfo/permissions.js @@ -218,7 +218,8 @@ function onIndexedDBUsageCallback(request) { throw new Error("Callback received for bad URI: " + uri); } - if (request.usage) { + let usage = request.result.usage; + if (usage) { if (!("DownloadUtils" in window)) { Components.utils.import("resource://gre/modules/DownloadUtils.jsm"); } @@ -228,7 +229,7 @@ function onIndexedDBUsageCallback(request) { status.value = gBundle.getFormattedString("indexedDBUsage", - DownloadUtils.convertByteUnits(request.usage)); + DownloadUtils.convertByteUnits(usage)); status.removeAttribute("hidden"); button.removeAttribute("hidden"); } diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index c0ae8e07acd2..eb6134cd7c7e 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -68,9 +68,6 @@ Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"] .getService(Components.interfaces.mozIPlacesAutoComplete); - - (Components.utils.import("resource://gre/modules/AppConstants.jsm", {})).AppConstants; - document.getAnonymousElementByAttribute(this, "anonid", "tabbox"); @@ -108,7 +105,7 @@ new Map(); - this.AppConstants.platform == "macosx"; + AppConstants == "macosx"; @@ -2655,7 +2652,10 @@ var browser = this.getBrowserForTab(aTab); - if (!aTab._pendingPermitUnload && !aAdoptedByTab && !aSkipPermitUnload) { + if (!aTab._pendingPermitUnload && + !aSkipPermitUnload && + aTab.linkedPanel && + !aAdoptedByTab) { // We need to block while calling permitUnload() because it // processes the event queue and may lead to another removeTab() // call before permitUnload() returns. @@ -2663,8 +2663,7 @@ TelemetryStopwatch.start("FX_TAB_CLOSE_PERMIT_UNLOAD_TIME_MS", aTab); aTab._pendingPermitUnload = true; - let {permitUnload, timedOut} = aTab.linkedPanel ? - browser.permitUnload() : {permitUnload: true, timedOut: false}; + let {permitUnload, timedOut} = browser.permitUnload(); delete aTab._pendingPermitUnload; TelemetryStopwatch.finish("FX_TAB_CLOSE_PERMIT_UNLOAD_TIME_MS", aTab); @@ -3425,7 +3424,7 @@ { let callback = { onUsageResult(request) { - site.quotaUsage = request.usage; + site.quotaUsage = request.result.usage; resolve(); } }; diff --git a/browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js b/browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js index 5dda6b7b51d5..7fb68627001d 100644 --- a/browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js +++ b/browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js @@ -132,7 +132,7 @@ function getQuotaUsage(origin) { return new Promise(resolve => { let uri = NetUtil.newURI(origin); let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); - Services.qms.getUsageForPrincipal(principal, request => resolve(request.usage)); + Services.qms.getUsageForPrincipal(principal, request => resolve(request.result.usage)); }); } diff --git a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js index 759ba2aeac8b..0d1f5062df32 100644 --- a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js +++ b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js @@ -132,7 +132,7 @@ function getQuotaUsage(origin) { return new Promise(resolve => { let uri = NetUtil.newURI(origin); let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); - Services.qms.getUsageForPrincipal(principal, request => resolve(request.usage)); + Services.qms.getUsageForPrincipal(principal, request => resolve(request.result.usage)); }); } diff --git a/build/macosx/local-mozconfig.common b/build/macosx/local-mozconfig.common index c49a0680f2c2..30d911615fee 100644 --- a/build/macosx/local-mozconfig.common +++ b/build/macosx/local-mozconfig.common @@ -32,6 +32,11 @@ fi ldflags="$ldflags -Wl,-no_data_in_code_info" export LDFLAGS="$ldflags" +# Until bug 1342503 is fixed, we can't build some of the webrender dependencies +# on buildbot OS X builders, because rustc will use some random system toolchain +# instead of the one we package with tooltool. +ac_add_options --disable-webrender + # If not set use the system default clang if [ -z "$CC" ]; then export CC=clang diff --git a/build/valgrind/i386-redhat-linux-gnu.sup b/build/valgrind/i386-redhat-linux-gnu.sup index c1d39cd24482..cfdc37bb0009 100644 --- a/build/valgrind/i386-redhat-linux-gnu.sup +++ b/build/valgrind/i386-redhat-linux-gnu.sup @@ -18,16 +18,6 @@ obj:/lib/libdbus-1.so.3.4.0 ... } -{ - Bug 793600 - Memcheck:Leak - fun:realloc - obj:/usr/lib/libfontconfig.so.1.4.4 - ... - fun:FcDefaultSubstitute - fun:_ZN17gfxPangoFontGroup11MakeFontSetEP14_PangoLanguagedP9nsAutoRefI10_FcPatternE - ... -} { Bug 794366 Memcheck:Leak diff --git a/build/valgrind/x86_64-redhat-linux-gnu.sup b/build/valgrind/x86_64-redhat-linux-gnu.sup index 06435e466526..aa8fb80a742d 100644 --- a/build/valgrind/x86_64-redhat-linux-gnu.sup +++ b/build/valgrind/x86_64-redhat-linux-gnu.sup @@ -18,16 +18,6 @@ obj:/lib64/libdbus-1.so.3.4.0 ... } -{ - Bug 793600 - Memcheck:Leak - fun:realloc - obj:/usr/lib64/libfontconfig.so.1.4.4 - ... - fun:FcDefaultSubstitute - fun:_ZN17gfxPangoFontGroup11MakeFontSetEP14_PangoLanguagedP9nsAutoRefI10_FcPatternE - ... -} # Fontconfig is going fancy with its cache structure and that confuses valgrind. # https://bugs.freedesktop.org/show_bug.cgi?id=8215 # https://bugs.freedesktop.org/show_bug.cgi?id=8428 diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index 466e4994cd0b..b4873eeb4498 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -12,292 +12,22 @@ #endif #include "nsIAddonPolicyService.h" #include "nsIContentSecurityPolicy.h" -#include "nsIEffectiveTLDService.h" #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "nsNetUtil.h" #include "nsIURIWithPrincipal.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsScriptSecurityManager.h" #include "nsServiceManagerUtils.h" #include "mozilla/dom/ChromeUtils.h" #include "mozilla/dom/CSPDictionariesBinding.h" -#include "mozilla/dom/quota/QuotaManager.h" #include "mozilla/dom/ToJSValue.h" -#include "mozilla/dom/URLSearchParams.h" namespace mozilla { -using dom::URLParams; - -bool OriginAttributes::sFirstPartyIsolation = false; -bool OriginAttributes::sRestrictedOpenerAccess = false; - -void -OriginAttributes::InitPrefs() -{ - MOZ_ASSERT(NS_IsMainThread()); - static bool sInited = false; - if (!sInited) { - sInited = true; - Preferences::AddBoolVarCache(&sFirstPartyIsolation, - "privacy.firstparty.isolate"); - Preferences::AddBoolVarCache(&sRestrictedOpenerAccess, - "privacy.firstparty.isolate.restrict_opener_access"); - } -} - -void -OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument, - nsIURI* aURI) -{ - bool isFirstPartyEnabled = IsFirstPartyEnabled(); - - // If the pref is off or this is not a top level load, bail out. - if (!isFirstPartyEnabled || !aIsTopLevelDocument) { - return; - } - - nsCOMPtr tldService = - do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); - MOZ_ASSERT(tldService); - if (!tldService) { - return; - } - - nsAutoCString baseDomain; - nsresult rv = tldService->GetBaseDomain(aURI, 0, baseDomain); - if (NS_FAILED(rv)) { - nsAutoCString scheme; - rv = aURI->GetScheme(scheme); - NS_ENSURE_SUCCESS_VOID(rv); - if (scheme.EqualsLiteral("about")) { - baseDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN); - } - } - - mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain); -} - -void -OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument, - const nsACString& aDomain) -{ - bool isFirstPartyEnabled = IsFirstPartyEnabled(); - - // If the pref is off or this is not a top level load, bail out. - if (!isFirstPartyEnabled || !aIsTopLevelDocument) { - return; - } - - mFirstPartyDomain = NS_ConvertUTF8toUTF16(aDomain); -} - -void -OriginAttributes::CreateSuffix(nsACString& aStr) const -{ - URLParams params; - nsAutoString value; - - // - // Important: While serializing any string-valued attributes, perform a - // release-mode assertion to make sure that they don't contain characters that - // will break the quota manager when it uses the serialization for file - // naming. - // - - if (mAppId != nsIScriptSecurityManager::NO_APP_ID) { - value.AppendInt(mAppId); - params.Set(NS_LITERAL_STRING("appId"), value); - } - - if (mInIsolatedMozBrowser) { - params.Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1")); - } - - if (mUserContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) { - value.Truncate(); - value.AppendInt(mUserContextId); - params.Set(NS_LITERAL_STRING("userContextId"), value); - } - - - if (mPrivateBrowsingId) { - value.Truncate(); - value.AppendInt(mPrivateBrowsingId); - params.Set(NS_LITERAL_STRING("privateBrowsingId"), value); - } - - if (!mFirstPartyDomain.IsEmpty()) { - MOZ_RELEASE_ASSERT(mFirstPartyDomain.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound); - params.Set(NS_LITERAL_STRING("firstPartyDomain"), mFirstPartyDomain); - } - - aStr.Truncate(); - - params.Serialize(value); - if (!value.IsEmpty()) { - aStr.AppendLiteral("^"); - aStr.Append(NS_ConvertUTF16toUTF8(value)); - } - -// In debug builds, check the whole string for illegal characters too (just in case). -#ifdef DEBUG - nsAutoCString str; - str.Assign(aStr); - MOZ_ASSERT(str.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound); -#endif -} - -void -OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const -{ - OriginAttributes attrs = *this; - - if (!attrs.mFirstPartyDomain.IsEmpty()) { - attrs.mFirstPartyDomain.AssignLiteral("_anonymizedFirstPartyDomain_"); - } - - attrs.CreateSuffix(aStr); -} - -namespace { - -class MOZ_STACK_CLASS PopulateFromSuffixIterator final - : public URLParams::ForEachIterator -{ -public: - explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes) - : mOriginAttributes(aOriginAttributes) - { - MOZ_ASSERT(aOriginAttributes); - // If mPrivateBrowsingId is passed in as >0 and is not present in the suffix, - // then it will remain >0 when it should be 0 according to the suffix. Set to 0 before - // iterating to fix this. - mOriginAttributes->mPrivateBrowsingId = 0; - } - - bool URLParamsIterator(const nsString& aName, - const nsString& aValue) override - { - if (aName.EqualsLiteral("appId")) { - nsresult rv; - int64_t val = aValue.ToInteger64(&rv); - NS_ENSURE_SUCCESS(rv, false); - NS_ENSURE_TRUE(val <= UINT32_MAX, false); - mOriginAttributes->mAppId = static_cast(val); - - return true; - } - - if (aName.EqualsLiteral("inBrowser")) { - if (!aValue.EqualsLiteral("1")) { - return false; - } - - mOriginAttributes->mInIsolatedMozBrowser = true; - return true; - } - - if (aName.EqualsLiteral("addonId")) { - // No longer supported. Silently ignore so that legacy origin strings - // don't cause failures. - return true; - } - - if (aName.EqualsLiteral("userContextId")) { - nsresult rv; - int64_t val = aValue.ToInteger64(&rv); - NS_ENSURE_SUCCESS(rv, false); - NS_ENSURE_TRUE(val <= UINT32_MAX, false); - mOriginAttributes->mUserContextId = static_cast(val); - - return true; - } - - if (aName.EqualsLiteral("privateBrowsingId")) { - nsresult rv; - int64_t val = aValue.ToInteger64(&rv); - NS_ENSURE_SUCCESS(rv, false); - NS_ENSURE_TRUE(val >= 0 && val <= UINT32_MAX, false); - mOriginAttributes->mPrivateBrowsingId = static_cast(val); - - return true; - } - - if (aName.EqualsLiteral("firstPartyDomain")) { - MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty()); - mOriginAttributes->mFirstPartyDomain.Assign(aValue); - return true; - } - - // No other attributes are supported. - return false; - } - -private: - OriginAttributes* mOriginAttributes; -}; - -} // namespace - -bool -OriginAttributes::PopulateFromSuffix(const nsACString& aStr) -{ - if (aStr.IsEmpty()) { - return true; - } - - if (aStr[0] != '^') { - return false; - } - - URLParams params; - params.ParseInput(Substring(aStr, 1, aStr.Length() - 1)); - - PopulateFromSuffixIterator iterator(this); - return params.ForEach(iterator); -} - -bool -OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin, - nsACString& aOriginNoSuffix) -{ - // RFindChar is only available on nsCString. - nsCString origin(aOrigin); - int32_t pos = origin.RFindChar('^'); - - if (pos == kNotFound) { - aOriginNoSuffix = origin; - return true; - } - - aOriginNoSuffix = Substring(origin, 0, pos); - return PopulateFromSuffix(Substring(origin, pos)); -} - -void -OriginAttributes::SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing) -{ - mPrivateBrowsingId = aInPrivateBrowsing ? 1 : 0; -} - -/* static */ -bool -OriginAttributes::IsPrivateBrowsing(const nsACString& aOrigin) -{ - nsAutoCString dummy; - OriginAttributes attrs; - if (NS_WARN_IF(!attrs.PopulateFromOrigin(aOrigin, dummy))) { - return false; - } - - return !!attrs.mPrivateBrowsingId; -} - BasePrincipal::BasePrincipal(PrincipalKind aKind) : mKind(aKind) , mDomainSet(false) @@ -645,7 +375,7 @@ BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAt nsresult rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, &inheritsPrincipal); if (NS_FAILED(rv) || inheritsPrincipal) { - return nsNullPrincipal::Create(aAttrs); + return NullPrincipal::Create(aAttrs); } // Check whether the URI knows what its principal is supposed to be. @@ -654,14 +384,14 @@ BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAt nsCOMPtr principal; uriPrinc->GetPrincipal(getter_AddRefs(principal)); if (!principal) { - return nsNullPrincipal::Create(aAttrs); + return NullPrincipal::Create(aAttrs); } RefPtr concrete = Cast(principal); return concrete.forget(); } // Mint a codebase principal. - RefPtr codebase = new nsPrincipal(); + RefPtr codebase = new ContentPrincipal(); rv = codebase->Init(aURI, aAttrs); NS_ENSURE_SUCCESS(rv, nullptr); return codebase.forget(); @@ -674,7 +404,7 @@ BasePrincipal::CreateCodebasePrincipal(const nsACString& aOrigin) "CreateCodebasePrincipal does not support System and Expanded principals"); MOZ_ASSERT(!StringBeginsWith(aOrigin, NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME ":")), - "CreateCodebasePrincipal does not support nsNullPrincipal"); + "CreateCodebasePrincipal does not support NullPrincipal"); nsAutoCString originNoSuffix; mozilla::OriginAttributes attrs; diff --git a/caps/BasePrincipal.h b/caps/BasePrincipal.h index 537b1a8e51e9..054f3764fcbc 100644 --- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -10,187 +10,17 @@ #include "nsJSPrincipals.h" #include "mozilla/Attributes.h" -#include "mozilla/dom/ChromeUtils.h" -#include "mozilla/dom/ChromeUtilsBinding.h" -#include "nsIScriptSecurityManager.h" +#include "mozilla/OriginAttributes.h" class nsIContentSecurityPolicy; class nsIObjectOutputStream; class nsIObjectInputStream; class nsIURI; -class nsExpandedPrincipal; +class ExpandedPrincipal; namespace mozilla { -// Base OriginAttributes class. This has several subclass flavors, and is not -// directly constructable itself. -class OriginAttributes : public dom::OriginAttributesDictionary -{ -public: - OriginAttributes() {} - - OriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser) - { - mAppId = aAppId; - mInIsolatedMozBrowser = aInIsolatedMozBrowser; - } - - explicit OriginAttributes(const OriginAttributesDictionary& aOther) - : OriginAttributesDictionary(aOther) - {} - - void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI); - void SetFirstPartyDomain(const bool aIsTopLevelDocument, const nsACString& aDomain); - - enum { - STRIP_FIRST_PARTY_DOMAIN = 0x01, - STRIP_USER_CONTEXT_ID = 0x02, - }; - - inline void StripAttributes(uint32_t aFlags) - { - if (aFlags & STRIP_FIRST_PARTY_DOMAIN) { - mFirstPartyDomain.Truncate(); - } - - if (aFlags & STRIP_USER_CONTEXT_ID) { - mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID; - } - } - - bool operator==(const OriginAttributes& aOther) const - { - return mAppId == aOther.mAppId && - mInIsolatedMozBrowser == aOther.mInIsolatedMozBrowser && - mUserContextId == aOther.mUserContextId && - mPrivateBrowsingId == aOther.mPrivateBrowsingId && - mFirstPartyDomain == aOther.mFirstPartyDomain; - } - - bool operator!=(const OriginAttributes& aOther) const - { - return !(*this == aOther); - } - - // Serializes/Deserializes non-default values into the suffix format, i.e. - // |!key1=value1&key2=value2|. If there are no non-default attributes, this - // returns an empty string. - void CreateSuffix(nsACString& aStr) const; - - // Don't use this method for anything else than debugging! - void CreateAnonymizedSuffix(nsACString& aStr) const; - - MOZ_MUST_USE bool PopulateFromSuffix(const nsACString& aStr); - - // Populates the attributes from a string like - // |uri!key1=value1&key2=value2| and returns the uri without the suffix. - MOZ_MUST_USE bool PopulateFromOrigin(const nsACString& aOrigin, - nsACString& aOriginNoSuffix); - - // Helper function to match mIsPrivateBrowsing to existing private browsing - // flags. Once all other flags are removed, this can be removed too. - void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing); - - // check if "privacy.firstparty.isolate" is enabled. - static inline bool IsFirstPartyEnabled() - { - return sFirstPartyIsolation; - } - - // check if the access of window.opener across different FPDs is restricted. - // We only restrict the access of window.opener when first party isolation - // is enabled and "privacy.firstparty.isolate.restrict_opener_access" is on. - static inline bool IsRestrictOpenerAccessForFPI() - { - // We always want to restrict window.opener if first party isolation is - // disabled. - return !sFirstPartyIsolation || sRestrictedOpenerAccess; - } - - // returns true if the originAttributes suffix has mPrivateBrowsingId value - // different than 0. - static bool IsPrivateBrowsing(const nsACString& aOrigin); - - static void InitPrefs(); - -private: - static bool sFirstPartyIsolation; - static bool sRestrictedOpenerAccess; -}; - -class OriginAttributesPattern : public dom::OriginAttributesPatternDictionary -{ -public: - // To convert a JSON string to an OriginAttributesPattern, do the following: - // - // OriginAttributesPattern pattern; - // if (!pattern.Init(aJSONString)) { - // ... // handle failure. - // } - OriginAttributesPattern() {} - - explicit OriginAttributesPattern(const OriginAttributesPatternDictionary& aOther) - : OriginAttributesPatternDictionary(aOther) {} - - // Performs a match of |aAttrs| against this pattern. - bool Matches(const OriginAttributes& aAttrs) const - { - if (mAppId.WasPassed() && mAppId.Value() != aAttrs.mAppId) { - return false; - } - - if (mInIsolatedMozBrowser.WasPassed() && mInIsolatedMozBrowser.Value() != aAttrs.mInIsolatedMozBrowser) { - return false; - } - - if (mUserContextId.WasPassed() && mUserContextId.Value() != aAttrs.mUserContextId) { - return false; - } - - if (mPrivateBrowsingId.WasPassed() && mPrivateBrowsingId.Value() != aAttrs.mPrivateBrowsingId) { - return false; - } - - if (mFirstPartyDomain.WasPassed() && mFirstPartyDomain.Value() != aAttrs.mFirstPartyDomain) { - return false; - } - - return true; - } - - bool Overlaps(const OriginAttributesPattern& aOther) const - { - if (mAppId.WasPassed() && aOther.mAppId.WasPassed() && - mAppId.Value() != aOther.mAppId.Value()) { - return false; - } - - if (mInIsolatedMozBrowser.WasPassed() && - aOther.mInIsolatedMozBrowser.WasPassed() && - mInIsolatedMozBrowser.Value() != aOther.mInIsolatedMozBrowser.Value()) { - return false; - } - - if (mUserContextId.WasPassed() && aOther.mUserContextId.WasPassed() && - mUserContextId.Value() != aOther.mUserContextId.Value()) { - return false; - } - - if (mPrivateBrowsingId.WasPassed() && aOther.mPrivateBrowsingId.WasPassed() && - mPrivateBrowsingId.Value() != aOther.mPrivateBrowsingId.Value()) { - return false; - } - - if (mFirstPartyDomain.WasPassed() && aOther.mFirstPartyDomain.WasPassed() && - mFirstPartyDomain.Value() != aOther.mFirstPartyDomain.Value()) { - return false; - } - - return true; - } -}; - /* * Base class from which all nsIPrincipal implementations inherit. Use this for * default implementations and other commonalities between principal @@ -283,7 +113,7 @@ protected: // principal would allow the load ignoring any common behavior implemented in // BasePrincipal::CheckMayLoad. virtual bool MayLoadInternal(nsIURI* aURI) = 0; - friend class ::nsExpandedPrincipal; + friend class ::ExpandedPrincipal; // This function should be called as the last step of the initialization of the // principal objects. It's typically called as the last step from the Init() diff --git a/caps/nsPrincipal.cpp b/caps/ContentPrincipal.cpp similarity index 92% rename from caps/nsPrincipal.cpp rename to caps/ContentPrincipal.cpp index 80a03b9476b7..127f6ce37f10 100644 --- a/caps/nsPrincipal.cpp +++ b/caps/ContentPrincipal.cpp @@ -4,7 +4,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 "nsPrincipal.h" +#include "ContentPrincipal.h" #include "mozIThirdPartyUtil.h" #include "nscore.h" @@ -19,6 +19,8 @@ #include "nsJSPrincipals.h" #include "nsIEffectiveTLDService.h" #include "nsIClassInfoImpl.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" #include "nsIProtocolHandler.h" #include "nsError.h" #include "nsIContentSecurityPolicy.h" @@ -58,25 +60,25 @@ GetAddonPolicyService(nsresult* aRv) return addonPolicyService; } -NS_IMPL_CLASSINFO(nsPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, +NS_IMPL_CLASSINFO(ContentPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, NS_PRINCIPAL_CID) -NS_IMPL_QUERY_INTERFACE_CI(nsPrincipal, +NS_IMPL_QUERY_INTERFACE_CI(ContentPrincipal, nsIPrincipal, nsISerializable) -NS_IMPL_CI_INTERFACE_GETTER(nsPrincipal, +NS_IMPL_CI_INTERFACE_GETTER(ContentPrincipal, nsIPrincipal, nsISerializable) // Called at startup: /* static */ void -nsPrincipal::InitializeStatics() +ContentPrincipal::InitializeStatics() { Preferences::AddBoolVarCache(&gCodeBasePrincipalSupport, "signed.applets.codebase_principal_support", false); } -nsPrincipal::nsPrincipal() +ContentPrincipal::ContentPrincipal() : BasePrincipal(eCodebasePrincipal) , mCodebaseImmutable(false) , mDomainImmutable(false) @@ -84,7 +86,7 @@ nsPrincipal::nsPrincipal() { } -nsPrincipal::~nsPrincipal() +ContentPrincipal::~ContentPrincipal() { // let's clear the principal within the csp to avoid a tangling pointer if (mCSP) { @@ -93,7 +95,8 @@ nsPrincipal::~nsPrincipal() } nsresult -nsPrincipal::Init(nsIURI *aCodebase, const OriginAttributes& aOriginAttributes) +ContentPrincipal::Init(nsIURI *aCodebase, + const OriginAttributes& aOriginAttributes) { NS_ENSURE_STATE(!mInitialized); NS_ENSURE_ARG(aCodebase); @@ -123,13 +126,13 @@ nsPrincipal::Init(nsIURI *aCodebase, const OriginAttributes& aOriginAttributes) } nsresult -nsPrincipal::GetScriptLocation(nsACString &aStr) +ContentPrincipal::GetScriptLocation(nsACString &aStr) { return mCodebase->GetSpec(aStr); } nsresult -nsPrincipal::GetOriginInternal(nsACString& aOrigin) +ContentPrincipal::GetOriginInternal(nsACString& aOrigin) { if (!mCodebase) { return NS_ERROR_FAILURE; @@ -249,12 +252,12 @@ nsPrincipal::GetOriginInternal(nsACString& aOrigin) } bool -nsPrincipal::SubsumesInternal(nsIPrincipal* aOther, - BasePrincipal::DocumentDomainConsideration aConsideration) +ContentPrincipal::SubsumesInternal(nsIPrincipal* aOther, + BasePrincipal::DocumentDomainConsideration aConsideration) { MOZ_ASSERT(aOther); - // For nsPrincipal, Subsumes is equivalent to Equals. + // For ContentPrincipal, Subsumes is equivalent to Equals. if (aOther == this) { return true; } @@ -286,7 +289,7 @@ nsPrincipal::SubsumesInternal(nsIPrincipal* aOther, } NS_IMETHODIMP -nsPrincipal::GetURI(nsIURI** aURI) +ContentPrincipal::GetURI(nsIURI** aURI) { if (mCodebaseImmutable) { NS_ADDREF(*aURI = mCodebase); @@ -302,7 +305,7 @@ nsPrincipal::GetURI(nsIURI** aURI) } bool -nsPrincipal::MayLoadInternal(nsIURI* aURI) +ContentPrincipal::MayLoadInternal(nsIURI* aURI) { // See if aURI is something like a Blob URI that is actually associated with // a principal. @@ -338,7 +341,7 @@ nsPrincipal::MayLoadInternal(nsIURI* aURI) } NS_IMETHODIMP -nsPrincipal::GetHashValue(uint32_t* aValue) +ContentPrincipal::GetHashValue(uint32_t* aValue) { NS_PRECONDITION(mCodebase, "Need a codebase"); @@ -347,7 +350,7 @@ nsPrincipal::GetHashValue(uint32_t* aValue) } NS_IMETHODIMP -nsPrincipal::GetDomain(nsIURI** aDomain) +ContentPrincipal::GetDomain(nsIURI** aDomain) { if (!mDomain) { *aDomain = nullptr; @@ -363,7 +366,7 @@ nsPrincipal::GetDomain(nsIURI** aDomain) } NS_IMETHODIMP -nsPrincipal::SetDomain(nsIURI* aDomain) +ContentPrincipal::SetDomain(nsIURI* aDomain) { mDomain = NS_TryToMakeImmutable(aDomain); mDomainImmutable = URIIsImmutable(mDomain); @@ -384,7 +387,7 @@ nsPrincipal::SetDomain(nsIURI* aDomain) } NS_IMETHODIMP -nsPrincipal::GetBaseDomain(nsACString& aBaseDomain) +ContentPrincipal::GetBaseDomain(nsACString& aBaseDomain) { // For a file URI, we return the file path. if (NS_URIIsLocalFile(mCodebase)) { @@ -419,7 +422,7 @@ nsPrincipal::GetBaseDomain(nsACString& aBaseDomain) } NS_IMETHODIMP -nsPrincipal::GetAddonId(nsAString& aAddonId) +ContentPrincipal::GetAddonId(nsAString& aAddonId) { if (mAddonIdCache.isSome()) { aAddonId.Assign(mAddonIdCache.ref()); @@ -448,7 +451,7 @@ nsPrincipal::GetAddonId(nsAString& aAddonId) }; NS_IMETHODIMP -nsPrincipal::Read(nsIObjectInputStream* aStream) +ContentPrincipal::Read(nsIObjectInputStream* aStream) { nsCOMPtr supports; nsCOMPtr codebase; @@ -494,7 +497,7 @@ nsPrincipal::Read(nsIObjectInputStream* aStream) } NS_IMETHODIMP -nsPrincipal::Write(nsIObjectOutputStream* aStream) +ContentPrincipal::Write(nsIObjectOutputStream* aStream) { NS_ENSURE_STATE(mCodebase); nsresult rv = NS_WriteOptionalCompoundObject(aStream, mCodebase, NS_GET_IID(nsIURI), diff --git a/caps/nsPrincipal.h b/caps/ContentPrincipal.h similarity index 85% rename from caps/nsPrincipal.h rename to caps/ContentPrincipal.h index f65dc81823d4..1acdafeda51d 100644 --- a/caps/nsPrincipal.h +++ b/caps/ContentPrincipal.h @@ -3,8 +3,8 @@ * 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 nsPrincipal_h__ -#define nsPrincipal_h__ +#ifndef ContentPrincipal_h +#define ContentPrincipal_h #include "nsCOMPtr.h" #include "nsJSPrincipals.h" @@ -15,7 +15,7 @@ #include "nsScriptSecurityManager.h" #include "mozilla/BasePrincipal.h" -class nsPrincipal final : public mozilla::BasePrincipal +class ContentPrincipal final : public mozilla::BasePrincipal { public: NS_DECL_NSISERIALIZABLE @@ -29,7 +29,7 @@ public: bool IsCodebasePrincipal() const override { return true; } nsresult GetOriginInternal(nsACString& aOrigin) override; - nsPrincipal(); + ContentPrincipal(); // Init() must be called before the principal is in a usable state. nsresult Init(nsIURI* aCodebase, @@ -50,9 +50,10 @@ public: bool mInitialized; protected: - virtual ~nsPrincipal(); + virtual ~ContentPrincipal(); - bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override; + bool SubsumesInternal(nsIPrincipal* aOther, + DocumentDomainConsideration aConsideration) override; bool MayLoadInternal(nsIURI* aURI) override; private: @@ -64,4 +65,4 @@ private: { 0x653e0e4d, 0x3ee4, 0x45fa, \ { 0xb2, 0x72, 0x97, 0xc2, 0x0b, 0xc0, 0x1e, 0xb8 } } -#endif // nsPrincipal_h__ +#endif // ContentPrincipal_h diff --git a/caps/nsExpandedPrincipal.cpp b/caps/ExpandedPrincipal.cpp similarity index 70% rename from caps/nsExpandedPrincipal.cpp rename to caps/ExpandedPrincipal.cpp index 9a06abe874d7..c3e30c23b1ba 100644 --- a/caps/nsExpandedPrincipal.cpp +++ b/caps/ExpandedPrincipal.cpp @@ -4,19 +4,19 @@ * 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 "nsExpandedPrincipal.h" +#include "ExpandedPrincipal.h" #include "nsIClassInfoImpl.h" using namespace mozilla; -NS_IMPL_CLASSINFO(nsExpandedPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, +NS_IMPL_CLASSINFO(ExpandedPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, NS_EXPANDEDPRINCIPAL_CID) -NS_IMPL_QUERY_INTERFACE_CI(nsExpandedPrincipal, +NS_IMPL_QUERY_INTERFACE_CI(ExpandedPrincipal, nsIPrincipal, nsIExpandedPrincipal) -NS_IMPL_CI_INTERFACE_GETTER(nsExpandedPrincipal, - nsIPrincipal, - nsIExpandedPrincipal) +NS_IMPL_CI_INTERFACE_GETTER(ExpandedPrincipal, + nsIPrincipal, + nsIExpandedPrincipal) struct OriginComparator { @@ -43,11 +43,11 @@ struct OriginComparator } }; -nsExpandedPrincipal::nsExpandedPrincipal(nsTArray> &aWhiteList, - const OriginAttributes& aAttrs) +ExpandedPrincipal::ExpandedPrincipal(nsTArray> &aWhiteList, + const OriginAttributes& aAttrs) : BasePrincipal(eExpandedPrincipal) { - // We force the principals to be sorted by origin so that nsExpandedPrincipal + // We force the principals to be sorted by origin so that ExpandedPrincipal // origins can have a canonical form. OriginComparator c; for (size_t i = 0; i < aWhiteList.Length(); ++i) { @@ -56,33 +56,33 @@ nsExpandedPrincipal::nsExpandedPrincipal(nsTArray> &aWhit mOriginAttributes = aAttrs; } -nsExpandedPrincipal::~nsExpandedPrincipal() +ExpandedPrincipal::~ExpandedPrincipal() { } -already_AddRefed -nsExpandedPrincipal::Create(nsTArray>& aWhiteList, - const OriginAttributes& aAttrs) +already_AddRefed +ExpandedPrincipal::Create(nsTArray>& aWhiteList, + const OriginAttributes& aAttrs) { - RefPtr ep = new nsExpandedPrincipal(aWhiteList, aAttrs); + RefPtr ep = new ExpandedPrincipal(aWhiteList, aAttrs); ep->FinishInit(); return ep.forget(); } NS_IMETHODIMP -nsExpandedPrincipal::GetDomain(nsIURI** aDomain) +ExpandedPrincipal::GetDomain(nsIURI** aDomain) { *aDomain = nullptr; return NS_OK; } NS_IMETHODIMP -nsExpandedPrincipal::SetDomain(nsIURI* aDomain) +ExpandedPrincipal::SetDomain(nsIURI* aDomain) { return NS_OK; } nsresult -nsExpandedPrincipal::GetOriginInternal(nsACString& aOrigin) +ExpandedPrincipal::GetOriginInternal(nsACString& aOrigin) { aOrigin.AssignLiteral("[Expanded Principal ["); for (size_t i = 0; i < mPrincipals.Length(); ++i) { @@ -101,8 +101,8 @@ nsExpandedPrincipal::GetOriginInternal(nsACString& aOrigin) } bool -nsExpandedPrincipal::SubsumesInternal(nsIPrincipal* aOther, - BasePrincipal::DocumentDomainConsideration aConsideration) +ExpandedPrincipal::SubsumesInternal(nsIPrincipal* aOther, + BasePrincipal::DocumentDomainConsideration aConsideration) { // If aOther is an ExpandedPrincipal too, we break it down into its component // nsIPrincipals, and check subsumes on each one. @@ -133,7 +133,7 @@ nsExpandedPrincipal::SubsumesInternal(nsIPrincipal* aOther, } bool -nsExpandedPrincipal::MayLoadInternal(nsIURI* uri) +ExpandedPrincipal::MayLoadInternal(nsIURI* uri) { for (uint32_t i = 0; i < mPrincipals.Length(); ++i){ if (BasePrincipal::Cast(mPrincipals[i])->MayLoadInternal(uri)) { @@ -145,40 +145,40 @@ nsExpandedPrincipal::MayLoadInternal(nsIURI* uri) } NS_IMETHODIMP -nsExpandedPrincipal::GetHashValue(uint32_t* result) +ExpandedPrincipal::GetHashValue(uint32_t* result) { MOZ_CRASH("extended principal should never be used as key in a hash map"); } NS_IMETHODIMP -nsExpandedPrincipal::GetURI(nsIURI** aURI) +ExpandedPrincipal::GetURI(nsIURI** aURI) { *aURI = nullptr; return NS_OK; } NS_IMETHODIMP -nsExpandedPrincipal::GetWhiteList(nsTArray >** aWhiteList) +ExpandedPrincipal::GetWhiteList(nsTArray >** aWhiteList) { *aWhiteList = &mPrincipals; return NS_OK; } NS_IMETHODIMP -nsExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain) +ExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain) { return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP -nsExpandedPrincipal::GetAddonId(nsAString& aAddonId) +ExpandedPrincipal::GetAddonId(nsAString& aAddonId) { aAddonId.Truncate(); return NS_OK; }; bool -nsExpandedPrincipal::AddonHasPermission(const nsAString& aPerm) +ExpandedPrincipal::AddonHasPermission(const nsAString& aPerm) { for (size_t i = 0; i < mPrincipals.Length(); ++i) { if (BasePrincipal::Cast(mPrincipals[i])->AddonHasPermission(aPerm)) { @@ -189,7 +189,7 @@ nsExpandedPrincipal::AddonHasPermission(const nsAString& aPerm) } nsresult -nsExpandedPrincipal::GetScriptLocation(nsACString& aStr) +ExpandedPrincipal::GetScriptLocation(nsACString& aStr) { aStr.Assign("[Expanded Principal ["); for (size_t i = 0; i < mPrincipals.Length(); ++i) { @@ -213,13 +213,13 @@ nsExpandedPrincipal::GetScriptLocation(nsACString& aStr) ////////////////////////////////////////// NS_IMETHODIMP -nsExpandedPrincipal::Read(nsIObjectInputStream* aStream) +ExpandedPrincipal::Read(nsIObjectInputStream* aStream) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsExpandedPrincipal::Write(nsIObjectOutputStream* aStream) +ExpandedPrincipal::Write(nsIObjectOutputStream* aStream) { return NS_ERROR_NOT_IMPLEMENTED; } diff --git a/caps/nsExpandedPrincipal.h b/caps/ExpandedPrincipal.h similarity index 76% rename from caps/nsExpandedPrincipal.h rename to caps/ExpandedPrincipal.h index 360f83ce65d0..06750a09353e 100644 --- a/caps/nsExpandedPrincipal.h +++ b/caps/ExpandedPrincipal.h @@ -3,8 +3,8 @@ * 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 nsExpandedPrincipal_h -#define nsExpandedPrincipal_h +#ifndef ExpandedPrincipal_h +#define ExpandedPrincipal_h #include "nsCOMPtr.h" #include "nsJSPrincipals.h" @@ -12,19 +12,20 @@ #include "nsNetUtil.h" #include "mozilla/BasePrincipal.h" -class nsExpandedPrincipal : public nsIExpandedPrincipal - , public mozilla::BasePrincipal +class ExpandedPrincipal : public nsIExpandedPrincipal + , public mozilla::BasePrincipal { - nsExpandedPrincipal(nsTArray> &aWhiteList, - const mozilla::OriginAttributes& aAttrs); + ExpandedPrincipal(nsTArray> &aWhiteList, + const mozilla::OriginAttributes& aAttrs); public: - static already_AddRefed + static already_AddRefed Create(nsTArray>& aWhiteList, const mozilla::OriginAttributes& aAttrs); NS_DECL_NSIEXPANDEDPRINCIPAL NS_DECL_NSISERIALIZABLE + NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return nsJSPrincipals::AddRef(); }; NS_IMETHOD_(MozExternalRefCountType) Release() override { return nsJSPrincipals::Release(); }; NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; @@ -39,9 +40,11 @@ public: nsresult GetOriginInternal(nsACString& aOrigin) override; protected: - virtual ~nsExpandedPrincipal(); + virtual ~ExpandedPrincipal(); + + bool SubsumesInternal(nsIPrincipal* aOther, + DocumentDomainConsideration aConsideration) override; - bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override; bool MayLoadInternal(nsIURI* aURI) override; private: @@ -53,4 +56,4 @@ private: { 0xe8ee88b0, 0x5571, 0x4086, \ { 0xa4, 0x5b, 0x39, 0xa7, 0x16, 0x90, 0x6b, 0xdb } } -#endif // nsExpandedPrincipal_h +#endif // ExpandedPrincipal_h diff --git a/caps/nsNullPrincipal.cpp b/caps/NullPrincipal.cpp similarity index 71% rename from caps/nsNullPrincipal.cpp rename to caps/NullPrincipal.cpp index fe846ac25b0c..8fff3211eb93 100644 --- a/caps/nsNullPrincipal.cpp +++ b/caps/NullPrincipal.cpp @@ -13,54 +13,54 @@ #include "mozilla/ArrayUtils.h" #include "nsDocShell.h" -#include "nsNullPrincipal.h" -#include "nsNullPrincipalURI.h" +#include "NullPrincipal.h" +#include "NullPrincipalURI.h" #include "nsMemory.h" #include "nsIURIWithPrincipal.h" #include "nsIClassInfoImpl.h" #include "nsNetCID.h" #include "nsError.h" #include "nsIScriptSecurityManager.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "nsScriptSecurityManager.h" #include "pratom.h" using namespace mozilla; -NS_IMPL_CLASSINFO(nsNullPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, +NS_IMPL_CLASSINFO(NullPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, NS_NULLPRINCIPAL_CID) -NS_IMPL_QUERY_INTERFACE_CI(nsNullPrincipal, +NS_IMPL_QUERY_INTERFACE_CI(NullPrincipal, nsIPrincipal, nsISerializable) -NS_IMPL_CI_INTERFACE_GETTER(nsNullPrincipal, +NS_IMPL_CI_INTERFACE_GETTER(NullPrincipal, nsIPrincipal, nsISerializable) -/* static */ already_AddRefed -nsNullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom) +/* static */ already_AddRefed +NullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom) { - RefPtr nullPrin = new nsNullPrincipal(); + RefPtr nullPrin = new NullPrincipal(); nsresult rv = nullPrin->Init(Cast(aInheritFrom)->OriginAttributesRef()); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); return nullPrin.forget(); } -/* static */ already_AddRefed -nsNullPrincipal::CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty) +/* static */ already_AddRefed +NullPrincipal::CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty) { OriginAttributes attrs = nsDocShell::Cast(aDocShell)->GetOriginAttributes(); attrs.SetFirstPartyDomain(aIsFirstParty, NS_LITERAL_CSTRING(NULL_PRINCIPAL_FIRST_PARTY_DOMAIN)); - RefPtr nullPrin = new nsNullPrincipal(); + RefPtr nullPrin = new NullPrincipal(); nsresult rv = nullPrin->Init(attrs); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); return nullPrin.forget(); } -/* static */ already_AddRefed -nsNullPrincipal::Create(const OriginAttributes& aOriginAttributes, nsIURI* aURI) +/* static */ already_AddRefed +NullPrincipal::Create(const OriginAttributes& aOriginAttributes, nsIURI* aURI) { - RefPtr nullPrin = new nsNullPrincipal(); + RefPtr nullPrin = new NullPrincipal(); nsresult rv = nullPrin->Init(aOriginAttributes, aURI); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); @@ -68,7 +68,7 @@ nsNullPrincipal::Create(const OriginAttributes& aOriginAttributes, nsIURI* aURI) } nsresult -nsNullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI) +NullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI) { mOriginAttributes = aOriginAttributes; @@ -82,7 +82,7 @@ nsNullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI) mURI = aURI; } else { - mURI = nsNullPrincipalURI::Create(); + mURI = NullPrincipalURI::Create(); NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_AVAILABLE); } @@ -92,7 +92,7 @@ nsNullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI) } nsresult -nsNullPrincipal::GetScriptLocation(nsACString &aStr) +NullPrincipal::GetScriptLocation(nsACString &aStr) { return mURI->GetSpec(aStr); } @@ -102,14 +102,15 @@ nsNullPrincipal::GetScriptLocation(nsACString &aStr) */ NS_IMETHODIMP -nsNullPrincipal::GetHashValue(uint32_t *aResult) +NullPrincipal::GetHashValue(uint32_t *aResult) { *aResult = (NS_PTR_TO_INT32(this) >> 2); return NS_OK; } NS_IMETHODIMP -nsNullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) { +NullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) +{ // Never destroy an existing CSP on the principal. // This method should only be called in rare cases. @@ -123,19 +124,19 @@ nsNullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) { } NS_IMETHODIMP -nsNullPrincipal::GetURI(nsIURI** aURI) +NullPrincipal::GetURI(nsIURI** aURI) { return NS_EnsureSafeToReturn(mURI, aURI); } NS_IMETHODIMP -nsNullPrincipal::GetDomain(nsIURI** aDomain) +NullPrincipal::GetDomain(nsIURI** aDomain) { return NS_EnsureSafeToReturn(mURI, aDomain); } NS_IMETHODIMP -nsNullPrincipal::SetDomain(nsIURI* aDomain) +NullPrincipal::SetDomain(nsIURI* aDomain) { // I think the right thing to do here is to just throw... Silently failing // seems counterproductive. @@ -143,13 +144,13 @@ nsNullPrincipal::SetDomain(nsIURI* aDomain) } nsresult -nsNullPrincipal::GetOriginInternal(nsACString& aOrigin) +NullPrincipal::GetOriginInternal(nsACString& aOrigin) { return mURI->GetSpec(aOrigin); } bool -nsNullPrincipal::MayLoadInternal(nsIURI* aURI) +NullPrincipal::MayLoadInternal(nsIURI* aURI) { // Also allow the load if we are the principal of the URI being checked. nsCOMPtr uriPrinc = do_QueryInterface(aURI); @@ -166,14 +167,14 @@ nsNullPrincipal::MayLoadInternal(nsIURI* aURI) } NS_IMETHODIMP -nsNullPrincipal::GetBaseDomain(nsACString& aBaseDomain) +NullPrincipal::GetBaseDomain(nsACString& aBaseDomain) { // For a null principal, we use our unique uuid as the base domain. return mURI->GetPath(aBaseDomain); } NS_IMETHODIMP -nsNullPrincipal::GetAddonId(nsAString& aAddonId) +NullPrincipal::GetAddonId(nsAString& aAddonId) { aAddonId.Truncate(); return NS_OK; @@ -183,11 +184,11 @@ nsNullPrincipal::GetAddonId(nsAString& aAddonId) * nsISerializable implementation */ NS_IMETHODIMP -nsNullPrincipal::Read(nsIObjectInputStream* aStream) +NullPrincipal::Read(nsIObjectInputStream* aStream) { - // Note - nsNullPrincipal use NS_GENERIC_FACTORY_CONSTRUCTOR_INIT, which means + // Note - NullPrincipal use NS_GENERIC_FACTORY_CONSTRUCTOR_INIT, which means // that the Init() method has already been invoked by the time we deserialize. - // This is in contrast to nsPrincipal, which uses NS_GENERIC_FACTORY_CONSTRUCTOR, + // This is in contrast to ContentPrincipal, which uses NS_GENERIC_FACTORY_CONSTRUCTOR, // in which case ::Read needs to invoke Init(). nsAutoCString spec; @@ -210,7 +211,7 @@ nsNullPrincipal::Read(nsIObjectInputStream* aStream) } NS_IMETHODIMP -nsNullPrincipal::Write(nsIObjectOutputStream* aStream) +NullPrincipal::Write(nsIObjectOutputStream* aStream) { NS_ENSURE_STATE(mURI); diff --git a/caps/nsNullPrincipal.h b/caps/NullPrincipal.h similarity index 84% rename from caps/nsNullPrincipal.h rename to caps/NullPrincipal.h index 653029258f4b..b036d0c3b220 100644 --- a/caps/nsNullPrincipal.h +++ b/caps/NullPrincipal.h @@ -9,8 +9,8 @@ * same-origin with anything but themselves. */ -#ifndef nsNullPrincipal_h__ -#define nsNullPrincipal_h__ +#ifndef NullPrincipal_h +#define NullPrincipal_h #include "nsIPrincipal.h" #include "nsJSPrincipals.h" @@ -30,13 +30,13 @@ class nsIURI; #define NS_NULLPRINCIPAL_SCHEME "moz-nullprincipal" -class nsNullPrincipal final : public mozilla::BasePrincipal +class NullPrincipal final : public mozilla::BasePrincipal { public: // This should only be used by deserialization, and the factory constructor. // Other consumers should use the Create and CreateWithInheritedAttributes // methods. - nsNullPrincipal() + NullPrincipal() : BasePrincipal(eNullPrincipal) { } @@ -53,15 +53,16 @@ public: NS_IMETHOD GetAddonId(nsAString& aAddonId) override; nsresult GetOriginInternal(nsACString& aOrigin) override; - static already_AddRefed CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom); + static already_AddRefed CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom); // Create NullPrincipal with origin attributes from docshell. // If aIsFirstParty is true, and the pref 'privacy.firstparty.isolate' is also // enabled, the mFirstPartyDomain value of the origin attributes will be set // to NULL_PRINCIPAL_FIRST_PARTY_DOMAIN. - static already_AddRefed CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty = false); + static already_AddRefed + CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty = false); - static already_AddRefed + static already_AddRefed Create(const mozilla::OriginAttributes& aOriginAttributes = mozilla::OriginAttributes(), nsIURI* aURI = nullptr); @@ -71,7 +72,7 @@ public: virtual nsresult GetScriptLocation(nsACString &aStr) override; protected: - virtual ~nsNullPrincipal() {} + virtual ~NullPrincipal() = default; bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override { @@ -83,4 +84,4 @@ public: nsCOMPtr mURI; }; -#endif // nsNullPrincipal_h__ +#endif // NullPrincipal_h__ diff --git a/caps/nsNullPrincipalURI.cpp b/caps/NullPrincipalURI.cpp similarity index 61% rename from caps/nsNullPrincipalURI.cpp rename to caps/NullPrincipalURI.cpp index f8b86716066b..17d98a488faf 100644 --- a/caps/nsNullPrincipalURI.cpp +++ b/caps/NullPrincipalURI.cpp @@ -4,7 +4,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 "nsNullPrincipalURI.h" +#include "NullPrincipalURI.h" #include "mozilla/DebugOnly.h" #include "mozilla/MemoryReporting.h" @@ -16,21 +16,21 @@ #include "nsIUUIDGenerator.h" //////////////////////////////////////////////////////////////////////////////// -//// nsNullPrincipalURI +//// NullPrincipalURI -nsNullPrincipalURI::nsNullPrincipalURI() +NullPrincipalURI::NullPrincipalURI() : mPath(mPathBytes, ArrayLength(mPathBytes), ArrayLength(mPathBytes) - 1) { } -nsNullPrincipalURI::nsNullPrincipalURI(const nsNullPrincipalURI& aOther) +NullPrincipalURI::NullPrincipalURI(const NullPrincipalURI& aOther) : mPath(mPathBytes, ArrayLength(mPathBytes), ArrayLength(mPathBytes) - 1) { mPath.Assign(aOther.mPath); } nsresult -nsNullPrincipalURI::Init() +NullPrincipalURI::Init() { // FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant. nsCOMPtr uuidgen = services::GetUUIDGenerator(); @@ -51,10 +51,10 @@ nsNullPrincipalURI::Init() } /* static */ -already_AddRefed -nsNullPrincipalURI::Create() +already_AddRefed +NullPrincipalURI::Create() { - RefPtr uri = new nsNullPrincipalURI(); + RefPtr uri = new NullPrincipalURI(); nsresult rv = uri->Init(); NS_ENSURE_SUCCESS(rv, nullptr); return uri.forget(); @@ -63,13 +63,13 @@ nsNullPrincipalURI::Create() static NS_DEFINE_CID(kNullPrincipalURIImplementationCID, NS_NULLPRINCIPALURI_IMPLEMENTATION_CID); -NS_IMPL_ADDREF(nsNullPrincipalURI) -NS_IMPL_RELEASE(nsNullPrincipalURI) +NS_IMPL_ADDREF(NullPrincipalURI) +NS_IMPL_RELEASE(NullPrincipalURI) -NS_INTERFACE_MAP_BEGIN(nsNullPrincipalURI) +NS_INTERFACE_MAP_BEGIN(NullPrincipalURI) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURI) if (aIID.Equals(kNullPrincipalURIImplementationCID)) - foundInterface = static_cast(this); + foundInterface = static_cast(this); else NS_INTERFACE_MAP_ENTRY(nsIURI) NS_INTERFACE_MAP_ENTRY(nsISizeOf) @@ -80,23 +80,23 @@ NS_INTERFACE_MAP_END //// nsIURI NS_IMETHODIMP -nsNullPrincipalURI::GetAsciiHost(nsACString &_host) +NullPrincipalURI::GetAsciiHost(nsACString& _host) { _host.Truncate(); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::GetAsciiHostPort(nsACString &_hostport) +NullPrincipalURI::GetAsciiHostPort(nsACString& _hostport) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetAsciiSpec(nsACString &_spec) +NullPrincipalURI::GetAsciiSpec(nsACString& _spec) { nsAutoCString buffer; - // Ignore the return value -- nsNullPrincipalURI::GetSpec() is infallible. + // Ignore the return value -- NullPrincipalURI::GetSpec() is infallible. Unused << GetSpec(buffer); // This uses the infallible version of |NS_EscapeURL| as |GetSpec| is // already infallible. @@ -105,141 +105,141 @@ nsNullPrincipalURI::GetAsciiSpec(nsACString &_spec) } NS_IMETHODIMP -nsNullPrincipalURI::GetHost(nsACString &_host) +NullPrincipalURI::GetHost(nsACString& _host) { _host.Truncate(); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SetHost(const nsACString &aHost) +NullPrincipalURI::SetHost(const nsACString& aHost) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetHostPort(nsACString &_host) +NullPrincipalURI::GetHostPort(nsACString& _host) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetHostPort(const nsACString &aHost) +NullPrincipalURI::SetHostPort(const nsACString& aHost) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetHostAndPort(const nsACString &aHost) +NullPrincipalURI::SetHostAndPort(const nsACString& aHost) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetOriginCharset(nsACString &_charset) +NullPrincipalURI::GetOriginCharset(nsACString& _charset) { _charset.Truncate(); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::GetPassword(nsACString &_password) +NullPrincipalURI::GetPassword(nsACString& _password) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetPassword(const nsACString &aPassword) +NullPrincipalURI::SetPassword(const nsACString& aPassword) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetPath(nsACString &_path) +NullPrincipalURI::GetPath(nsACString& _path) { _path = mPath; return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SetPath(const nsACString &aPath) +NullPrincipalURI::SetPath(const nsACString& aPath) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetFilePath(nsACString &aFilePath) +NullPrincipalURI::GetFilePath(nsACString& aFilePath) { aFilePath.Truncate(); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetFilePath(const nsACString &aFilePath) +NullPrincipalURI::SetFilePath(const nsACString& aFilePath) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetQuery(nsACString &aQuery) +NullPrincipalURI::GetQuery(nsACString& aQuery) { aQuery.Truncate(); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetQuery(const nsACString &aQuery) +NullPrincipalURI::SetQuery(const nsACString& aQuery) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetRef(nsACString &_ref) +NullPrincipalURI::GetRef(nsACString& _ref) { _ref.Truncate(); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetRef(const nsACString &aRef) +NullPrincipalURI::SetRef(const nsACString& aRef) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetPrePath(nsACString &_prePath) +NullPrincipalURI::GetPrePath(nsACString& _prePath) { _prePath = NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME ":"); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::GetPort(int32_t *_port) +NullPrincipalURI::GetPort(int32_t* _port) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetPort(int32_t aPort) +NullPrincipalURI::SetPort(int32_t aPort) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetScheme(nsACString &_scheme) +NullPrincipalURI::GetScheme(nsACString& _scheme) { _scheme = NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SetScheme(const nsACString &aScheme) +NullPrincipalURI::SetScheme(const nsACString& aScheme) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetSpec(nsACString &_spec) +NullPrincipalURI::GetSpec(nsACString& _spec) { _spec = NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME ":") + mPath; return NS_OK; @@ -247,77 +247,77 @@ nsNullPrincipalURI::GetSpec(nsACString &_spec) // result may contain unescaped UTF-8 characters NS_IMETHODIMP -nsNullPrincipalURI::GetSpecIgnoringRef(nsACString &result) +NullPrincipalURI::GetSpecIgnoringRef(nsACString& _result) { - return GetSpec(result); + return GetSpec(_result); } NS_IMETHODIMP -nsNullPrincipalURI::GetHasRef(bool *result) +NullPrincipalURI::GetHasRef(bool* _result) { - *result = false; + *_result = false; return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SetSpec(const nsACString &aSpec) +NullPrincipalURI::SetSpec(const nsACString& aSpec) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetUsername(nsACString &_username) +NullPrincipalURI::GetUsername(nsACString& _username) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetUsername(const nsACString &aUsername) +NullPrincipalURI::SetUsername(const nsACString& aUsername) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetUserPass(nsACString &_userPass) +NullPrincipalURI::GetUserPass(nsACString& _userPass) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetUserPass(const nsACString &aUserPass) +NullPrincipalURI::SetUserPass(const nsACString& aUserPass) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::Clone(nsIURI **_newURI) +NullPrincipalURI::Clone(nsIURI** _newURI) { - nsCOMPtr uri = new nsNullPrincipalURI(*this); + nsCOMPtr uri = new NullPrincipalURI(*this); uri.forget(_newURI); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::CloneIgnoringRef(nsIURI **_newURI) +NullPrincipalURI::CloneIgnoringRef(nsIURI** _newURI) { - // GetRef/SetRef not supported by nsNullPrincipalURI, so + // GetRef/SetRef not supported by NullPrincipalURI, so // CloneIgnoringRef() is the same as Clone(). return Clone(_newURI); } NS_IMETHODIMP -nsNullPrincipalURI::CloneWithNewRef(const nsACString& newRef, nsIURI **_newURI) +NullPrincipalURI::CloneWithNewRef(const nsACString& newRef, nsIURI** _newURI) { - // GetRef/SetRef not supported by nsNullPrincipalURI, so + // GetRef/SetRef not supported by NullPrincipalURI, so // CloneWithNewRef() is the same as Clone(). return Clone(_newURI); } NS_IMETHODIMP -nsNullPrincipalURI::Equals(nsIURI *aOther, bool *_equals) +NullPrincipalURI::Equals(nsIURI* aOther, bool* _equals) { *_equals = false; - RefPtr otherURI; + RefPtr otherURI; nsresult rv = aOther->QueryInterface(kNullPrincipalURIImplementationCID, getter_AddRefs(otherURI)); if (NS_SUCCEEDED(rv)) { @@ -327,23 +327,23 @@ nsNullPrincipalURI::Equals(nsIURI *aOther, bool *_equals) } NS_IMETHODIMP -nsNullPrincipalURI::EqualsExceptRef(nsIURI *aOther, bool *_equals) +NullPrincipalURI::EqualsExceptRef(nsIURI* aOther, bool* _equals) { - // GetRef/SetRef not supported by nsNullPrincipalURI, so + // GetRef/SetRef not supported by NullPrincipalURI, so // EqualsExceptRef() is the same as Equals(). return Equals(aOther, _equals); } NS_IMETHODIMP -nsNullPrincipalURI::Resolve(const nsACString &aRelativePath, - nsACString &_resolvedURI) +NullPrincipalURI::Resolve(const nsACString& aRelativePath, + nsACString& _resolvedURI) { _resolvedURI = aRelativePath; return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SchemeIs(const char *aScheme, bool *_schemeIs) +NullPrincipalURI::SchemeIs(const char* aScheme, bool* _schemeIs) { *_schemeIs = (0 == nsCRT::strcasecmp(NS_NULLPRINCIPAL_SCHEME, aScheme)); return NS_OK; @@ -353,13 +353,13 @@ nsNullPrincipalURI::SchemeIs(const char *aScheme, bool *_schemeIs) //// nsIIPCSerializableURI void -nsNullPrincipalURI::Serialize(mozilla::ipc::URIParams &aParams) +NullPrincipalURI::Serialize(mozilla::ipc::URIParams& aParams) { aParams = mozilla::ipc::NullPrincipalURIParams(); } bool -nsNullPrincipalURI::Deserialize(const mozilla::ipc::URIParams &aParams) +NullPrincipalURI::Deserialize(const mozilla::ipc::URIParams& aParams) { if (aParams.type() != mozilla::ipc::URIParams::TNullPrincipalURIParams) { MOZ_ASSERT_UNREACHABLE("unexpected URIParams type"); @@ -376,13 +376,13 @@ nsNullPrincipalURI::Deserialize(const mozilla::ipc::URIParams &aParams) //// nsISizeOf size_t -nsNullPrincipalURI::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const +NullPrincipalURI::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { return mPath.SizeOfExcludingThisIfUnshared(aMallocSizeOf); } size_t -nsNullPrincipalURI::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { +NullPrincipalURI::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const +{ return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } - diff --git a/caps/nsNullPrincipalURI.h b/caps/NullPrincipalURI.h similarity index 73% rename from caps/nsNullPrincipalURI.h rename to caps/NullPrincipalURI.h index 63d7221c2832..fb4c60c0b4cb 100644 --- a/caps/nsNullPrincipalURI.h +++ b/caps/NullPrincipalURI.h @@ -8,8 +8,8 @@ * This wraps nsSimpleURI so that all calls to it are done on the main thread. */ -#ifndef __nsNullPrincipalURI_h__ -#define __nsNullPrincipalURI_h__ +#ifndef __NullPrincipalURI_h__ +#define __NullPrincipalURI_h__ #include "nsIURI.h" #include "nsISizeOf.h" @@ -17,7 +17,7 @@ #include "mozilla/Attributes.h" #include "nsIIPCSerializableURI.h" #include "mozilla/MemoryReporting.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsID.h" // {51fcd543-3b52-41f7-b91b-6b54102236e6} @@ -25,9 +25,9 @@ {0x51fcd543, 0x3b52, 0x41f7, \ {0xb9, 0x1b, 0x6b, 0x54, 0x10, 0x22, 0x36, 0xe6} } -class nsNullPrincipalURI final : public nsIURI - , public nsISizeOf - , public nsIIPCSerializableURI +class NullPrincipalURI final : public nsIURI + , public nsISizeOf + , public nsIIPCSerializableURI { public: NS_DECL_THREADSAFE_ISUPPORTS @@ -40,15 +40,15 @@ public: // NB: This constructor exists only for deserialization. Everyone // else should call Create. - nsNullPrincipalURI(); + NullPrincipalURI(); // Returns null on failure. - static already_AddRefed Create(); + static already_AddRefed Create(); private: - nsNullPrincipalURI(const nsNullPrincipalURI& aOther); + NullPrincipalURI(const NullPrincipalURI& aOther); - ~nsNullPrincipalURI() {} + ~NullPrincipalURI() {} nsresult Init(); @@ -56,4 +56,4 @@ private: nsFixedCString mPath; }; -#endif // __nsNullPrincipalURI_h__ +#endif // __NullPrincipalURI_h__ diff --git a/caps/OriginAttributes.cpp b/caps/OriginAttributes.cpp new file mode 100644 index 000000000000..9ee38822e33a --- /dev/null +++ b/caps/OriginAttributes.cpp @@ -0,0 +1,283 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et 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/OriginAttributes.h" +#include "mozilla/Preferences.h" +#include "mozilla/dom/URLSearchParams.h" +#include "mozilla/dom/quota/QuotaManager.h" +#include "nsIEffectiveTLDService.h" +#include "nsIURI.h" + +namespace mozilla { + +using dom::URLParams; + +bool OriginAttributes::sFirstPartyIsolation = false; +bool OriginAttributes::sRestrictedOpenerAccess = false; + +void +OriginAttributes::InitPrefs() +{ + MOZ_ASSERT(NS_IsMainThread()); + static bool sInited = false; + if (!sInited) { + sInited = true; + Preferences::AddBoolVarCache(&sFirstPartyIsolation, + "privacy.firstparty.isolate"); + Preferences::AddBoolVarCache(&sRestrictedOpenerAccess, + "privacy.firstparty.isolate.restrict_opener_access"); + } +} + +void +OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument, + nsIURI* aURI) +{ + bool isFirstPartyEnabled = IsFirstPartyEnabled(); + + // If the pref is off or this is not a top level load, bail out. + if (!isFirstPartyEnabled || !aIsTopLevelDocument) { + return; + } + + nsCOMPtr tldService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + MOZ_ASSERT(tldService); + if (!tldService) { + return; + } + + nsAutoCString baseDomain; + nsresult rv = tldService->GetBaseDomain(aURI, 0, baseDomain); + if (NS_FAILED(rv)) { + nsAutoCString scheme; + rv = aURI->GetScheme(scheme); + NS_ENSURE_SUCCESS_VOID(rv); + if (scheme.EqualsLiteral("about")) { + baseDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN); + } + } + + mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain); +} + +void +OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument, + const nsACString& aDomain) +{ + bool isFirstPartyEnabled = IsFirstPartyEnabled(); + + // If the pref is off or this is not a top level load, bail out. + if (!isFirstPartyEnabled || !aIsTopLevelDocument) { + return; + } + + mFirstPartyDomain = NS_ConvertUTF8toUTF16(aDomain); +} + +void +OriginAttributes::CreateSuffix(nsACString& aStr) const +{ + URLParams params; + nsAutoString value; + + // + // Important: While serializing any string-valued attributes, perform a + // release-mode assertion to make sure that they don't contain characters that + // will break the quota manager when it uses the serialization for file + // naming. + // + + if (mAppId != nsIScriptSecurityManager::NO_APP_ID) { + value.AppendInt(mAppId); + params.Set(NS_LITERAL_STRING("appId"), value); + } + + if (mInIsolatedMozBrowser) { + params.Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1")); + } + + if (mUserContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) { + value.Truncate(); + value.AppendInt(mUserContextId); + params.Set(NS_LITERAL_STRING("userContextId"), value); + } + + + if (mPrivateBrowsingId) { + value.Truncate(); + value.AppendInt(mPrivateBrowsingId); + params.Set(NS_LITERAL_STRING("privateBrowsingId"), value); + } + + if (!mFirstPartyDomain.IsEmpty()) { + MOZ_RELEASE_ASSERT(mFirstPartyDomain.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound); + params.Set(NS_LITERAL_STRING("firstPartyDomain"), mFirstPartyDomain); + } + + aStr.Truncate(); + + params.Serialize(value); + if (!value.IsEmpty()) { + aStr.AppendLiteral("^"); + aStr.Append(NS_ConvertUTF16toUTF8(value)); + } + +// In debug builds, check the whole string for illegal characters too (just in case). +#ifdef DEBUG + nsAutoCString str; + str.Assign(aStr); + MOZ_ASSERT(str.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound); +#endif +} + +void +OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const +{ + OriginAttributes attrs = *this; + + if (!attrs.mFirstPartyDomain.IsEmpty()) { + attrs.mFirstPartyDomain.AssignLiteral("_anonymizedFirstPartyDomain_"); + } + + attrs.CreateSuffix(aStr); +} + +namespace { + +class MOZ_STACK_CLASS PopulateFromSuffixIterator final + : public URLParams::ForEachIterator +{ +public: + explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes) + : mOriginAttributes(aOriginAttributes) + { + MOZ_ASSERT(aOriginAttributes); + // If mPrivateBrowsingId is passed in as >0 and is not present in the suffix, + // then it will remain >0 when it should be 0 according to the suffix. Set to 0 before + // iterating to fix this. + mOriginAttributes->mPrivateBrowsingId = 0; + } + + bool URLParamsIterator(const nsString& aName, + const nsString& aValue) override + { + if (aName.EqualsLiteral("appId")) { + nsresult rv; + int64_t val = aValue.ToInteger64(&rv); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(val <= UINT32_MAX, false); + mOriginAttributes->mAppId = static_cast(val); + + return true; + } + + if (aName.EqualsLiteral("inBrowser")) { + if (!aValue.EqualsLiteral("1")) { + return false; + } + + mOriginAttributes->mInIsolatedMozBrowser = true; + return true; + } + + if (aName.EqualsLiteral("addonId")) { + // No longer supported. Silently ignore so that legacy origin strings + // don't cause failures. + return true; + } + + if (aName.EqualsLiteral("userContextId")) { + nsresult rv; + int64_t val = aValue.ToInteger64(&rv); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(val <= UINT32_MAX, false); + mOriginAttributes->mUserContextId = static_cast(val); + + return true; + } + + if (aName.EqualsLiteral("privateBrowsingId")) { + nsresult rv; + int64_t val = aValue.ToInteger64(&rv); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(val >= 0 && val <= UINT32_MAX, false); + mOriginAttributes->mPrivateBrowsingId = static_cast(val); + + return true; + } + + if (aName.EqualsLiteral("firstPartyDomain")) { + MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty()); + mOriginAttributes->mFirstPartyDomain.Assign(aValue); + return true; + } + + // No other attributes are supported. + return false; + } + +private: + OriginAttributes* mOriginAttributes; +}; + +} // namespace + +bool +OriginAttributes::PopulateFromSuffix(const nsACString& aStr) +{ + if (aStr.IsEmpty()) { + return true; + } + + if (aStr[0] != '^') { + return false; + } + + URLParams params; + params.ParseInput(Substring(aStr, 1, aStr.Length() - 1)); + + PopulateFromSuffixIterator iterator(this); + return params.ForEach(iterator); +} + +bool +OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin, + nsACString& aOriginNoSuffix) +{ + // RFindChar is only available on nsCString. + nsCString origin(aOrigin); + int32_t pos = origin.RFindChar('^'); + + if (pos == kNotFound) { + aOriginNoSuffix = origin; + return true; + } + + aOriginNoSuffix = Substring(origin, 0, pos); + return PopulateFromSuffix(Substring(origin, pos)); +} + +void +OriginAttributes::SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing) +{ + mPrivateBrowsingId = aInPrivateBrowsing ? 1 : 0; +} + +/* static */ +bool +OriginAttributes::IsPrivateBrowsing(const nsACString& aOrigin) +{ + nsAutoCString dummy; + OriginAttributes attrs; + if (NS_WARN_IF(!attrs.PopulateFromOrigin(aOrigin, dummy))) { + return false; + } + + return !!attrs.mPrivateBrowsingId; +} + +} // namespace mozilla diff --git a/caps/OriginAttributes.h b/caps/OriginAttributes.h new file mode 100644 index 000000000000..b0ca8bf2fa19 --- /dev/null +++ b/caps/OriginAttributes.h @@ -0,0 +1,184 @@ +/* -*- 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 mozilla_OriginAttributes_h +#define mozilla_OriginAttributes_h + +#include "mozilla/dom/ChromeUtils.h" +#include "mozilla/dom/ChromeUtilsBinding.h" +#include "nsIScriptSecurityManager.h" + +namespace mozilla { + +class OriginAttributes : public dom::OriginAttributesDictionary +{ +public: + OriginAttributes() {} + + OriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser) + { + mAppId = aAppId; + mInIsolatedMozBrowser = aInIsolatedMozBrowser; + } + + explicit OriginAttributes(const OriginAttributesDictionary& aOther) + : OriginAttributesDictionary(aOther) + {} + + void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI); + void SetFirstPartyDomain(const bool aIsTopLevelDocument, const nsACString& aDomain); + + enum { + STRIP_FIRST_PARTY_DOMAIN = 0x01, + STRIP_USER_CONTEXT_ID = 0x02, + }; + + inline void StripAttributes(uint32_t aFlags) + { + if (aFlags & STRIP_FIRST_PARTY_DOMAIN) { + mFirstPartyDomain.Truncate(); + } + + if (aFlags & STRIP_USER_CONTEXT_ID) { + mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID; + } + } + + bool operator==(const OriginAttributes& aOther) const + { + return mAppId == aOther.mAppId && + mInIsolatedMozBrowser == aOther.mInIsolatedMozBrowser && + mUserContextId == aOther.mUserContextId && + mPrivateBrowsingId == aOther.mPrivateBrowsingId && + mFirstPartyDomain == aOther.mFirstPartyDomain; + } + + bool operator!=(const OriginAttributes& aOther) const + { + return !(*this == aOther); + } + + // Serializes/Deserializes non-default values into the suffix format, i.e. + // |!key1=value1&key2=value2|. If there are no non-default attributes, this + // returns an empty string. + void CreateSuffix(nsACString& aStr) const; + + // Don't use this method for anything else than debugging! + void CreateAnonymizedSuffix(nsACString& aStr) const; + + MOZ_MUST_USE bool PopulateFromSuffix(const nsACString& aStr); + + // Populates the attributes from a string like + // |uri!key1=value1&key2=value2| and returns the uri without the suffix. + MOZ_MUST_USE bool PopulateFromOrigin(const nsACString& aOrigin, + nsACString& aOriginNoSuffix); + + // Helper function to match mIsPrivateBrowsing to existing private browsing + // flags. Once all other flags are removed, this can be removed too. + void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing); + + // check if "privacy.firstparty.isolate" is enabled. + static inline bool IsFirstPartyEnabled() + { + return sFirstPartyIsolation; + } + + // check if the access of window.opener across different FPDs is restricted. + // We only restrict the access of window.opener when first party isolation + // is enabled and "privacy.firstparty.isolate.restrict_opener_access" is on. + static inline bool IsRestrictOpenerAccessForFPI() + { + // We always want to restrict window.opener if first party isolation is + // disabled. + return !sFirstPartyIsolation || sRestrictedOpenerAccess; + } + + // returns true if the originAttributes suffix has mPrivateBrowsingId value + // different than 0. + static bool IsPrivateBrowsing(const nsACString& aOrigin); + + static void InitPrefs(); + +private: + static bool sFirstPartyIsolation; + static bool sRestrictedOpenerAccess; +}; + +class OriginAttributesPattern : public dom::OriginAttributesPatternDictionary +{ +public: + // To convert a JSON string to an OriginAttributesPattern, do the following: + // + // OriginAttributesPattern pattern; + // if (!pattern.Init(aJSONString)) { + // ... // handle failure. + // } + OriginAttributesPattern() {} + + explicit OriginAttributesPattern(const OriginAttributesPatternDictionary& aOther) + : OriginAttributesPatternDictionary(aOther) {} + + // Performs a match of |aAttrs| against this pattern. + bool Matches(const OriginAttributes& aAttrs) const + { + if (mAppId.WasPassed() && mAppId.Value() != aAttrs.mAppId) { + return false; + } + + if (mInIsolatedMozBrowser.WasPassed() && mInIsolatedMozBrowser.Value() != aAttrs.mInIsolatedMozBrowser) { + return false; + } + + if (mUserContextId.WasPassed() && mUserContextId.Value() != aAttrs.mUserContextId) { + return false; + } + + if (mPrivateBrowsingId.WasPassed() && mPrivateBrowsingId.Value() != aAttrs.mPrivateBrowsingId) { + return false; + } + + if (mFirstPartyDomain.WasPassed() && mFirstPartyDomain.Value() != aAttrs.mFirstPartyDomain) { + return false; + } + + return true; + } + + bool Overlaps(const OriginAttributesPattern& aOther) const + { + if (mAppId.WasPassed() && aOther.mAppId.WasPassed() && + mAppId.Value() != aOther.mAppId.Value()) { + return false; + } + + if (mInIsolatedMozBrowser.WasPassed() && + aOther.mInIsolatedMozBrowser.WasPassed() && + mInIsolatedMozBrowser.Value() != aOther.mInIsolatedMozBrowser.Value()) { + return false; + } + + if (mUserContextId.WasPassed() && aOther.mUserContextId.WasPassed() && + mUserContextId.Value() != aOther.mUserContextId.Value()) { + return false; + } + + if (mPrivateBrowsingId.WasPassed() && aOther.mPrivateBrowsingId.WasPassed() && + mPrivateBrowsingId.Value() != aOther.mPrivateBrowsingId.Value()) { + return false; + } + + if (mFirstPartyDomain.WasPassed() && aOther.mFirstPartyDomain.WasPassed() && + mFirstPartyDomain.Value() != aOther.mFirstPartyDomain.Value()) { + return false; + } + + return true; + } +}; + +} // namespace mozilla + +#endif /* mozilla_OriginAttributes_h */ diff --git a/caps/nsSystemPrincipal.cpp b/caps/SystemPrincipal.cpp similarity index 66% rename from caps/nsSystemPrincipal.cpp rename to caps/SystemPrincipal.cpp index b1c33553ac8d..0f03793c552c 100644 --- a/caps/nsSystemPrincipal.cpp +++ b/caps/SystemPrincipal.cpp @@ -6,7 +6,7 @@ /* The privileged system principal. */ #include "nscore.h" -#include "nsSystemPrincipal.h" +#include "SystemPrincipal.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsIURL.h" @@ -19,28 +19,28 @@ #include "nsIScriptSecurityManager.h" #include "pratom.h" -NS_IMPL_CLASSINFO(nsSystemPrincipal, nullptr, +NS_IMPL_CLASSINFO(SystemPrincipal, nullptr, nsIClassInfo::SINGLETON | nsIClassInfo::MAIN_THREAD_ONLY, NS_SYSTEMPRINCIPAL_CID) -NS_IMPL_QUERY_INTERFACE_CI(nsSystemPrincipal, +NS_IMPL_QUERY_INTERFACE_CI(SystemPrincipal, nsIPrincipal, nsISerializable) -NS_IMPL_CI_INTERFACE_GETTER(nsSystemPrincipal, +NS_IMPL_CI_INTERFACE_GETTER(SystemPrincipal, nsIPrincipal, nsISerializable) #define SYSTEM_PRINCIPAL_SPEC "[System Principal]" -already_AddRefed -nsSystemPrincipal::Create() +already_AddRefed +SystemPrincipal::Create() { - RefPtr sp = new nsSystemPrincipal(); + RefPtr sp = new SystemPrincipal(); sp->FinishInit(); return sp.forget(); } nsresult -nsSystemPrincipal::GetScriptLocation(nsACString &aStr) +SystemPrincipal::GetScriptLocation(nsACString &aStr) { aStr.AssignLiteral(SYSTEM_PRINCIPAL_SPEC); return NS_OK; @@ -51,35 +51,35 @@ nsSystemPrincipal::GetScriptLocation(nsACString &aStr) /////////////////////////////////////// NS_IMETHODIMP -nsSystemPrincipal::GetHashValue(uint32_t *result) +SystemPrincipal::GetHashValue(uint32_t *result) { *result = NS_PTR_TO_INT32(this); return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetURI(nsIURI** aURI) +SystemPrincipal::GetURI(nsIURI** aURI) { *aURI = nullptr; return NS_OK; } nsresult -nsSystemPrincipal::GetOriginInternal(nsACString& aOrigin) +SystemPrincipal::GetOriginInternal(nsACString& aOrigin) { aOrigin.AssignLiteral(SYSTEM_PRINCIPAL_SPEC); return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) +SystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) { *aCsp = nullptr; return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) +SystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) { // Never destroy an existing CSP on the principal. // This method should only be called in rare cases. @@ -88,50 +88,50 @@ nsSystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) } NS_IMETHODIMP -nsSystemPrincipal::EnsureCSP(nsIDOMDocument* aDocument, - nsIContentSecurityPolicy** aCSP) +SystemPrincipal::EnsureCSP(nsIDOMDocument* aDocument, + nsIContentSecurityPolicy** aCSP) { // CSP on a system principal makes no sense return NS_ERROR_FAILURE; } NS_IMETHODIMP -nsSystemPrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) +SystemPrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) { *aPreloadCSP = nullptr; return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument, - nsIContentSecurityPolicy** aPreloadCSP) +SystemPrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument, + nsIContentSecurityPolicy** aPreloadCSP) { // CSP on a system principal makes no sense return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetDomain(nsIURI** aDomain) +SystemPrincipal::GetDomain(nsIURI** aDomain) { *aDomain = nullptr; return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::SetDomain(nsIURI* aDomain) +SystemPrincipal::SetDomain(nsIURI* aDomain) { return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetBaseDomain(nsACString& aBaseDomain) +SystemPrincipal::GetBaseDomain(nsACString& aBaseDomain) { // No base domain for chrome. return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetAddonId(nsAString& aAddonId) +SystemPrincipal::GetAddonId(nsAString& aAddonId) { aAddonId.Truncate(); return NS_OK; @@ -142,14 +142,14 @@ nsSystemPrincipal::GetAddonId(nsAString& aAddonId) ////////////////////////////////////////// NS_IMETHODIMP -nsSystemPrincipal::Read(nsIObjectInputStream* aStream) +SystemPrincipal::Read(nsIObjectInputStream* aStream) { // no-op: CID is sufficient to identify the mSystemPrincipal singleton return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::Write(nsIObjectOutputStream* aStream) +SystemPrincipal::Write(nsIObjectOutputStream* aStream) { // no-op: CID is sufficient to identify the mSystemPrincipal singleton return NS_OK; diff --git a/caps/nsSystemPrincipal.h b/caps/SystemPrincipal.h similarity index 82% rename from caps/nsSystemPrincipal.h rename to caps/SystemPrincipal.h index 0e67ce45e490..d542f578ef5b 100644 --- a/caps/nsSystemPrincipal.h +++ b/caps/SystemPrincipal.h @@ -6,8 +6,8 @@ /* The privileged system principal. */ -#ifndef nsSystemPrincipal_h__ -#define nsSystemPrincipal_h__ +#ifndef SystemPrincipal_h +#define SystemPrincipal_h #include "nsIPrincipal.h" #include "nsJSPrincipals.h" @@ -20,15 +20,15 @@ #define NS_SYSTEMPRINCIPAL_CONTRACTID "@mozilla.org/systemprincipal;1" -class nsSystemPrincipal final : public mozilla::BasePrincipal +class SystemPrincipal final : public mozilla::BasePrincipal { - nsSystemPrincipal() + SystemPrincipal() : BasePrincipal(eSystemPrincipal) { } public: - static already_AddRefed Create(); + static already_AddRefed Create(); NS_DECL_NSISERIALIZABLE NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; @@ -48,9 +48,10 @@ public: virtual nsresult GetScriptLocation(nsACString &aStr) override; protected: - virtual ~nsSystemPrincipal(void) {} + virtual ~SystemPrincipal(void) {} - bool SubsumesInternal(nsIPrincipal *aOther, DocumentDomainConsideration aConsideration) override + bool SubsumesInternal(nsIPrincipal *aOther, + DocumentDomainConsideration aConsideration) override { return true; } @@ -61,4 +62,4 @@ protected: } }; -#endif // nsSystemPrincipal_h__ +#endif // SystemPrincipal_h diff --git a/caps/moz.build b/caps/moz.build index 4a2189bf958e..46331e93f097 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -25,29 +25,31 @@ XPIDL_MODULE = 'caps' EXPORTS += [ 'nsJSPrincipals.h', - 'nsNullPrincipal.h', - 'nsNullPrincipalURI.h', + 'NullPrincipal.h', + 'NullPrincipalURI.h', ] EXPORTS.mozilla = [ - 'BasePrincipal.h' + 'BasePrincipal.h', + 'OriginAttributes.h', ] SOURCES += [ # Compile this separately since nsExceptionHandler.h conflicts - # with something from nsNullPrincipal.cpp. + # with something from NullPrincipal.cpp. 'BasePrincipal.cpp', ] UNIFIED_SOURCES += [ + 'ContentPrincipal.cpp', 'DomainPolicy.cpp', - 'nsExpandedPrincipal.cpp', + 'ExpandedPrincipal.cpp', 'nsJSPrincipals.cpp', - 'nsNullPrincipal.cpp', - 'nsNullPrincipalURI.cpp', - 'nsPrincipal.cpp', 'nsScriptSecurityManager.cpp', - 'nsSystemPrincipal.cpp', + 'NullPrincipal.cpp', + 'NullPrincipalURI.cpp', + 'OriginAttributes.cpp', + 'SystemPrincipal.cpp', ] LOCAL_INCLUDES += [ diff --git a/caps/nsIPrincipal.idl b/caps/nsIPrincipal.idl index 870792527813..258aa384a9f5 100644 --- a/caps/nsIPrincipal.idl +++ b/caps/nsIPrincipal.idl @@ -357,12 +357,12 @@ interface nsIPrincipal : nsISerializable }; /** - * If nsSystemPrincipal is too risky to use, but we want a principal to access - * more than one origin, nsExpandedPrincipals letting us define an array of - * principals it subsumes. So script with an nsExpandedPrincipals will gain + * If SystemPrincipal is too risky to use, but we want a principal to access + * more than one origin, ExpandedPrincipals letting us define an array of + * principals it subsumes. So script with an ExpandedPrincipals will gain * same origin access when at least one of its principals it contains gained - * sameorigin acccess. An nsExpandedPrincipal will be subsumed by the system - * principal, and by another nsExpandedPrincipal that has all its principals. + * sameorigin acccess. An ExpandedPrincipal will be subsumed by the system + * principal, and by another ExpandedPrincipal that has all its principals. * It is added for jetpack content-scripts to let them interact with the * content and a well defined set of other domains, without the risk of * leaking out a system principal to the content. See: Bug 734891 diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index a3874ab22ce0..0d587f8115a3 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -20,9 +20,8 @@ #include "nspr.h" #include "nsJSPrincipals.h" #include "mozilla/BasePrincipal.h" -#include "nsSystemPrincipal.h" -#include "nsPrincipal.h" -#include "nsNullPrincipal.h" +#include "SystemPrincipal.h" +#include "NullPrincipal.h" #include "DomainPolicy.h" #include "nsXPIDLString.h" #include "nsCRT.h" @@ -1141,7 +1140,7 @@ nsScriptSecurityManager::CreateNullPrincipal(JS::Handle aOriginAttrib if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { return NS_ERROR_INVALID_ARG; } - nsCOMPtr prin = nsNullPrincipal::Create(attrs); + nsCOMPtr prin = NullPrincipal::Create(attrs); prin.forget(aPrincipal); return NS_OK; } @@ -1335,7 +1334,7 @@ nsresult nsScriptSecurityManager::Init() NS_ENSURE_SUCCESS(rv, rv); // Create our system principal singleton - RefPtr system = nsSystemPrincipal::Create(); + RefPtr system = SystemPrincipal::Create(); mSystemPrincipal = system; @@ -1407,13 +1406,13 @@ nsScriptSecurityManager::InitStatics() // Currently this nsGenericFactory constructor is used only from FastLoad // (XPCOM object deserialization) code, when "creating" the system principal // singleton. -nsSystemPrincipal * +SystemPrincipal * nsScriptSecurityManager::SystemPrincipalSingletonConstructor() { nsIPrincipal *sysprin = nullptr; if (gScriptSecMan) NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal); - return static_cast(sysprin); + return static_cast(sysprin); } struct IsWhitespace { diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h index da20441dd60a..d633c9a4a941 100644 --- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -24,7 +24,7 @@ class nsCString; class nsIIOService; class nsIStringBundle; -class nsSystemPrincipal; +class SystemPrincipal; namespace mozilla { class OriginAttributes; @@ -55,7 +55,7 @@ public: // Invoked exactly once, by XPConnect. static void InitStatics(); - static nsSystemPrincipal* + static SystemPrincipal* SystemPrincipalSingletonConstructor(); /** diff --git a/devtools/client/inspector/boxmodel/components/BoxModelEditable.js b/devtools/client/inspector/boxmodel/components/BoxModelEditable.js index f90954d5ffe5..9b20cd560338 100644 --- a/devtools/client/inspector/boxmodel/components/BoxModelEditable.js +++ b/devtools/client/inspector/boxmodel/components/BoxModelEditable.js @@ -16,7 +16,7 @@ module.exports = createClass({ propTypes: { box: PropTypes.string.isRequired, - direction: PropTypes.string.isRequired, + direction: PropTypes.string, property: PropTypes.string.isRequired, textContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, onShowBoxModelEditor: PropTypes.func.isRequired, @@ -42,13 +42,15 @@ module.exports = createClass({ textContent, } = this.props; - let rotate = (direction == "left" || direction == "right") && + let rotate = direction && + (direction == "left" || direction == "right") && textContent.toString().length > LONG_TEXT_ROTATE_LIMIT; return dom.p( { - className: `boxmodel-${box} boxmodel-${direction} - ${rotate ? "boxmodel-rotate" : ""}`, + className: `boxmodel-${box} + ${direction ? " boxmodel-" + direction : "boxmodel-" + property} + ${rotate ? " boxmodel-rotate" : ""}`, }, dom.span( { diff --git a/devtools/client/inspector/boxmodel/components/BoxModelMain.js b/devtools/client/inspector/boxmodel/components/BoxModelMain.js index 37581a630cae..07a4c84ab4b5 100644 --- a/devtools/client/inspector/boxmodel/components/BoxModelMain.js +++ b/devtools/client/inspector/boxmodel/components/BoxModelMain.js @@ -134,6 +134,41 @@ module.exports = createClass({ height = this.getHeightValue(height); width = this.getWidthValue(width); + let contentBox = layout["box-sizing"] == "content-box" ? + dom.p( + { + className: "boxmodel-size", + }, + BoxModelEditable({ + box: "content", + property: "width", + textContent: width, + onShowBoxModelEditor + }), + dom.span( + {}, + "\u00D7" + ), + BoxModelEditable({ + box: "content", + property: "height", + textContent: height, + onShowBoxModelEditor + }) + ) + : + dom.p( + { + className: "boxmodel-size", + }, + dom.span( + { + title: BOXMODEL_L10N.getStr("boxmodel.content"), + }, + SHARED_L10N.getFormatStr("dimensions", width, height) + ) + ); + return dom.div( { className: "boxmodel-main", @@ -198,7 +233,7 @@ module.exports = createClass({ title: BOXMODEL_L10N.getStr("boxmodel.padding"), }, dom.div({ - className: "boxmodel-content", + className: "boxmodel-contents", "data-box": "content", title: BOXMODEL_L10N.getStr("boxmodel.content"), }) @@ -330,18 +365,7 @@ module.exports = createClass({ textContent: paddingLeft, onShowBoxModelEditor, }), - dom.p( - { - className: "boxmodel-size", - }, - dom.span( - { - "data-box": "content", - title: BOXMODEL_L10N.getStr("boxmodel.content"), - }, - SHARED_L10N.getFormatStr("dimensions", width, height) - ) - ) + contentBox ); }, diff --git a/devtools/client/inspector/boxmodel/components/ComputedProperty.js b/devtools/client/inspector/boxmodel/components/ComputedProperty.js index 87fef1a3d4c2..262258ba6184 100644 --- a/devtools/client/inspector/boxmodel/components/ComputedProperty.js +++ b/devtools/client/inspector/boxmodel/components/ComputedProperty.js @@ -28,6 +28,7 @@ module.exports = createClass({ return dom.div( { className: "property-view", + "data-property-name": name, tabIndex: "0", ref: container => { this.container = container; diff --git a/devtools/client/inspector/boxmodel/test/browser.ini b/devtools/client/inspector/boxmodel/test/browser.ini index c9881c903937..ba05da95490b 100644 --- a/devtools/client/inspector/boxmodel/test/browser.ini +++ b/devtools/client/inspector/boxmodel/test/browser.ini @@ -22,6 +22,7 @@ support-files = [browser_boxmodel_guides.js] [browser_boxmodel_navigation.js] skip-if = true # Bug 1336198 +[browser_boxmodel_properties.js] [browser_boxmodel_rotate-labels-on-sides.js] [browser_boxmodel_sync.js] [browser_boxmodel_tooltips.js] diff --git a/devtools/client/inspector/boxmodel/test/browser_boxmodel.js b/devtools/client/inspector/boxmodel/test/browser_boxmodel.js index 9e085cafe232..3ad67b4da72d 100644 --- a/devtools/client/inspector/boxmodel/test/browser_boxmodel.js +++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel.js @@ -14,8 +14,12 @@ var res1 = [ value: "160" + "\u00D7" + "160.117" }, { - selector: ".boxmodel-size > span", - value: "100" + "\u00D7" + "100.117" + selector: ".boxmodel-size > .boxmodel-width", + value: "100" + }, + { + selector: ".boxmodel-size > .boxmodel-height", + value: "100.117" }, { selector: ".boxmodel-margin.boxmodel-top > span", @@ -73,8 +77,12 @@ var res2 = [ value: "190" + "\u00D7" + "210" }, { - selector: ".boxmodel-size > span", - value: "100" + "\u00D7" + "150" + selector: ".boxmodel-size > .boxmodel-width", + value: "100" + }, + { + selector: ".boxmodel-size > .boxmodel-height", + value: "150" }, { selector: ".boxmodel-margin.boxmodel-top > span", diff --git a/devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js b/devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js new file mode 100644 index 000000000000..95479f756538 --- /dev/null +++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js @@ -0,0 +1,120 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that the box model properties list displays the right values +// and that it updates when the node's style is changed. + +const TEST_URI = ` + +
Test Node
+`; + +const res1 = [ + { + property: "box-sizing", + value: "border-box" + }, + { + property: "display", + value: "block" + }, + { + property: "float", + value: "left" + }, + { + property: "line-height", + value: "20px" + }, + { + property: "position", + value: "relative" + }, + { + property: "z-index", + value: 2 + }, +]; + +const res2 = [ + { + property: "box-sizing", + value: "content-box" + }, + { + property: "display", + value: "block" + }, + { + property: "float", + value: "right" + }, + { + property: "line-height", + value: "10px" + }, + { + property: "position", + value: "static" + }, + { + property: "z-index", + value: 5 + }, +]; + +add_task(function* () { + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + let { inspector, boxmodel, testActor } = yield openLayoutView(); + yield selectNode("div", inspector); + + yield testInitialValues(inspector, boxmodel); + yield testChangingValues(inspector, boxmodel, testActor); +}); + +function* testInitialValues(inspector, boxmodel) { + info("Test that the initial values of the box model are correct"); + let doc = boxmodel.document; + + for (let { property, value } of res1) { + let elt = doc.querySelector(getPropertySelector(property)); + is(elt.textContent, value, property + " has the right value."); + } +} + +function* testChangingValues(inspector, boxmodel, testActor) { + info("Test that changing the document updates the box model"); + let doc = boxmodel.document; + + let onUpdated = waitForUpdate(inspector); + yield testActor.setAttribute("div", "style", + "box-sizing:content-box;float:right;" + + "line-height:10px;position:static;z-index:5;"); + yield onUpdated; + + for (let { property, value } of res2) { + let elt = doc.querySelector(getPropertySelector(property)); + is(elt.textContent, value, property + " has the right value after style update."); + } +} + +function getPropertySelector(propertyName) { + return `.boxmodel-properties-wrapper .property-view` + + `[data-property-name=${propertyName}] .property-value`; +} diff --git a/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html b/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html index 1f1b0463c3d4..0fa6dc02e97d 100644 --- a/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html +++ b/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html @@ -1,3 +1,3 @@ -

iframe 1

- +

iframe 1

+ diff --git a/devtools/client/inspector/boxmodel/test/head.js b/devtools/client/inspector/boxmodel/test/head.js index b842968a5595..4df6e686a28e 100644 --- a/devtools/client/inspector/boxmodel/test/head.js +++ b/devtools/client/inspector/boxmodel/test/head.js @@ -11,8 +11,10 @@ Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/devtools/client/inspector/test/head.js", this); +Services.prefs.setBoolPref("devtools.layoutview.enabled", true); Services.prefs.setIntPref("devtools.toolbox.footer.height", 350); registerCleanupFunction(() => { + Services.prefs.clearUserPref("devtools.layoutview.enabled"); Services.prefs.clearUserPref("devtools.toolbox.footer.height"); }); @@ -66,6 +68,36 @@ function openBoxModelView() { }); } +/** + * Open the toolbox, with the inspector tool visible, and the layout view + * sidebar tab selected to display the box model view with properties. + * + * @return {Promise} a promise that resolves when the inspector is ready and the box model + * view is visible and ready. + */ +function openLayoutView() { + return openInspectorSidebarTab("layoutview").then(data => { + // The actual highligher show/hide methods are mocked in box model tests. + // The highlighter is tested in devtools/inspector/test. + function mockHighlighter({highlighter}) { + highlighter.showBoxModel = function () { + return promise.resolve(); + }; + highlighter.hideBoxModel = function () { + return promise.resolve(); + }; + } + mockHighlighter(data.toolbox); + + return { + toolbox: data.toolbox, + inspector: data.inspector, + boxmodel: data.inspector.boxmodel, + testActor: data.testActor + }; + }); +} + /** * Wait for the boxmodel-view-updated event. * diff --git a/devtools/client/inspector/inspector.js b/devtools/client/inspector/inspector.js index b58dce429004..349945a49cae 100644 --- a/devtools/client/inspector/inspector.js +++ b/devtools/client/inspector/inspector.js @@ -926,10 +926,18 @@ Inspector.prototype = { this.ruleview.destroy(); } + if (this.boxmodel) { + this.boxmodel.destroy(); + } + if (this.computedview) { this.computedview.destroy(); } + if (this.gridInspector) { + this.gridInspector.destroy(); + } + if (this.layoutview) { this.layoutview.destroy(); } diff --git a/devtools/client/jsonview/main.js b/devtools/client/jsonview/main.js index eb552649717b..b12fe414225b 100644 --- a/devtools/client/jsonview/main.js +++ b/devtools/client/jsonview/main.js @@ -50,7 +50,7 @@ var JsonView = { * in the parent process. */ onSave: function (message) { - JsonViewUtils.getTargetFile(file => { + JsonViewUtils.getTargetFile().then(file => { if (file) { JsonViewUtils.saveToFile(file, message.data); } diff --git a/devtools/client/themes/boxmodel.css b/devtools/client/themes/boxmodel.css index d8e2b4d31efd..4cef659de5aa 100644 --- a/devtools/client/themes/boxmodel.css +++ b/devtools/client/themes/boxmodel.css @@ -52,7 +52,7 @@ /* Regions are 3 nested elements with wide borders and outlines */ -.boxmodel-content { +.boxmodel-contents { height: 18px; } @@ -84,7 +84,7 @@ border-color: #6a5acd; } -.boxmodel-content { +.boxmodel-contents { background-color: #87ceeb; } @@ -104,7 +104,8 @@ /* Editable region sizes are contained in absolutely positioned

*/ -.boxmodel-main > p { +.boxmodel-main > p, +.boxmodel-size { position: absolute; pointer-events: none; margin: 0; @@ -112,7 +113,8 @@ } .boxmodel-main > p > span, -.boxmodel-main > p > input { +.boxmodel-main > p > input, +.boxmodel-content { vertical-align: middle; pointer-events: auto; } @@ -172,8 +174,8 @@ .boxmodel-position.boxmodel-right, .boxmodel-margin.boxmodel-right, .boxmodel-margin.boxmodel-left, -.boxmodel-border.boxmodel-left, .boxmodel-border.boxmodel-right, +.boxmodel-border.boxmodel-left, .boxmodel-padding.boxmodel-right, .boxmodel-padding.boxmodel-left { width: 21px; @@ -218,6 +220,12 @@ height: 30px; } +.boxmodel-size > p { + display: inline-block; + margin: auto; + line-height: 0; +} + .boxmodel-rotate.boxmodel-right.boxmodel-position:not(.boxmodel-editing) { border-top: none; border-left: 1px solid var(--theme-highlight-purple); @@ -290,8 +298,6 @@ border-bottom-color: hsl(0, 0%, 50%); } -/* Make sure the content size doesn't appear as editable like the other sizes */ - .boxmodel-size > span { cursor: default; } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 04fa021fcb79..6ed2909fb70e 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -120,7 +120,7 @@ #include "nsITimer.h" #include "nsISHistoryInternal.h" #include "nsIPrincipal.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsISHEntry.h" #include "nsIWindowWatcher.h" #include "nsIPromptFactory.h" @@ -1501,7 +1501,7 @@ nsDocShell::LoadURI(nsIURI* aURI, // // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't // have origin attributes. - principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this); + principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this); inheritPrincipal = false; } } @@ -1514,7 +1514,7 @@ nsDocShell::LoadURI(nsIURI* aURI, inheritPrincipal = false; // If aFirstParty is true and the pref 'privacy.firstparty.isolate' is // enabled, we will set firstPartyDomain on the origin attributes. - principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this, aFirstParty); + principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this, aFirstParty); } // If the triggeringPrincipal is not passed explicitly, we first try to create @@ -8127,9 +8127,9 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal, nsCOMPtr principal; if (mSandboxFlags & SANDBOXED_ORIGIN) { if (aPrincipal) { - principal = nsNullPrincipal::CreateWithInheritedAttributes(aPrincipal); + principal = NullPrincipal::CreateWithInheritedAttributes(aPrincipal); } else { - principal = nsNullPrincipal::CreateWithInheritedAttributes(this); + principal = NullPrincipal::CreateWithInheritedAttributes(this); } } else { principal = aPrincipal; @@ -12409,13 +12409,13 @@ nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel, if (!principalToInherit) { if (loadInfo->GetLoadingSandboxed()) { if (loadInfo->LoadingPrincipal()) { - principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes( + principalToInherit = NullPrincipal::CreateWithInheritedAttributes( loadInfo->LoadingPrincipal()); } else { // get the OriginAttributes OriginAttributes attrs; loadInfo->GetOriginAttributes(&attrs); - principalToInherit = nsNullPrincipal::Create(attrs); + principalToInherit = NullPrincipal::Create(attrs); } } else { principalToInherit = loadInfo->PrincipalToInherit(); @@ -12606,7 +12606,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType) // Ensure that we have a triggeringPrincipal. Otherwise javascript: // URIs will pick it up from the about:blank page we just loaded, // and we don't really want even that in this case. - triggeringPrincipal = nsNullPrincipal::CreateWithInheritedAttributes(this); + triggeringPrincipal = NullPrincipal::CreateWithInheritedAttributes(this); } } @@ -14378,7 +14378,7 @@ nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview) // we QI the mContentViewer if the current URI is either about:blank // or about:printpreview. Stop(nsIWebNavigation::STOP_ALL); - nsCOMPtr principal = nsNullPrincipal::CreateWithInheritedAttributes(this); + nsCOMPtr principal = NullPrincipal::CreateWithInheritedAttributes(this); nsCOMPtr uri; NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:printpreview")); nsresult rv = CreateAboutBlankContentViewer(principal, uri); diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp index 3c2c959ca8f5..e8f657bff0cf 100644 --- a/dom/asmjscache/AsmJSCache.cpp +++ b/dom/asmjscache/AsmJSCache.cpp @@ -1623,18 +1623,24 @@ public: InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override { if (!aUsageInfo) { return NS_OK; } - return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aUsageInfo); + return GetUsageForOrigin(aPersistenceType, + aGroup, + aOrigin, + aCanceled, + aUsageInfo); } nsresult GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override { QuotaManager* qm = QuotaManager::Get(); @@ -1658,7 +1664,7 @@ public: bool hasMore; while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && - hasMore && !aUsageInfo->Canceled()) { + hasMore && !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/base/DOMParser.cpp b/dom/base/DOMParser.cpp index 3d063369a49b..da81cfc6b672 100644 --- a/dom/base/DOMParser.cpp +++ b/dom/base/DOMParser.cpp @@ -18,7 +18,7 @@ #include "nsDOMJSUtils.h" #include "nsError.h" #include "nsPIDOMWindow.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/LoadInfo.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ScriptSettings.h" @@ -345,7 +345,7 @@ DOMParser::Init(nsIPrincipal* principal, nsIURI* documentURI, // Don't give DOMParsers the system principal. Use a null // principal instead. mOriginalPrincipalWasSystem = true; - mPrincipal = nsNullPrincipal::Create(); + mPrincipal = NullPrincipal::Create(); if (!mDocumentURI) { rv = mPrincipal->GetURI(getter_AddRefs(mDocumentURI)); @@ -456,7 +456,7 @@ DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult) NS_ENSURE_TRUE(!mAttemptedInit, NS_ERROR_NOT_INITIALIZED); AttemptedInitMarker marker(&mAttemptedInit); - nsCOMPtr prin = nsNullPrincipal::Create(); + nsCOMPtr prin = NullPrincipal::Create(); rv = Init(prin, nullptr, nullptr, scriptHandlingObject); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp index d93dee5f3f52..6a269fe631e4 100644 --- a/dom/base/Location.cpp +++ b/dom/base/Location.cpp @@ -31,7 +31,7 @@ #include "nsGlobalWindow.h" #include "mozilla/Likely.h" #include "nsCycleCollectionParticipant.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "ScriptSettings.h" #include "mozilla/Unused.h" #include "mozilla/dom/LocationBinding.h" @@ -164,7 +164,7 @@ Location::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo) sourceURI = docCurrentURI; } else { - // Use principalURI as long as it is not an nsNullPrincipalURI. We + // Use principalURI as long as it is not an NullPrincipalURI. We // could add a method such as GetReferrerURI to principals to make this // cleaner, but given that we need to start using Source Browsing // Context for referrer (see Bug 960639) this may be wasted effort at diff --git a/dom/base/ScriptSettings.cpp b/dom/base/ScriptSettings.cpp index 7d0e4566b294..a89b3419127a 100644 --- a/dom/base/ScriptSettings.cpp +++ b/dom/base/ScriptSettings.cpp @@ -164,7 +164,7 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() // If the entry or incumbent global ends up being something that the subject // principal doesn't subsume, we don't want to use it. This never happens on // the web, but can happen with asymmetric privilege relationships (i.e. -// nsExpandedPrincipal and System Principal). +// ExpandedPrincipal and System Principal). // // The most correct thing to use instead would be the topmost global on the // callstack whose principal is subsumed by the subject principal. But that's diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index f7e0c1c9b96e..d3fa869985d8 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -182,7 +182,7 @@ #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsNodeInfoManager.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsParserCIID.h" #include "nsParserConstants.h" #include "nsPIDOMWindow.h" @@ -514,7 +514,7 @@ nsContentUtils::Init() sSecurityManager->GetSystemPrincipal(&sSystemPrincipal); MOZ_ASSERT(sSystemPrincipal); - RefPtr nullPrincipal = nsNullPrincipal::Create(); + RefPtr nullPrincipal = NullPrincipal::Create(); if (!nullPrincipal) { return NS_ERROR_FAILURE; } @@ -4790,7 +4790,7 @@ nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer, { nsCOMPtr uri; NS_NewURI(getter_AddRefs(uri), "about:blank"); - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); nsCOMPtr domDocument; nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument), EmptyString(), diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 159343549fe6..3aab08822895 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -1578,12 +1578,12 @@ public: static bool IsSystemPrincipal(nsIPrincipal* aPrincipal); /** - * Returns true if aPrincipal is an nsExpandedPrincipal. + * Returns true if aPrincipal is an ExpandedPrincipal. */ static bool IsExpandedPrincipal(nsIPrincipal* aPrincipal); /** - * Returns true if aPrincipal is the system or an nsExpandedPrincipal. + * Returns true if aPrincipal is the system or an ExpandedPrincipal. */ static bool IsSystemOrExpandedPrincipal(nsIPrincipal* aPrincipal) { diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 58a4b17ceb78..a4602c997103 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -106,7 +106,7 @@ #include "nsIScriptSecurityManager.h" #include "nsIPermissionManager.h" #include "nsIPrincipal.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIDOMWindow.h" #include "nsPIDOMWindow.h" @@ -2717,7 +2717,7 @@ nsDocument::InitCSP(nsIChannel* aChannel) if (cspSandboxFlags & SANDBOXED_ORIGIN) { // If the new CSP sandbox flags do not have the allow-same-origin flag // reset the document principal to a null principal - principal = nsNullPrincipal::Create(); + principal = NullPrincipal::Create(); SetPrincipal(principal); } diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 0217c97ffa54..e261b1860f41 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -50,7 +50,7 @@ #include "nsIEditor.h" #include "nsIMozBrowserFrame.h" #include "nsISHistory.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIScriptError.h" #include "nsGlobalWindow.h" #include "nsPIWindowRoot.h" @@ -98,7 +98,7 @@ #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseNativeHandler.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #ifdef XP_WIN #include "mozilla/plugins/PPluginWidgetParent.h" @@ -831,7 +831,7 @@ nsFrameLoader::ReallyStartLoadingInternal() NS_ENSURE_SUCCESS(rv, rv); } - // Use referrer as long as it is not an nsNullPrincipalURI. + // Use referrer as long as it is not an NullPrincipalURI. // We could add a method such as GetReferrerURI to principals to make this // cleaner, but given that we need to start using Source Browsing Context for // referrer (see Bug 960639) this may be wasted effort at this stage. diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 4214a8abc3e5..f0d69a3f0cbf 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -13077,9 +13077,14 @@ nsGlobalWindow::RunTimeoutHandler(Timeout* aTimeout, AutoEntryScript aes(this, reason, true); JS::CompileOptions options(aes.cx()); options.setFileAndLine(filename, lineNo).setVersion(JSVERSION_DEFAULT); + options.setNoScriptRval(true); JS::Rooted global(aes.cx(), FastGetGlobalJSObject()); - nsresult rv = - nsJSUtils::EvaluateString(aes.cx(), script, global, options); + nsresult rv = NS_OK; + { + nsJSUtils::ExecutionContext exec(aes.cx(), global); + rv = exec.CompileAndExec(options, script); + } + if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) { abortIntervalHandler = true; } diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index 98b367b663a4..6fcf17a1fd1e 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -123,156 +123,162 @@ nsJSUtils::CompileFunction(AutoJSAPI& jsapi, return NS_OK; } -nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - const nsAString& aScript, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue) +static nsresult +EvaluationExceptionToNSResult(JSContext* aCx) { - const nsPromiseFlatString& flatScript = PromiseFlatString(aScript); - JS::SourceBufferHolder srcBuf(flatScript.get(), aScript.Length(), - JS::SourceBufferHolder::NoOwnership); - return EvaluateString(aCx, srcBuf, aEvaluationGlobal, aCompileOptions, - aEvaluateOptions, aRetValue, nullptr); + if (JS_IsExceptionPending(aCx)) { + return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW; + } + return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE; +} + +nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx, + JS::Handle aGlobal) + : mSamplerRAII("nsJSUtils::ExecutionContext", /* PROFILER_LABEL */ + js::ProfileEntry::Category::JS, __LINE__) + , mCx(aCx) + , mCompartment(aCx, aGlobal) + , mRetValue(aCx) + , mScopeChain(aCx) + , mRv(NS_OK) + , mSkip(false) + , mCoerceToString(false) +#ifdef DEBUG + , mWantsReturnValue(false) + , mExpectScopeChain(false) +#endif +{ + MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(nsContentUtils::IsInMicroTask()); + MOZ_ASSERT(mRetValue.isUndefined()); + + MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aGlobal) == aGlobal); + if (MOZ_UNLIKELY(!xpc::Scriptability::Get(aGlobal).Allowed())) { + mSkip = true; + mRv = NS_OK; + } +} + +void +nsJSUtils::ExecutionContext::SetScopeChain( + const JS::AutoObjectVector& aScopeChain) +{ + if (mSkip) { + return; + } + +#ifdef DEBUG + mExpectScopeChain = true; +#endif + // Now make sure to wrap the scope chain into the right compartment. + if (!mScopeChain.reserve(aScopeChain.length())) { + mSkip = true; + mRv = NS_ERROR_OUT_OF_MEMORY; + return; + } + + for (size_t i = 0; i < aScopeChain.length(); ++i) { + JS::ExposeObjectToActiveJS(aScopeChain[i]); + mScopeChain.infallibleAppend(aScopeChain[i]); + if (!JS_WrapObject(mCx, mScopeChain[i])) { + mSkip = true; + mRv = NS_ERROR_OUT_OF_MEMORY; + return; + } + } } nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue, - void **aOffThreadToken) +nsJSUtils::ExecutionContext::SyncAndExec(void **aOffThreadToken, + JS::MutableHandle aScript) { - PROFILER_LABEL("nsJSUtils", "EvaluateString", - js::ProfileEntry::Category::JS); + if (mSkip) { + return mRv; + } + + MOZ_ASSERT(!mWantsReturnValue); + MOZ_ASSERT(!mExpectScopeChain); + aScript.set(JS::FinishOffThreadScript(mCx, *aOffThreadToken)); + *aOffThreadToken = nullptr; // Mark the token as having been finished. + if (!aScript || !JS_ExecuteScript(mCx, mScopeChain, aScript)) { + mSkip = true; + mRv = EvaluationExceptionToNSResult(mCx); + return mRv; + } + + return NS_OK; +} + +nsresult +nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions, + JS::SourceBufferHolder& aSrcBuf) +{ + if (mSkip) { + return mRv; + } MOZ_ASSERT_IF(aCompileOptions.versionSet, aCompileOptions.version != JSVERSION_UNKNOWN); - MOZ_ASSERT_IF(aEvaluateOptions.coerceToString, !aCompileOptions.noScriptRval); - MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); MOZ_ASSERT(aSrcBuf.get()); - MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aEvaluationGlobal) == - aEvaluationGlobal); - MOZ_ASSERT_IF(aOffThreadToken, aCompileOptions.noScriptRval); - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(nsContentUtils::IsInMicroTask()); - - // Unfortunately, the JS engine actually compiles scripts with a return value - // in a different, less efficient way. Furthermore, it can't JIT them in many - // cases. So we need to be explicitly told whether the caller cares about the - // return value. Callers can do this by calling the other overload of - // EvaluateString() which calls this function with - // aCompileOptions.noScriptRval set to true. - aRetValue.setUndefined(); - - nsresult rv = NS_OK; - - NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK); - - bool ok = true; - // Scope the JSAutoCompartment so that we can later wrap the return value - // into the caller's cx. - { - JSAutoCompartment ac(aCx, aEvaluationGlobal); - - // Now make sure to wrap the scope chain into the right compartment. - JS::AutoObjectVector scopeChain(aCx); - if (!scopeChain.reserve(aEvaluateOptions.scopeChain.length())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - for (size_t i = 0; i < aEvaluateOptions.scopeChain.length(); ++i) { - JS::ExposeObjectToActiveJS(aEvaluateOptions.scopeChain[i]); - scopeChain.infallibleAppend(aEvaluateOptions.scopeChain[i]); - if (!JS_WrapObject(aCx, scopeChain[i])) { - ok = false; - break; - } - } - - if (ok && aOffThreadToken) { - JS::Rooted - script(aCx, JS::FinishOffThreadScript(aCx, *aOffThreadToken)); - *aOffThreadToken = nullptr; // Mark the token as having been finished. - if (script) { - ok = JS_ExecuteScript(aCx, scopeChain, script); - } else { - ok = false; - } - } else if (ok) { - ok = JS::Evaluate(aCx, scopeChain, aCompileOptions, aSrcBuf, aRetValue); - } - - if (ok && aEvaluateOptions.coerceToString && !aRetValue.isUndefined()) { - JS::Rooted value(aCx, aRetValue); - JSString* str = JS::ToString(aCx, value); - ok = !!str; - aRetValue.set(ok ? JS::StringValue(str) : JS::UndefinedValue()); - } + MOZ_ASSERT(mRetValue.isUndefined()); +#ifdef DEBUG + mWantsReturnValue = !aCompileOptions.noScriptRval; +#endif + MOZ_ASSERT(!mCoerceToString || mWantsReturnValue); + if (!JS::Evaluate(mCx, mScopeChain, aCompileOptions, aSrcBuf, &mRetValue)) { + mSkip = true; + mRv = EvaluationExceptionToNSResult(mCx); + return mRv; } - if (!ok) { - if (JS_IsExceptionPending(aCx)) { - rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW; - } else { - rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE; - } - - if (!aCompileOptions.noScriptRval) { - aRetValue.setUndefined(); - } - } - - // Wrap the return value into whatever compartment aCx was in. - if (ok && !aCompileOptions.noScriptRval) { - if (!JS_WrapValue(aCx, aRetValue)) { - return NS_ERROR_OUT_OF_MEMORY; - } - } - return rv; + return NS_OK; } nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue) +nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions, + const nsAString& aScript) { - return EvaluateString(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions, - aEvaluateOptions, aRetValue, nullptr); + if (mSkip) { + return mRv; + } + + const nsPromiseFlatString& flatScript = PromiseFlatString(aScript); + JS::SourceBufferHolder srcBuf(flatScript.get(), aScript.Length(), + JS::SourceBufferHolder::NoOwnership); + return CompileAndExec(aCompileOptions, srcBuf); } nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - const nsAString& aScript, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions) +nsJSUtils::ExecutionContext::ExtractReturnValue(JS::MutableHandle aRetValue) { - EvaluateOptions options(aCx); - aCompileOptions.setNoScriptRval(true); - JS::RootedValue unused(aCx); - return EvaluateString(aCx, aScript, aEvaluationGlobal, aCompileOptions, - options, &unused); -} + MOZ_ASSERT(aRetValue.isUndefined()); + if (mSkip) { + // Repeat earlier result, as NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW are not + // failures cases. +#ifdef DEBUG + mWantsReturnValue = false; +#endif + return mRv; + } -nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - void **aOffThreadToken) -{ - EvaluateOptions options(aCx); - aCompileOptions.setNoScriptRval(true); - JS::RootedValue unused(aCx); - return EvaluateString(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions, - options, &unused, aOffThreadToken); + MOZ_ASSERT(mWantsReturnValue); +#ifdef DEBUG + mWantsReturnValue = false; +#endif + if (mCoerceToString && !mRetValue.isUndefined()) { + JSString* str = JS::ToString(mCx, mRetValue); + if (!str) { + // ToString can be a function call, so an exception can be raised while + // executing the function. + mSkip = true; + return EvaluationExceptionToNSResult(mCx); + } + mRetValue.set(JS::StringValue(str)); + } + + aRetValue.set(mRetValue); + return NS_OK; } nsresult diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h index 4affab2d3644..e6285b9bf9da 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -16,6 +16,7 @@ #include "mozilla/Assertions.h" +#include "GeckoProfiler.h" #include "jsapi.h" #include "jsfriendapi.h" #include "js/Conversions.h" @@ -64,52 +65,95 @@ public: const nsAString& aBody, JSObject** aFunctionObject); - struct MOZ_STACK_CLASS EvaluateOptions { - bool coerceToString; - JS::AutoObjectVector scopeChain; - explicit EvaluateOptions(JSContext* cx) - : coerceToString(false) - , scopeChain(cx) - {} + // ExecutionContext is used to switch compartment. + class MOZ_STACK_CLASS ExecutionContext { + // Register stack annotations for the Gecko profiler. + mozilla::SamplerStackFrameRAII mSamplerRAII; - EvaluateOptions& setCoerceToString(bool aCoerce) { - coerceToString = aCoerce; + JSContext* mCx; + + // Handles switching to our global's compartment. + JSAutoCompartment mCompartment; + + // Set to a valid handle if a return value is expected. + JS::Rooted mRetValue; + + // Scope chain in which the execution takes place. + JS::AutoObjectVector mScopeChain; + + // returned value forwarded when we have to interupt the execution eagerly + // with mSkip. + nsresult mRv; + + // Used to skip upcoming phases in case of a failure. In such case the + // result is carried by mRv. + bool mSkip; + + // Should the result be serialized before being returned. + bool mCoerceToString; + +#ifdef DEBUG + // Should we set the return value. + bool mWantsReturnValue; + + bool mExpectScopeChain; +#endif + + public: + + // Enter compartment in which the code would be executed. The JSContext + // must come from an AutoEntryScript that has had + // TakeOwnershipOfErrorReporting() called on it. + ExecutionContext(JSContext* aCx, JS::Handle aGlobal); + + ExecutionContext(const ExecutionContext&) = delete; + ExecutionContext(ExecutionContext&&) = delete; + + ~ExecutionContext() { + // This flag is resetted, when the returned value is extracted. + MOZ_ASSERT(!mWantsReturnValue); + } + + // The returned value would be converted to a string if the + // |aCoerceToString| is flag set. + ExecutionContext& SetCoerceToString(bool aCoerceToString) { + mCoerceToString = aCoerceToString; return *this; } + + // Set the scope chain in which the code should be executed. + void SetScopeChain(const JS::AutoObjectVector& aScopeChain); + + // Copy the returned value in the mutable handle argument, in case of a + // evaluation failure either during the execution or the conversion of the + // result to a string, the nsresult would be set to the corresponding result + // code, and the mutable handle argument would remain unchanged. + // + // The value returned in the mutable handle argument is part of the + // compartment given as argument to the ExecutionContext constructor. If the + // caller is in a different compartment, then the out-param value should be + // wrapped by calling |JS_WrapValue|. + MOZ_MUST_USE nsresult + ExtractReturnValue(JS::MutableHandle aRetValue); + + // After getting a notification that an off-thread compilation terminated, + // this function will synchronize the result by moving it to the main thread + // before starting the execution of the script. + // + // The compiled script would be returned in the |aScript| out-param. + MOZ_MUST_USE nsresult SyncAndExec(void **aOffThreadToken, + JS::MutableHandle aScript); + + // Compile a script contained in a SourceBuffer, and execute it. + nsresult CompileAndExec(JS::CompileOptions& aCompileOptions, + JS::SourceBufferHolder& aSrcBuf); + + // Compile a script contained in a string, and execute it. + nsresult CompileAndExec(JS::CompileOptions& aCompileOptions, + const nsAString& aScript); }; - // aEvaluationGlobal is the global to evaluate in. The return value - // will then be wrapped back into the compartment aCx is in when - // this function is called. For all the EvaluateString overloads, - // the JSContext must come from an AutoJSAPI that has had - // TakeOwnershipOfErrorReporting() called on it. - static nsresult EvaluateString(JSContext* aCx, - const nsAString& aScript, - JS::Handle aEvaluationGlobal, - JS::CompileOptions &aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue); - - static nsresult EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions &aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue); - - - static nsresult EvaluateString(JSContext* aCx, - const nsAString& aScript, - JS::Handle aEvaluationGlobal, - JS::CompileOptions &aCompileOptions); - - static nsresult EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions &aCompileOptions, - void **aOffThreadToken); - static nsresult CompileModule(JSContext* aCx, JS::SourceBufferHolder& aSrcBuf, JS::Handle aEvaluationGlobal, @@ -129,16 +173,6 @@ public: JS::AutoObjectVector& aScopeChain); static void ResetTimeZone(); - -private: - // Implementation for our EvaluateString bits - static nsresult EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue, - void **aOffThreadToken); }; template diff --git a/dom/base/nsNodeInfoManager.cpp b/dom/base/nsNodeInfoManager.cpp index 66c8c84cfd31..b0169b82ba0e 100644 --- a/dom/base/nsNodeInfoManager.cpp +++ b/dom/base/nsNodeInfoManager.cpp @@ -30,7 +30,7 @@ #include "nsCCUncollectableMarker.h" #include "nsNameSpaceManager.h" #include "nsDocument.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" using namespace mozilla; using mozilla::dom::NodeInfo; @@ -182,7 +182,7 @@ nsNodeInfoManager::Init(nsIDocument *aDocument) NS_PRECONDITION(!mPrincipal, "Being inited when we already have a principal?"); - mPrincipal = nsNullPrincipal::Create(); + mPrincipal = NullPrincipal::Create(); if (aDocument) { mBindingManager = new nsBindingManager(aDocument); diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 76eb388b171e..e3aab285aa20 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -2152,8 +2152,6 @@ nsScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi, aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo); aOptions->setVersion(JSVersion(aRequest->mJSVersion)); aOptions->setIsRunOnce(true); - // We only need the setNoScriptRval bit when compiling off-thread here, since - // otherwise nsJSUtils::EvaluateString will set it up for us. aOptions->setNoScriptRval(true); if (aRequest->mHasSourceMapURL) { aOptions->setSourceMapURL(aRequest->mSourceMapURL.get()); @@ -2258,10 +2256,17 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest) rv = FillCompileOptionsForRequest(aes, aRequest, global, &options); if (NS_SUCCEEDED(rv)) { - nsAutoString inlineData; - SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData); - rv = nsJSUtils::EvaluateString(aes.cx(), srcBuf, global, options, - aRequest->OffThreadTokenPtr()); + { + nsJSUtils::ExecutionContext exec(aes.cx(), global); + if (aRequest->mOffThreadToken) { + JS::Rooted script(aes.cx()); + rv = exec.SyncAndExec(&aRequest->mOffThreadToken, &script); + } else { + nsAutoString inlineData; + SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData); + rv = exec.CompileAndExec(options, srcBuf); + } + } } } } diff --git a/dom/base/nsTreeSanitizer.cpp b/dom/base/nsTreeSanitizer.cpp index c234a15301ba..b9dd8e4e1db0 100644 --- a/dom/base/nsTreeSanitizer.cpp +++ b/dom/base/nsTreeSanitizer.cpp @@ -19,7 +19,7 @@ #include "nsIScriptSecurityManager.h" #include "nsNetUtil.h" #include "nsComponentManagerUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsContentUtils.h" #include "nsIParserUtils.h" #include "nsIDocument.h" @@ -1522,7 +1522,7 @@ nsTreeSanitizer::InitializeStatics() sAttributesMathML->PutEntry(*kAttributesMathML[i]); } - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); principal.forget(&sNullPrincipal); } diff --git a/dom/bindings/SimpleGlobalObject.cpp b/dom/bindings/SimpleGlobalObject.cpp index 5659138c852f..2a9f5656c532 100644 --- a/dom/bindings/SimpleGlobalObject.cpp +++ b/dom/bindings/SimpleGlobalObject.cpp @@ -10,7 +10,7 @@ #include "js/Class.h" #include "nsJSPrincipals.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsThreadUtils.h" #include "nsContentUtils.h" @@ -113,7 +113,7 @@ SimpleGlobalObject::Create(GlobalType globalType, JS::Handle proto) .setSystemZone(); if (NS_IsMainThread()) { - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); options.creationOptions().setTrace(xpc::TraceXPCGlobal); global = xpc::CreateGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass), nsJSPrincipals::get(principal), diff --git a/dom/cache/QuotaClient.cpp b/dom/cache/QuotaClient.cpp index b33fa8c34a31..5641c953c6c0 100644 --- a/dom/cache/QuotaClient.cpp +++ b/dom/cache/QuotaClient.cpp @@ -16,6 +16,7 @@ namespace { +using mozilla::Atomic; using mozilla::dom::ContentParentId; using mozilla::dom::cache::Manager; using mozilla::dom::quota::Client; @@ -25,7 +26,8 @@ using mozilla::dom::quota::UsageInfo; using mozilla::ipc::AssertIsOnBackgroundThread; static nsresult -GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo) +GetBodyUsage(nsIFile* aDir, const Atomic& aCanceled, + UsageInfo* aUsageInfo) { nsCOMPtr entries; nsresult rv = aDir->GetDirectoryEntries(getter_AddRefs(entries)); @@ -33,7 +35,7 @@ GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo) bool hasMore; while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore && - !aUsageInfo->Canceled()) { + !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -45,7 +47,7 @@ GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo) if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (isDir) { - rv = GetBodyUsage(file, aUsageInfo); + rv = GetBodyUsage(file, aCanceled, aUsageInfo); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } continue; } @@ -72,7 +74,8 @@ public: virtual nsresult InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, - const nsACString& aOrigin, UsageInfo* aUsageInfo) override + const nsACString& aOrigin, const AtomicBool& aCanceled, + UsageInfo* aUsageInfo) override { // The QuotaManager passes a nullptr UsageInfo if there is no quota being // enforced against the origin. @@ -80,12 +83,13 @@ public: return NS_OK; } - return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aUsageInfo); + return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aCanceled, + aUsageInfo); } virtual nsresult GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, - const nsACString& aOrigin, + const nsACString& aOrigin, const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override { MOZ_DIAGNOSTIC_ASSERT(aUsageInfo); @@ -107,7 +111,7 @@ public: bool hasMore; while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore && - !aUsageInfo->Canceled()) { + !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -124,7 +128,7 @@ public: if (isDir) { if (leafName.EqualsLiteral("morgue")) { - rv = GetBodyUsage(file, aUsageInfo); + rv = GetBodyUsage(file, aCanceled, aUsageInfo); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { NS_WARNING("Unknown Cache directory found!"); diff --git a/dom/cache/test/mochitest/test_cache_orphaned_body.html b/dom/cache/test/mochitest/test_cache_orphaned_body.html index a806cb30005f..049a97a79421 100644 --- a/dom/cache/test/mochitest/test_cache_orphaned_body.html +++ b/dom/cache/test/mochitest/test_cache_orphaned_body.html @@ -37,7 +37,8 @@ function storageUsage() { var qms = SpecialPowers.Services.qms; var principal = SpecialPowers.wrap(document).nodePrincipal; var cb = SpecialPowers.wrapCallback(function(request) { - resolve(request.usage, request.fileUsage); + var result = request.result; + resolve(result.usage, result.fileUsage); }); qms.getUsageForPrincipal(principal, cb); }); diff --git a/dom/cache/test/mochitest/test_cache_orphaned_cache.html b/dom/cache/test/mochitest/test_cache_orphaned_cache.html index c797da7b2f75..c6086e4877fc 100644 --- a/dom/cache/test/mochitest/test_cache_orphaned_cache.html +++ b/dom/cache/test/mochitest/test_cache_orphaned_cache.html @@ -37,7 +37,8 @@ function storageUsage() { var qms = SpecialPowers.Services.qms; var principal = SpecialPowers.wrap(document).nodePrincipal; var cb = SpecialPowers.wrapCallback(function(request) { - resolve(request.usage, request.fileUsage); + var result = request.result; + resolve(result.usage, result.fileUsage); }); qms.getUsageForPrincipal(principal, cb); }); diff --git a/dom/cache/test/mochitest/test_cache_shrink.html b/dom/cache/test/mochitest/test_cache_shrink.html index e6b362eb2215..b7136cb750f4 100644 --- a/dom/cache/test/mochitest/test_cache_shrink.html +++ b/dom/cache/test/mochitest/test_cache_shrink.html @@ -37,7 +37,8 @@ function storageUsage() { var qms = SpecialPowers.Services.qms; var principal = SpecialPowers.wrap(document).nodePrincipal; var cb = SpecialPowers.wrapCallback(function(request) { - resolve(request.usage, request.fileUsage); + var result = request.result; + resolve(result.usage, result.fileUsage); }); qms.getUsageForPrincipal(principal, cb); }); diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index b574cb5946ef..7c98e1e2696a 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -379,9 +379,10 @@ nsTextInputSelectionImpl::ScrollSelectionIntoView( if (!mFrameSelection) return NS_ERROR_FAILURE; - return mFrameSelection->ScrollSelectionIntoView( - ToSelectionType(aRawSelectionType), - aRegion, aFlags); + RefPtr frameSelection = mFrameSelection; + return frameSelection->ScrollSelectionIntoView( + ToSelectionType(aRawSelectionType), + aRegion, aFlags); } NS_IMETHODIMP @@ -390,7 +391,8 @@ nsTextInputSelectionImpl::RepaintSelection(RawSelectionType aRawSelectionType) if (!mFrameSelection) return NS_ERROR_FAILURE; - return mFrameSelection->RepaintSelection(ToSelectionType(aRawSelectionType)); + RefPtr frameSelection = mFrameSelection; + return frameSelection->RepaintSelection(ToSelectionType(aRawSelectionType)); } nsresult @@ -400,7 +402,8 @@ nsTextInputSelectionImpl::RepaintSelection(nsPresContext* aPresContext, if (!mFrameSelection) return NS_ERROR_FAILURE; - return mFrameSelection->RepaintSelection(aSelectionType); + RefPtr frameSelection = mFrameSelection; + return frameSelection->RepaintSelection(aSelectionType); } NS_IMETHODIMP @@ -487,48 +490,60 @@ NS_IMETHODIMP nsTextInputSelectionImpl::PhysicalMove(int16_t aDirection, int16_t aAmount, bool aExtend) { - if (mFrameSelection) - return mFrameSelection->PhysicalMove(aDirection, aAmount, aExtend); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->PhysicalMove(aDirection, aAmount, aExtend); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::CharacterMove(bool aForward, bool aExtend) { - if (mFrameSelection) - return mFrameSelection->CharacterMove(aForward, aExtend); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->CharacterMove(aForward, aExtend); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::CharacterExtendForDelete() { - if (mFrameSelection) - return mFrameSelection->CharacterExtendForDelete(); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->CharacterExtendForDelete(); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::CharacterExtendForBackspace() { - if (mFrameSelection) - return mFrameSelection->CharacterExtendForBackspace(); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->CharacterExtendForBackspace(); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::WordMove(bool aForward, bool aExtend) { - if (mFrameSelection) - return mFrameSelection->WordMove(aForward, aExtend); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->WordMove(aForward, aExtend); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::WordExtendForDelete(bool aForward) { - if (mFrameSelection) - return mFrameSelection->WordExtendForDelete(aForward); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->WordExtendForDelete(aForward); + } return NS_ERROR_NULL_POINTER; } @@ -537,7 +552,8 @@ nsTextInputSelectionImpl::LineMove(bool aForward, bool aExtend) { if (mFrameSelection) { - nsresult result = mFrameSelection->LineMove(aForward, aExtend); + RefPtr frameSelection = mFrameSelection; + nsresult result = frameSelection->LineMove(aForward, aExtend); if (NS_FAILED(result)) result = CompleteMove(aForward,aExtend); return result; @@ -549,8 +565,10 @@ nsTextInputSelectionImpl::LineMove(bool aForward, bool aExtend) NS_IMETHODIMP nsTextInputSelectionImpl::IntraLineMove(bool aForward, bool aExtend) { - if (mFrameSelection) - return mFrameSelection->IntraLineMove(aForward, aExtend); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->IntraLineMove(aForward, aExtend); + } return NS_ERROR_NULL_POINTER; } @@ -562,7 +580,8 @@ nsTextInputSelectionImpl::PageMove(bool aForward, bool aExtend) // and to remain relative position of the caret in view. see Bug 4302. if (mScrollFrame) { - mFrameSelection->CommonPageMove(aForward, aExtend, mScrollFrame); + RefPtr frameSelection = mFrameSelection; + frameSelection->CommonPageMove(aForward, aExtend, mScrollFrame); } // After ScrollSelectionIntoView(), the pending notifications might be // flushed and PresShell/PresContext/Frames may be dead. See bug 418470. @@ -590,8 +609,11 @@ nsTextInputSelectionImpl::CompleteScroll(bool aForward) NS_IMETHODIMP nsTextInputSelectionImpl::CompleteMove(bool aForward, bool aExtend) { + NS_ENSURE_STATE(mFrameSelection); + RefPtr frameSelection = mFrameSelection; + // grab the parent / root DIV for this text widget - nsIContent* parentDIV = mFrameSelection->GetLimiter(); + nsIContent* parentDIV = frameSelection->GetLimiter(); if (!parentDIV) return NS_ERROR_UNEXPECTED; @@ -617,7 +639,7 @@ nsTextInputSelectionImpl::CompleteMove(bool aForward, bool aExtend) } } - mFrameSelection->HandleClick(parentDIV, offset, offset, aExtend, + frameSelection->HandleClick(parentDIV, offset, offset, aExtend, false, hint); // if we got this far, attempt to scroll no matter what the above result is @@ -672,8 +694,10 @@ nsTextInputSelectionImpl::ScrollCharacter(bool aRight) NS_IMETHODIMP nsTextInputSelectionImpl::SelectAll() { - if (mFrameSelection) - return mFrameSelection->SelectAll(); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->SelectAll(); + } return NS_ERROR_NULL_POINTER; } diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index d30f58e8d456..083810be7723 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -9347,12 +9347,14 @@ public: InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override; nsresult GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override; void @@ -9394,13 +9396,14 @@ private: nsresult GetDatabaseFilenames(nsIFile* aDirectory, - UsageInfo* aUsageInfo, + const AtomicBool& aCanceled, bool aForUpgrade, nsTArray& aSubdirsToProcess, nsTHashtable& aDatabaseFilename); nsresult GetUsageForDirectoryInternal(nsIFile* aDirectory, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo, bool aDatabaseFiles); @@ -17828,10 +17831,11 @@ QuotaClient::UpgradeStorageFrom1_0To2_0(nsIFile* aDirectory) AssertIsOnIOThread(); MOZ_ASSERT(aDirectory); + AtomicBool dummy(false); AutoTArray subdirsToProcess; nsTHashtable databaseFilenames(20); nsresult rv = GetDatabaseFilenames(aDirectory, - nullptr, + /* aCanceled */ dummy, /* aForUpgrade */ true, subdirsToProcess, databaseFilenames); @@ -17924,6 +17928,7 @@ nsresult QuotaClient::InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) { AssertIsOnIOThread(); @@ -17942,7 +17947,7 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType, AutoTArray subdirsToProcess; nsTHashtable databaseFilenames(20); rv = GetDatabaseFilenames(directory, - aUsageInfo, + aCanceled, /* aForUpgrade */ false, subdirsToProcess, databaseFilenames); @@ -17974,7 +17979,9 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType, const NS_ConvertASCIItoUTF16 walSuffix(kSQLiteWALSuffix, LiteralStringLength(kSQLiteWALSuffix)); - for (auto iter = databaseFilenames.ConstIter(); !iter.Done(); iter.Next()) { + for (auto iter = databaseFilenames.ConstIter(); + !iter.Done() && !aCanceled; + iter.Next()) { auto& databaseFilename = iter.Get()->GetKey(); nsCOMPtr fmDirectory; @@ -18022,7 +18029,7 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType, return rv; } - if (aUsageInfo && !aUsageInfo->Canceled()) { + if (aUsageInfo) { int64_t fileSize; rv = databaseFile->GetFileSize(&fileSize); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -18059,6 +18066,7 @@ nsresult QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) { AssertIsOnIOThread(); @@ -18071,7 +18079,7 @@ QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType, return rv; } - rv = GetUsageForDirectoryInternal(directory, aUsageInfo, true); + rv = GetUsageForDirectoryInternal(directory, aCanceled, aUsageInfo, true); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -18260,12 +18268,13 @@ QuotaClient::GetDirectory(PersistenceType aPersistenceType, nsresult QuotaClient::GetDatabaseFilenames( nsIFile* aDirectory, - UsageInfo* aUsageInfo, + const AtomicBool& aCanceled, bool aForUpgrade, nsTArray& aSubdirsToProcess, nsTHashtable& aDatabaseFilenames) { AssertIsOnIOThread(); + MOZ_ASSERT(aDirectory); nsCOMPtr entries; nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries)); @@ -18286,7 +18295,7 @@ QuotaClient::GetDatabaseFilenames( bool hasMore; while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore && - (!aUsageInfo || !aUsageInfo->Canceled())) { + !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -18362,6 +18371,7 @@ QuotaClient::GetDatabaseFilenames( nsresult QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo, bool aDatabaseFiles) { @@ -18388,7 +18398,7 @@ QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory, bool hasMore; while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore && - !aUsageInfo->Canceled()) { + !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -18423,7 +18433,7 @@ QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory, if (isDirectory) { if (aDatabaseFiles) { - rv = GetUsageForDirectoryInternal(file, aUsageInfo, false); + rv = GetUsageForDirectoryInternal(file, aCanceled, aUsageInfo, false); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -21236,8 +21246,7 @@ FactoryOp::CheckPermission(ContentParent* aContentParent, if (State::Initial == mState) { QuotaManager::GetInfoForChrome(&mSuffix, &mGroup, &mOrigin); - MOZ_ASSERT( - QuotaManager::IsOriginWhitelistedForPersistentStorage(mOrigin)); + MOZ_ASSERT(QuotaManager::IsOriginInternal(mOrigin)); mEnforcingQuota = false; } @@ -21269,7 +21278,7 @@ FactoryOp::CheckPermission(ContentParent* aContentParent, PermissionRequestBase::PermissionValue permission; if (persistenceType == PERSISTENCE_TYPE_PERSISTENT) { - if (QuotaManager::IsOriginWhitelistedForPersistentStorage(origin)) { + if (QuotaManager::IsOriginInternal(origin)) { permission = PermissionRequestBase::kPermissionAllowed; } else { #ifdef IDB_MOBILE diff --git a/dom/indexedDB/test/file.js b/dom/indexedDB/test/file.js index 6c70eff1be25..744a92b33a0c 100644 --- a/dom/indexedDB/test/file.js +++ b/dom/indexedDB/test/file.js @@ -220,10 +220,10 @@ function verifyWasmModule(module1, module2) function grabFileUsageAndContinueHandler(request) { - testGenerator.next(request.fileUsage); + testGenerator.next(request.result.fileUsage); } -function getUsage(usageHandler) +function getCurrentUsage(usageHandler) { let qms = SpecialPowers.Services.qms; let principal = SpecialPowers.wrap(document).nodePrincipal; diff --git a/dom/indexedDB/test/test_file_os_delete.html b/dom/indexedDB/test/test_file_os_delete.html index e5acf079c420..81c8fd1a8c50 100644 --- a/dom/indexedDB/test/test_file_os_delete.html +++ b/dom/indexedDB/test/test_file_os_delete.html @@ -18,7 +18,7 @@ const objectStoreName = "Blobs"; - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); let startUsage = yield undefined; const fileData1 = { @@ -61,7 +61,7 @@ is(event.type, "success", "Got correct event type"); - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); let usage = yield undefined; is(usage, startUsage + fileData1.obj.file.size + fileData2.obj.file.size, @@ -74,7 +74,7 @@ is(event.type, "complete", "Got correct event type"); - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); usage = yield undefined; is(usage, startUsage + fileData1.obj.file.size + fileData2.obj.file.size, @@ -90,7 +90,7 @@ // Flush pending file deletions before checking usage. flushPendingFileDeletions(); - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); let endUsage = yield undefined; is(endUsage, startUsage, "OS files deleted"); diff --git a/dom/indexedDB/test/unit/test_idle_maintenance.js b/dom/indexedDB/test/unit/test_idle_maintenance.js index 51bcf0b11c93..a0cf01fd778d 100644 --- a/dom/indexedDB/test/unit/test_idle_maintenance.js +++ b/dom/indexedDB/test/unit/test_idle_maintenance.js @@ -122,8 +122,9 @@ function* testSteps() let usageBeforeMaintenance; quotaManagerService.getUsageForPrincipal(principal, (request) => { - ok(request.usage > 0, "Usage is non-zero"); - usageBeforeMaintenance = request.usage; + let usage = request.result.usage; + ok(usage > 0, "Usage is non-zero"); + usageBeforeMaintenance = usage; continueToNextStep(); }); yield undefined; @@ -155,8 +156,9 @@ function* testSteps() let usageAfterMaintenance; quotaManagerService.getUsageForPrincipal(principal, (request) => { - ok(request.usage > 0, "Usage is non-zero"); - usageAfterMaintenance = request.usage; + let usage = request.result.usage; + ok(usage > 0, "Usage is non-zero"); + usageAfterMaintenance = usage; continueToNextStep(); }); yield undefined; diff --git a/dom/indexedDB/test/unit/test_view_put_get_values.js b/dom/indexedDB/test/unit/test_view_put_get_values.js index 2dad2f64c653..2b4b8bf060ce 100644 --- a/dom/indexedDB/test/unit/test_view_put_get_values.js +++ b/dom/indexedDB/test/unit/test_view_put_get_values.js @@ -80,7 +80,7 @@ function* testSteps() verifyView(request.result, viewData.view); yield undefined; - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); let fileUsage = yield undefined; if (external) { diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js index d56e8269cf8a..ba757ba9a248 100644 --- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js +++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js @@ -516,10 +516,10 @@ function verifyWasmModule(module1, module2) function grabFileUsageAndContinueHandler(request) { - testGenerator.next(request.fileUsage); + testGenerator.next(request.result.fileUsage); } -function getUsage(usageHandler) +function getCurrentUsage(usageHandler) { let qms = Cc["@mozilla.org/dom/quota-manager-service;1"] .getService(Ci.nsIQuotaManagerService); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 06b69a77a49a..87163e1bcb91 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -58,7 +58,6 @@ #include "nsIDOMWindowUtils.h" #include "nsIInterfaceRequestorUtils.h" #include "nsILoadInfo.h" -#include "nsPrincipal.h" #include "nsIPromptFactory.h" #include "nsIURI.h" #include "nsIWindowWatcher.h" @@ -69,6 +68,7 @@ #include "nsViewManager.h" #include "nsVariant.h" #include "nsIWidget.h" +#include "nsNetUtil.h" #ifndef XP_WIN #include "nsJARProtocolHandler.h" #endif diff --git a/dom/json/nsJSON.cpp b/dom/json/nsJSON.cpp index 4a6503fb8eaf..2884c7bc96f3 100644 --- a/dom/json/nsJSON.cpp +++ b/dom/json/nsJSON.cpp @@ -22,7 +22,7 @@ #include "nsIScriptError.h" #include "nsCRTGlue.h" #include "nsIScriptSecurityManager.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/Maybe.h" #include @@ -407,7 +407,7 @@ nsJSON::DecodeInternal(JSContext* cx, } nsresult rv; - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); // The ::Decode function is deprecated [Bug 675797] and the following // channel is never openend, so it does not matter what securityFlags diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp index bd8f70e2bc87..0c1b5d9599fc 100644 --- a/dom/jsurl/nsJSProtocolHandler.cpp +++ b/dom/jsurl/nsJSProtocolHandler.cpp @@ -269,10 +269,14 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel, JS::CompileOptions options(cx); options.setFileAndLine(mURL.get(), 1) .setVersion(JSVERSION_DEFAULT); - nsJSUtils::EvaluateOptions evalOptions(cx); - evalOptions.setCoerceToString(true); - rv = nsJSUtils::EvaluateString(cx, NS_ConvertUTF8toUTF16(script), - globalJSObject, options, evalOptions, &v); + { + nsJSUtils::ExecutionContext exec(cx, globalJSObject); + exec.SetCoerceToString(true); + exec.CompileAndExec(options, NS_ConvertUTF8toUTF16(script)); + rv = exec.ExtractReturnValue(&v); + } + + js::AssertSameCompartment(cx, v); if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) { return NS_ERROR_MALFORMED_URI; diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 7a81f835a086..2e3763325484 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -28,7 +28,6 @@ #include "nsIIDNService.h" #include "nsNetCID.h" #include "nsNetUtil.h" -#include "nsPrincipal.h" #include "nsICryptoHash.h" #include "nsICryptoHMAC.h" #include "nsIKeyModule.h" @@ -54,7 +53,7 @@ #include "VideoUtils.h" #include "Latency.h" #include "nsProxyRelease.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsVariant.h" // For snprintf @@ -1155,7 +1154,7 @@ public: nsCOMPtr principal; if (mPeerIdentity) { - principal = nsNullPrincipal::CreateWithInheritedAttributes(window->GetExtantDoc()->NodePrincipal()); + principal = NullPrincipal::CreateWithInheritedAttributes(window->GetExtantDoc()->NodePrincipal()); } else { principal = window->GetExtantDoc()->NodePrincipal(); } diff --git a/dom/media/MediaStreamTrack.h b/dom/media/MediaStreamTrack.h index cb11e919ac2e..c433f1a5656c 100644 --- a/dom/media/MediaStreamTrack.h +++ b/dom/media/MediaStreamTrack.h @@ -97,7 +97,7 @@ public: * This is used in WebRTC. A peerIdentity constrained MediaStreamTrack cannot * be sent across the network to anything other than a peer with the provided * identity. If this is set, then GetPrincipal() should return an instance of - * nsNullPrincipal. + * NullPrincipal. * * A track's PeerIdentity is immutable and will not change during the track's * lifetime. diff --git a/dom/media/mediasink/AudioSink.cpp b/dom/media/mediasink/AudioSink.cpp index a92d8294d708..4938a870748f 100644 --- a/dom/media/mediasink/AudioSink.cpp +++ b/dom/media/mediasink/AudioSink.cpp @@ -258,27 +258,6 @@ AudioSink::PopFrames(uint32_t aFrames) AudioDataValue* const mData; }; - class SilentChunk : public AudioStream::Chunk { - public: - SilentChunk(uint32_t aFrames, uint32_t aChannels, uint32_t aRate) - : mFrames(aFrames) - , mChannels(aChannels) - , mRate(aRate) - , mData(MakeUnique(aChannels * aFrames)) { - memset(mData.get(), 0, aChannels * aFrames * sizeof(AudioDataValue)); - } - const AudioDataValue* Data() const { return mData.get(); } - uint32_t Frames() const { return mFrames; } - uint32_t Channels() const { return mChannels; } - uint32_t Rate() const { return mRate; } - AudioDataValue* GetWritable() const { return mData.get(); } - private: - const uint32_t mFrames; - const uint32_t mChannels; - const uint32_t mRate; - UniquePtr mData; - }; - bool needPopping = false; if (!mCurrentData) { // No data in the queue. Return an empty chunk. diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index f0e97c75fdae..b78b6478b54f 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -384,10 +384,9 @@ FindD3D9BlacklistedDLL() class CreateDXVAManagerEvent : public Runnable { public: - CreateDXVAManagerEvent(LayersBackend aBackend, - layers::KnowsCompositor* aKnowsCompositor, + CreateDXVAManagerEvent(layers::KnowsCompositor* aKnowsCompositor, nsCString& aFailureReason) - : mBackend(aBackend) + : mBackend(LayersBackend::LAYERS_D3D11) , mKnowsCompositor(aKnowsCompositor) , mFailureReason(aFailureReason) { @@ -435,7 +434,7 @@ public: }; bool -WMFVideoMFTManager::InitializeDXVA(bool aForceD3D9) +WMFVideoMFTManager::InitializeDXVA() { // If we use DXVA but aren't running with a D3D layer manager then the // readback of decoded video frames from GPU to CPU memory grinds painting @@ -447,17 +446,14 @@ WMFVideoMFTManager::InitializeDXVA(bool aForceD3D9) } MOZ_ASSERT(!mDXVA2Manager); LayersBackend backend = GetCompositorBackendType(mKnowsCompositor); - if (backend != LayersBackend::LAYERS_D3D9 - && backend != LayersBackend::LAYERS_D3D11) { + if (backend != LayersBackend::LAYERS_D3D11) { mDXVAFailureReason.AssignLiteral("Unsupported layers backend"); return false; } // The DXVA manager must be created on the main thread. RefPtr event = - new CreateDXVAManagerEvent(aForceD3D9 ? LayersBackend::LAYERS_D3D9 - : backend, - mKnowsCompositor, + new CreateDXVAManagerEvent(mKnowsCompositor, mDXVAFailureReason); if (NS_IsMainThread()) { @@ -499,7 +495,7 @@ WMFVideoMFTManager::Init() return false; } - bool success = InitInternal(/* aForceD3D9 = */ false); + bool success = InitInternal(); if (success && mDXVA2Manager) { // If we had some failures but eventually made it work, @@ -515,10 +511,10 @@ WMFVideoMFTManager::Init() } bool -WMFVideoMFTManager::InitInternal(bool aForceD3D9) +WMFVideoMFTManager::InitInternal() { mUseHwAccel = false; // default value; changed if D3D setup succeeds. - bool useDxva = InitializeDXVA(aForceD3D9); + bool useDxva = InitializeDXVA(); RefPtr decoder(new MFTDecoder()); @@ -836,8 +832,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample, nsIntRect pictureRegion = mVideoInfo.ScaledImageRect(videoWidth, videoHeight); LayersBackend backend = GetCompositorBackendType(mKnowsCompositor); - if (backend != LayersBackend::LAYERS_D3D9 && - backend != LayersBackend::LAYERS_D3D11) { + if (backend != LayersBackend::LAYERS_D3D11) { RefPtr v = VideoData::CreateAndCopyData(mVideoInfo, mImageContainer, diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.h b/dom/media/platforms/wmf/WMFVideoMFTManager.h index 7d9851790135..56dbfaac1314 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.h +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h @@ -69,9 +69,9 @@ public: private: bool ValidateVideoInfo(); - bool InitializeDXVA(bool aForceD3D9); + bool InitializeDXVA(); - bool InitInternal(bool aForceD3D9); + bool InitInternal(); HRESULT CreateBasicVideoFrame(IMFSample* aSample, int64_t aStreamOffset, diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index af8a182b5e99..6fcc157ce7b9 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -1368,14 +1368,23 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result) options.setFileAndLine(spec, 0) .setVersion(JSVERSION_DEFAULT); JS::Rooted rval(cx); - nsJSUtils::EvaluateOptions evalOptions(cx); + JS::AutoObjectVector scopeChain(cx); if (obj != js::GetGlobalForObjectCrossCompartment(obj) && - !evalOptions.scopeChain.append(obj)) { + !scopeChain.append(obj)) { return false; } obj = js::GetGlobalForObjectCrossCompartment(obj); - nsresult rv = nsJSUtils::EvaluateString(cx, utf16script, obj, options, - evalOptions, &rval); + nsresult rv = NS_OK; + { + nsJSUtils::ExecutionContext exec(cx, obj); + exec.SetScopeChain(scopeChain); + exec.CompileAndExec(options, utf16script); + rv = exec.ExtractReturnValue(&rval); + } + + if (!JS_WrapValue(cx, &rval)) { + return false; + } return NS_SUCCEEDED(rv) && (!result || JSValToNPVariant(npp, cx, rval, result)); diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 24816654569f..3b8ace19e1ee 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -94,7 +94,7 @@ #include "nsIImageLoadingContent.h" #include "mozilla/Preferences.h" #include "nsVersionComparator.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #if defined(XP_WIN) #include "nsIWindowMediator.h" diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp index 283f1da7e277..a6d0634fbdfc 100644 --- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp +++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp @@ -33,7 +33,7 @@ #include "GeckoProfiler.h" #include "nsPluginInstanceOwner.h" #include "nsDataHashtable.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #define BYTERANGE_REQUEST_CONTEXT 0x01020304 diff --git a/dom/quota/ActorsChild.cpp b/dom/quota/ActorsChild.cpp index ab900dc39e6e..364896c54695 100644 --- a/dom/quota/ActorsChild.cpp +++ b/dom/quota/ActorsChild.cpp @@ -9,6 +9,7 @@ #include "nsVariant.h" #include "QuotaManagerService.h" #include "QuotaRequests.h" +#include "QuotaResults.h" namespace mozilla { namespace dom { @@ -141,14 +142,56 @@ QuotaUsageRequestChild::HandleResponse(nsresult aResponse) } void -QuotaUsageRequestChild::HandleResponse(const UsageResponse& aResponse) +QuotaUsageRequestChild::HandleResponse(const nsTArray& aResponse) { AssertIsOnOwningThread(); MOZ_ASSERT(mRequest); - mRequest->SetResult(aResponse.usage(), - aResponse.fileUsage(), - aResponse.limit()); + RefPtr variant = new nsVariant(); + + if (aResponse.IsEmpty()) { + variant->SetAsEmptyArray(); + } else { + nsTArray> usageResults; + + const uint32_t count = aResponse.Length(); + + usageResults.SetCapacity(count); + + for (uint32_t index = 0; index < count; index++) { + auto& originUsage = aResponse[index]; + + RefPtr usageResult = new UsageResult(originUsage.origin(), + originUsage.persisted(), + originUsage.usage()); + + usageResults.AppendElement(usageResult.forget()); + } + + variant->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS, + &NS_GET_IID(nsIQuotaUsageResult), + usageResults.Length(), + static_cast(usageResults.Elements())); + } + + mRequest->SetResult(variant); +} + +void +QuotaUsageRequestChild::HandleResponse(const OriginUsageResponse& aResponse) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mRequest); + + RefPtr result = + new OriginUsageResult(aResponse.usage(), + aResponse.fileUsage(), + aResponse.limit()); + + RefPtr variant = new nsVariant(); + variant->SetAsInterface(NS_GET_IID(nsIQuotaOriginUsageResult), result); + + mRequest->SetResult(variant); } void @@ -175,8 +218,12 @@ QuotaUsageRequestChild::Recv__delete__(const UsageRequestResponse& aResponse) HandleResponse(aResponse.get_nsresult()); break; - case UsageRequestResponse::TUsageResponse: - HandleResponse(aResponse.get_UsageResponse()); + case UsageRequestResponse::TAllUsageResponse: + HandleResponse(aResponse.get_AllUsageResponse().originUsages()); + break; + + case UsageRequestResponse::TOriginUsageResponse: + HandleResponse(aResponse.get_OriginUsageResponse()); break; default: diff --git a/dom/quota/ActorsChild.h b/dom/quota/ActorsChild.h index 90a952e3b65e..fe1abf1094d0 100644 --- a/dom/quota/ActorsChild.h +++ b/dom/quota/ActorsChild.h @@ -98,7 +98,10 @@ private: HandleResponse(nsresult aResponse); void - HandleResponse(const UsageResponse& aResponse); + HandleResponse(const nsTArray& aResponse); + + void + HandleResponse(const OriginUsageResponse& aResponse); // IPDL methods are only called by IPDL. virtual void diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 22a3559d39bb..9e2bceee0044 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -915,6 +915,7 @@ class NormalOriginOperationBase protected: Nullable mPersistenceType; OriginScope mOriginScope; + mozilla::Atomic mCanceled; const bool mExclusive; public: @@ -1042,49 +1043,103 @@ private: RecvStopIdleMaintenance() override; }; -class GetUsageOp final +class QuotaUsageRequestBase : public NormalOriginOperationBase , public PQuotaUsageRequestParent +{ +public: + // May be overridden by subclasses if they need to perform work on the + // background thread before being run. + virtual bool + Init(Quota* aQuota); + +protected: + QuotaUsageRequestBase() + : NormalOriginOperationBase(Nullable(), + OriginScope::FromNull(), + /* aExclusive */ false) + { } + + nsresult + GetUsageForOrigin(QuotaManager* aQuotaManager, + PersistenceType aPersistenceType, + const nsACString& aGroup, + const nsACString& aOrigin, + UsageInfo* aUsageInfo); + + // Subclasses use this override to set the IPDL response value. + virtual void + GetResponse(UsageRequestResponse& aResponse) = 0; + +private: + void + SendResults() override; + + // IPDL methods. + void + ActorDestroy(ActorDestroyReason aWhy) override; + + mozilla::ipc::IPCResult + RecvCancel() override; +}; + +class GetUsageOp final + : public QuotaUsageRequestBase +{ + nsTArray mOriginUsages; + nsDataHashtable mOriginUsagesIndex; + + bool mGetAll; + +public: + explicit GetUsageOp(const UsageRequestParams& aParams); + +private: + ~GetUsageOp() + { } + + nsresult + TraverseRepository(QuotaManager* aQuotaManager, + PersistenceType aPersistenceType); + + nsresult + DoDirectoryWork(QuotaManager* aQuotaManager) override; + + void + GetResponse(UsageRequestResponse& aResponse) override; +}; + +class GetOriginUsageOp final + : public QuotaUsageRequestBase { // If mGetGroupUsage is false, we use mUsageInfo to record the origin usage // and the file usage. Otherwise, we use it to record the group usage and the // limit. UsageInfo mUsageInfo; - const UsageParams mParams; + const OriginUsageParams mParams; nsCString mSuffix; nsCString mGroup; bool mGetGroupUsage; public: - explicit GetUsageOp(const UsageRequestParams& aParams); + explicit GetOriginUsageOp(const UsageRequestParams& aParams); MOZ_IS_CLASS_INIT bool - Init(Quota* aQuota); + Init(Quota* aQuota) override; private: - ~GetUsageOp() + ~GetOriginUsageOp() { } MOZ_IS_CLASS_INIT virtual nsresult DoInitOnMainThread() override; - nsresult - AddToUsage(QuotaManager* aQuotaManager, - PersistenceType aPersistenceType); - virtual nsresult DoDirectoryWork(QuotaManager* aQuotaManager) override; - virtual void - SendResults() override; - - // IPDL methods. - virtual void - ActorDestroy(ActorDestroyReason aWhy) override; - - virtual mozilla::ipc::IPCResult - RecvCancel() override; + void + GetResponse(UsageRequestResponse& aResponse) override; }; class QuotaRequestBase @@ -4196,7 +4251,11 @@ QuotaManager::InitializeOrigin(PersistenceType aPersistenceType, return NS_ERROR_UNEXPECTED; } - rv = mClients[clientType]->InitOrigin(aPersistenceType, aGroup, aOrigin, + Atomic dummy(false); + rv = mClients[clientType]->InitOrigin(aPersistenceType, + aGroup, + aOrigin, + /* aCanceled */ dummy, usageInfo); NS_ENSURE_SUCCESS(rv, rv); } @@ -5296,10 +5355,9 @@ QuotaManager::GetInfoForChrome(nsACString* aSuffix, // static bool -QuotaManager::IsOriginWhitelistedForPersistentStorage(const nsACString& aOrigin) +QuotaManager::IsOriginInternal(const nsACString& aOrigin) { - // The first prompt and quota tracking is not required for these origins in - // persistent storage. + // The first prompt is not required for these origins. if (aOrigin.EqualsLiteral(kChromeOrigin) || StringBeginsWith(aOrigin, nsDependentCString(kAboutHomeOriginPrefix)) || StringBeginsWith(aOrigin, nsDependentCString(kIndexedDBOriginPrefix)) || @@ -6230,7 +6288,25 @@ Quota::ActorDestroy(ActorDestroyReason aWhy) PQuotaUsageRequestParent* Quota::AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams) { - RefPtr actor = new GetUsageOp(aParams); + AssertIsOnBackgroundThread(); + MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None); + + RefPtr actor; + + switch (aParams.type()) { + case UsageRequestParams::TAllUsageParams: + actor = new GetUsageOp(aParams); + break; + + case UsageRequestParams::TOriginUsageParams: + actor = new GetOriginUsageOp(aParams); + break; + + default: + MOZ_CRASH("Should never get here!"); + } + + MOZ_ASSERT(actor); // Transfer ownership to IPDL. return actor.forget().take(); @@ -6244,7 +6320,7 @@ Quota::RecvPQuotaUsageRequestConstructor(PQuotaUsageRequestParent* aActor, MOZ_ASSERT(aActor); MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None); - auto* op = static_cast(aActor); + auto* op = static_cast(aActor); if (NS_WARN_IF(!op->Init(this))) { return IPC_FAIL_NO_REASON(this); @@ -6261,8 +6337,8 @@ Quota::DeallocPQuotaUsageRequestParent(PQuotaUsageRequestParent* aActor) MOZ_ASSERT(aActor); // Transfer ownership back from IPDL. - RefPtr actor = - dont_AddRef(static_cast(aActor)); + RefPtr actor = + dont_AddRef(static_cast(aActor)); return true; } @@ -6336,6 +6412,7 @@ Quota::RecvPQuotaRequestConstructor(PQuotaRequestParent* aActor, MOZ_ASSERT(aParams.type() != RequestParams::T__None); auto* op = static_cast(aActor); + if (NS_WARN_IF(!op->Init(this))) { return IPC_FAIL_NO_REASON(this); } @@ -6414,67 +6491,32 @@ Quota::RecvStopIdleMaintenance() return IPC_OK(); } -GetUsageOp::GetUsageOp(const UsageRequestParams& aParams) - : NormalOriginOperationBase(Nullable(), - OriginScope::FromNull(), - /* aExclusive */ false) - , mParams(aParams.get_UsageParams()) - , mGetGroupUsage(aParams.get_UsageParams().getGroupUsage()) -{ - AssertIsOnOwningThread(); - MOZ_ASSERT(aParams.type() == UsageRequestParams::TUsageParams); -} - bool -GetUsageOp::Init(Quota* aQuota) +QuotaUsageRequestBase::Init(Quota* aQuota) { AssertIsOnOwningThread(); MOZ_ASSERT(aQuota); - mNeedsMainThreadInit = true; mNeedsQuotaManagerInit = true; return true; } nsresult -GetUsageOp::DoInitOnMainThread() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(GetState() == State_Initializing); - MOZ_ASSERT(mNeedsMainThreadInit); - - const PrincipalInfo& principalInfo = mParams.principalInfo(); - - nsresult rv; - nsCOMPtr principal = - PrincipalInfoToPrincipal(principalInfo, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - // Figure out which origin we're dealing with. - nsCString origin; - rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup, - &origin); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - mOriginScope.SetFromOrigin(origin); - - return NS_OK; -} - -nsresult -GetUsageOp::AddToUsage(QuotaManager* aQuotaManager, - PersistenceType aPersistenceType) +QuotaUsageRequestBase::GetUsageForOrigin(QuotaManager* aQuotaManager, + PersistenceType aPersistenceType, + const nsACString& aGroup, + const nsACString& aOrigin, + UsageInfo* aUsageInfo) { AssertIsOnIOThread(); + MOZ_ASSERT(aQuotaManager); + MOZ_ASSERT(aUsageInfo); + MOZ_ASSERT(aUsageInfo->TotalUsage() == 0); nsCOMPtr directory; nsresult rv = aQuotaManager->GetDirectoryForOrigin(aPersistenceType, - mOriginScope.GetOrigin(), + aOrigin, getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, rv); @@ -6484,12 +6526,11 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager, // If the directory exists then enumerate all the files inside, adding up // the sizes to get the final usage statistic. - if (exists && !mUsageInfo.Canceled()) { + if (exists && !mCanceled) { bool initialized; if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) { - initialized = - aQuotaManager->IsOriginInitialized(mOriginScope.GetOrigin()); + initialized = aQuotaManager->IsOriginInitialized(aOrigin); } else { initialized = aQuotaManager->IsTemporaryStorageInitialized(); } @@ -6500,7 +6541,7 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager, bool hasMore; while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && - hasMore && !mUsageInfo.Canceled()) { + hasMore && !mCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); NS_ENSURE_SUCCESS(rv, rv); @@ -6562,15 +6603,17 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager, if (initialized) { rv = client->GetUsageForOrigin(aPersistenceType, - mGroup, - mOriginScope.GetOrigin(), - &mUsageInfo); + aGroup, + aOrigin, + mCanceled, + aUsageInfo); } else { rv = client->InitOrigin(aPersistenceType, - mGroup, - mOriginScope.GetOrigin(), - &mUsageInfo); + aGroup, + aOrigin, + mCanceled, + aUsageInfo); } NS_ENSURE_SUCCESS(rv, rv); } @@ -6579,17 +6622,290 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager, return NS_OK; } +void +QuotaUsageRequestBase::SendResults() +{ + AssertIsOnOwningThread(); + + if (IsActorDestroyed()) { + if (NS_SUCCEEDED(mResultCode)) { + mResultCode = NS_ERROR_FAILURE; + } + } else { + if (mCanceled) { + mResultCode = NS_ERROR_FAILURE; + } + + UsageRequestResponse response; + + if (NS_SUCCEEDED(mResultCode)) { + GetResponse(response); + } else { + response = mResultCode; + } + + Unused << PQuotaUsageRequestParent::Send__delete__(this, response); + } +} + +void +QuotaUsageRequestBase::ActorDestroy(ActorDestroyReason aWhy) +{ + AssertIsOnOwningThread(); + + NoteActorDestroyed(); +} + +mozilla::ipc::IPCResult +QuotaUsageRequestBase::RecvCancel() +{ + AssertIsOnOwningThread(); + + if (mCanceled.exchange(true)) { + NS_WARNING("Canceled more than once?!"); + return IPC_FAIL_NO_REASON(this); + } + + return IPC_OK(); +} + +GetUsageOp::GetUsageOp(const UsageRequestParams& aParams) + : mGetAll(aParams.get_AllUsageParams().getAll()) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams); +} + +nsresult +GetUsageOp::TraverseRepository(QuotaManager* aQuotaManager, + PersistenceType aPersistenceType) +{ + AssertIsOnIOThread(); + MOZ_ASSERT(aQuotaManager); + + nsresult rv; + + nsCOMPtr directory = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool exists; + rv = directory->Exists(&exists); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!exists) { + return NS_OK; + } + + nsCOMPtr entries; + rv = directory->GetDirectoryEntries(getter_AddRefs(entries)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT; + + bool hasMore; + while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && + hasMore && !mCanceled) { + nsCOMPtr entry; + rv = entries->GetNext(getter_AddRefs(entry)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr originDir = do_QueryInterface(entry); + MOZ_ASSERT(originDir); + + bool isDirectory; + rv = originDir->IsDirectory(&isDirectory); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!isDirectory) { + nsString leafName; + rv = originDir->GetLeafName(leafName); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!IsOSMetadata(leafName)) { + UNKNOWN_FILE_WARNING(leafName); + } + continue; + } + + int64_t timestamp; + bool persisted; + nsCString suffix; + nsCString group; + nsCString origin; + rv = aQuotaManager->GetDirectoryMetadata2WithRestore(originDir, + persistent, + ×tamp, + &persisted, + suffix, + group, + origin); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!mGetAll && aQuotaManager->IsOriginInternal(origin)) { + continue; + } + + OriginUsage* originUsage; + + // We can't store pointers to OriginUsage objects in the hashtable + // since AppendElement() reallocates its internal array buffer as number + // of elements grows. + uint32_t index; + if (mOriginUsagesIndex.Get(origin, &index)) { + originUsage = &mOriginUsages[index]; + } else { + index = mOriginUsages.Length(); + + originUsage = mOriginUsages.AppendElement(); + + originUsage->origin() = origin; + originUsage->persisted() = false; + originUsage->usage() = 0; + + mOriginUsagesIndex.Put(origin, index); + } + + if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) { + originUsage->persisted() = persisted; + } + + UsageInfo usageInfo; + rv = GetUsageForOrigin(aQuotaManager, + aPersistenceType, + group, + origin, + &usageInfo); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + originUsage->usage() = originUsage->usage() + usageInfo.TotalUsage(); + } + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + nsresult GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) { AssertIsOnIOThread(); - MOZ_ASSERT(mUsageInfo.TotalUsage() == 0); PROFILER_LABEL("Quota", "GetUsageOp::DoDirectoryWork", js::ProfileEntry::Category::OTHER); nsresult rv; + for (const PersistenceType type : kAllPersistenceTypes) { + rv = TraverseRepository(aQuotaManager, type); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + return NS_OK; +} + +void +GetUsageOp::GetResponse(UsageRequestResponse& aResponse) +{ + AssertIsOnOwningThread(); + + aResponse = AllUsageResponse(); + + if (!mOriginUsages.IsEmpty()) { + nsTArray& originUsages = + aResponse.get_AllUsageResponse().originUsages(); + + mOriginUsages.SwapElements(originUsages); + } +} + +GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams) + : mParams(aParams.get_OriginUsageParams()) + , mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage()) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams); +} + +bool +GetOriginUsageOp::Init(Quota* aQuota) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aQuota); + + if (NS_WARN_IF(!QuotaUsageRequestBase::Init(aQuota))) { + return false; + } + + mNeedsMainThreadInit = true; + + return true; +} + +nsresult +GetOriginUsageOp::DoInitOnMainThread() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(GetState() == State_Initializing); + MOZ_ASSERT(mNeedsMainThreadInit); + + const PrincipalInfo& principalInfo = mParams.principalInfo(); + + nsresult rv; + nsCOMPtr principal = + PrincipalInfoToPrincipal(principalInfo, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Figure out which origin we're dealing with. + nsCString origin; + rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup, + &origin); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mOriginScope.SetFromOrigin(origin); + + return NS_OK; +} + +nsresult +GetOriginUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) +{ + AssertIsOnIOThread(); + MOZ_ASSERT(mUsageInfo.TotalUsage() == 0); + + PROFILER_LABEL("Quota", "GetOriginUsageOp::DoDirectoryWork", + js::ProfileEntry::Category::OTHER); + + nsresult rv; + if (mGetGroupUsage) { nsCOMPtr directory; @@ -6611,72 +6927,40 @@ GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) // Add all the persistent/temporary/default storage files we care about. for (const PersistenceType type : kAllPersistenceTypes) { - rv = AddToUsage(aQuotaManager, type); + UsageInfo usageInfo; + rv = GetUsageForOrigin(aQuotaManager, + type, + mGroup, + mOriginScope.GetOrigin(), + &usageInfo); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + + mUsageInfo.Append(usageInfo); } return NS_OK; } void -GetUsageOp::SendResults() +GetOriginUsageOp::GetResponse(UsageRequestResponse& aResponse) { AssertIsOnOwningThread(); - if (IsActorDestroyed()) { - if (NS_SUCCEEDED(mResultCode)) { - mResultCode = NS_ERROR_FAILURE; - } + OriginUsageResponse usageResponse; + + // We'll get the group usage when mGetGroupUsage is true and get the + // origin usage when mGetGroupUsage is false. + usageResponse.usage() = mUsageInfo.TotalUsage(); + + if (mGetGroupUsage) { + usageResponse.limit() = mUsageInfo.Limit(); } else { - if (mUsageInfo.Canceled()) { - mResultCode = NS_ERROR_FAILURE; - } - - UsageRequestResponse response; - - if (NS_SUCCEEDED(mResultCode)) { - UsageResponse usageResponse; - - // We'll get the group usage when mGetGroupUsage is true and get the - // origin usage when mGetGroupUsage is false. - usageResponse.usage() = mUsageInfo.TotalUsage(); - - if (mGetGroupUsage) { - usageResponse.limit() = mUsageInfo.Limit(); - } else { - usageResponse.fileUsage() = mUsageInfo.FileUsage(); - } - - response = usageResponse; - } else { - response = mResultCode; - } - - Unused << PQuotaUsageRequestParent::Send__delete__(this, response); - } -} - -void -GetUsageOp::ActorDestroy(ActorDestroyReason aWhy) -{ - AssertIsOnOwningThread(); - - NoteActorDestroyed(); -} - -mozilla::ipc::IPCResult -GetUsageOp::RecvCancel() -{ - AssertIsOnOwningThread(); - - nsresult rv = mUsageInfo.Cancel(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return IPC_FAIL_NO_REASON(this); + usageResponse.fileUsage() = mUsageInfo.FileUsage(); } - return IPC_OK(); + aResponse = usageResponse; } bool @@ -8185,9 +8469,7 @@ CreateOrUpgradeDirectoryMetadataHelper::CreateOrUpgradeMetadataFiles() } } else { - bool persistent = - QuotaManager::IsOriginWhitelistedForPersistentStorage( - originProps.mSpec); + bool persistent = QuotaManager::IsOriginInternal(originProps.mSpec); originProps.mTimestamp = GetLastModifiedTime(originDir, persistent); } @@ -8331,9 +8613,8 @@ CreateOrUpgradeDirectoryMetadataHelper::ProcessOriginDirectory( return rv; } - // Move whitelisted origins to new persistent storage. - if (QuotaManager::IsOriginWhitelistedForPersistentStorage( - aOriginProps.mSpec)) { + // Move internal origins to new persistent storage. + if (QuotaManager::IsOriginInternal(aOriginProps.mSpec)) { if (!mPermanentStorageDir) { mPermanentStorageDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); diff --git a/dom/quota/Client.h b/dom/quota/Client.h index b70d3e606914..4ee5ed228646 100644 --- a/dom/quota/Client.h +++ b/dom/quota/Client.h @@ -31,6 +31,8 @@ class UsageInfo; class Client { public: + typedef mozilla::Atomic AtomicBool; + NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING enum Type { @@ -100,12 +102,14 @@ public: InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) = 0; virtual nsresult GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) = 0; virtual void diff --git a/dom/quota/PQuota.ipdl b/dom/quota/PQuota.ipdl index 88333e5bee6b..566cb02eef76 100644 --- a/dom/quota/PQuota.ipdl +++ b/dom/quota/PQuota.ipdl @@ -27,7 +27,12 @@ struct InitOriginParams PersistenceType persistenceType; }; -struct UsageParams +struct AllUsageParams +{ + bool getAll; +}; + +struct OriginUsageParams { PrincipalInfo principalInfo; bool getGroupUsage; @@ -35,7 +40,8 @@ struct UsageParams union UsageRequestParams { - UsageParams; + AllUsageParams; + OriginUsageParams; }; struct ClearOriginParams diff --git a/dom/quota/PQuotaUsageRequest.ipdl b/dom/quota/PQuotaUsageRequest.ipdl index fbf7941c15d1..16994e627d1b 100644 --- a/dom/quota/PQuotaUsageRequest.ipdl +++ b/dom/quota/PQuotaUsageRequest.ipdl @@ -8,7 +8,19 @@ namespace mozilla { namespace dom { namespace quota { -struct UsageResponse +struct OriginUsage +{ + nsCString origin; + bool persisted; + uint64_t usage; +}; + +struct AllUsageResponse +{ + OriginUsage[] originUsages; +}; + +struct OriginUsageResponse { uint64_t usage; uint64_t fileUsage; @@ -18,7 +30,8 @@ struct UsageResponse union UsageRequestResponse { nsresult; - UsageResponse; + AllUsageResponse; + OriginUsageResponse; }; protocol PQuotaUsageRequest diff --git a/dom/quota/QuotaManager.h b/dom/quota/QuotaManager.h index 176ec5c3fe33..2d4c893cf1ce 100644 --- a/dom/quota/QuotaManager.h +++ b/dom/quota/QuotaManager.h @@ -398,7 +398,7 @@ public: nsACString* aOrigin); static bool - IsOriginWhitelistedForPersistentStorage(const nsACString& aOrigin); + IsOriginInternal(const nsACString& aOrigin); static void ChromeOrigin(nsACString& aOrigin); diff --git a/dom/quota/QuotaManagerService.cpp b/dom/quota/QuotaManagerService.cpp index 659d87a9e102..01be3f87e203 100644 --- a/dom/quota/QuotaManagerService.cpp +++ b/dom/quota/QuotaManagerService.cpp @@ -584,6 +584,31 @@ QuotaManagerService::InitStoragesForPrincipal( return NS_OK; } +NS_IMETHODIMP +QuotaManagerService::GetUsage(nsIQuotaUsageCallback* aCallback, + bool aGetAll, + nsIQuotaUsageRequest** _retval) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aCallback); + + RefPtr request = new UsageRequest(aCallback); + + AllUsageParams params; + + params.getAll() = aGetAll; + + nsAutoPtr info(new UsageRequestInfo(request, params)); + + nsresult rv = InitiateRequest(info); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + request.forget(_retval); + return NS_OK; +} + NS_IMETHODIMP QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback, @@ -596,7 +621,7 @@ QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, RefPtr request = new UsageRequest(aPrincipal, aCallback); - UsageParams params; + OriginUsageParams params; nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo()); diff --git a/dom/quota/QuotaRequests.cpp b/dom/quota/QuotaRequests.cpp index 10b36b04078d..c9c1cbff6764 100644 --- a/dom/quota/QuotaRequests.cpp +++ b/dom/quota/QuotaRequests.cpp @@ -91,13 +91,19 @@ RequestBase::GetResultCode(nsresult* aResultCode) return NS_OK; } +UsageRequest::UsageRequest(nsIQuotaUsageCallback* aCallback) + : mCallback(aCallback) + , mBackgroundActor(nullptr) + , mCanceled(false) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aCallback); +} + UsageRequest::UsageRequest(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback) : RequestBase(aPrincipal) , mCallback(aCallback) - , mUsage(0) - , mFileUsage(0) - , mLimit(0) , mBackgroundActor(nullptr) , mCanceled(false) { @@ -126,14 +132,14 @@ UsageRequest::SetBackgroundActor(QuotaUsageRequestChild* aBackgroundActor) } void -UsageRequest::SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit) +UsageRequest::SetResult(nsIVariant* aResult) { AssertIsOnOwningThread(); + MOZ_ASSERT(aResult); MOZ_ASSERT(!mHaveResultOrErrorCode); - mUsage = aUsage; - mFileUsage = aFileUsage; - mLimit = aLimit; + mResult = aResult; + mHaveResultOrErrorCode = true; FireCallback(); @@ -149,43 +155,18 @@ NS_IMPL_ADDREF_INHERITED(UsageRequest, RequestBase) NS_IMPL_RELEASE_INHERITED(UsageRequest, RequestBase) NS_IMETHODIMP -UsageRequest::GetUsage(uint64_t* aUsage) +UsageRequest::GetResult(nsIVariant** aResult) { AssertIsOnOwningThread(); + MOZ_ASSERT(aResult); if (!mHaveResultOrErrorCode) { return NS_ERROR_FAILURE; } - *aUsage = mUsage; - return NS_OK; -} + MOZ_ASSERT(mResult); -NS_IMETHODIMP -UsageRequest::GetFileUsage(uint64_t* aFileUsage) -{ - AssertIsOnOwningThread(); - MOZ_ASSERT(aFileUsage); - - if (!mHaveResultOrErrorCode) { - return NS_ERROR_FAILURE; - } - - *aFileUsage = mFileUsage; - return NS_OK; -} - -NS_IMETHODIMP -UsageRequest::GetLimit(uint64_t* aLimit) -{ - AssertIsOnOwningThread(); - MOZ_ASSERT(aLimit); - - if (!mHaveResultOrErrorCode) { - return NS_ERROR_FAILURE; - } - - *aLimit = mLimit; + NS_ADDREF(*aResult = mResult); return NS_OK; } diff --git a/dom/quota/QuotaRequests.h b/dom/quota/QuotaRequests.h index 37c276039278..9a51a382085b 100644 --- a/dom/quota/QuotaRequests.h +++ b/dom/quota/QuotaRequests.h @@ -72,17 +72,15 @@ class UsageRequest final { nsCOMPtr mCallback; - uint64_t mUsage; - uint64_t mFileUsage; - - // Group Limit. - uint64_t mLimit; + nsCOMPtr mResult; QuotaUsageRequestChild* mBackgroundActor; bool mCanceled; public: + explicit UsageRequest(nsIQuotaUsageCallback* aCallback); + UsageRequest(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback); @@ -98,7 +96,7 @@ public: } void - SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit); + SetResult(nsIVariant* aResult); NS_DECL_ISUPPORTS_INHERITED NS_FORWARD_NSIQUOTAREQUESTBASE(RequestBase::) diff --git a/dom/quota/QuotaResults.cpp b/dom/quota/QuotaResults.cpp new file mode 100644 index 000000000000..f5dbbd657e2a --- /dev/null +++ b/dom/quota/QuotaResults.cpp @@ -0,0 +1,91 @@ +/* -*- 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 "QuotaResults.h" + +namespace mozilla { +namespace dom { +namespace quota { + +UsageResult::UsageResult(const nsACString& aOrigin, + bool aPersisted, + uint64_t aUsage) + : mOrigin(aOrigin) + , mUsage(aUsage) + , mPersisted(aPersisted) +{ +} + +NS_IMPL_ISUPPORTS(UsageResult, + nsIQuotaUsageResult) + +NS_IMETHODIMP +UsageResult::GetOrigin(nsACString& aOrigin) +{ + aOrigin = mOrigin; + return NS_OK; +} + +NS_IMETHODIMP +UsageResult::GetPersisted(bool* aPersisted) +{ + MOZ_ASSERT(aPersisted); + + *aPersisted = mPersisted; + return NS_OK; +} + +NS_IMETHODIMP +UsageResult::GetUsage(uint64_t* aUsage) +{ + MOZ_ASSERT(aUsage); + + *aUsage = mUsage; + return NS_OK; +} + +OriginUsageResult::OriginUsageResult(uint64_t aUsage, + uint64_t aFileUsage, + uint64_t aLimit) + : mUsage(aUsage) + , mFileUsage(aFileUsage) + , mLimit(aLimit) +{ +} + +NS_IMPL_ISUPPORTS(OriginUsageResult, + nsIQuotaOriginUsageResult) + +NS_IMETHODIMP +OriginUsageResult::GetUsage(uint64_t* aUsage) +{ + MOZ_ASSERT(aUsage); + + *aUsage = mUsage; + return NS_OK; +} + +NS_IMETHODIMP +OriginUsageResult::GetFileUsage(uint64_t* aFileUsage) +{ + MOZ_ASSERT(aFileUsage); + + *aFileUsage = mFileUsage; + return NS_OK; +} + +NS_IMETHODIMP +OriginUsageResult::GetLimit(uint64_t* aLimit) +{ + MOZ_ASSERT(aLimit); + + *aLimit = mLimit; + return NS_OK; +} + +} // namespace quota +} // namespace dom +} // namespace mozilla diff --git a/dom/quota/QuotaResults.h b/dom/quota/QuotaResults.h new file mode 100644 index 000000000000..73fe6b790174 --- /dev/null +++ b/dom/quota/QuotaResults.h @@ -0,0 +1,60 @@ +/* -*- 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 mozilla_dom_quota_QuotaResults_h +#define mozilla_dom_quota_QuotaResults_h + +#include "nsIQuotaResults.h" + +namespace mozilla { +namespace dom { +namespace quota { + +class UsageResult + : public nsIQuotaUsageResult +{ + nsCString mOrigin; + uint64_t mUsage; + bool mPersisted; + +public: + UsageResult(const nsACString& aOrigin, + bool aPersisted, + uint64_t aUsage); + +private: + virtual ~UsageResult() + { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIQUOTAUSAGERESULT +}; + +class OriginUsageResult + : public nsIQuotaOriginUsageResult +{ + uint64_t mUsage; + uint64_t mFileUsage; + uint64_t mLimit; + +public: + OriginUsageResult(uint64_t aUsage, + uint64_t aFileUsage, + uint64_t aLimit); + +private: + virtual ~OriginUsageResult() + { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIQUOTAORIGINUSAGERESULT +}; + +} // namespace quota +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_quota_QuotaResults_h diff --git a/dom/quota/StorageManager.cpp b/dom/quota/StorageManager.cpp index 988fac57409c..4e9f0cf8c6b2 100644 --- a/dom/quota/StorageManager.cpp +++ b/dom/quota/StorageManager.cpp @@ -133,20 +133,31 @@ GetStorageEstimate(nsIQuotaUsageRequest* aRequest, { MOZ_ASSERT(aRequest); - uint64_t usage; - nsresult rv = aRequest->GetUsage(&usage); + nsCOMPtr result; + nsresult rv = aRequest->GetResult(getter_AddRefs(result)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - uint64_t limit; - rv = aRequest->GetLimit(&limit); + nsID* iid; + nsCOMPtr supports; + rv = result->GetAsInterface(&iid, getter_AddRefs(supports)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - aStorageEstimate.mUsage.Construct() = usage; - aStorageEstimate.mQuota.Construct() = limit; + free(iid); + + nsCOMPtr originUsageResult = + do_QueryInterface(supports); + MOZ_ASSERT(originUsageResult); + + MOZ_ALWAYS_SUCCEEDS( + originUsageResult->GetUsage(&aStorageEstimate.mUsage.Construct())); + + MOZ_ALWAYS_SUCCEEDS( + originUsageResult->GetLimit(&aStorageEstimate.mQuota.Construct())); + return NS_OK; } diff --git a/dom/quota/UsageInfo.h b/dom/quota/UsageInfo.h index 688e168707fa..9d34f1bff61e 100644 --- a/dom/quota/UsageInfo.h +++ b/dom/quota/UsageInfo.h @@ -18,26 +18,19 @@ class UsageInfo { public: UsageInfo() - : mCanceled(false), mDatabaseUsage(0), mFileUsage(0), mLimit(0) + : mDatabaseUsage(0) + , mFileUsage(0) + , mLimit(0) { } virtual ~UsageInfo() { } - bool - Canceled() + void + Append(const UsageInfo& aUsageInfo) { - return mCanceled; - } - - nsresult - Cancel() - { - if (mCanceled.exchange(true)) { - NS_WARNING("Canceled more than once?!"); - return NS_ERROR_UNEXPECTED; - } - return NS_OK; + IncrementUsage(&mDatabaseUsage, aUsageInfo.mDatabaseUsage); + IncrementUsage(&mFileUsage, aUsageInfo.mFileUsage); } void @@ -104,9 +97,6 @@ public: } } -protected: - mozilla::Atomic mCanceled; - private: uint64_t mDatabaseUsage; uint64_t mFileUsage; diff --git a/dom/quota/moz.build b/dom/quota/moz.build index dca28101d3db..33c465666d4b 100644 --- a/dom/quota/moz.build +++ b/dom/quota/moz.build @@ -15,6 +15,7 @@ XPIDL_SOURCES += [ 'nsIQuotaCallbacks.idl', 'nsIQuotaManagerService.idl', 'nsIQuotaRequests.idl', + 'nsIQuotaResults.idl', ] XPIDL_MODULE = 'dom_quota' @@ -43,6 +44,7 @@ UNIFIED_SOURCES += [ 'FileStreams.cpp', 'QuotaManagerService.cpp', 'QuotaRequests.cpp', + 'QuotaResults.cpp', 'StorageManager.cpp', ] diff --git a/dom/quota/nsIQuotaManagerService.idl b/dom/quota/nsIQuotaManagerService.idl index 99a44476c6ec..b5c1869a9b68 100644 --- a/dom/quota/nsIQuotaManagerService.idl +++ b/dom/quota/nsIQuotaManagerService.idl @@ -41,6 +41,21 @@ interface nsIQuotaManagerService : nsISupports initStoragesForPrincipal(in nsIPrincipal aPrincipal, in ACString aPersistenceType); + /** + * Schedules an asynchronous callback that will inspect all origins and + * return the total amount of disk space being used by storages for each + * origin separately. + * + * @param aCallback + * The callback that will be called when the usage is available. + * @param aGetAll + * An optional boolean to indicate inspection of all origins, + * including internal ones. + */ + [must_use] nsIQuotaUsageRequest + getUsage(in nsIQuotaUsageCallback aCallback, + [optional] in boolean aGetAll); + /** * Schedules an asynchronous callback that will return the total amount of * disk space being used by storages for the given origin. diff --git a/dom/quota/nsIQuotaRequests.idl b/dom/quota/nsIQuotaRequests.idl index 4a3d8547ae11..5d7cff3b9350 100644 --- a/dom/quota/nsIQuotaRequests.idl +++ b/dom/quota/nsIQuotaRequests.idl @@ -22,11 +22,10 @@ interface nsIQuotaRequestBase : nsISupports [scriptable, uuid(166e28e6-cf6d-4927-a6d7-b51bca9d3469)] interface nsIQuotaUsageRequest : nsIQuotaRequestBase { - [must_use] readonly attribute unsigned long long usage; - - [must_use] readonly attribute unsigned long long fileUsage; - - [must_use] readonly attribute unsigned long long limit; + // The result can contain one of these types: + // array of nsIQuotaUsageResult + // nsIQuotaOriginUsageResult + [must_use] readonly attribute nsIVariant result; attribute nsIQuotaUsageCallback callback; @@ -37,6 +36,9 @@ interface nsIQuotaUsageRequest : nsIQuotaRequestBase [scriptable, uuid(22890e3e-ff25-4372-9684-d901060e2f6c)] interface nsIQuotaRequest : nsIQuotaRequestBase { + // The result can contain one of these types: + // void + // bool [must_use] readonly attribute nsIVariant result; attribute nsIQuotaCallback callback; diff --git a/dom/quota/nsIQuotaResults.idl b/dom/quota/nsIQuotaResults.idl new file mode 100644 index 000000000000..cd7ffd3a02c6 --- /dev/null +++ b/dom/quota/nsIQuotaResults.idl @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=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 "nsISupports.idl" + +[scriptable, function, uuid(d8c9328b-9aa8-4f5d-90e6-482de4a6d5b8)] +interface nsIQuotaUsageResult : nsISupports +{ + readonly attribute ACString origin; + + readonly attribute boolean persisted; + + readonly attribute unsigned long long usage; +}; + +[scriptable, function, uuid(96df03d2-116a-493f-bb0b-118c212a6b32)] +interface nsIQuotaOriginUsageResult : nsISupports +{ + readonly attribute unsigned long long usage; + + readonly attribute unsigned long long fileUsage; + + readonly attribute unsigned long long limit; +}; diff --git a/dom/quota/test/unit/getUsage_profile.zip b/dom/quota/test/unit/getUsage_profile.zip new file mode 100644 index 000000000000..5144112bde35 Binary files /dev/null and b/dom/quota/test/unit/getUsage_profile.zip differ diff --git a/dom/quota/test/unit/head.js b/dom/quota/test/unit/head.js index e3606c47dece..8413ffc9efb3 100644 --- a/dom/quota/test/unit/head.js +++ b/dom/quota/test/unit/head.js @@ -261,12 +261,24 @@ function getPersistedFromMetadata(readBuffer) return !!view[persistedPosition]; } -function grabUsageAndContinueHandler(request) +function grabResultAndContinueHandler(request) { - testGenerator.next(request.usage); + testGenerator.next(request.result); } -function getUsage(usageHandler) +function grabUsageAndContinueHandler(request) +{ + testGenerator.next(request.result.usage); +} + +function getUsage(usageHandler, getAll) +{ + let request = SpecialPowers._getQuotaManager().getUsage(usageHandler, getAll); + + return request; +} + +function getCurrentUsage(usageHandler) { let principal = Cc["@mozilla.org/systemprincipal;1"] .createInstance(Ci.nsIPrincipal); diff --git a/dom/quota/test/unit/test_basics.js b/dom/quota/test/unit/test_basics.js index f23898c45abc..29aadf1fe11c 100644 --- a/dom/quota/test/unit/test_basics.js +++ b/dom/quota/test/unit/test_basics.js @@ -38,7 +38,7 @@ function* testSteps() info("Getting usage"); - getUsage(grabUsageAndContinueHandler); + getCurrentUsage(grabUsageAndContinueHandler); let usage = yield undefined; ok(usage == 0, "Usage is zero"); @@ -53,7 +53,7 @@ function* testSteps() info("Getting usage"); - getUsage(grabUsageAndContinueHandler); + getCurrentUsage(grabUsageAndContinueHandler); usage = yield undefined; ok(usage > 0, "Usage is not zero"); diff --git a/dom/quota/test/unit/test_getUsage.js b/dom/quota/test/unit/test_getUsage.js new file mode 100644 index 000000000000..37d9d197a47b --- /dev/null +++ b/dom/quota/test/unit/test_getUsage.js @@ -0,0 +1,127 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var testGenerator = testSteps(); + +function* testSteps() +{ + const origins = [ + { + origin: "http://example.com", + persisted: false, + usage: 49152 + }, + + { + origin: "http://localhost", + persisted: false, + usage: 147456 + }, + + { + origin: "http://www.mozilla.org", + persisted: true, + usage: 98304 + } + ]; + + const allOrigins = [ + { + origin: "chrome", + persisted: false, + usage: 147456 + }, + + { + origin: "http://example.com", + persisted: false, + usage: 49152 + }, + + { + origin: "http://localhost", + persisted: false, + usage: 147456 + }, + + { + origin: "http://www.mozilla.org", + persisted: true, + usage: 98304 + } + ]; + + function verifyResult(result, origins) { + ok(result instanceof Array, "Got an array object"); + ok(result.length == origins.length, "Correct number of elements"); + + info("Sorting elements"); + + result.sort(function(a, b) { + let originA = a.origin + let originB = b.origin + + if (originA < originB) { + return -1; + } + if (originA > originB) { + return 1; + } + return 0; + }); + + info("Verifying elements"); + + for (let i = 0; i < result.length; i++) { + let a = result[i]; + let b = origins[i]; + ok(a.origin == b.origin, "Origin equals"); + ok(a.persisted == b.persisted, "Persisted equals"); + ok(a.usage == b.usage, "Usage equals"); + } + } + + info("Clearing"); + + clear(continueToNextStepSync); + yield undefined; + + info("Getting usage"); + + getUsage(grabResultAndContinueHandler, /* getAll */ true); + let result = yield undefined; + + info("Verifying result"); + + verifyResult(result, []); + + info("Installing package"); + + // The profile contains IndexedDB databases placed across the repositories. + // The file create_db.js in the package was run locally, specifically it was + // temporarily added to xpcshell.ini and then executed: + // mach xpcshell-test --interactive dom/quota/test/unit/create_db.js + installPackage("getUsage_profile"); + + info("Getting usage"); + + getUsage(grabResultAndContinueHandler, /* getAll */ false); + result = yield undefined; + + info("Verifying result"); + + verifyResult(result, origins); + + info("Getting usage"); + + getUsage(grabResultAndContinueHandler, /* getAll */ true); + result = yield undefined; + + info("Verifying result"); + + verifyResult(result, allOrigins); + + finishTest(); +} diff --git a/dom/quota/test/unit/test_unknownFiles.js b/dom/quota/test/unit/test_unknownFiles.js index 8eef05b83024..e14af9695cdf 100644 --- a/dom/quota/test/unit/test_unknownFiles.js +++ b/dom/quota/test/unit/test_unknownFiles.js @@ -131,7 +131,7 @@ function* testSteps() info("Getting usage"); - request = getUsage(continueToNextStepSync); + request = getCurrentUsage(continueToNextStepSync); yield undefined; ok(request.resultCode == NS_ERROR_UNEXPECTED, "Get usage failed"); @@ -140,7 +140,7 @@ function* testSteps() info("Getting usage"); - request = getUsage(continueToNextStepSync); + request = getCurrentUsage(continueToNextStepSync); yield undefined; ok(request.resultCode == NS_OK, "Get usage succeeded"); @@ -156,7 +156,7 @@ function* testSteps() info("Getting usage"); - request = getUsage(continueToNextStepSync); + request = getCurrentUsage(continueToNextStepSync); yield undefined; ok(request.resultCode == NS_OK, "Get usage succeeded"); diff --git a/dom/quota/test/unit/xpcshell.ini b/dom/quota/test/unit/xpcshell.ini index 1ad1b8ff0edb..fc825a035c30 100644 --- a/dom/quota/test/unit/xpcshell.ini +++ b/dom/quota/test/unit/xpcshell.ini @@ -7,6 +7,7 @@ head = head.js support-files = basics_profile.zip defaultStorageUpgrade_profile.zip + getUsage_profile.zip idbSubdirUpgrade1_profile.zip idbSubdirUpgrade2_profile.zip morgueCleanup_profile.zip @@ -18,6 +19,7 @@ support-files = [test_basics.js] [test_defaultStorageUpgrade.js] +[test_getUsage.js] [test_idbSubdirUpgrade.js] [test_morgueCleanup.js] [test_obsoleteOriginAttributesUpgrade.js] diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp index b5bb2109f28e..3aa3e0ed0e38 100644 --- a/dom/security/nsCSPService.cpp +++ b/dom/security/nsCSPService.cpp @@ -20,7 +20,6 @@ #include "nsIScriptError.h" #include "nsContentUtils.h" #include "nsContentPolicyUtils.h" -#include "nsPrincipal.h" using namespace mozilla; diff --git a/dom/security/test/csp/file_upgrade_insecure.html b/dom/security/test/csp/file_upgrade_insecure.html index 0daaa853ebb2..e3243c1bbe9c 100644 --- a/dom/security/test/csp/file_upgrade_insecure.html +++ b/dom/security/test/csp/file_upgrade_insecure.html @@ -57,6 +57,7 @@ else { window.parent.postMessage({result: "websocket-error"}, "*"); } + mySocket.close(); }; mySocket.onerror = function(e) { // debug information for Bug 1316305 diff --git a/dom/security/test/csp/file_upgrade_insecure_meta.html b/dom/security/test/csp/file_upgrade_insecure_meta.html index 5f65e78ec30b..15f565a6b8a7 100644 --- a/dom/security/test/csp/file_upgrade_insecure_meta.html +++ b/dom/security/test/csp/file_upgrade_insecure_meta.html @@ -58,6 +58,7 @@ else { window.parent.postMessage({result: "websocket-error"}, "*"); } + mySocket.close(); }; mySocket.onerror = function(e) { window.parent.postMessage({result: "websocket-unexpected-error"}, "*"); diff --git a/dom/worklet/Worklet.cpp b/dom/worklet/Worklet.cpp index 133ad8cf9224..77b8a9647ba6 100644 --- a/dom/worklet/Worklet.cpp +++ b/dom/worklet/Worklet.cpp @@ -205,9 +205,6 @@ public: compileOptions.setFileAndLine(NS_ConvertUTF16toUTF8(mURL).get(), 0); compileOptions.setVersion(JSVERSION_DEFAULT); compileOptions.setIsRunOnce(true); - - // We only need the setNoScriptRval bit when compiling off-thread here, - // since otherwise nsJSUtils::EvaluateString will set it up for us. compileOptions.setNoScriptRval(true); JSAutoCompartment comp(cx, globalObj); diff --git a/dom/xbl/nsXBLProtoImplField.cpp b/dom/xbl/nsXBLProtoImplField.cpp index cc4d0c7591d8..8860deec1019 100644 --- a/dom/xbl/nsXBLProtoImplField.cpp +++ b/dom/xbl/nsXBLProtoImplField.cpp @@ -427,14 +427,19 @@ nsXBLProtoImplField::InstallField(JS::Handle aBoundNode, JS::CompileOptions options(cx); options.setFileAndLine(uriSpec.get(), mLineNumber) .setVersion(JSVERSION_LATEST); - nsJSUtils::EvaluateOptions evalOptions(cx); - if (!nsJSUtils::GetScopeChainForElement(cx, boundElement, - evalOptions.scopeChain)) { + JS::AutoObjectVector scopeChain(cx); + if (!nsJSUtils::GetScopeChainForElement(cx, boundElement, scopeChain)) { return NS_ERROR_OUT_OF_MEMORY; } - rv = nsJSUtils::EvaluateString(cx, nsDependentString(mFieldText, - mFieldTextLength), - scopeObject, options, evalOptions, &result); + rv = NS_OK; + { + nsJSUtils::ExecutionContext exec(cx, scopeObject); + exec.SetScopeChain(scopeChain); + exec.CompileAndExec(options, nsDependentString(mFieldText, + mFieldTextLength)); + rv = exec.ExtractReturnValue(&result); + } + if (NS_FAILED(rv)) { return rv; } diff --git a/dom/xslt/xslt/txExecutionState.cpp b/dom/xslt/xslt/txExecutionState.cpp index ed57c79351dd..a32fdb0b8065 100644 --- a/dom/xslt/xslt/txExecutionState.cpp +++ b/dom/xslt/xslt/txExecutionState.cpp @@ -87,7 +87,10 @@ txExecutionState::~txExecutionState() txStackIterator handlerIter(&mResultHandlerStack); while (handlerIter.hasNext()) { - delete (txAXMLEventHandler*)handlerIter.next(); + txAXMLEventHandler* handler = (txAXMLEventHandler*)handlerIter.next(); + if (handler != mObsoleteHandler) { + delete handler; + } } txStackIterator paramIter(&mParamStack); @@ -159,6 +162,17 @@ txExecutionState::end(nsresult aResult) return mOutputHandler->endDocument(aResult); } +void +txExecutionState::popAndDeleteEvalContext() +{ + if (!mEvalContextStack.isEmpty()) { + auto ctx = popEvalContext(); + if (ctx != mInitialEvalContext) { + delete ctx; + } + } +} + void txExecutionState::popAndDeleteEvalContextUntil(txIEvalContext* aContext) { diff --git a/dom/xslt/xslt/txExecutionState.h b/dom/xslt/xslt/txExecutionState.h index 44f1918c86b0..3aa6d5a660bf 100644 --- a/dom/xslt/xslt/txExecutionState.h +++ b/dom/xslt/xslt/txExecutionState.h @@ -95,6 +95,8 @@ public: nsresult pushEvalContext(txIEvalContext* aContext); txIEvalContext* popEvalContext(); + void popAndDeleteEvalContext(); + /** * Helper that deletes all entries before |aContext| and then * pops it off the stack. The caller must delete |aContext| if diff --git a/dom/xslt/xslt/txInstructions.cpp b/dom/xslt/xslt/txInstructions.cpp index 38253e0cb332..f769680474f3 100644 --- a/dom/xslt/xslt/txInstructions.cpp +++ b/dom/xslt/xslt/txInstructions.cpp @@ -37,16 +37,7 @@ txApplyDefaultElementTemplate::execute(txExecutionState& aEs) } nsresult -txApplyImportsEnd::execute(txExecutionState& aEs) -{ - aEs.popTemplateRule(); - aEs.popParamMap(); - - return NS_OK; -} - -nsresult -txApplyImportsStart::execute(txExecutionState& aEs) +txApplyImports::execute(txExecutionState& aEs) { txExecutionState::TemplateRule* rule = aEs.getCurrentTemplateRule(); // The frame is set to null when there is no current template rule, or @@ -68,7 +59,12 @@ txApplyImportsStart::execute(txExecutionState& aEs) aEs.pushTemplateRule(frame, mode, rule->mParams); - return aEs.runTemplate(templ); + rv = aEs.runTemplate(templ); + + aEs.popTemplateRule(); + aEs.popParamMap(); + + return rv; } txApplyTemplates::txApplyTemplates(const txExpandedName& aMode) @@ -474,7 +470,7 @@ txLoopNodeSet::execute(txExecutionState& aEs) txNodeSetContext* context = static_cast(aEs.getEvalContext()); if (!context->hasNext()) { - delete aEs.popEvalContext(); + aEs.popAndDeleteEvalContext(); return NS_OK; } diff --git a/dom/xslt/xslt/txInstructions.h b/dom/xslt/xslt/txInstructions.h index 55138a600a54..d363400e868c 100644 --- a/dom/xslt/xslt/txInstructions.h +++ b/dom/xslt/xslt/txInstructions.h @@ -47,13 +47,7 @@ public: TX_DECL_TXINSTRUCTION }; -class txApplyImportsEnd : public txInstruction -{ -public: - TX_DECL_TXINSTRUCTION -}; - -class txApplyImportsStart : public txInstruction +class txApplyImports : public txInstruction { public: TX_DECL_TXINSTRUCTION diff --git a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp index f447df7cfc46..4d451e3c303f 100644 --- a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp +++ b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp @@ -1312,8 +1312,7 @@ txFnText(const nsAString& aStr, txStylesheetCompilerState& aState) /* xsl:apply-imports - txApplyImportsStart - txApplyImportsEnd + txApplyImports */ static nsresult txFnStartApplyImports(int32_t aNamespaceID, @@ -1325,11 +1324,7 @@ txFnStartApplyImports(int32_t aNamespaceID, { nsresult rv = NS_OK; - nsAutoPtr instr(new txApplyImportsStart); - rv = aState.addInstruction(Move(instr)); - NS_ENSURE_SUCCESS(rv, rv); - - instr = new txApplyImportsEnd; + nsAutoPtr instr(new txApplyImports); rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/extensions/gio/nsGIOProtocolHandler.cpp b/extensions/gio/nsGIOProtocolHandler.cpp index 793f80267014..eae6e1da0fe5 100644 --- a/extensions/gio/nsGIOProtocolHandler.cpp +++ b/extensions/gio/nsGIOProtocolHandler.cpp @@ -24,7 +24,7 @@ #include "nsIChannel.h" #include "nsIInputStream.h" #include "nsIProtocolHandler.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/Monitor.h" #include "plstr.h" #include "prtime.h" diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp index 6d3688ac05f3..370ac98d1ffe 100644 --- a/gfx/2d/RecordedEvent.cpp +++ b/gfx/2d/RecordedEvent.cpp @@ -1299,6 +1299,10 @@ RecordedSourceSurfaceCreation::~RecordedSourceSurfaceCreation() bool RecordedSourceSurfaceCreation::PlayEvent(Translator *aTranslator) const { + if (!mData) { + return false; + } + RefPtr src = aTranslator->GetReferenceDrawTarget()-> CreateSourceSurfaceFromData(mData, mSize, mSize.width * BytesPerPixel(mFormat), mFormat); aTranslator->AddSourceSurface(mRefPtr, src); @@ -1311,6 +1315,7 @@ RecordedSourceSurfaceCreation::RecordToStream(ostream &aStream) const WriteElement(aStream, mRefPtr); WriteElement(aStream, mSize); WriteElement(aStream, mFormat); + MOZ_ASSERT(mData); for (int y = 0; y < mSize.height; y++) { aStream.write((const char*)mData + y * mStride, BytesPerPixel(mFormat) * mSize.width); } @@ -1322,8 +1327,12 @@ RecordedSourceSurfaceCreation::RecordedSourceSurfaceCreation(istream &aStream) ReadElement(aStream, mRefPtr); ReadElement(aStream, mSize); ReadElement(aStream, mFormat); - mData = (uint8_t*)new char[mSize.width * mSize.height * BytesPerPixel(mFormat)]; - aStream.read((char*)mData, mSize.width * mSize.height * BytesPerPixel(mFormat)); + mData = (uint8_t*)new (fallible) char[mSize.width * mSize.height * BytesPerPixel(mFormat)]; + if (!mData) { + gfxWarning() << "RecordedSourceSurfaceCreation failed to allocate data"; + } else { + aStream.read((char*)mData, mSize.width * mSize.height * BytesPerPixel(mFormat)); + } } void diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp index 6cfcf9797ff7..c502f9f0827e 100644 --- a/gfx/gl/GLLibraryEGL.cpp +++ b/gfx/gl/GLLibraryEGL.cpp @@ -154,7 +154,7 @@ IsAccelAngleSupported(const nsCOMPtr& gfxInfo, if (CompositorThreadHolder::IsInCompositorThread()) { // We can only enter here with WebRender, so assert that this is a // WebRender-enabled build. -#ifndef MOZ_ENABLE_WEBRENDER +#ifndef MOZ_BUILD_WEBRENDER MOZ_ASSERT(false); #endif return true; diff --git a/gfx/layers/LayersTypes.h b/gfx/layers/LayersTypes.h index f9ac335c1c9b..adc70fefb9f3 100644 --- a/gfx/layers/LayersTypes.h +++ b/gfx/layers/LayersTypes.h @@ -46,7 +46,6 @@ enum class LayersBackend : int8_t { LAYERS_NONE = 0, LAYERS_BASIC, LAYERS_OPENGL, - LAYERS_D3D9, LAYERS_D3D11, LAYERS_CLIENT, LAYERS_WR, diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 19683a6c82b3..03d406b5b924 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -336,9 +336,7 @@ TexClientFromReadback(SharedSurface* src, CompositableForwarder* allocator, // RB_SWAPPED doesn't work with D3D11. (bug 1051010) // RB_SWAPPED doesn't work with Basic. (bug ???????) - // RB_SWAPPED doesn't work with D3D9. (bug ???????) bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_BASIC || - layersBackend == LayersBackend::LAYERS_D3D9 || layersBackend == LayersBackend::LAYERS_D3D11; if (texClient->HasFlags(TextureFlags::RB_SWAPPED) && layersNeedsManualSwap) diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index 9a57682b0b5f..08fe6c4d2b13 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -826,7 +826,6 @@ ClientLayerManager::GetBackendName(nsAString& aName) case LayersBackend::LAYERS_NONE: aName.AssignLiteral("None"); return; case LayersBackend::LAYERS_BASIC: aName.AssignLiteral("Basic"); return; case LayersBackend::LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return; - case LayersBackend::LAYERS_D3D9: aName.AssignLiteral("Direct3D 9"); return; case LayersBackend::LAYERS_D3D11: { #ifdef XP_WIN if (DeviceManagerDx::Get()->IsWARP()) { diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 69384ae7ebde..1d2840920d84 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -61,7 +61,6 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder) { LayersBackend backend = aForwarder->GetCompositorBackendType(); if (backend != LayersBackend::LAYERS_OPENGL && - backend != LayersBackend::LAYERS_D3D9 && backend != LayersBackend::LAYERS_D3D11 && backend != LayersBackend::LAYERS_WR && backend != LayersBackend::LAYERS_BASIC) { diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index b30b9405e04f..812f126319a0 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1579,7 +1579,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel TextureFactoryIdentifier* aTextureFactoryIdentifier, uint32_t* aIdNamespace) { -#ifndef MOZ_ENABLE_WEBRENDER +#ifndef MOZ_BUILD_WEBRENDER // Extra guard since this in the parent process and we don't want a malicious // child process invoking this codepath before it's ready MOZ_RELEASE_ASSERT(false); @@ -1614,7 +1614,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel bool CompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) { -#ifndef MOZ_ENABLE_WEBRENDER +#ifndef MOZ_BUILD_WEBRENDER // Extra guard since this in the parent process and we don't want a malicious // child process invoking this codepath before it's ready MOZ_RELEASE_ASSERT(false); diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp index 3f5d968589aa..9369d7317acf 100644 --- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp @@ -203,7 +203,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli TextureFactoryIdentifier* aTextureFactoryIdentifier, uint32_t *aIdNamespace) { -#ifndef MOZ_ENABLE_WEBRENDER +#ifndef MOZ_BUILD_WEBRENDER // Extra guard since this in the parent process and we don't want a malicious // child process invoking this codepath before it's ready MOZ_RELEASE_ASSERT(false); @@ -238,7 +238,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli bool CrossProcessCompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor) { -#ifndef MOZ_ENABLE_WEBRENDER +#ifndef MOZ_BUILD_WEBRENDER // Extra guard since this in the parent process and we don't want a malicious // child process invoking this codepath before it's ready MOZ_RELEASE_ASSERT(false); diff --git a/gfx/skia/skia/src/core/SkScan_Path.cpp b/gfx/skia/skia/src/core/SkScan_Path.cpp index a3116bb92922..5b80492cfa28 100644 --- a/gfx/skia/skia/src/core/SkScan_Path.cpp +++ b/gfx/skia/skia/src/core/SkScan_Path.cpp @@ -592,29 +592,35 @@ static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) { } /** - * Variant of SkScalarRoundToInt, identical to SkDScalarRoundToInt except when the input fraction - * is 0.5. In this case only, round the value down. This is used to round the top and left - * of a rectangle, and corresponds to the way the scan converter treats the top and left edges. + * Variants of SkScalarRoundToInt, identical to SkDScalarRoundToInt except when the input fraction + * is 0.5. When SK_RASTERIZE_EVEN_ROUNDING is enabled, we must bias the result before rounding to + * account for potential FDot6 rounding edge-cases. + */ +#ifdef SK_RASTERIZE_EVEN_ROUNDING +static const double kRoundBias = 0.5 / SK_FDot6One; +#else +static const double kRoundBias = 0.0; +#endif + +/** + * Round the value down. This is used to round the top and left of a rectangle, + * and corresponds to the way the scan converter treats the top and left edges. */ static inline int round_down_to_int(SkScalar x) { double xx = x; - xx += 0.5; - double floorXX = floor(xx); - return (int)floorXX - (xx == floorXX); + xx -= 0.5 + kRoundBias; + return (int)ceil(xx); } -#ifdef SK_RASTERIZE_EVEN_ROUNDING /** - * Variant of SkDScalarRoundToInt that allows offseting the input by a small fraction - * while trying to preserve intermediate double-precision (rather than directly adding - * the bias to the input at lower single-precision). + * Round the value up. This is used to round the bottom and right of a rectangle, + * and corresponds to the way the scan converter treats the bottom and right edges. */ -static inline int round_biased_to_int(SkScalar x, SkScalar bias) { +static inline int round_up_to_int(SkScalar x) { double xx = x; - xx += 0.5 + bias; + xx += 0.5 + kRoundBias; return (int)floor(xx); } -#endif /** * Variant of SkRect::round() that explicitly performs the rounding step (i.e. floor(x + 0.5)) @@ -635,26 +641,21 @@ static inline int round_biased_to_int(SkScalar x, SkScalar bias) { * SkASSERT(0 == iright); // <--- succeeds * * - * If using SK_RASTERIZE_EVEN_ROUNDING, we need to ensure that bottom and right account for - * edges bounded by this rect being rounded to FDot6 format before being later rounded to an - * integer. For example, a value like 0.499 can be below 0.5, but round to 0.5 as FDot6, which - * would finally round to the integer 1, instead of just rounding to 0. + * If using SK_RASTERIZE_EVEN_ROUNDING, we need to ensure we account for edges bounded by this + * rect being rounded to FDot6 format before being later rounded to an integer. For example, a + * value like 0.499 can be below 0.5, but round to 0.5 as FDot6, which would finally round to + * the integer 1, instead of just rounding to 0. * * To handle this, a small bias of half an FDot6 increment is added before actually rounding to * an integer value. This simulates the rounding of SkScalarRoundToFDot6 without incurring the * range loss of converting to FDot6 format first, preserving the integer range for the SkIRect. - * Thus, bottom and right are rounded in this manner (biased up), ensuring the rect is large enough. - * Top and left can round as normal since they will round (biased down) to values less or equal - * to the desired rect origin. + * Thus, bottom and right are rounded in this manner (biased up), ensuring the rect is large + * enough. */ static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) { SkASSERT(dst); dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop), -#ifdef SK_RASTERIZE_EVEN_ROUNDING - round_biased_to_int(src.fRight, 0.5f / SK_FDot6One), round_biased_to_int(src.fBottom, 0.5f / SK_FDot6One)); -#else - SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom)); -#endif + round_up_to_int(src.fRight), round_up_to_int(src.fBottom)); } void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, diff --git a/gfx/tests/gtest/TestCompositor.cpp b/gfx/tests/gtest/TestCompositor.cpp index 816c0d011aee..0a8498bb6988 100644 --- a/gfx/tests/gtest/TestCompositor.cpp +++ b/gfx/tests/gtest/TestCompositor.cpp @@ -63,9 +63,6 @@ static already_AddRefed CreateTestCompositor(LayersBackend backend, } else if (backend == LayersBackend::LAYERS_D3D11) { //compositor = new CompositorD3D11(); MOZ_CRASH(); // No support yet - } else if (backend == LayersBackend::LAYERS_D3D9) { - //compositor = new CompositorD3D9(this, mWidget); - MOZ_CRASH(); // No support yet #endif } nsCString failureReason; diff --git a/gfx/thebes/gfxFontconfigFonts.cpp b/gfx/thebes/gfxFontconfigFonts.cpp deleted file mode 100644 index bbcbbabf9159..000000000000 --- a/gfx/thebes/gfxFontconfigFonts.cpp +++ /dev/null @@ -1,2262 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * 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 "prlink.h" -#include "gfxTypes.h" - -#include "nsTArray.h" - -#include "gfxContext.h" -#ifdef MOZ_WIDGET_GTK -#include "gfxPlatformGtk.h" -#endif -#include "gfxFontconfigFonts.h" -#include "gfxFT2FontBase.h" -#include "gfxFT2Utils.h" -#include "harfbuzz/hb.h" -#include "harfbuzz/hb-glib.h" -#include "harfbuzz/hb-ot.h" -#include "nsUnicodeProperties.h" -#include "nsUnicodeScriptCodes.h" -#include "gfxFontconfigUtils.h" -#include "gfxUserFontSet.h" -#include "gfxFontConstants.h" -#include "nsGkAtoms.h" -#include "nsILanguageAtomService.h" -#include "nsServiceManagerUtils.h" - -#include -#include -#include "mozilla/gfx/HelpersCairo.h" - -#include -#include - -#include FT_TRUETYPE_TABLES_H - -#ifdef MOZ_WIDGET_GTK -#include -#endif - -#include - -using namespace mozilla; -using namespace mozilla::unicode; - -#define PRINTING_FC_PROPERTY "gfx.printing" - -static PangoLanguage *GuessPangoLanguage(nsIAtom *aLanguage); - -static cairo_scaled_font_t * -CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace); - -static FT_Library gFTLibrary; - -// FC_FAMILYLANG and FC_FULLNAME were introduced in fontconfig-2.2.97 -// and so fontconfig-2.3.0 (2005). -#ifndef FC_FAMILYLANG -#define FC_FAMILYLANG "familylang" -#endif -#ifndef FC_FULLNAME -#define FC_FULLNAME "fullname" -#endif - -static PRFuncPtr -FindFunctionSymbol(const char *name) -{ - PRLibrary *lib = nullptr; - PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(name, &lib); - if (lib) { - PR_UnloadLibrary(lib); - } - - return result; -} - -static bool HasChar(FcPattern *aFont, FcChar32 wc) -{ - FcCharSet *charset = nullptr; - FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset); - - return charset && FcCharSetHasChar(charset, wc); -} - -/** - * gfxFcFontEntry: - * - * An abstract base class of for gfxFontEntry implementations used by - * gfxFcFont and gfxUserFontSet. - */ - -class gfxFcFontEntry : public gfxFontEntry { -public: - // For all FontEntrys attached to gfxFcFonts, there will be only one - // pattern in this array. This is always a font pattern, not a fully - // resolved pattern. gfxFcFont only uses this to construct a PangoFont. - // - // FontEntrys for src:local() fonts in gfxUserFontSet may return more than - // one pattern. (See comment in gfxUserFcFontEntry.) - const nsTArray< nsCountedRef >& GetPatterns() - { - return mPatterns; - } - - static gfxFcFontEntry *LookupFontEntry(cairo_font_face_t *aFace) - { - return static_cast - (cairo_font_face_get_user_data(aFace, &sFontEntryKey)); - } - - // override the gfxFontEntry impl to read the name from fontconfig - // instead of trying to get the 'name' table, as we don't implement - // GetFontTable() here - virtual nsString RealFaceName(); - - // This is needed to make gfxFontEntry::HasCharacter(aCh) work. - virtual bool TestCharacterMap(uint32_t aCh) - { - for (uint32_t i = 0; i < mPatterns.Length(); ++i) { - if (HasChar(mPatterns[i], aCh)) { - return true; - } - } - return false; - } - -protected: - explicit gfxFcFontEntry(const nsAString& aName) - : gfxFontEntry(aName) - { - } - - // One pattern is the common case and some subclasses rely on successful - // addition of the first element to the array. - AutoTArray,1> mPatterns; - - static cairo_user_data_key_t sFontEntryKey; -}; - -cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey; - -nsString -gfxFcFontEntry::RealFaceName() -{ - FcChar8 *name; - if (!mPatterns.IsEmpty()) { - if (FcPatternGetString(mPatterns[0], - FC_FULLNAME, 0, &name) == FcResultMatch) { - return NS_ConvertUTF8toUTF16((const char*)name); - } - if (FcPatternGetString(mPatterns[0], - FC_FAMILY, 0, &name) == FcResultMatch) { - NS_ConvertUTF8toUTF16 result((const char*)name); - if (FcPatternGetString(mPatterns[0], - FC_STYLE, 0, &name) == FcResultMatch) { - result.Append(' '); - AppendUTF8toUTF16((const char*)name, result); - } - return result; - } - } - // fall back to gfxFontEntry implementation (only works for sfnt fonts) - return gfxFontEntry::RealFaceName(); -} - -/** - * gfxSystemFcFontEntry: - * - * An implementation of gfxFcFontEntry used by gfxFcFonts for system fonts, - * including those from regular family-name based font selection as well as - * those from src:local(). - * - * All gfxFcFonts using the same cairo_font_face_t share the same FontEntry. - */ - -class gfxSystemFcFontEntry : public gfxFcFontEntry { -public: - // For memory efficiency, aFontPattern should be a font pattern, - // not a fully resolved pattern. - gfxSystemFcFontEntry(cairo_font_face_t *aFontFace, - FcPattern *aFontPattern, - const nsAString& aName) - : gfxFcFontEntry(aName), mFontFace(aFontFace), - mFTFace(nullptr), mFTFaceInitialized(false) - { - cairo_font_face_reference(mFontFace); - cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, nullptr); - - // mPatterns is an AutoTArray with 1 space always available, so the - // AppendElement always succeeds. - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible)); - mPatterns[0] = aFontPattern; - - FcChar8 *name; - if (FcPatternGetString(aFontPattern, - FC_FAMILY, 0, &name) == FcResultMatch) { - mFamilyName = NS_ConvertUTF8toUTF16((const char*)name); - } - } - - ~gfxSystemFcFontEntry() - { - cairo_font_face_set_user_data(mFontFace, - &sFontEntryKey, - nullptr, - nullptr); - cairo_font_face_destroy(mFontFace); - } - - virtual void ForgetHBFace() override; - virtual void ReleaseGrFace(gr_face* aFace) override; - -protected: - virtual nsresult - CopyFontTable(uint32_t aTableTag, nsTArray& aBuffer) override; - - void MaybeReleaseFTFace(); - -private: - cairo_font_face_t *mFontFace; - FT_Face mFTFace; - bool mFTFaceInitialized; -}; - -nsresult -gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag, - nsTArray& aBuffer) -{ - if (!mFTFaceInitialized) { - mFTFaceInitialized = true; - FcChar8 *filename; - if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) { - return NS_ERROR_FAILURE; - } - int index; - if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) { - index = 0; // default to 0 if not found in pattern - } - if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(), - (const char*)filename, index, &mFTFace) != 0) { - return NS_ERROR_FAILURE; - } - } - - if (!mFTFace) { - return NS_ERROR_NOT_AVAILABLE; - } - - FT_ULong length = 0; - if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) { - return NS_ERROR_NOT_AVAILABLE; - } - if (!aBuffer.SetLength(length, fallible)) { - return NS_ERROR_OUT_OF_MEMORY; - } - if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) { - aBuffer.Clear(); - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - -void -gfxSystemFcFontEntry::MaybeReleaseFTFace() -{ - // don't release if either HB or Gr face still exists - if (mHBFace || mGrFace) { - return; - } - if (mFTFace) { - FT_Done_Face(mFTFace); - mFTFace = nullptr; - } - mFTFaceInitialized = false; -} - -void -gfxSystemFcFontEntry::ForgetHBFace() -{ - gfxFontEntry::ForgetHBFace(); - MaybeReleaseFTFace(); -} - -void -gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace) -{ - gfxFontEntry::ReleaseGrFace(aFace); - MaybeReleaseFTFace(); -} - -// A namespace for @font-face family names in FcPatterns so that fontconfig -// aliases do not pick up families from @font-face rules and so that -// fontconfig rules can distinguish between web fonts and platform fonts. -// http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html -#define FONT_FACE_FAMILY_PREFIX "@font-face:" - -/** - * gfxUserFcFontEntry: - * - * An abstract class for objects in a gfxUserFontSet that can provide - * FcPattern* handles to fonts. - * - * Separate implementations of this class support local fonts from src:local() - * and web fonts from src:url(). - */ - -// There is a one-to-one correspondence between gfxUserFcFontEntry objects and -// @font-face rules, but sometimes a one-to-many correspondence between font -// entries and font patterns. -// -// http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions -// provided a font-size descriptor to specify the sizes supported by the face, -// but the "Editor's Draft 27 June 2008" -// http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a -// descriptor, and Mozilla does not recognize such a descriptor. -// -// Font face names used in src:local() also do not usually specify a size. -// -// PCF format fonts have each size in a different file, and each of these -// files is referenced by its own pattern, but really these are each -// different sizes of one face with one name. -// -// Multiple patterns in an entry also effectively deals with a set of -// PostScript Type 1 font files that all have the same face name but are in -// several files because of the limit on the number of glyphs in a Type 1 font -// file. (e.g. Computer Modern.) - -class gfxUserFcFontEntry : public gfxFcFontEntry { -protected: - explicit gfxUserFcFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle) - : gfxFcFontEntry(aFontName) - { - mStyle = aStyle; - mWeight = aWeight; - mStretch = aStretch; - } - - // Helper function to change a pattern so that it matches the CSS style - // descriptors and so gets properly sorted in font selection. This also - // avoids synthetic style effects being added by the renderer when the - // style of the font itself does not match the descriptor provided by the - // author. - void AdjustPatternToCSS(FcPattern *aPattern); -}; - -void -gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern) -{ - int fontWeight = -1; - FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight); - int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight / 100); - if (cssWeight != fontWeight) { - FcPatternDel(aPattern, FC_WEIGHT); - FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight); - } - - int fontSlant; - FcResult res = FcPatternGetInteger(aPattern, FC_SLANT, 0, &fontSlant); - // gfxFontEntry doesn't understand the difference between oblique - // and italic. - if (res != FcResultMatch || - IsItalic() != (fontSlant != FC_SLANT_ROMAN)) { - FcPatternDel(aPattern, FC_SLANT); - FcPatternAddInteger(aPattern, FC_SLANT, - IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN); - } - - int fontWidth = -1; - FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth); - int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch); - if (cssWidth != fontWidth) { - FcPatternDel(aPattern, FC_WIDTH); - FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth); - } - - // Ensure that there is a fullname property (if there is a family - // property) so that fontconfig rules can identify the real name of the - // font, because the family property will be replaced. - FcChar8 *unused; - if (FcPatternGetString(aPattern, - FC_FULLNAME, 0, &unused) == FcResultNoMatch) { - nsAutoCString fullname; - if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern, - &fullname)) { - FcPatternAddString(aPattern, FC_FULLNAME, - gfxFontconfigUtils::ToFcChar8(fullname)); - } - } - - nsAutoCString family; - family.Append(FONT_FACE_FAMILY_PREFIX); - AppendUTF16toUTF8(Name(), family); - - FcPatternDel(aPattern, FC_FAMILY); - FcPatternDel(aPattern, FC_FAMILYLANG); - FcPatternAddString(aPattern, FC_FAMILY, - gfxFontconfigUtils::ToFcChar8(family)); -} - -/** - * gfxLocalFcFontEntry: - * - * An implementation of gfxUserFcFontEntry for local fonts from src:local(). - * - * This class is used only in gfxUserFontSet and for providing FcPattern* - * handles to system fonts for font selection. gfxFcFonts created from these - * patterns will use gfxSystemFcFontEntrys, which may be shared with - * gfxFcFonts from regular family-name based font selection. - */ - -class gfxLocalFcFontEntry : public gfxUserFcFontEntry { -public: - gfxLocalFcFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const nsTArray< nsCountedRef >& aPatterns) - : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle) - { - if (!mPatterns.SetCapacity(aPatterns.Length(), fallible)) - return; // OOM - - for (uint32_t i = 0; i < aPatterns.Length(); ++i) { - FcPattern *pattern = FcPatternDuplicate(aPatterns.ElementAt(i)); - if (!pattern) - return; // OOM - - AdjustPatternToCSS(pattern); - - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible)); - mPatterns[i].own(pattern); - } - mIsLocalUserFont = true; - } -}; - -/** - * gfxDownloadedFcFontEntry: - * - * An implementation of gfxFcFontEntry for web fonts from src:url(). - * - * When a cairo_font_face_t is created for these fonts, the cairo_font_face_t - * keeps a reference to the FontEntry to keep the font data alive. - */ - -class gfxDownloadedFcFontEntry : public gfxUserFcFontEntry { -public: - // This takes ownership of the face and its underlying data - gfxDownloadedFcFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const uint8_t *aData, FT_Face aFace) - : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle), - mFontData(aData), mFace(aFace) - { - NS_PRECONDITION(aFace != nullptr, "aFace is NULL!"); - mIsDataUserFont = true; - InitPattern(); - } - - virtual ~gfxDownloadedFcFontEntry(); - - // Returns true on success - bool SetCairoFace(cairo_font_face_t *aFace); - - virtual hb_blob_t* GetFontTable(uint32_t aTableTag) override; - -protected: - void InitPattern(); - - // mFontData holds the data used to instantiate the FT_Face; - // this has to persist until we are finished with the face, - // then be released with free(). - const uint8_t* mFontData; - - FT_Face mFace; -}; - -// A property for recording gfxDownloadedFcFontEntrys on FcPatterns. -static const char *kFontEntryFcProp = "-moz-font-entry"; - -static FcBool AddDownloadedFontEntry(FcPattern *aPattern, - gfxDownloadedFcFontEntry *aFontEntry) -{ - FcValue value; - value.type = FcTypeFTFace; // void* field of union - value.u.f = aFontEntry; - - return FcPatternAdd(aPattern, kFontEntryFcProp, value, FcFalse); -} - -static FcBool DelDownloadedFontEntry(FcPattern *aPattern) -{ - return FcPatternDel(aPattern, kFontEntryFcProp); -} - -static gfxDownloadedFcFontEntry *GetDownloadedFontEntry(FcPattern *aPattern) -{ - FcValue value; - if (FcPatternGet(aPattern, kFontEntryFcProp, 0, &value) != FcResultMatch) - return nullptr; - - if (value.type != FcTypeFTFace) { - NS_NOTREACHED("Wrong type for -moz-font-entry font property"); - return nullptr; - } - - return static_cast(value.u.f); -} - -gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry() -{ - if (mPatterns.Length() != 0) { - // Remove back reference to this font entry and the face in case - // anyone holds a reference to the pattern. - NS_ASSERTION(mPatterns.Length() == 1, - "More than one pattern in gfxDownloadedFcFontEntry!"); - DelDownloadedFontEntry(mPatterns[0]); - FcPatternDel(mPatterns[0], FC_FT_FACE); - } - FT_Done_Face(mFace); - free((void*)mFontData); -} - -typedef FcPattern* (*QueryFaceFunction)(const FT_Face face, - const FcChar8 *file, int id, - FcBlanks *blanks); - -void -gfxDownloadedFcFontEntry::InitPattern() -{ - static QueryFaceFunction sQueryFacePtr = - reinterpret_cast - (FindFunctionSymbol("FcFreeTypeQueryFace")); - FcPattern *pattern; - - // FcFreeTypeQueryFace is the same function used to construct patterns for - // system fonts and so is the preferred function to use for this purpose. - // This will set up the langset property, which helps with sorting, and - // the foundry, fullname, and fontversion properties, which properly - // identify the font to fontconfig rules. However, FcFreeTypeQueryFace is - // available only from fontconfig-2.4.2 (December 2006). (CentOS 5.0 has - // fontconfig-2.4.1.) - if (sQueryFacePtr) { - // The "file" argument cannot be nullptr (in fontconfig-2.6.0 at - // least). The dummy file passed here is removed below. - // - // When fontconfig scans the system fonts, FcConfigGetBlanks(nullptr) - // is passed as the "blanks" argument, which provides that unexpectedly - // blank glyphs are elided. Here, however, we pass nullptr for - // "blanks", effectively assuming that, if the font has a blank glyph, - // then the author intends any associated character to be rendered - // blank. - pattern = - (*sQueryFacePtr)(mFace, - gfxFontconfigUtils::ToFcChar8(""), - 0, - nullptr); - if (!pattern) - // Either OOM, or fontconfig chose to skip this font because it - // has "no encoded characters", which I think means "BDF and PCF - // fonts which are not in Unicode (or the effectively equivalent - // ISO Latin-1) encoding". - return; - - // These properties don't make sense for this face without a file. - FcPatternDel(pattern, FC_FILE); - FcPatternDel(pattern, FC_INDEX); - - } else { - // Do the minimum necessary to construct a pattern for sorting. - - // FC_CHARSET is vital to determine which characters are supported. - nsAutoRef charset(FcFreeTypeCharSet(mFace, nullptr)); - // If there are no characters then assume we don't know how to read - // this font. - if (!charset || FcCharSetCount(charset) == 0) - return; - - pattern = FcPatternCreate(); - FcPatternAddCharSet(pattern, FC_CHARSET, charset); - - // FC_PIXEL_SIZE can be important for font selection of fixed-size - // fonts. - if (!(mFace->face_flags & FT_FACE_FLAG_SCALABLE)) { - for (FT_Int i = 0; i < mFace->num_fixed_sizes; ++i) { -#if HAVE_FT_BITMAP_SIZE_Y_PPEM - double size = FLOAT_FROM_26_6(mFace->available_sizes[i].y_ppem); -#else - double size = mFace->available_sizes[i].height; -#endif - FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size); - } - - // Not sure whether this is important; - // imitating FcFreeTypeQueryFace: - FcPatternAddBool (pattern, FC_ANTIALIAS, FcFalse); - } - - // Setting up the FC_LANGSET property is very difficult with the APIs - // available prior to FcFreeTypeQueryFace. Having no FC_LANGSET - // property seems better than having a property with an empty LangSet. - // With no FC_LANGSET property, fontconfig sort functions will - // consider this face to have the same priority as (otherwise equal) - // faces that have support for the primary requested language, but - // will not consider any language to have been satisfied (and so will - // continue to look for a face with language support in fallback - // fonts). - } - - AdjustPatternToCSS(pattern); - - FcPatternAddFTFace(pattern, FC_FT_FACE, mFace); - AddDownloadedFontEntry(pattern, this); - - // There is never more than one pattern - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible)); - mPatterns[0].own(pattern); -} - -static void ReleaseDownloadedFontEntry(void *data) -{ - gfxDownloadedFcFontEntry *downloadedFontEntry = - static_cast(data); - NS_RELEASE(downloadedFontEntry); -} - -bool gfxDownloadedFcFontEntry::SetCairoFace(cairo_font_face_t *aFace) -{ - if (CAIRO_STATUS_SUCCESS != - cairo_font_face_set_user_data(aFace, &sFontEntryKey, this, - ReleaseDownloadedFontEntry)) - return false; - - // Hold a reference to this font entry to keep the font face data. - NS_ADDREF(this); - return true; -} - -hb_blob_t * -gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag) -{ - // The entry already owns the (sanitized) sfnt data in mFontData, - // so we can just return a blob that "wraps" the appropriate chunk of it. - // The blob should not attempt to free its data, as the entire sfnt data - // will be freed when the font entry is deleted. - return gfxFontUtils::GetTableFromFontData(mFontData, aTableTag); -} - -/* - * gfxFcFont - * - * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT - * cairo_scaled_font created from an FcPattern. - */ - -class gfxFcFont : public gfxFontconfigFontBase { -public: - virtual ~gfxFcFont(); - static already_AddRefed - GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern, - const gfxFontStyle *aFontStyle); - - // return a cloned font resized and offset to simulate sub/superscript glyphs - virtual already_AddRefed - GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) override; - -protected: - virtual already_AddRefed MakeScaledFont(gfxFontStyle *aFontStyle, - gfxFloat aFontScale); - virtual already_AddRefed GetSmallCapsFont() override; - -private: - gfxFcFont(cairo_scaled_font_t *aCairoFont, - FcPattern *aPattern, - gfxFcFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle); - - // key for locating a gfxFcFont corresponding to a cairo_scaled_font - static cairo_user_data_key_t sGfxFontKey; -}; - -/** - * gfxFcFontSet: - * - * Translation from a desired FcPattern to a sorted set of font references - * (fontconfig cache data) and (when needed) fonts. - */ - -class gfxFcFontSet final { -public: - NS_INLINE_DECL_REFCOUNTING(gfxFcFontSet) - - explicit gfxFcFontSet(FcPattern *aPattern, - gfxUserFontSet *aUserFontSet) - : mSortPattern(aPattern), mUserFontSet(aUserFontSet), - mFcFontsTrimmed(0), - mHaveFallbackFonts(false) - { - bool waitForUserFont; - mFcFontSet = SortPreferredFonts(waitForUserFont); - mWaitingForUserFont = waitForUserFont; - } - - // A reference is held by the FontSet. - // The caller may add a ref to keep the font alive longer than the FontSet. - gfxFcFont *GetFontAt(uint32_t i, const gfxFontStyle *aFontStyle) - { - if (i >= mFonts.Length() || !mFonts[i].mFont) { - // GetFontPatternAt sets up mFonts - FcPattern *fontPattern = GetFontPatternAt(i); - if (!fontPattern) - return nullptr; - - mFonts[i].mFont = - gfxFcFont::GetOrMakeFont(mSortPattern, fontPattern, - aFontStyle); - } - return mFonts[i].mFont; - } - - FcPattern *GetFontPatternAt(uint32_t i); - - bool WaitingForUserFont() const { - return mWaitingForUserFont; - } - -private: - // Private destructor, to discourage deletion outside of Release(): - ~gfxFcFontSet() - { - } - - nsReturnRef SortPreferredFonts(bool& aWaitForUserFont); - nsReturnRef SortFallbackFonts(); - - struct FontEntry { - explicit FontEntry(FcPattern *aPattern) : mPattern(aPattern) {} - nsCountedRef mPattern; - RefPtr mFont; - }; - - struct LangSupportEntry { - LangSupportEntry(FcChar8 *aLang, FcLangResult aSupport) : - mLang(aLang), mBestSupport(aSupport) {} - FcChar8 *mLang; - FcLangResult mBestSupport; - }; - -public: - // public for nsTArray - class LangComparator { - public: - bool Equals(const LangSupportEntry& a, const FcChar8 *b) const - { - return FcStrCmpIgnoreCase(a.mLang, b) == 0; - } - }; - -private: - // The requested pattern - nsCountedRef mSortPattern; - // Fonts from @font-face rules - RefPtr mUserFontSet; - // A (trimmed) list of font patterns and fonts that is built up as - // required. - nsTArray mFonts; - // Holds a list of font patterns that will be trimmed. This is first set - // to a list of preferred fonts. Then, if/when all the preferred fonts - // have been trimmed and added to mFonts, this is set to a list of - // fallback fonts. - nsAutoRef mFcFontSet; - // The set of characters supported by the fonts in mFonts. - nsAutoRef mCharSet; - // The index of the next font in mFcFontSet that has not yet been - // considered for mFonts. - int mFcFontsTrimmed; - // True iff fallback fonts are either stored in mFcFontSet or have been - // trimmed and added to mFonts (so that mFcFontSet is nullptr). - bool mHaveFallbackFonts; - // True iff there was a user font set with pending downloads, - // so the set may be updated when downloads complete - bool mWaitingForUserFont; -}; - -// Find the FcPattern for an @font-face font suitable for CSS family |aFamily| -// and style |aStyle| properties. -static const nsTArray< nsCountedRef >* -FindFontPatterns(gfxUserFontSet *mUserFontSet, - const nsACString &aFamily, uint8_t aStyle, - uint16_t aWeight, int16_t aStretch, - bool& aWaitForUserFont) -{ - // Convert to UTF16 - NS_ConvertUTF8toUTF16 utf16Family(aFamily); - - // needsBold is not used here. Instead synthetic bold is enabled through - // FcFontRenderPrepare when the weight in the requested pattern is - // compared against the weight in the font pattern. - bool needsBold; - - gfxFontStyle style; - style.style = aStyle; - style.weight = aWeight; - style.stretch = aStretch; - - gfxUserFcFontEntry *fontEntry = nullptr; - gfxFontFamily *family = mUserFontSet->LookupFamily(utf16Family); - if (family) { - gfxUserFontEntry* userFontEntry = - mUserFontSet->FindUserFontEntryAndLoad(family, style, needsBold, - aWaitForUserFont); - if (userFontEntry) { - fontEntry = static_cast - (userFontEntry->GetPlatformFontEntry()); - } - - // Accept synthetic oblique for italic and oblique. - // xxx - this isn't really ideal behavior, for docs that only use a - // single italic face it will also pull down the normal face - // and probably never use it - if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) { - style.style = NS_FONT_STYLE_NORMAL; - userFontEntry = - mUserFontSet->FindUserFontEntryAndLoad(family, style, - needsBold, - aWaitForUserFont); - if (userFontEntry) { - fontEntry = static_cast - (userFontEntry->GetPlatformFontEntry()); - } - } - } - - if (!fontEntry) { - return nullptr; - } - - return &fontEntry->GetPatterns(); -} - -typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object, - int id); - -// FcPatternRemove is available in fontconfig-2.3.0 (2005) -static FcBool -moz_FcPatternRemove(FcPattern *p, const char *object, int id) -{ - static FcPatternRemoveFunction sFcPatternRemovePtr = - reinterpret_cast - (FindFunctionSymbol("FcPatternRemove")); - - if (!sFcPatternRemovePtr) - return FcFalse; - - return (*sFcPatternRemovePtr)(p, object, id); -} - -// fontconfig prefers a matching family or lang to pixelsize of bitmap -// fonts. CSS suggests a tolerance of 20% on pixelsize. -static bool -SizeIsAcceptable(FcPattern *aFont, double aRequestedSize) -{ - double size; - int v = 0; - while (FcPatternGetDouble(aFont, - FC_PIXEL_SIZE, v, &size) == FcResultMatch) { - ++v; - if (5.0 * fabs(size - aRequestedSize) < aRequestedSize) - return true; - } - - // No size means scalable - return v == 0; -} - -// Sorting only the preferred fonts first usually saves having to sort through -// every font on the system. -nsReturnRef -gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont) -{ - aWaitForUserFont = false; - - gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); - if (!utils) - return nsReturnRef(); - - // The list of families in mSortPattern has values with both weak and - // strong bindings. Values with strong bindings should be preferred. - // Values with weak bindings are default fonts that should be considered - // only when the font provides the best support for a requested language - // or after other fonts have satisfied all the requested languages. - // - // There are no direct fontconfig APIs to get the binding type. The - // binding only takes effect in the sort and match functions. - - // |requiredLangs| is a list of requested languages that have not yet been - // satisfied. gfxFontconfigUtils only sets one FC_LANG property value, - // but FcConfigSubstitute may add more values (e.g. prepending "en" to - // "ja" will use western fonts to render Latin/Arabic numerals in Japanese - // text.) - AutoTArray requiredLangs; - for (int v = 0; ; ++v) { - FcChar8 *lang; - FcResult result = FcPatternGetString(mSortPattern, FC_LANG, v, &lang); - if (result != FcResultMatch) { - // No need to check FcPatternGetLangSet() because - // gfxFontconfigUtils sets only a string value for FC_LANG and - // FcConfigSubstitute cannot add LangSets. - NS_ASSERTION(result != FcResultTypeMismatch, - "Expected a string for FC_LANG"); - break; - } - - if (!requiredLangs.Contains(lang, LangComparator())) { - FcLangResult bestLangSupport = utils->GetBestLangSupport(lang); - if (bestLangSupport != FcLangDifferentLang) { - requiredLangs. - AppendElement(LangSupportEntry(lang, bestLangSupport)); - } - } - } - - nsAutoRef fontSet(FcFontSetCreate()); - if (!fontSet) - return fontSet.out(); - - // FcDefaultSubstitute() ensures a slant on mSortPattern, but, if that ever - // doesn't happen, Roman will be used. - int requestedSlant = FC_SLANT_ROMAN; - FcPatternGetInteger(mSortPattern, FC_SLANT, 0, &requestedSlant); - double requestedSize = -1.0; - FcPatternGetDouble(mSortPattern, FC_PIXEL_SIZE, 0, &requestedSize); - - nsTHashtable existingFamilies(32); - FcChar8 *family; - for (int v = 0; - FcPatternGetString(mSortPattern, - FC_FAMILY, v, &family) == FcResultMatch; ++v) { - const nsTArray< nsCountedRef > *familyFonts = nullptr; - - // Is this an @font-face family? - bool isUserFont = false; - if (mUserFontSet) { - // Have some @font-face definitions - - nsDependentCString cFamily(gfxFontconfigUtils::ToCString(family)); - NS_NAMED_LITERAL_CSTRING(userPrefix, FONT_FACE_FAMILY_PREFIX); - - if (StringBeginsWith(cFamily, userPrefix)) { - isUserFont = true; - - // Trim off the prefix - nsDependentCSubstring cssFamily(cFamily, userPrefix.Length()); - - uint8_t thebesStyle = - gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant); - uint16_t thebesWeight = - gfxFontconfigUtils::GetThebesWeight(mSortPattern); - int16_t thebesStretch = - gfxFontconfigUtils::GetThebesStretch(mSortPattern); - - bool waitForUserFont; - familyFonts = FindFontPatterns(mUserFontSet, cssFamily, - thebesStyle, - thebesWeight, thebesStretch, - waitForUserFont); - if (waitForUserFont) { - aWaitForUserFont = true; - } - } - } - - if (!isUserFont) { - familyFonts = &utils->GetFontsForFamily(family); - } - - if (!familyFonts || familyFonts->Length() == 0) { - // There are no fonts matching this family, so there is no point - // in searching for this family in the FontSort. - // - // Perhaps the original pattern should be retained for - // FcFontRenderPrepare. However, the only a useful config - // substitution test against missing families that i can imagine - // would only be interested in the preferred family - // (qual="first"), so always keep the first family and use the - // same pattern for Sort and RenderPrepare. - if (v != 0 && moz_FcPatternRemove(mSortPattern, FC_FAMILY, v)) { - --v; - } - continue; - } - - // Aliases seem to often end up occurring more than once, but - // duplicate families can't be removed from the sort pattern without - // knowing whether duplicates have the same binding. - gfxFontconfigUtils::DepFcStrEntry *familyEntry = - existingFamilies.PutEntry(family); - if (familyEntry) { - if (familyEntry->mKey) // old entry - continue; - - familyEntry->mKey = family; // initialize new entry - } - - for (uint32_t f = 0; f < familyFonts->Length(); ++f) { - FcPattern *font = familyFonts->ElementAt(f); - - // Fix up the family name of user-font patterns, as the same - // font entry may be used (via the UserFontCache) for multiple - // CSS family names - if (isUserFont) { - font = FcPatternDuplicate(font); - FcPatternDel(font, FC_FAMILY); - FcPatternAddString(font, FC_FAMILY, family); - } - - // User fonts are already filtered by slant (but not size) in - // mUserFontSet->FindUserFontEntry(). - if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize)) - continue; - - for (uint32_t r = 0; r < requiredLangs.Length(); ++r) { - const LangSupportEntry& langEntry = requiredLangs[r]; - FcLangResult support = - gfxFontconfigUtils::GetLangSupport(font, langEntry.mLang); - if (support <= langEntry.mBestSupport) { // lower is better - requiredLangs.RemoveElementAt(r); - --r; - } - } - - // FcFontSetDestroy will remove a reference but FcFontSetAdd - // does _not_ take a reference! - if (FcFontSetAdd(fontSet, font)) { - // We don't add a reference here for user fonts, because we're - // using a local clone of the pattern (see above) in order to - // override the family name - if (!isUserFont) { - FcPatternReference(font); - } - } - } - } - - FcPattern *truncateMarker = nullptr; - for (uint32_t r = 0; r < requiredLangs.Length(); ++r) { - const nsTArray< nsCountedRef >& langFonts = - utils->GetFontsForLang(requiredLangs[r].mLang); - - bool haveLangFont = false; - for (uint32_t f = 0; f < langFonts.Length(); ++f) { - FcPattern *font = langFonts[f]; - if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize)) - continue; - - haveLangFont = true; - if (FcFontSetAdd(fontSet, font)) { - FcPatternReference(font); - } - } - - if (!haveLangFont && langFonts.Length() > 0) { - // There is a font that supports this language but it didn't pass - // the slant and size criteria. Weak default font families should - // not be considered until the language has been satisfied. - // - // Insert a font that supports the language so that it will mark - // the position of fonts from weak families in the sorted set and - // they can be removed. The language and weak families will be - // considered in the fallback fonts, which use fontconfig's - // algorithm. - // - // Of the fonts that don't meet slant and size criteria, strong - // default font families should be considered before (other) fonts - // for this language, so this marker font will be removed (as well - // as the fonts from weak families), and strong families will be - // reconsidered in the fallback fonts. - FcPattern *font = langFonts[0]; - if (FcFontSetAdd(fontSet, font)) { - FcPatternReference(font); - truncateMarker = font; - } - break; - } - } - - FcFontSet *sets[1] = { fontSet }; - FcResult result; -#ifdef SOLARIS - // Get around a crash of FcFontSetSort when FcConfig is nullptr - // Solaris's FcFontSetSort needs an FcConfig (bug 474758) - fontSet.own(FcFontSetSort(FcConfigGetCurrent(), sets, 1, mSortPattern, - FcFalse, nullptr, &result)); -#else - fontSet.own(FcFontSetSort(nullptr, sets, 1, mSortPattern, - FcFalse, nullptr, &result)); -#endif - - if (truncateMarker != nullptr && fontSet) { - nsAutoRef truncatedSet(FcFontSetCreate()); - - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - if (font == truncateMarker) - break; - - if (FcFontSetAdd(truncatedSet, font)) { - FcPatternReference(font); - } - } - - fontSet.steal(truncatedSet); - } - - return fontSet.out(); -} - -nsReturnRef -gfxFcFontSet::SortFallbackFonts() -{ - // Setting trim to FcTrue would provide a much smaller (~ 1/10) FcFontSet, - // but would take much longer due to comparing all the character sets. - // - // The references to fonts in this FcFontSet are almost free - // as they are pointers into mmaped cache files. - // - // GetFontPatternAt() will trim lazily if and as needed, which will also - // remove duplicates of preferred fonts. - FcResult result; - return nsReturnRef(FcFontSort(nullptr, mSortPattern, - FcFalse, nullptr, &result)); -} - -// GetFontAt relies on this setting up all patterns up to |i|. -FcPattern * -gfxFcFontSet::GetFontPatternAt(uint32_t i) -{ - while (i >= mFonts.Length()) { - while (!mFcFontSet) { - if (mHaveFallbackFonts) - return nullptr; - - mFcFontSet = SortFallbackFonts(); - mHaveFallbackFonts = true; - mFcFontsTrimmed = 0; - // Loop to test that mFcFontSet is non-nullptr. - } - - while (mFcFontsTrimmed < mFcFontSet->nfont) { - FcPattern *font = mFcFontSet->fonts[mFcFontsTrimmed]; - ++mFcFontsTrimmed; - - if (mFonts.Length() != 0) { - // See if the next font provides support for any extra - // characters. Most often the next font is not going to - // support more characters so check for a SubSet first before - // allocating a new CharSet with Union. - FcCharSet *supportedChars = mCharSet; - if (!supportedChars) { - FcPatternGetCharSet(mFonts[mFonts.Length() - 1].mPattern, - FC_CHARSET, 0, &supportedChars); - } - - if (supportedChars) { - FcCharSet *newChars = nullptr; - FcPatternGetCharSet(font, FC_CHARSET, 0, &newChars); - if (newChars) { - if (FcCharSetIsSubset(newChars, supportedChars)) - continue; - - mCharSet.own(FcCharSetUnion(supportedChars, newChars)); - } else if (!mCharSet) { - mCharSet.own(FcCharSetCopy(supportedChars)); - } - } - } - - mFonts.AppendElement(font); - if (mFonts.Length() >= i) - break; - } - - if (mFcFontsTrimmed == mFcFontSet->nfont) { - // finished with this font set - mFcFontSet.reset(); - } - } - - return mFonts[i].mPattern; -} - -#ifdef MOZ_WIDGET_GTK -static void ApplyGdkScreenFontOptions(FcPattern *aPattern); -#endif - -// Apply user settings and defaults to pattern in preparation for matching. -static void -PrepareSortPattern(FcPattern *aPattern, double aFallbackSize, - double aSizeAdjustFactor, bool aIsPrinterFont) -{ - FcConfigSubstitute(nullptr, aPattern, FcMatchPattern); - - // This gets cairo_font_options_t for the Screen. We should have - // different font options for printing (no hinting) but we are not told - // what we are measuring for. - // - // If cairo adds support for lcd_filter, gdk will not provide the default - // setting for that option. We could get the default setting by creating - // an xlib surface once, recording its font_options, and then merging the - // gdk options. - // - // Using an xlib surface would also be an option to get Screen font - // options for non-GTK X11 toolkits, but less efficient than using GDK to - // pick up dynamic changes. - if(aIsPrinterFont) { - cairo_font_options_t *options = cairo_font_options_create(); - cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); - cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); - cairo_ft_font_options_substitute(options, aPattern); - cairo_font_options_destroy(options); - FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue); - } else { -#ifdef MOZ_WIDGET_GTK - ApplyGdkScreenFontOptions(aPattern); -#endif - } - - // Protect against any fontconfig settings that may have incorrectly - // modified the pixelsize, and consider aSizeAdjustFactor. - double size = aFallbackSize; - if (FcPatternGetDouble(aPattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch - || aSizeAdjustFactor != 1.0) { - FcPatternDel(aPattern, FC_PIXEL_SIZE); - FcPatternAddDouble(aPattern, FC_PIXEL_SIZE, size * aSizeAdjustFactor); - } - - FcDefaultSubstitute(aPattern); -} - -/** - ** gfxPangoFontGroup - **/ - -gfxPangoFontGroup::gfxPangoFontGroup(const FontFamilyList& aFontFamilyList, - const gfxFontStyle *aStyle, - gfxUserFontSet *aUserFontSet, - gfxFloat aDevToCssSize) - : gfxFontGroup(aFontFamilyList, aStyle, nullptr, aUserFontSet, aDevToCssSize), - mPangoLanguage(GuessPangoLanguage(aStyle->language)) -{ - // This language is passed to the font for shaping. - // Shaping doesn't know about lang groups so make it a real language. - if (mPangoLanguage) { - mStyle.language = NS_Atomize(pango_language_to_string(mPangoLanguage)); - } - - // dummy entry, will be replaced when actually needed - mFonts.AppendElement(FamilyFace()); - mSkipUpdateUserFonts = true; -} - -gfxPangoFontGroup::~gfxPangoFontGroup() -{ -} - -gfxFontGroup * -gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle) -{ - return new gfxPangoFontGroup(mFamilyList, aStyle, mUserFontSet, mDevToCssSize); -} - -void -gfxPangoFontGroup::FindGenericFontsPFG(FontFamilyType aGenericType, - nsIAtom *aLanguage, - void *aClosure) -{ - AutoTArray resolvedGenerics; - ResolveGenericFontNamesPFG(aGenericType, aLanguage, resolvedGenerics); - uint32_t g = 0, numGenerics = resolvedGenerics.Length(); - for (g = 0; g < numGenerics; g++) { - FindPlatformFontPFG(resolvedGenerics[g], false, aClosure); - } -} - -/* static */ void -gfxPangoFontGroup::ResolveGenericFontNamesPFG(FontFamilyType aGenericType, - nsIAtom *aLanguage, - nsTArray& aGenericFamilies) -{ - static const char kGeneric_serif[] = "serif"; - static const char kGeneric_sans_serif[] = "sans-serif"; - static const char kGeneric_monospace[] = "monospace"; - static const char kGeneric_cursive[] = "cursive"; - static const char kGeneric_fantasy[] = "fantasy"; - - // treat -moz-fixed as monospace - if (aGenericType == eFamily_moz_fixed) { - aGenericType = eFamily_monospace; - } - - // type should be standard generic type at this point - NS_ASSERTION(aGenericType >= eFamily_serif && - aGenericType <= eFamily_fantasy, - "standard generic font family type required"); - - // create the lang string - nsIAtom *langGroupAtom = nullptr; - nsAutoCString langGroupString; - if (aLanguage) { - if (!gLangService) { - CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService); - } - if (gLangService) { - nsresult rv; - langGroupAtom = gLangService->GetLanguageGroup(aLanguage, &rv); - } - } - if (!langGroupAtom) { - langGroupAtom = nsGkAtoms::Unicode; - } - langGroupAtom->ToUTF8String(langGroupString); - - // map generic type to string - const char *generic = nullptr; - switch (aGenericType) { - case eFamily_serif: - generic = kGeneric_serif; - break; - case eFamily_sans_serif: - generic = kGeneric_sans_serif; - break; - case eFamily_monospace: - generic = kGeneric_monospace; - break; - case eFamily_cursive: - generic = kGeneric_cursive; - break; - case eFamily_fantasy: - generic = kGeneric_fantasy; - break; - default: - break; - } - - if (!generic) { - return; - } - - aGenericFamilies.Clear(); - - // load family for "font.name.generic.lang" - nsAutoCString prefFontName("font.name."); - prefFontName.Append(generic); - prefFontName.Append('.'); - prefFontName.Append(langGroupString); - gfxFontUtils::AppendPrefsFontList(prefFontName.get(), - aGenericFamilies); - - // if lang has pref fonts, also load fonts for "font.name-list.generic.lang" - if (!aGenericFamilies.IsEmpty()) { - nsAutoCString prefFontListName("font.name-list."); - prefFontListName.Append(generic); - prefFontListName.Append('.'); - prefFontListName.Append(langGroupString); - gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), - aGenericFamilies); - } - -#if 0 // dump out generic mappings - printf("%s ===> ", prefFontName.get()); - for (uint32_t k = 0; k < aGenericFamilies.Length(); k++) { - if (k > 0) printf(", "); - printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]).get()); - } - printf("\n"); -#endif -} - -void gfxPangoFontGroup::EnumerateFontListPFG(nsIAtom *aLanguage, void *aClosure) -{ - // initialize fonts in the font family list - const nsTArray& fontlist = mFamilyList.GetFontlist(); - - // lookup fonts in the fontlist - uint32_t i, numFonts = fontlist.Length(); - for (i = 0; i < numFonts; i++) { - const FontFamilyName& name = fontlist[i]; - if (name.IsNamed()) { - FindPlatformFontPFG(name.mName, true, aClosure); - } else { - FindGenericFontsPFG(name.mType, aLanguage, aClosure); - } - } - - // if necessary, append default generic onto the end - if (mFamilyList.GetDefaultFontType() != eFamily_none && - !mFamilyList.HasDefaultGeneric()) { - FindGenericFontsPFG(mFamilyList.GetDefaultFontType(), - aLanguage, aClosure); - } -} - -void -gfxPangoFontGroup::FindPlatformFontPFG(const nsAString& fontName, - bool aUseFontSet, - void *aClosure) -{ - nsTArray *list = static_cast*>(aClosure); - - if (!list->Contains(fontName)) { - // names present in the user fontset are not matched against system fonts - if (aUseFontSet && mUserFontSet && mUserFontSet->HasFamily(fontName)) { - nsAutoString userFontName = - NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX) + fontName; - list->AppendElement(userFontName); - } else { - list->AppendElement(fontName); - } - } -} - -gfxFcFont * -gfxPangoFontGroup::GetBaseFont() -{ - if (mFonts[0].Font() == nullptr) { - gfxFont* font = GetBaseFontSet()->GetFontAt(0, GetStyle()); - mFonts[0] = FamilyFace(nullptr, font); - } - - return static_cast(mFonts[0].Font()); -} - -gfxFont* -gfxPangoFontGroup::GetFirstValidFont(uint32_t aCh) -{ - return GetFontAt(0); -} - -gfxFont * -gfxPangoFontGroup::GetFontAt(int32_t i, uint32_t aCh) -{ - // If it turns out to be hard for all clients that cache font - // groups to call UpdateUserFonts at appropriate times, we could - // instead consider just calling UpdateUserFonts from someplace - // more central (such as here). - NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(), - "Whoever was caching this font group should have " - "called UpdateUserFonts on it"); - - NS_PRECONDITION(i == 0, "Only have one font"); - - return GetBaseFont(); -} - -void -gfxPangoFontGroup::UpdateUserFonts() -{ - uint64_t newGeneration = GetGeneration(); - if (newGeneration == mCurrGeneration) - return; - - mFonts[0] = FamilyFace(); - mFontSets.Clear(); - ClearCachedData(); - mCurrGeneration = newGeneration; -} - -already_AddRefed -gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor, - nsAutoRef *aMatchPattern) -{ - const char *lang = pango_language_to_string(aLang); - - RefPtr langGroup; - if (aLang != mPangoLanguage) { - // Set up langGroup for Mozilla's font prefs. - langGroup = NS_Atomize(lang); - } - - AutoTArray fcFamilyList; - EnumerateFontListPFG(langGroup ? langGroup.get() : mStyle.language.get(), - &fcFamilyList); - - // To consider: A fontset cache here could be helpful. - - // Get a pattern suitable for matching. - nsAutoRef pattern - (gfxFontconfigUtils::NewPattern(fcFamilyList, mStyle, lang)); - - PrepareSortPattern(pattern, mStyle.size, aSizeAdjustFactor, mStyle.printerFont); - - RefPtr fontset = - new gfxFcFontSet(pattern, mUserFontSet); - - mSkipDrawing = fontset->WaitingForUserFont(); - - if (aMatchPattern) - aMatchPattern->steal(pattern); - - return fontset.forget(); -} - -gfxPangoFontGroup:: -FontSetByLangEntry::FontSetByLangEntry(PangoLanguage *aLang, - gfxFcFontSet *aFontSet) - : mLang(aLang), mFontSet(aFontSet) -{ -} - -gfxFcFontSet * -gfxPangoFontGroup::GetFontSet(PangoLanguage *aLang) -{ - GetBaseFontSet(); // sets mSizeAdjustFactor and mFontSets[0] - - if (!aLang) - return mFontSets[0].mFontSet; - - for (uint32_t i = 0; i < mFontSets.Length(); ++i) { - if (mFontSets[i].mLang == aLang) - return mFontSets[i].mFontSet; - } - - RefPtr fontSet = - MakeFontSet(aLang, mSizeAdjustFactor); - mFontSets.AppendElement(FontSetByLangEntry(aLang, fontSet)); - - return fontSet; -} - -already_AddRefed -gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, - uint32_t aNextCh, Script aRunScript, - gfxFont *aPrevMatchedFont, - uint8_t *aMatchType) -{ - if (aPrevMatchedFont) { - // Don't switch fonts for control characters, regardless of - // whether they are present in the current font, as they won't - // actually be rendered (see bug 716229) - uint8_t category = GetGeneralCategory(aCh); - if (category == HB_UNICODE_GENERAL_CATEGORY_CONTROL) { - return RefPtr(aPrevMatchedFont).forget(); - } - - // if this character is a join-control or the previous is a join-causer, - // use the same font as the previous range if we can - if (gfxFontUtils::IsJoinControl(aCh) || - gfxFontUtils::IsJoinCauser(aPrevCh)) { - if (aPrevMatchedFont->HasCharacter(aCh)) { - return RefPtr(aPrevMatchedFont).forget(); - } - } - } - - // if this character is a variation selector, - // use the previous font regardless of whether it supports VS or not. - // otherwise the text run will be divided. - if (gfxFontUtils::IsVarSelector(aCh)) { - if (aPrevMatchedFont) { - return RefPtr(aPrevMatchedFont).forget(); - } - // VS alone. it's meaningless to search different fonts - return nullptr; - } - - // The real fonts that fontconfig provides for generic/fallback families - // depend on the language used, so a different FontSet is used for each - // language (except for the variation below). - // - // With most fontconfig configurations any real family names prior to a - // fontconfig generic with corresponding fonts installed will still lead - // to the same leading fonts in each FontSet. - // - // There is an inefficiency here therefore because the same base FontSet - // could often be used if these real families support the character. - // However, with fontconfig aliases, it is difficult to distinguish - // where exactly alias fonts end and generic/fallback fonts begin. - // - // The variation from pure language-based matching used here is that the - // same primary/base font is always used irrespective of the language. - // This provides that SCRIPT_COMMON characters are consistently rendered - // with the same font (bug 339513 and bug 416725). This is particularly - // important with the word cache as script can't be reliably determined - // from surrounding words. It also often avoids the unnecessary extra - // FontSet efficiency mentioned above. - // - // However, in two situations, the base font is not checked before the - // language-specific FontSet. - // - // 1. When we don't have a language to make a good choice for - // the base font. - // - // 2. For system fonts, use the default Pango behavior to give - // consistency with other apps. This is relevant when un-localized - // builds are run in non-Latin locales. This special-case probably - // wouldn't be necessary but for bug 91190. - - gfxFcFontSet *fontSet = GetBaseFontSet(); - uint32_t nextFont = 0; - FcPattern *basePattern = nullptr; - if (!mStyle.systemFont && mPangoLanguage) { - basePattern = fontSet->GetFontPatternAt(0); - if (HasChar(basePattern, aCh)) { - *aMatchType = gfxTextRange::kFontGroup; - return RefPtr(GetBaseFont()).forget(); - } - - nextFont = 1; - } - - // Our MOZ_SCRIPT_* codes may not match the PangoScript enumeration values - // (if we're using ICU's codes), so convert by mapping through ISO 15924 tag. - // Note that PangoScript is defined to be compatible with GUnicodeScript: - // https://developer.gnome.org/pango/stable/pango-Scripts-and-Languages.html#PangoScript - const hb_tag_t scriptTag = GetScriptTagForCode(aRunScript); - const PangoScript script = - (const PangoScript)hb_glib_script_from_script(hb_script_from_iso15924_tag(scriptTag)); - - // Might be nice to call pango_language_includes_script only once for the - // run rather than for each character. - PangoLanguage *scriptLang; - if ((!basePattern || - !pango_language_includes_script(mPangoLanguage, script)) && - (scriptLang = pango_script_get_sample_language(script))) { - fontSet = GetFontSet(scriptLang); - nextFont = 0; - } - - for (uint32_t i = nextFont; - FcPattern *pattern = fontSet->GetFontPatternAt(i); - ++i) { - if (pattern == basePattern) { - continue; // already checked basePattern - } - - if (HasChar(pattern, aCh)) { - *aMatchType = gfxTextRange::kFontGroup; - return RefPtr(fontSet->GetFontAt(i, GetStyle())).forget(); - } - } - - return nullptr; -} - -/** - ** gfxFcFont - **/ - -cairo_user_data_key_t gfxFcFont::sGfxFontKey; - -gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont, - FcPattern *aPattern, - gfxFcFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle) - : gfxFontconfigFontBase(aCairoFont, aPattern, aFontEntry, aFontStyle) -{ - cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, this, nullptr); -} - -gfxFcFont::~gfxFcFont() -{ - cairo_scaled_font_set_user_data(mScaledFont, - &sGfxFontKey, - nullptr, - nullptr); -} - -already_AddRefed -gfxFcFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) -{ - gfxFontStyle style(*GetStyle()); - style.AdjustForSubSuperscript(aAppUnitsPerDevPixel); - return MakeScaledFont(&style, style.size / GetStyle()->size); -} - -already_AddRefed -gfxFcFont::MakeScaledFont(gfxFontStyle *aFontStyle, gfxFloat aScaleFactor) -{ - gfxFcFontEntry* fe = static_cast(GetFontEntry()); - RefPtr font = - gfxFontCache::GetCache()->Lookup(fe, aFontStyle, nullptr); - if (font) { - return font.forget(); - } - - cairo_matrix_t fontMatrix; - cairo_scaled_font_get_font_matrix(mScaledFont, &fontMatrix); - cairo_matrix_scale(&fontMatrix, aScaleFactor, aScaleFactor); - - cairo_matrix_t ctm; - cairo_scaled_font_get_ctm(mScaledFont, &ctm); - - cairo_font_options_t *options = cairo_font_options_create(); - cairo_scaled_font_get_font_options(mScaledFont, options); - - cairo_scaled_font_t *newFont = - cairo_scaled_font_create(cairo_scaled_font_get_font_face(mScaledFont), - &fontMatrix, &ctm, options); - cairo_font_options_destroy(options); - - font = new gfxFcFont(newFont, GetPattern(), fe, aFontStyle); - gfxFontCache::GetCache()->AddNew(font); - cairo_scaled_font_destroy(newFont); - - return font.forget(); -} - -already_AddRefed -gfxFcFont::GetSmallCapsFont() -{ - gfxFontStyle style(*GetStyle()); - style.size *= SMALL_CAPS_SCALE_FACTOR; - style.variantCaps = NS_FONT_VARIANT_CAPS_NORMAL; - return MakeScaledFont(&style, SMALL_CAPS_SCALE_FACTOR); -} - -/* static */ void -gfxPangoFontGroup::Shutdown() -{ - // Resetting gFTLibrary in case this is wanted again after a - // cairo_debug_reset_static_data. - gFTLibrary = nullptr; -} - -/* static */ gfxFontEntry * -gfxPangoFontGroup::NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle) -{ - gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); - if (!utils) - return nullptr; - - // The font face name from @font-face { src: local() } is not well - // defined. - // - // On MS Windows, this name gets compared with - // ENUMLOGFONTEXW::elfFullName, which for OpenType fonts seems to be the - // full font name from the name table. For CFF OpenType fonts this is the - // same as the PostScript name, but for TrueType fonts it is usually - // different. - // - // On Mac, the font face name is compared with the PostScript name, even - // for TrueType fonts. - // - // Fontconfig only records the full font names, so the behavior here - // follows that on MS Windows. However, to provide the possibility - // of aliases to compensate for variations, the font face name is passed - // through FcConfigSubstitute. - - nsAutoRef pattern(FcPatternCreate()); - if (!pattern) - return nullptr; - - NS_ConvertUTF16toUTF8 fullname(aFontName); - FcPatternAddString(pattern, FC_FULLNAME, - gfxFontconfigUtils::ToFcChar8(fullname)); - FcConfigSubstitute(nullptr, pattern, FcMatchPattern); - - FcChar8 *name; - for (int v = 0; - FcPatternGetString(pattern, FC_FULLNAME, v, &name) == FcResultMatch; - ++v) { - const nsTArray< nsCountedRef >& fonts = - utils->GetFontsForFullname(name); - - if (fonts.Length() != 0) - return new gfxLocalFcFontEntry(aFontName, - aWeight, - aStretch, - aStyle, - fonts); - } - - return nullptr; -} - -/* static */ FT_Library -gfxPangoFontGroup::GetFTLibrary() -{ - if (!gFTLibrary) { - // Use cairo's FT_Library so that cairo takes care of shutdown of the - // FT_Library after it has destroyed its font_faces, and FT_Done_Face - // has been called on each FT_Face, at least until this bug is fixed: - // https://bugs.freedesktop.org/show_bug.cgi?id=18857 - // - // Cairo's FT_Library can be obtained from any cairo_scaled_font. The - // font properties requested here are chosen to get an FT_Face that is - // likely to be also used elsewhere. - gfxFontStyle style; - RefPtr fontGroup = - new gfxPangoFontGroup(FontFamilyList(eFamily_sans_serif), - &style, nullptr, 1.0); - - gfxFcFont *font = fontGroup->GetBaseFont(); - if (!font) - return nullptr; - - gfxFT2LockedFace face(font); - if (!face.get()) - return nullptr; - - gFTLibrary = face.get()->glyph->library; - } - - return gFTLibrary; -} - -/* static */ gfxFontEntry * -gfxPangoFontGroup::NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const uint8_t* aFontData, - uint32_t aLength) -{ - // Ownership of aFontData is passed in here, and transferred to the - // new fontEntry, which will release it when no longer needed. - - // Using face_index = 0 for the first face in the font, as we have no - // other information. FT_New_Memory_Face checks for a nullptr FT_Library. - FT_Face face; - FT_Error error = - FT_New_Memory_Face(GetFTLibrary(), aFontData, aLength, 0, &face); - if (error != 0) { - free((void*)aFontData); - return nullptr; - } - - return new gfxDownloadedFcFontEntry(aFontName, aWeight, - aStretch, aStyle, - aFontData, face); -} - - -static double -GetPixelSize(FcPattern *aPattern) -{ - double size; - if (FcPatternGetDouble(aPattern, - FC_PIXEL_SIZE, 0, &size) == FcResultMatch) - return size; - - NS_NOTREACHED("No size on pattern"); - return 0.0; -} - -/** - * The following gfxFcFonts are accessed from the cairo_scaled_font or created - * from the FcPattern, not from the gfxFontCache hash table. The gfxFontCache - * hash table is keyed by desired family and style, whereas here we only know - * actual family and style. There may be more than one of these fonts with - * the same family and style, but different PangoFont and actual font face. - * - * The point of this is to record the exact font face for gfxTextRun glyph - * indices. The style of this font does not necessarily represent the exact - * gfxFontStyle used to build the text run. Notably, the language is not - * recorded. - */ - -/* static */ -already_AddRefed -gfxFcFont::GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern, - const gfxFontStyle *aFontStyle) -{ - nsAutoRef renderPattern - (FcFontRenderPrepare(nullptr, aRequestedPattern, aFontPattern)); - - // If synthetic bold/italic is not allowed by the style, adjust the - // resulting pattern to match the actual properties of the font. - if (!aFontStyle->allowSyntheticWeight) { - int weight; - if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, - &weight) == FcResultMatch) { - FcPatternDel(renderPattern, FC_WEIGHT); - FcPatternAddInteger(renderPattern, FC_WEIGHT, weight); - } - } - if (!aFontStyle->allowSyntheticStyle) { - int slant; - if (FcPatternGetInteger(aFontPattern, FC_SLANT, 0, - &slant) == FcResultMatch) { - FcPatternDel(renderPattern, FC_SLANT); - FcPatternAddInteger(renderPattern, FC_SLANT, slant); - } - } - - cairo_font_face_t *face = - cairo_ft_font_face_create_for_pattern(renderPattern); - - // Reuse an existing font entry if available. - RefPtr fe = gfxFcFontEntry::LookupFontEntry(face); - if (!fe) { - gfxDownloadedFcFontEntry *downloadedFontEntry = - GetDownloadedFontEntry(aFontPattern); - if (downloadedFontEntry) { - // Web font - fe = downloadedFontEntry; - if (cairo_font_face_status(face) == CAIRO_STATUS_SUCCESS) { - // cairo_font_face_t is using the web font data. - // Hold a reference to the font entry to keep the font face - // data. - if (!downloadedFontEntry->SetCairoFace(face)) { - // OOM. Let cairo pick a fallback font - cairo_font_face_destroy(face); - face = cairo_ft_font_face_create_for_pattern(aRequestedPattern); - fe = gfxFcFontEntry::LookupFontEntry(face); - } - } - } - if (!fe) { - // Get a unique name for the font face from the file and id. - nsAutoString name; - FcChar8 *fc_file; - if (FcPatternGetString(renderPattern, - FC_FILE, 0, &fc_file) == FcResultMatch) { - int index; - if (FcPatternGetInteger(renderPattern, - FC_INDEX, 0, &index) != FcResultMatch) { - // cairo defaults to 0. - index = 0; - } - - AppendUTF8toUTF16(gfxFontconfigUtils::ToCString(fc_file), name); - if (index != 0) { - name.Append('/'); - name.AppendInt(index); - } - } - - fe = new gfxSystemFcFontEntry(face, aFontPattern, name); - } - } - - gfxFontStyle style(*aFontStyle); - style.size = GetPixelSize(renderPattern); - style.style = gfxFontconfigUtils::GetThebesStyle(renderPattern); - style.weight = gfxFontconfigUtils::GetThebesWeight(renderPattern); - - RefPtr font = - gfxFontCache::GetCache()->Lookup(fe, &style, nullptr); - if (!font) { - // Note that a file/index pair (or FT_Face) and the gfxFontStyle are - // not necessarily enough to provide a key that will describe a unique - // font. cairoFont contains information from renderPattern, which is a - // fully resolved pattern from FcFontRenderPrepare. - // FcFontRenderPrepare takes the requested pattern and the face - // pattern as input and can modify elements of the resulting pattern - // that affect rendering but are not included in the gfxFontStyle. - cairo_scaled_font_t *cairoFont = CreateScaledFont(renderPattern, face); - font = new gfxFcFont(cairoFont, renderPattern, fe, &style); - gfxFontCache::GetCache()->AddNew(font); - cairo_scaled_font_destroy(cairoFont); - } - - cairo_font_face_destroy(face); - - RefPtr retval(static_cast(font.get())); - return retval.forget(); -} - -gfxFcFontSet * -gfxPangoFontGroup::GetBaseFontSet() -{ - if (mFontSets.Length() > 0) - return mFontSets[0].mFontSet; - - mSizeAdjustFactor = 1.0; // will be adjusted below if necessary - nsAutoRef pattern; - RefPtr fontSet = - MakeFontSet(mPangoLanguage, mSizeAdjustFactor, &pattern); - - double size = GetPixelSize(pattern); - if (size != 0.0 && mStyle.sizeAdjust > 0.0) { - gfxFcFont *font = fontSet->GetFontAt(0, GetStyle()); - if (font) { - const gfxFont::Metrics& metrics = - font->GetMetrics(gfxFont::eHorizontal); // XXX vertical? - - // The factor of 0.1 ensures that xHeight is sane so fonts don't - // become huge. Strictly ">" ensures that xHeight and emHeight are - // not both zero. - if (metrics.xHeight > 0.1 * metrics.emHeight) { - mSizeAdjustFactor = - mStyle.sizeAdjust * metrics.emHeight / metrics.xHeight; - - size *= mSizeAdjustFactor; - FcPatternDel(pattern, FC_PIXEL_SIZE); - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size); - - fontSet = new gfxFcFontSet(pattern, mUserFontSet); - } - } - } - - PangoLanguage *pangoLang = mPangoLanguage; - FcChar8 *fcLang; - if (!pangoLang && - FcPatternGetString(pattern, FC_LANG, 0, &fcLang) == FcResultMatch) { - pangoLang = - pango_language_from_string(gfxFontconfigUtils::ToCString(fcLang)); - } - - mFontSets.AppendElement(FontSetByLangEntry(pangoLang, fontSet)); - - return fontSet; -} - -/** - ** gfxTextRun - * - * A serious problem: - * - * -- We draw with a font that's hinted for the CTM, but we measure with a font - * hinted to the identity matrix, so our "bounding metrics" may not be accurate. - * - **/ - -// This will fetch an existing scaled_font if one exists. -static cairo_scaled_font_t * -CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace) -{ - double size = GetPixelSize(aPattern); - - cairo_matrix_t fontMatrix; - FcMatrix *fcMatrix; - if (FcPatternGetMatrix(aPattern, FC_MATRIX, 0, &fcMatrix) == FcResultMatch) - cairo_matrix_init(&fontMatrix, fcMatrix->xx, -fcMatrix->yx, -fcMatrix->xy, fcMatrix->yy, 0, 0); - else - cairo_matrix_init_identity(&fontMatrix); - cairo_matrix_scale(&fontMatrix, size, size); - - FcBool printing; - if (FcPatternGetBool(aPattern, PRINTING_FC_PROPERTY, 0, &printing) != FcResultMatch) { - printing = FcFalse; - } - - // The cairo_scaled_font is created with a unit ctm so that metrics and - // positions are in user space, but this means that hinting effects will - // not be estimated accurately for non-unit transformations. - cairo_matrix_t identityMatrix; - cairo_matrix_init_identity(&identityMatrix); - - // Font options are set explicitly here to improve cairo's caching - // behavior and to record the relevant parts of the pattern for - // SetupCairoFont (so that the pattern can be released). - // - // Most font_options have already been set as defaults on the FcPattern - // with cairo_ft_font_options_substitute(), then user and system - // fontconfig configurations were applied. The resulting font_options - // have been recorded on the face during - // cairo_ft_font_face_create_for_pattern(). - // - // None of the settings here cause this scaled_font to behave any - // differently from how it would behave if it were created from the same - // face with default font_options. - // - // We set options explicitly so that the same scaled_font will be found in - // the cairo_scaled_font_map when cairo loads glyphs from a context with - // the same font_face, font_matrix, ctm, and surface font_options. - // - // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the - // font_options on the cairo_ft_font_face, and doesn't consider default - // option values to not match any explicit values. - // - // Even after cairo_set_scaled_font is used to set font_options for the - // cairo context, when cairo looks for a scaled_font for the context, it - // will look for a font with some option values from the target surface if - // any values are left default on the context font_options. If this - // scaled_font is created with default font_options, cairo will not find - // it. - cairo_font_options_t *fontOptions = cairo_font_options_create(); - - // The one option not recorded in the pattern is hint_metrics, which will - // affect glyph metrics. The default behaves as CAIRO_HINT_METRICS_ON. - // We should be considering the font_options of the surface on which this - // font will be used, but currently we don't have different gfxFonts for - // different surface font_options, so we'll create a font suitable for the - // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON. - if (printing) { - cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF); - } else { - cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_ON); - } - - // The remaining options have been recorded on the pattern and the face. - // _cairo_ft_options_merge has some logic to decide which options from the - // scaled_font or from the cairo_ft_font_face take priority in the way the - // font behaves. - // - // In the majority of cases, _cairo_ft_options_merge uses the options from - // the cairo_ft_font_face, so sometimes it is not so important which - // values are set here so long as they are not defaults, but we'll set - // them to the exact values that we expect from the font, to be consistent - // and to protect against changes in cairo. - // - // In some cases, _cairo_ft_options_merge uses some options from the - // scaled_font's font_options rather than options on the - // cairo_ft_font_face (from fontconfig). - // https://bugs.freedesktop.org/show_bug.cgi?id=11838 - // - // Surface font options were set on the pattern in - // cairo_ft_font_options_substitute. If fontconfig has changed the - // hint_style then that is what the user (or distribution) wants, so we - // use the setting from the FcPattern. - // - // Fallback values here mirror treatment of defaults in cairo-ft-font.c. - FcBool hinting = FcFalse; - if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) { - hinting = FcTrue; - } - - cairo_hint_style_t hint_style; - if (printing || !hinting) { - hint_style = CAIRO_HINT_STYLE_NONE; - } else { -#ifdef FC_HINT_STYLE // FC_HINT_STYLE is available from fontconfig 2.2.91. - int fc_hintstyle; - if (FcPatternGetInteger(aPattern, FC_HINT_STYLE, - 0, &fc_hintstyle ) != FcResultMatch) { - fc_hintstyle = FC_HINT_FULL; - } - switch (fc_hintstyle) { - case FC_HINT_NONE: - hint_style = CAIRO_HINT_STYLE_NONE; - break; - case FC_HINT_SLIGHT: - hint_style = CAIRO_HINT_STYLE_SLIGHT; - break; - case FC_HINT_MEDIUM: - default: // This fallback mirrors _get_pattern_ft_options in cairo. - hint_style = CAIRO_HINT_STYLE_MEDIUM; - break; - case FC_HINT_FULL: - hint_style = CAIRO_HINT_STYLE_FULL; - break; - } -#else // no FC_HINT_STYLE - hint_style = CAIRO_HINT_STYLE_FULL; -#endif - } - cairo_font_options_set_hint_style(fontOptions, hint_style); - - int rgba; - if (FcPatternGetInteger(aPattern, - FC_RGBA, 0, &rgba) != FcResultMatch) { - rgba = FC_RGBA_UNKNOWN; - } - cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; - switch (rgba) { - case FC_RGBA_UNKNOWN: - case FC_RGBA_NONE: - default: - // There is no CAIRO_SUBPIXEL_ORDER_NONE. Subpixel antialiasing - // is disabled through cairo_antialias_t. - rgba = FC_RGBA_NONE; - // subpixel_order won't be used by the font as we won't use - // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for - // caching reasons described above. Fall through: - MOZ_FALLTHROUGH; - case FC_RGBA_RGB: - subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; - break; - case FC_RGBA_BGR: - subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; - break; - case FC_RGBA_VRGB: - subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; - break; - case FC_RGBA_VBGR: - subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; - break; - } - cairo_font_options_set_subpixel_order(fontOptions, subpixel_order); - - FcBool fc_antialias; - if (FcPatternGetBool(aPattern, - FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) { - fc_antialias = FcTrue; - } - cairo_antialias_t antialias; - if (!fc_antialias) { - antialias = CAIRO_ANTIALIAS_NONE; - } else if (rgba == FC_RGBA_NONE) { - antialias = CAIRO_ANTIALIAS_GRAY; - } else { - antialias = CAIRO_ANTIALIAS_SUBPIXEL; - } - cairo_font_options_set_antialias(fontOptions, antialias); - - cairo_scaled_font_t *scaledFont = - cairo_scaled_font_create(aFace, &fontMatrix, &identityMatrix, - fontOptions); - - cairo_font_options_destroy(fontOptions); - - NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS, - "Failed to create scaled font"); - return scaledFont; -} - -/* static */ -PangoLanguage * -GuessPangoLanguage(nsIAtom *aLanguage) -{ - if (!aLanguage) - return nullptr; - - // Pango and fontconfig won't understand mozilla's internal langGroups, so - // find a real language. - nsAutoCString lang; - gfxFontconfigUtils::GetSampleLangForGroup(aLanguage, &lang); - if (lang.IsEmpty()) - return nullptr; - - return pango_language_from_string(lang.get()); -} - -#ifdef MOZ_WIDGET_GTK -/*************************************************************************** - * - * This function must be last in the file because it uses the system cairo - * library. Above this point the cairo library used is the tree cairo if - * MOZ_TREE_CAIRO. - */ - -#if MOZ_TREE_CAIRO -// Tree cairo symbols have different names. Disable their activation through -// preprocessor macros. -#undef cairo_ft_font_options_substitute - -// The system cairo functions are not declared because the include paths cause -// the gdk headers to pick up the tree cairo.h. -extern "C" { -NS_VISIBILITY_DEFAULT void -cairo_ft_font_options_substitute (const cairo_font_options_t *options, - FcPattern *pattern); -} -#endif - -static void -ApplyGdkScreenFontOptions(FcPattern *aPattern) -{ - const cairo_font_options_t *options = - gdk_screen_get_font_options(gdk_screen_get_default()); - - cairo_ft_font_options_substitute(options, aPattern); -} - -#endif // MOZ_WIDGET_GTK - diff --git a/gfx/thebes/gfxFontconfigFonts.h b/gfx/thebes/gfxFontconfigFonts.h index cd59cfc68c62..09bf51c6e98b 100644 --- a/gfx/thebes/gfxFontconfigFonts.h +++ b/gfx/thebes/gfxFontconfigFonts.h @@ -21,103 +21,4 @@ typedef struct _FcPattern FcPattern; typedef struct FT_FaceRec_* FT_Face; typedef struct FT_LibraryRec_ *FT_Library; -class gfxPangoFontGroup : public gfxFontGroup { -public: - gfxPangoFontGroup(const mozilla::FontFamilyList& aFontFamilyList, - const gfxFontStyle *aStyle, - gfxUserFontSet *aUserFontSet, - gfxFloat aDevToCssSize); - virtual ~gfxPangoFontGroup(); - - virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle); - - virtual gfxFont* GetFirstValidFont(uint32_t aCh = 0x20); - - virtual void UpdateUserFonts(); - - virtual already_AddRefed - FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, - Script aRunScript, gfxFont *aPrevMatchedFont, - uint8_t *aMatchType); - - static void Shutdown(); - - // Used for @font-face { src: local(); } - static gfxFontEntry *NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle); - // Used for @font-face { src: url(); } - static gfxFontEntry *NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const uint8_t* aFontData, - uint32_t aLength); - - static FT_Library GetFTLibrary(); - -private: - - virtual gfxFont *GetFontAt(int32_t i, uint32_t aCh = 0x20); - - // @param aLang [in] language to use for pref fonts and system default font - // selection, or nullptr for the language guessed from the - // gfxFontStyle. - // The FontGroup holds a reference to this set. - gfxFcFontSet *GetFontSet(PangoLanguage *aLang = nullptr); - - class FontSetByLangEntry { - public: - FontSetByLangEntry(PangoLanguage *aLang, gfxFcFontSet *aFontSet); - PangoLanguage *mLang; - RefPtr mFontSet; - }; - // There is only one of entry in this array unless characters from scripts - // of other languages are measured. - AutoTArray mFontSets; - - gfxFloat mSizeAdjustFactor; - PangoLanguage *mPangoLanguage; - - // @param aLang [in] language to use for pref fonts and system font - // resolution, or nullptr to guess a language from the gfxFontStyle. - // @param aMatchPattern [out] if non-nullptr, will return the pattern used. - already_AddRefed - MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor, - nsAutoRef *aMatchPattern = nullptr); - - gfxFcFontSet *GetBaseFontSet(); - gfxFcFont *GetBaseFont(); - - gfxFloat GetSizeAdjustFactor() - { - if (mFontSets.Length() == 0) - GetBaseFontSet(); - return mSizeAdjustFactor; - } - - // old helper methods from gfxFontGroup, moved here so that those methods - // can be revamped without affecting the legacy code here - - // iterate over the fontlist, lookup names and expand generics - void EnumerateFontListPFG(nsIAtom *aLanguage, void *aClosure); - - // expand a generic to a list of specific names based on prefs - void FindGenericFontsPFG(mozilla::FontFamilyType aGenericType, - nsIAtom *aLanguage, - void *aClosure); - - // lookup and add a font with a given name (i.e. *not* a generic!) - void FindPlatformFontPFG(const nsAString& aName, - bool aUseFontSet, - void *aClosure); - - static void - ResolveGenericFontNamesPFG(mozilla::FontFamilyType aGenericType, - nsIAtom *aLanguage, - nsTArray& aGenericFamilies); - -}; - #endif /* GFX_FONTCONFIG_FONTS_H */ diff --git a/gfx/thebes/gfxFontconfigUtils.cpp b/gfx/thebes/gfxFontconfigUtils.cpp deleted file mode 100644 index 5bf606c13e25..000000000000 --- a/gfx/thebes/gfxFontconfigUtils.cpp +++ /dev/null @@ -1,1100 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * 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/ArrayUtils.h" - -#include "gfxFontconfigUtils.h" -#include "gfxFont.h" -#include "nsGkAtoms.h" - -#include -#include - -#include "nsServiceManagerUtils.h" -#include "nsILanguageAtomService.h" -#include "nsTArray.h" -#include "mozilla/Preferences.h" -#include "nsDirectoryServiceUtils.h" -#include "nsDirectoryServiceDefs.h" -#include "nsAppDirectoryServiceDefs.h" - -#include "nsIAtom.h" -#include "nsCRT.h" -#include "gfxFontConstants.h" -#include "mozilla/gfx/2D.h" - -using namespace mozilla; - -/* static */ gfxFontconfigUtils* gfxFontconfigUtils::sUtils = nullptr; -static nsILanguageAtomService* gLangService = nullptr; - -/* static */ void -gfxFontconfigUtils::Shutdown() { - if (sUtils) { - delete sUtils; - sUtils = nullptr; - } - NS_IF_RELEASE(gLangService); -} - -/* static */ uint8_t -gfxFontconfigUtils::FcSlantToThebesStyle(int aFcSlant) -{ - switch (aFcSlant) { - case FC_SLANT_ITALIC: - return NS_FONT_STYLE_ITALIC; - case FC_SLANT_OBLIQUE: - return NS_FONT_STYLE_OBLIQUE; - default: - return NS_FONT_STYLE_NORMAL; - } -} - -/* static */ uint8_t -gfxFontconfigUtils::GetThebesStyle(FcPattern *aPattern) -{ - int slant; - if (FcPatternGetInteger(aPattern, FC_SLANT, 0, &slant) != FcResultMatch) { - return NS_FONT_STYLE_NORMAL; - } - - return FcSlantToThebesStyle(slant); -} - -/* static */ int -gfxFontconfigUtils::GetFcSlant(const gfxFontStyle& aFontStyle) -{ - if (aFontStyle.style == NS_FONT_STYLE_ITALIC) - return FC_SLANT_ITALIC; - if (aFontStyle.style == NS_FONT_STYLE_OBLIQUE) - return FC_SLANT_OBLIQUE; - - return FC_SLANT_ROMAN; -} - -// OS/2 weight classes were introduced in fontconfig-2.1.93 (2003). -#ifndef FC_WEIGHT_THIN -#define FC_WEIGHT_THIN 0 // 2.1.93 -#define FC_WEIGHT_EXTRALIGHT 40 // 2.1.93 -#define FC_WEIGHT_REGULAR 80 // 2.1.93 -#define FC_WEIGHT_EXTRABOLD 205 // 2.1.93 -#endif -// book was introduced in fontconfig-2.2.90 (and so fontconfig-2.3.0 in 2005) -#ifndef FC_WEIGHT_BOOK -#define FC_WEIGHT_BOOK 75 -#endif -// extra black was introduced in fontconfig-2.4.91 (2007) -#ifndef FC_WEIGHT_EXTRABLACK -#define FC_WEIGHT_EXTRABLACK 215 -#endif - -/* static */ uint16_t -gfxFontconfigUtils::GetThebesWeight(FcPattern *aPattern) -{ - int weight; - if (FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &weight) != FcResultMatch) - return NS_FONT_WEIGHT_NORMAL; - - if (weight <= (FC_WEIGHT_THIN + FC_WEIGHT_EXTRALIGHT) / 2) - return 100; - if (weight <= (FC_WEIGHT_EXTRALIGHT + FC_WEIGHT_LIGHT) / 2) - return 200; - if (weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_BOOK) / 2) - return 300; - if (weight <= (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2) - // This includes FC_WEIGHT_BOOK - return 400; - if (weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) - return 500; - if (weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) - return 600; - if (weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_EXTRABOLD) / 2) - return 700; - if (weight <= (FC_WEIGHT_EXTRABOLD + FC_WEIGHT_BLACK) / 2) - return 800; - if (weight <= FC_WEIGHT_BLACK) - return 900; - - // including FC_WEIGHT_EXTRABLACK - return 901; -} - -/* static */ int -gfxFontconfigUtils::FcWeightForBaseWeight(int8_t aBaseWeight) -{ - NS_PRECONDITION(aBaseWeight >= 0 && aBaseWeight <= 10, - "base weight out of range"); - - switch (aBaseWeight) { - case 2: - return FC_WEIGHT_EXTRALIGHT; - case 3: - return FC_WEIGHT_LIGHT; - case 4: - return FC_WEIGHT_REGULAR; - case 5: - return FC_WEIGHT_MEDIUM; - case 6: - return FC_WEIGHT_DEMIBOLD; - case 7: - return FC_WEIGHT_BOLD; - case 8: - return FC_WEIGHT_EXTRABOLD; - case 9: - return FC_WEIGHT_BLACK; - } - - // extremes - return aBaseWeight < 2 ? FC_WEIGHT_THIN : FC_WEIGHT_EXTRABLACK; -} - -/* static */ int16_t -gfxFontconfigUtils::GetThebesStretch(FcPattern *aPattern) -{ - int width; - if (FcPatternGetInteger(aPattern, FC_WIDTH, 0, &width) != FcResultMatch) { - return NS_FONT_STRETCH_NORMAL; - } - - if (width <= (FC_WIDTH_ULTRACONDENSED + FC_WIDTH_EXTRACONDENSED) / 2) { - return NS_FONT_STRETCH_ULTRA_CONDENSED; - } - if (width <= (FC_WIDTH_EXTRACONDENSED + FC_WIDTH_CONDENSED) / 2) { - return NS_FONT_STRETCH_EXTRA_CONDENSED; - } - if (width <= (FC_WIDTH_CONDENSED + FC_WIDTH_SEMICONDENSED) / 2) { - return NS_FONT_STRETCH_CONDENSED; - } - if (width <= (FC_WIDTH_SEMICONDENSED + FC_WIDTH_NORMAL) / 2) { - return NS_FONT_STRETCH_SEMI_CONDENSED; - } - if (width <= (FC_WIDTH_NORMAL + FC_WIDTH_SEMIEXPANDED) / 2) { - return NS_FONT_STRETCH_NORMAL; - } - if (width <= (FC_WIDTH_SEMIEXPANDED + FC_WIDTH_EXPANDED) / 2) { - return NS_FONT_STRETCH_SEMI_EXPANDED; - } - if (width <= (FC_WIDTH_EXPANDED + FC_WIDTH_EXTRAEXPANDED) / 2) { - return NS_FONT_STRETCH_EXPANDED; - } - if (width <= (FC_WIDTH_EXTRAEXPANDED + FC_WIDTH_ULTRAEXPANDED) / 2) { - return NS_FONT_STRETCH_EXTRA_EXPANDED; - } - return NS_FONT_STRETCH_ULTRA_EXPANDED; -} - -/* static */ int -gfxFontconfigUtils::FcWidthForThebesStretch(int16_t aStretch) -{ - switch (aStretch) { - default: // this will catch "normal" (0) as well as out-of-range values - return FC_WIDTH_NORMAL; - case NS_FONT_STRETCH_ULTRA_CONDENSED: - return FC_WIDTH_ULTRACONDENSED; - case NS_FONT_STRETCH_EXTRA_CONDENSED: - return FC_WIDTH_EXTRACONDENSED; - case NS_FONT_STRETCH_CONDENSED: - return FC_WIDTH_CONDENSED; - case NS_FONT_STRETCH_SEMI_CONDENSED: - return FC_WIDTH_SEMICONDENSED; - case NS_FONT_STRETCH_SEMI_EXPANDED: - return FC_WIDTH_SEMIEXPANDED; - case NS_FONT_STRETCH_EXPANDED: - return FC_WIDTH_EXPANDED; - case NS_FONT_STRETCH_EXTRA_EXPANDED: - return FC_WIDTH_EXTRAEXPANDED; - case NS_FONT_STRETCH_ULTRA_EXPANDED: - return FC_WIDTH_ULTRAEXPANDED; - } -} - -// This makes a guess at an FC_WEIGHT corresponding to a base weight and -// offset (without any knowledge of which weights are available). - -/* static */ int -GuessFcWeight(const gfxFontStyle& aFontStyle) -{ - /* - * weights come in two parts crammed into one - * integer -- the "base" weight is weight / 100, - * the rest of the value is the "offset" from that - * weight -- the number of steps to move to adjust - * the weight in the list of supported font weights, - * this value can be negative or positive. - */ - int8_t weight = aFontStyle.ComputeWeight(); - - // ComputeWeight trimmed the range of weights for us - NS_ASSERTION(weight >= 0 && weight <= 10, - "base weight out of range"); - - return gfxFontconfigUtils::FcWeightForBaseWeight(weight); -} - -static void -AddString(FcPattern *aPattern, const char *object, const char *aString) -{ - FcPatternAddString(aPattern, object, - gfxFontconfigUtils::ToFcChar8(aString)); -} - -static void -AddWeakString(FcPattern *aPattern, const char *object, const char *aString) -{ - FcValue value; - value.type = FcTypeString; - value.u.s = gfxFontconfigUtils::ToFcChar8(aString); - - FcPatternAddWeak(aPattern, object, value, FcTrue); -} - -static void -AddLangGroup(FcPattern *aPattern, nsIAtom *aLangGroup) -{ - // Translate from mozilla's internal mapping into fontconfig's - nsAutoCString lang; - gfxFontconfigUtils::GetSampleLangForGroup(aLangGroup, &lang); - - if (!lang.IsEmpty()) { - AddString(aPattern, FC_LANG, lang.get()); - } -} - -nsReturnRef -gfxFontconfigUtils::NewPattern(const nsTArray& aFamilies, - const gfxFontStyle& aFontStyle, - const char *aLang) -{ - static const char* sFontconfigGenerics[] = - { "sans-serif", "serif", "monospace", "fantasy", "cursive" }; - - nsAutoRef pattern(FcPatternCreate()); - if (!pattern) - return nsReturnRef(); - - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aFontStyle.size); - FcPatternAddInteger(pattern, FC_SLANT, GetFcSlant(aFontStyle)); - FcPatternAddInteger(pattern, FC_WEIGHT, GuessFcWeight(aFontStyle)); - FcPatternAddInteger(pattern, FC_WIDTH, FcWidthForThebesStretch(aFontStyle.stretch)); - - if (aLang) { - AddString(pattern, FC_LANG, aLang); - } - - bool useWeakBinding = false; - for (uint32_t i = 0; i < aFamilies.Length(); ++i) { - NS_ConvertUTF16toUTF8 family(aFamilies[i]); - if (!useWeakBinding) { - AddString(pattern, FC_FAMILY, family.get()); - - // fontconfig generic families are typically implemented with weak - // aliases (so that the preferred font depends on language). - // However, this would give them lower priority than subsequent - // non-generic families in the list. To ensure that subsequent - // families do not have a higher priority, they are given weak - // bindings. - for (uint32_t g = 0; - g < ArrayLength(sFontconfigGenerics); - ++g) { - if (0 == FcStrCmpIgnoreCase(ToFcChar8(sFontconfigGenerics[g]), - ToFcChar8(family.get()))) { - useWeakBinding = true; - break; - } - } - } else { - AddWeakString(pattern, FC_FAMILY, family.get()); - } - } - - return pattern.out(); -} - -gfxFontconfigUtils::gfxFontconfigUtils() - : mFontsByFamily(32) - , mFontsByFullname(32) - , mLangSupportTable(32) - , mLastConfig(nullptr) -#ifdef MOZ_BUNDLED_FONTS - , mBundledFontsInitialized(false) -#endif -{ - UpdateFontListInternal(); -} - -nsresult -gfxFontconfigUtils::GetFontList(nsIAtom *aLangGroup, - const nsACString& aGenericFamily, - nsTArray& aListOfFonts) -{ - aListOfFonts.Clear(); - - nsTArray fonts; - nsresult rv = GetFontListInternal(fonts, aLangGroup); - if (NS_FAILED(rv)) - return rv; - - for (uint32_t i = 0; i < fonts.Length(); ++i) { - aListOfFonts.AppendElement(NS_ConvertUTF8toUTF16(fonts[i])); - } - - aListOfFonts.Sort(); - - int32_t serif = 0, sansSerif = 0, monospace = 0; - - // Fontconfig supports 3 generic fonts, "serif", "sans-serif", and - // "monospace", slightly different from CSS's 5. - if (aGenericFamily.IsEmpty()) - serif = sansSerif = monospace = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("serif")) - serif = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("sans-serif")) - sansSerif = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("monospace")) - monospace = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("cursive") || - aGenericFamily.LowerCaseEqualsLiteral("fantasy")) - serif = sansSerif = 1; - else - NS_NOTREACHED("unexpected CSS generic font family"); - - // The first in the list becomes the default in - // FontBuilder.readFontSelection() if the preference-selected font is not - // available, so put system configured defaults first. - if (monospace) - aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("monospace")); - if (sansSerif) - aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("sans-serif")); - if (serif) - aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("serif")); - - return NS_OK; -} - -struct MozLangGroupData { - nsIAtom* const& mozLangGroup; - const char *defaultLang; -}; - -const MozLangGroupData MozLangGroups[] = { - { nsGkAtoms::x_western, "en" }, - { nsGkAtoms::x_cyrillic, "ru" }, - { nsGkAtoms::x_devanagari, "hi" }, - { nsGkAtoms::x_tamil, "ta" }, - { nsGkAtoms::x_armn, "hy" }, - { nsGkAtoms::x_beng, "bn" }, - { nsGkAtoms::x_cans, "iu" }, - { nsGkAtoms::x_ethi, "am" }, - { nsGkAtoms::x_geor, "ka" }, - { nsGkAtoms::x_gujr, "gu" }, - { nsGkAtoms::x_guru, "pa" }, - { nsGkAtoms::x_khmr, "km" }, - { nsGkAtoms::x_knda, "kn" }, - { nsGkAtoms::x_mlym, "ml" }, - { nsGkAtoms::x_orya, "or" }, - { nsGkAtoms::x_sinh, "si" }, - { nsGkAtoms::x_telu, "te" }, - { nsGkAtoms::x_tibt, "bo" }, - { nsGkAtoms::Unicode, 0 }, -}; - -static bool -TryLangForGroup(const nsACString& aOSLang, nsIAtom *aLangGroup, - nsACString *aFcLang) -{ - // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'. - // aOSLang is in the form "language[_territory][.codeset][@modifier]". - // fontconfig takes languages in the form "language-territory". - // nsILanguageAtomService takes languages in the form language-subtag, - // where subtag may be a territory. fontconfig and nsILanguageAtomService - // handle case-conversion for us. - const char *pos, *end; - aOSLang.BeginReading(pos); - aOSLang.EndReading(end); - aFcLang->Truncate(); - while (pos < end) { - switch (*pos) { - case '.': - case '@': - end = pos; - break; - case '_': - aFcLang->Append('-'); - break; - default: - aFcLang->Append(*pos); - } - ++pos; - } - - nsIAtom *atom = - gLangService->LookupLanguage(*aFcLang); - - return atom == aLangGroup; -} - -/* static */ void -gfxFontconfigUtils::GetSampleLangForGroup(nsIAtom *aLangGroup, - nsACString *aFcLang) -{ - NS_PRECONDITION(aFcLang != nullptr, "aFcLang must not be NULL"); - - const MozLangGroupData *langGroup = nullptr; - - for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) { - if (aLangGroup == MozLangGroups[i].mozLangGroup) { - langGroup = &MozLangGroups[i]; - break; - } - } - - if (!langGroup) { - // Not a special mozilla language group. - // Use aLangGroup as a language code. - aLangGroup->ToUTF8String(*aFcLang); - return; - } - - // Check the environment for the users preferred language that corresponds - // to this langGroup. - if (!gLangService) { - CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService); - } - - if (gLangService) { - const char *languages = getenv("LANGUAGE"); - if (languages) { - const char separator = ':'; - - for (const char *pos = languages; true; ++pos) { - if (*pos == '\0' || *pos == separator) { - if (languages < pos && - TryLangForGroup(Substring(languages, pos), - aLangGroup, aFcLang)) - return; - - if (*pos == '\0') - break; - - languages = pos + 1; - } - } - } - const char *ctype = setlocale(LC_CTYPE, nullptr); - if (ctype && - TryLangForGroup(nsDependentCString(ctype), aLangGroup, aFcLang)) - return; - } - - if (langGroup->defaultLang) { - aFcLang->Assign(langGroup->defaultLang); - } else { - aFcLang->Truncate(); - } -} - -nsresult -gfxFontconfigUtils::GetFontListInternal(nsTArray& aListOfFonts, - nsIAtom *aLangGroup) -{ - FcPattern *pat = nullptr; - FcObjectSet *os = nullptr; - FcFontSet *fs = nullptr; - nsresult rv = NS_ERROR_FAILURE; - - aListOfFonts.Clear(); - - pat = FcPatternCreate(); - if (!pat) - goto end; - - os = FcObjectSetBuild(FC_FAMILY, nullptr); - if (!os) - goto end; - - // take the pattern and add the lang group to it - if (aLangGroup) { - AddLangGroup(pat, aLangGroup); - } - - fs = FcFontList(nullptr, pat, os); - if (!fs) - goto end; - - for (int i = 0; i < fs->nfont; i++) { - char *family; - - if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, - (FcChar8 **) &family) != FcResultMatch) - { - continue; - } - - // Remove duplicates... - nsAutoCString strFamily(family); - if (aListOfFonts.Contains(strFamily)) - continue; - - aListOfFonts.AppendElement(strFamily); - } - - rv = NS_OK; - - end: - if (NS_FAILED(rv)) - aListOfFonts.Clear(); - - if (pat) - FcPatternDestroy(pat); - if (os) - FcObjectSetDestroy(os); - if (fs) - FcFontSetDestroy(fs); - - return rv; -} - -nsresult -gfxFontconfigUtils::UpdateFontList() -{ - return UpdateFontListInternal(true); -} - -nsresult -gfxFontconfigUtils::UpdateFontListInternal(bool aForce) -{ - if (!aForce) { - // This checks periodically according to fontconfig's configured - // interval. - FcInitBringUptoDate(); - } else if (!FcConfigUptoDate(nullptr)) { // check now with aForce - mLastConfig = nullptr; - FcInitReinitialize(); - } - - // FcInitReinitialize() (used by FcInitBringUptoDate) creates a new config - // before destroying the old config, so the only way that we'd miss an - // update is if fontconfig did more than one update and the memory for the - // most recent config happened to be at the same location as the original - // config. - FcConfig *currentConfig = FcConfigGetCurrent(); - if (currentConfig == mLastConfig) - return NS_OK; - -#ifdef MOZ_BUNDLED_FONTS - ActivateBundledFonts(); -#endif - - // These FcFontSets are owned by fontconfig - FcFontSet *fontSets[] = { - FcConfigGetFonts(currentConfig, FcSetSystem) -#ifdef MOZ_BUNDLED_FONTS - , FcConfigGetFonts(currentConfig, FcSetApplication) -#endif - }; - - mFontsByFamily.Clear(); - mFontsByFullname.Clear(); - mLangSupportTable.Clear(); - - // Record the existing font families - for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) { - FcFontSet *fontSet = fontSets[fs]; - if (!fontSet) { // the application set might not exist - continue; - } - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - - FcChar8 *family; - for (int v = 0; - FcPatternGetString(font, FC_FAMILY, v, &family) == FcResultMatch; - ++v) { - FontsByFcStrEntry *entry = mFontsByFamily.PutEntry(family); - if (entry) { - bool added = entry->AddFont(font); - - if (!entry->mKey) { - // The reference to the font pattern keeps the pointer - // to string for the key valid. If adding the font - // failed then the entry must be removed. - if (added) { - entry->mKey = family; - } else { - mFontsByFamily.RemoveEntry(entry); - } - } - } - } - } - } - - mLastConfig = currentConfig; - return NS_OK; -} - -nsresult -gfxFontconfigUtils::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) -{ - aFamilyName.Truncate(); - - // The fontconfig has generic family names in the font list. - if (aFontName.EqualsLiteral("serif") || - aFontName.EqualsLiteral("sans-serif") || - aFontName.EqualsLiteral("monospace")) { - aFamilyName.Assign(aFontName); - return NS_OK; - } - - nsresult rv = UpdateFontListInternal(); - if (NS_FAILED(rv)) - return rv; - - NS_ConvertUTF16toUTF8 fontname(aFontName); - - // return empty string if no such family exists - if (!IsExistingFamily(fontname)) - return NS_OK; - - FcPattern *pat = nullptr; - FcObjectSet *os = nullptr; - FcFontSet *givenFS = nullptr; - nsTArray candidates; - FcFontSet *candidateFS = nullptr; - rv = NS_ERROR_FAILURE; - - pat = FcPatternCreate(); - if (!pat) - goto end; - - FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)fontname.get()); - - os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_INDEX, nullptr); - if (!os) - goto end; - - givenFS = FcFontList(nullptr, pat, os); - if (!givenFS) - goto end; - - // The first value associated with a FC_FAMILY property is the family - // returned by GetFontList(), so use this value if appropriate. - - // See if there is a font face with first family equal to the given family. - for (int i = 0; i < givenFS->nfont; ++i) { - char *firstFamily; - if (FcPatternGetString(givenFS->fonts[i], FC_FAMILY, 0, - (FcChar8 **) &firstFamily) != FcResultMatch) - continue; - - nsDependentCString first(firstFamily); - if (!candidates.Contains(first)) { - candidates.AppendElement(first); - - if (fontname.Equals(first)) { - aFamilyName.Assign(aFontName); - rv = NS_OK; - goto end; - } - } - } - - // See if any of the first family names represent the same set of font - // faces as the given family. - for (uint32_t j = 0; j < candidates.Length(); ++j) { - FcPatternDel(pat, FC_FAMILY); - FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)candidates[j].get()); - - candidateFS = FcFontList(nullptr, pat, os); - if (!candidateFS) - goto end; - - if (candidateFS->nfont != givenFS->nfont) - continue; - - bool equal = true; - for (int i = 0; i < givenFS->nfont; ++i) { - if (!FcPatternEqual(candidateFS->fonts[i], givenFS->fonts[i])) { - equal = false; - break; - } - } - if (equal) { - AppendUTF8toUTF16(candidates[j], aFamilyName); - rv = NS_OK; - goto end; - } - } - - // No match found; return empty string. - rv = NS_OK; - - end: - if (pat) - FcPatternDestroy(pat); - if (os) - FcObjectSetDestroy(os); - if (givenFS) - FcFontSetDestroy(givenFS); - if (candidateFS) - FcFontSetDestroy(candidateFS); - - return rv; -} - -bool -gfxFontconfigUtils::IsExistingFamily(const nsCString& aFamilyName) -{ - return mFontsByFamily.GetEntry(ToFcChar8(aFamilyName)) != nullptr; -} - -const nsTArray< nsCountedRef >& -gfxFontconfigUtils::GetFontsForFamily(const FcChar8 *aFamilyName) -{ - FontsByFcStrEntry *entry = mFontsByFamily.GetEntry(aFamilyName); - - if (!entry) - return mEmptyPatternArray; - - return entry->GetFonts(); -} - -// Fontconfig only provides a fullname property for fonts in formats with SFNT -// wrappers. For other font formats (including PCF and PS Type 1), a fullname -// must be generated from the family and style properties. Only the first -// family and style is checked, but that should be OK, as I don't expect -// non-SFNT fonts to have multiple families or styles. -bool -gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(FcPattern *aFont, - nsACString *aFullname) -{ - FcChar8 *family; - if (FcPatternGetString(aFont, FC_FAMILY, 0, &family) != FcResultMatch) - return false; - - aFullname->Truncate(); - aFullname->Append(ToCString(family)); - - FcChar8 *style; - if (FcPatternGetString(aFont, FC_STYLE, 0, &style) == FcResultMatch && - strcmp(ToCString(style), "Regular") != 0) { - aFullname->Append(' '); - aFullname->Append(ToCString(style)); - } - - return true; -} - -bool -gfxFontconfigUtils::FontsByFullnameEntry::KeyEquals(KeyTypePointer aKey) const -{ - const FcChar8 *key = mKey; - // If mKey is nullptr, key comes from the style and family of the first - // font. - nsAutoCString fullname; - if (!key) { - NS_ASSERTION(mFonts.Length(), "No font in FontsByFullnameEntry!"); - GetFullnameFromFamilyAndStyle(mFonts[0], &fullname); - - key = ToFcChar8(fullname); - } - - return FcStrCmpIgnoreCase(aKey, key) == 0; -} - -void -gfxFontconfigUtils::AddFullnameEntries() -{ - // These FcFontSets are owned by fontconfig - FcFontSet *fontSets[] = { - FcConfigGetFonts(nullptr, FcSetSystem) -#ifdef MOZ_BUNDLED_FONTS - , FcConfigGetFonts(nullptr, FcSetApplication) -#endif - }; - - for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) { - FcFontSet *fontSet = fontSets[fs]; - if (!fontSet) { - continue; - } - // Record the existing font families - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - - int v = 0; - FcChar8 *fullname; - while (FcPatternGetString(font, - FC_FULLNAME, v, &fullname) == FcResultMatch) { - FontsByFullnameEntry *entry = - mFontsByFullname.PutEntry(fullname); - if (entry) { - // entry always has space for one font, so the first - // AddFont will always succeed, and so the entry will - // always have a font from which to obtain the key. - bool added = entry->AddFont(font); - // The key may be nullptr either if this is the first - // font, or if the first font does not have a fullname - // property, and so the key is obtained from the font. - // Set the key in both cases. The check that AddFont - // succeeded is required for the second case. - if (!entry->mKey && added) { - entry->mKey = fullname; - } - } - - ++v; - } - - // Fontconfig does not provide a fullname property for all fonts. - if (v == 0) { - nsAutoCString name; - if (!GetFullnameFromFamilyAndStyle(font, &name)) - continue; - - FontsByFullnameEntry *entry = - mFontsByFullname.PutEntry(ToFcChar8(name)); - if (entry) { - entry->AddFont(font); - // Either entry->mKey has been set for a previous font or it - // remains nullptr to indicate that the key is obtained from - // the first font. - } - } - } - } -} - -const nsTArray< nsCountedRef >& -gfxFontconfigUtils::GetFontsForFullname(const FcChar8 *aFullname) -{ - if (mFontsByFullname.Count() == 0) { - AddFullnameEntries(); - } - - FontsByFullnameEntry *entry = mFontsByFullname.GetEntry(aFullname); - - if (!entry) - return mEmptyPatternArray; - - return entry->GetFonts(); -} - -static FcLangResult -CompareLangString(const FcChar8 *aLangA, const FcChar8 *aLangB) { - FcLangResult result = FcLangDifferentLang; - for (uint32_t i = 0; ; ++i) { - FcChar8 a = FcToLower(aLangA[i]); - FcChar8 b = FcToLower(aLangB[i]); - - if (a != b) { - if ((a == '\0' && b == '-') || (a == '-' && b == '\0')) - return FcLangDifferentCountry; - - return result; - } - if (a == '\0') - return FcLangEqual; - - if (a == '-') { - result = FcLangDifferentCountry; - } - } -} - -/* static */ -FcLangResult -gfxFontconfigUtils::GetLangSupport(FcPattern *aFont, const FcChar8 *aLang) -{ - // When fontconfig builds a pattern for a system font, it will set a - // single LangSet property value for the font. That value may be removed - // and additional string values may be added through FcConfigSubsitute - // with FcMatchScan. Values that are neither LangSet nor string are - // considered errors in fontconfig sort and match functions. - // - // If no string nor LangSet value is found, then either the font is a - // system font and the LangSet has been removed through FcConfigSubsitute, - // or the font is a web font and its language support is unknown. - // Returning FcLangDifferentLang for these fonts ensures that this font - // will not be assumed to satisfy the language, and so language will be - // prioritized in sorting fallback fonts. - FcValue value; - FcLangResult best = FcLangDifferentLang; - for (int v = 0; - FcPatternGet(aFont, FC_LANG, v, &value) == FcResultMatch; - ++v) { - - FcLangResult support; - switch (value.type) { - case FcTypeLangSet: - support = FcLangSetHasLang(value.u.l, aLang); - break; - case FcTypeString: - support = CompareLangString(value.u.s, aLang); - break; - default: - // error. continue to see if there is a useful value. - continue; - } - - if (support < best) { // lower is better - if (support == FcLangEqual) - return support; - best = support; - } - } - - return best; -} - -gfxFontconfigUtils::LangSupportEntry * -gfxFontconfigUtils::GetLangSupportEntry(const FcChar8 *aLang, bool aWithFonts) -{ - // Currently any unrecognized languages from documents will be converted - // to x-unicode by nsILanguageAtomService, so there is a limit on the - // langugages that will be added here. Reconsider when/if document - // languages are passed to this routine. - - LangSupportEntry *entry = mLangSupportTable.PutEntry(aLang); - if (!entry) - return nullptr; - - FcLangResult best = FcLangDifferentLang; - - if (!entry->IsKeyInitialized()) { - entry->InitKey(aLang); - } else { - // mSupport is already initialized. - if (!aWithFonts) - return entry; - - best = entry->mSupport; - // If there is support for this language, an empty font list indicates - // that the list hasn't been initialized yet. - if (best == FcLangDifferentLang || entry->mFonts.Length() > 0) - return entry; - } - - // These FcFontSets are owned by fontconfig - FcFontSet *fontSets[] = { - FcConfigGetFonts(nullptr, FcSetSystem) -#ifdef MOZ_BUNDLED_FONTS - , FcConfigGetFonts(nullptr, FcSetApplication) -#endif - }; - - AutoTArray fonts; - - for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) { - FcFontSet *fontSet = fontSets[fs]; - if (!fontSet) { - continue; - } - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - - FcLangResult support = GetLangSupport(font, aLang); - - if (support < best) { // lower is better - best = support; - if (aWithFonts) { - fonts.Clear(); - } else if (best == FcLangEqual) { - break; - } - } - - // The font list in the LangSupportEntry is expected to be used - // only when no default fonts support the language. There would - // be a large number of fonts in entries for languages using Latin - // script but these do not need to be created because default - // fonts already support these languages. - if (aWithFonts && support != FcLangDifferentLang && - support == best) { - fonts.AppendElement(font); - } - } - } - - entry->mSupport = best; - if (aWithFonts) { - if (fonts.Length() != 0) { - entry->mFonts.AppendElements(fonts.Elements(), fonts.Length()); - } else if (best != FcLangDifferentLang) { - // Previously there was a font that supported this language at the - // level of entry->mSupport, but it has now disappeared. At least - // entry->mSupport needs to be recalculated, but this is an - // indication that the set of installed fonts has changed, so - // update all caches. - mLastConfig = nullptr; // invalidates caches - UpdateFontListInternal(true); - return GetLangSupportEntry(aLang, aWithFonts); - } - } - - return entry; -} - -FcLangResult -gfxFontconfigUtils::GetBestLangSupport(const FcChar8 *aLang) -{ - UpdateFontListInternal(); - - LangSupportEntry *entry = GetLangSupportEntry(aLang, false); - if (!entry) - return FcLangEqual; - - return entry->mSupport; -} - -const nsTArray< nsCountedRef >& -gfxFontconfigUtils::GetFontsForLang(const FcChar8 *aLang) -{ - LangSupportEntry *entry = GetLangSupportEntry(aLang, true); - if (!entry) - return mEmptyPatternArray; - - return entry->mFonts; -} - -#ifdef MOZ_BUNDLED_FONTS - -void -gfxFontconfigUtils::ActivateBundledFonts() -{ - if (!mBundledFontsInitialized) { - mBundledFontsInitialized = true; - nsCOMPtr localDir; - nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir)); - if (NS_FAILED(rv)) { - return; - } - if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("fonts")))) { - return; - } - bool isDir; - if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) { - return; - } - if (NS_FAILED(localDir->GetNativePath(mBundledFontsPath))) { - return; - } - } - if (!mBundledFontsPath.IsEmpty()) { - FcConfigAppFontAddDir(nullptr, (const FcChar8*)mBundledFontsPath.get()); - } -} - -#endif - -gfxFontconfigFontBase::gfxFontconfigFontBase(cairo_scaled_font_t *aScaledFont, - FcPattern *aPattern, - gfxFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle) - : gfxFT2FontBase(aScaledFont, aFontEntry, aFontStyle) - , mPattern(aPattern) -{ -} - diff --git a/gfx/thebes/gfxFontconfigUtils.h b/gfx/thebes/gfxFontconfigUtils.h index eee69e481646..3f502c124345 100644 --- a/gfx/thebes/gfxFontconfigUtils.h +++ b/gfx/thebes/gfxFontconfigUtils.h @@ -8,11 +8,7 @@ #include "gfxPlatform.h" -#include "mozilla/MathAlgorithms.h" #include "nsAutoRef.h" -#include "nsTArray.h" -#include "nsTHashtable.h" -#include "nsISupportsImpl.h" #include "gfxFT2FontBase.h" #include @@ -40,285 +36,14 @@ public: static void Release(FcCharSet *ptr) { FcCharSetDestroy(ptr); } }; -class gfxIgnoreCaseCStringComparator -{ - public: - bool Equals(const nsACString& a, const nsACString& b) const - { - return nsCString(a).Equals(b, nsCaseInsensitiveCStringComparator()); - } - - bool LessThan(const nsACString& a, const nsACString& b) const - { - return a < b; - } -}; - -class gfxFontconfigUtils { -public: - gfxFontconfigUtils(); - - static gfxFontconfigUtils* GetFontconfigUtils() { - if (!sUtils) - sUtils = new gfxFontconfigUtils(); - return sUtils; - } - - static void Shutdown(); - - nsresult GetFontList(nsIAtom *aLangGroup, - const nsACString& aGenericFamily, - nsTArray& aListOfFonts); - - nsresult UpdateFontList(); - - nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName); - - const nsTArray< nsCountedRef >& - GetFontsForFamily(const FcChar8 *aFamilyName); - - const nsTArray< nsCountedRef >& - GetFontsForFullname(const FcChar8 *aFullname); - - // Returns the best support that any font offers for |aLang|. - FcLangResult GetBestLangSupport(const FcChar8 *aLang); - // Returns the fonts offering this best level of support. - const nsTArray< nsCountedRef >& - GetFontsForLang(const FcChar8 *aLang); - - // Retuns the language support for a fontconfig font pattern - static FcLangResult GetLangSupport(FcPattern *aFont, const FcChar8 *aLang); - - // Conversions between FcChar8*, which is unsigned char*, - // and (signed) char*, that check the type of the argument. - static const FcChar8 *ToFcChar8(const char *aCharPtr) - { - return reinterpret_cast(aCharPtr); - } - static const FcChar8 *ToFcChar8(const nsCString& aCString) - { - return ToFcChar8(aCString.get()); - } - static const char *ToCString(const FcChar8 *aChar8Ptr) - { - return reinterpret_cast(aChar8Ptr); - } - - static uint8_t FcSlantToThebesStyle(int aFcSlant); - static uint8_t GetThebesStyle(FcPattern *aPattern); // slant - static uint16_t GetThebesWeight(FcPattern *aPattern); - static int16_t GetThebesStretch(FcPattern *aPattern); - - static int GetFcSlant(const gfxFontStyle& aFontStyle); - // Returns a precise FC_WEIGHT from |aBaseWeight|, - // which is a CSS absolute weight / 100. - static int FcWeightForBaseWeight(int8_t aBaseWeight); - - static int FcWidthForThebesStretch(int16_t aStretch); - - static bool GetFullnameFromFamilyAndStyle(FcPattern *aFont, - nsACString *aFullname); - - // This doesn't consider which faces exist, and so initializes the pattern - // using a guessed weight, and doesn't consider sizeAdjust. - static nsReturnRef - NewPattern(const nsTArray& aFamilies, - const gfxFontStyle& aFontStyle, const char *aLang); - - /** - * @param aLangGroup [in] a Mozilla langGroup. - * @param aFcLang [out] returns a language suitable for fontconfig - * matching |aLangGroup| or an empty string if no match is found. - */ - static void GetSampleLangForGroup(nsIAtom *aLangGroup, - nsACString *aFcLang); - -protected: - // Base class for hash table entries with case-insensitive FcChar8 - // string keys. - class FcStrEntryBase : public PLDHashEntryHdr { - public: - typedef const FcChar8 *KeyType; - typedef const FcChar8 *KeyTypePointer; - - static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } - // Case-insensitive hash. - // - // fontconfig always ignores case of ASCII characters in family - // names and languages, but treatment of whitespace in families is - // not consistent. FcFontSort and FcFontMatch ignore whitespace - // except for whitespace in the first character, while FcFontList - // and config subsitution tests require whitespace to match - // exactly. CSS 2.1 implies that whitespace is important in the - // font-family property. FcStrCmpIgnoreCase considers whitespace - // important. - static PLDHashNumber HashKey(const FcChar8 *aKey) { - uint32_t hash = 0; - for (const FcChar8 *c = aKey; *c != '\0'; ++c) { - hash = mozilla::RotateLeft(hash, 3) ^ FcToLower(*c); - } - return hash; - } - enum { ALLOW_MEMMOVE = true }; - }; - -public: - // Hash entry with a dependent const FcChar8* pointer to an external - // string for a key (and no data). The user must ensure that the string - // associated with the pointer is not destroyed. This entry type is - // useful for family name keys as the family name string is held in the - // font pattern. - class DepFcStrEntry : public FcStrEntryBase { - public: - // When constructing a new entry in the hashtable, the key is left - // nullptr. The caller of PutEntry() must fill in mKey when nullptr. - // This provides a mechanism for the caller of PutEntry() to determine - // whether the entry has been initialized. - explicit DepFcStrEntry(KeyTypePointer aName) - : mKey(nullptr) { } - - DepFcStrEntry(const DepFcStrEntry& toCopy) - : mKey(toCopy.mKey) { } - - bool KeyEquals(KeyTypePointer aKey) const { - return FcStrCmpIgnoreCase(aKey, mKey) == 0; - } - - const FcChar8 *mKey; - }; - - // Hash entry that uses a copy of an FcChar8 string to store the key. - // This entry type is useful for language keys, as languages are usually - // not stored as strings in font patterns. - class CopiedFcStrEntry : public FcStrEntryBase { - public: - // When constructing a new entry in the hashtable, the key is void. - // The caller of PutEntry() must call InitKey() when IsKeyInitialized() - // returns false. This provides a mechanism for the caller of - // PutEntry() to determine whether the entry has been initialized. - explicit CopiedFcStrEntry(KeyTypePointer aName) { - mKey.SetIsVoid(true); - } - - CopiedFcStrEntry(const CopiedFcStrEntry& toCopy) - : mKey(toCopy.mKey) { } - - bool KeyEquals(KeyTypePointer aKey) const { - return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey)) == 0; - } - - bool IsKeyInitialized() { return !mKey.IsVoid(); } - void InitKey(const FcChar8* aKey) { mKey.Assign(ToCString(aKey)); } - - private: - nsCString mKey; - }; - -protected: - class FontsByFcStrEntry : public DepFcStrEntry { - public: - explicit FontsByFcStrEntry(KeyTypePointer aName) - : DepFcStrEntry(aName) { } - - FontsByFcStrEntry(const FontsByFcStrEntry& toCopy) - : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } - - bool AddFont(FcPattern *aFont) { - return mFonts.AppendElement(aFont) != nullptr; - } - const nsTArray< nsCountedRef >& GetFonts() { - return mFonts; - } - private: - nsTArray< nsCountedRef > mFonts; - }; - - // FontsByFullnameEntry is similar to FontsByFcStrEntry (used for - // mFontsByFamily) except for two differences: - // - // * The font does not always contain a single string for the fullname, so - // the key is sometimes a combination of family and style. - // - // * There is usually only one font. - class FontsByFullnameEntry : public DepFcStrEntry { - public: - // When constructing a new entry in the hashtable, the key is left - // nullptr. The caller of PutEntry() is must fill in mKey when adding - // the first font if the key is not derived from the family and style. - // If the key is derived from family and style, a font must be added. - explicit FontsByFullnameEntry(KeyTypePointer aName) - : DepFcStrEntry(aName) { } - - FontsByFullnameEntry(const FontsByFullnameEntry& toCopy) - : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } - - bool KeyEquals(KeyTypePointer aKey) const; - - bool AddFont(FcPattern *aFont) { - return mFonts.AppendElement(aFont) != nullptr; - } - const nsTArray< nsCountedRef >& GetFonts() { - return mFonts; - } - - // Don't memmove the AutoTArray. - enum { ALLOW_MEMMOVE = false }; - private: - // There is usually only one font, but sometimes more. - AutoTArray,1> mFonts; - }; - - class LangSupportEntry : public CopiedFcStrEntry { - public: - explicit LangSupportEntry(KeyTypePointer aName) - : CopiedFcStrEntry(aName) { } - - LangSupportEntry(const LangSupportEntry& toCopy) - : CopiedFcStrEntry(toCopy), mSupport(toCopy.mSupport) { } - - FcLangResult mSupport; - nsTArray< nsCountedRef > mFonts; - }; - - static gfxFontconfigUtils* sUtils; - - bool IsExistingFamily(const nsCString& aFamilyName); - - nsresult GetFontListInternal(nsTArray& aListOfFonts, - nsIAtom *aLangGroup); - nsresult UpdateFontListInternal(bool aForce = false); - - void AddFullnameEntries(); - - LangSupportEntry *GetLangSupportEntry(const FcChar8 *aLang, - bool aWithFonts); - - // mFontsByFamily and mFontsByFullname contain entries only for families - // and fullnames for which there are fonts. - nsTHashtable mFontsByFamily; - nsTHashtable mFontsByFullname; - // mLangSupportTable contains an entry for each language that has been - // looked up through GetLangSupportEntry, even when the language is not - // supported. - nsTHashtable mLangSupportTable; - const nsTArray< nsCountedRef > mEmptyPatternArray; - - FcConfig *mLastConfig; - -#ifdef MOZ_BUNDLED_FONTS - void ActivateBundledFonts(); - - nsCString mBundledFontsPath; - bool mBundledFontsInitialized; -#endif -}; - class gfxFontconfigFontBase : public gfxFT2FontBase { public: gfxFontconfigFontBase(cairo_scaled_font_t *aScaledFont, FcPattern *aPattern, gfxFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle); + const gfxFontStyle *aFontStyle) + : gfxFT2FontBase(aScaledFont, aFontEntry, aFontStyle) + , mPattern(aPattern) { } virtual FontType GetType() const override { return FONT_TYPE_FONTCONFIG; } virtual FcPattern *GetPattern() const { return mPattern; } diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 95536eea123d..f61a82a02b57 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -88,10 +88,6 @@ #include "GLContextProvider.h" #include "mozilla/gfx/Logging.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - #ifdef MOZ_WIDGET_ANDROID #include "TexturePoolOGL.h" #include "mozilla/layers/UiCompositorControllerChild.h" @@ -711,17 +707,9 @@ gfxPlatform::Init() gPlatform->ComputeTileSize(); nsresult rv; - - bool usePlatformFontList = true; -#if defined(MOZ_WIDGET_GTK) - usePlatformFontList = gfxPlatformGtk::UseFcFontList(); -#endif - - if (usePlatformFontList) { - rv = gfxPlatformFontList::Init(); - if (NS_FAILED(rv)) { - MOZ_CRASH("Could not initialize gfxPlatformFontList"); - } + rv = gfxPlatformFontList::Init(); + if (NS_FAILED(rv)) { + MOZ_CRASH("Could not initialize gfxPlatformFontList"); } gPlatform->mScreenReferenceSurface = @@ -2301,12 +2289,13 @@ gfxPlatform::InitWebRenderConfig() { FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER); - featureWebRender.EnableByDefault(); + featureWebRender.DisableByDefault( + FeatureStatus::OptIn, + "WebRender is an opt-in feature", + NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF")); - if (!Preferences::GetBool("gfx.webrender.enabled", false)) { - featureWebRender.UserDisable( - "User disabled WebRender", - NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_DISABLED")); + if (Preferences::GetBool("gfx.webrender.enabled", false)) { + featureWebRender.UserEnable("Enabled by pref"); } // WebRender relies on the GPU process when on Windows @@ -2326,7 +2315,7 @@ gfxPlatform::InitWebRenderConfig() NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE")); } -#ifndef MOZ_ENABLE_WEBRENDER +#ifndef MOZ_BUILD_WEBRENDER featureWebRender.ForceDisable( FeatureStatus::Unavailable, "Build doesn't include WebRender", diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index 501389934abd..a7629ed5916b 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -67,23 +67,14 @@ using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::unicode; -gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nullptr; - #if (MOZ_WIDGET_GTK == 2) static cairo_user_data_key_t cairo_gdk_drawable_key; #endif -bool gfxPlatformGtk::sUseFcFontList = false; - gfxPlatformGtk::gfxPlatformGtk() { gtk_init(nullptr, nullptr); - sUseFcFontList = mozilla::Preferences::GetBool("gfx.font_rendering.fontconfig.fontlist.enabled"); - if (!sUseFcFontList && !sFontconfigUtils) { - sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils(); - } - mMaxGenericSubstitutions = UNINITIALIZED_VALUE; #ifdef MOZ_X11 @@ -117,12 +108,6 @@ gfxPlatformGtk::gfxPlatformGtk() gfxPlatformGtk::~gfxPlatformGtk() { - if (!sUseFcFontList) { - gfxFontconfigUtils::Shutdown(); - sFontconfigUtils = nullptr; - gfxPangoFontGroup::Shutdown(); - } - #ifdef MOZ_X11 if (mCompositorDisplay) { XCloseDisplay(mCompositorDisplay); @@ -200,27 +185,17 @@ gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, nsTArray& aListOfFonts) { - if (sUseFcFontList) { - gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, - aGenericFamily, - aListOfFonts); - return NS_OK; - } - - return sFontconfigUtils->GetFontList(aLangGroup, - aGenericFamily, - aListOfFonts); + gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, + aGenericFamily, + aListOfFonts); + return NS_OK; } nsresult gfxPlatformGtk::UpdateFontList() { - if (sUseFcFontList) { - gfxPlatformFontList::PlatformFontList()->UpdateFontList(); - return NS_OK; - } - - return sFontconfigUtils->UpdateFontList(); + gfxPlatformFontList::PlatformFontList()->UpdateFontList(); + return NS_OK; } // xxx - this is ubuntu centric, need to go through other distros and flesh @@ -287,13 +262,9 @@ gfxPlatformGtk::CreatePlatformFontList() nsresult gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) { - if (sUseFcFontList) { - gfxPlatformFontList::PlatformFontList()-> - GetStandardFamilyName(aFontName, aFamilyName); - return NS_OK; - } - - return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName); + gfxPlatformFontList::PlatformFontList()-> + GetStandardFamilyName(aFontName, aFamilyName); + return NS_OK; } gfxFontGroup * @@ -303,13 +274,8 @@ gfxPlatformGtk::CreateFontGroup(const FontFamilyList& aFontFamilyList, gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize) { - if (sUseFcFontList) { - return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, - aUserFontSet, aDevToCssSize); - } - - return new gfxPangoFontGroup(aFontFamilyList, aStyle, - aUserFontSet, aDevToCssSize); + return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, + aUserFontSet, aDevToCssSize); } gfxFontEntry* @@ -318,14 +284,9 @@ gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName, int16_t aStretch, uint8_t aStyle) { - if (sUseFcFontList) { - gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); - return pfl->LookupLocalFont(aFontName, aWeight, aStretch, - aStyle); - } - - return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight, - aStretch, aStyle); + gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); + return pfl->LookupLocalFont(aFontName, aWeight, aStretch, + aStyle); } gfxFontEntry* @@ -336,26 +297,15 @@ gfxPlatformGtk::MakePlatformFont(const nsAString& aFontName, const uint8_t* aFontData, uint32_t aLength) { - if (sUseFcFontList) { - gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); - return pfl->MakePlatformFont(aFontName, aWeight, aStretch, - aStyle, aFontData, aLength); - } - - // passing ownership of the font data to the new font entry - return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight, - aStretch, aStyle, - aFontData, aLength); + gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); + return pfl->MakePlatformFont(aFontName, aWeight, aStretch, + aStyle, aFontData, aLength); } FT_Library gfxPlatformGtk::GetFTLibrary() { - if (sUseFcFontList) { - return gfxFcPlatformFontList::GetFTLibrary(); - } - - return gfxPangoFontGroup::GetFTLibrary(); + return gfxFcPlatformFontList::GetFTLibrary(); } bool @@ -447,11 +397,9 @@ void gfxPlatformGtk::FontsPrefsChanged(const char *aPref) } mMaxGenericSubstitutions = UNINITIALIZED_VALUE; - if (sUseFcFontList) { - gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList(); - pfl->ClearGenericMappings(); - FlushFontAndWordCaches(); - } + gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList(); + pfl->ClearGenericMappings(); + FlushFontAndWordCaches(); } uint32_t gfxPlatformGtk::MaxGenericSubstitions() diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h index 25706de85bf8..baa4353cab37 100644 --- a/gfx/thebes/gfxPlatformGtk.h +++ b/gfx/thebes/gfxPlatformGtk.h @@ -113,8 +113,6 @@ public: } #endif - static bool UseFcFontList() { return sUseFcFontList; } - bool UseImageOffscreenSurfaces(); virtual gfxImageFormat GetOffscreenFormat() override; @@ -158,10 +156,6 @@ private: #ifdef MOZ_X11 Display* mCompositorDisplay; #endif - - // xxx - this will be removed once the new fontconfig platform font list - // replaces gfxPangoFontGroup - static bool sUseFcFontList; }; #endif /* GFX_PLATFORM_GTK_H */ diff --git a/gfx/thebes/gfxSVGGlyphs.cpp b/gfx/thebes/gfxSVGGlyphs.cpp index 21e88212deab..6276e882ddf7 100644 --- a/gfx/thebes/gfxSVGGlyphs.cpp +++ b/gfx/thebes/gfxSVGGlyphs.cpp @@ -16,7 +16,7 @@ #include "nsServiceManagerUtils.h" #include "nsIPresShell.h" #include "nsNetUtil.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIInputStream.h" #include "nsStringStream.h" #include "nsStreamUtils.h" @@ -359,7 +359,7 @@ gfxSVGGlyphsDocument::ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen) rv = NS_NewURI(getter_AddRefs(uri), mSVGGlyphsDocumentURI); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); nsCOMPtr domDoc; rv = NS_NewDOMDocument(getter_AddRefs(domDoc), diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index e32d50c89146..6e968736feac 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -28,10 +28,6 @@ #include "mozilla/gfx/Logging.h" // for gfxCriticalError #include "mozilla/UniquePtr.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - #ifdef XP_WIN #include "gfxWindowsPlatform.h" #endif @@ -1715,7 +1711,6 @@ gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList, , mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aStyle->language)) , mLastPrefFirstFont(false) , mSkipDrawing(false) - , mSkipUpdateUserFonts(false) { // We don't use SetUserFontSet() here, as we want to unconditionally call // BuildFontList() rather than only do UpdateUserFonts() if it changed. @@ -1730,16 +1725,6 @@ gfxFontGroup::~gfxFontGroup() void gfxFontGroup::BuildFontList() { - bool enumerateFonts = true; - -#if defined(MOZ_WIDGET_GTK) - // xxx - eliminate this once gfxPangoFontGroup is no longer needed - enumerateFonts = gfxPlatformGtk::UseFcFontList(); -#endif - if (!enumerateFonts) { - return; - } - // initialize fonts in the font family list AutoTArray fonts; gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); @@ -2454,7 +2439,7 @@ gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, "don't call InitScriptRun with aborted shaping state"); // confirm the load state of userfonts in the list - if (!mSkipUpdateUserFonts && mUserFontSet && + if (mUserFontSet && mCurrGeneration != mUserFontSet->GetGeneration()) { UpdateUserFonts(); } @@ -3192,8 +3177,6 @@ gfxFontGroup::GetRebuildGeneration() return mUserFontSet->GetRebuildGeneration(); } -// note: gfxPangoFontGroup overrides UpdateUserFonts, such that -// BuildFontList is never used void gfxFontGroup::UpdateUserFonts() { diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index e817518982da..2e1f4b495be8 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -1115,9 +1115,6 @@ protected: // download to complete (or fallback // timer to fire) - // xxx - gfxPangoFontGroup skips UpdateUserFonts - bool mSkipUpdateUserFonts; - /** * Textrun creation short-cuts for special cases where we don't need to * call a font shaper to generate glyphs. diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index d918b4877d68..8fc68c9c7fd1 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -978,32 +978,6 @@ gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName, } } -gfxUserFontEntry* -gfxUserFontSet::FindUserFontEntryAndLoad(gfxFontFamily* aFamily, - const gfxFontStyle& aFontStyle, - bool& aNeedsBold, - bool& aWaitForUserFont) -{ - aWaitForUserFont = false; - gfxFontEntry* fe = aFamily->FindFontForStyle(aFontStyle, aNeedsBold); - NS_ASSERTION(!fe || fe->mIsUserFontContainer, - "should only have userfont entries in userfont families"); - if (!fe) { - return nullptr; - } - - gfxUserFontEntry* userFontEntry = static_cast(fe); - - // start the load if it hasn't been loaded - userFontEntry->Load(); - if (userFontEntry->GetPlatformFontEntry()) { - return userFontEntry; - } - - aWaitForUserFont = userFontEntry->WaitForUserFont(); - return nullptr; -} - void gfxUserFontSet::IncrementGeneration(bool aIsRebuild) { diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 0a5da53830f6..c869d8911933 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -248,14 +248,6 @@ public: // Look up names in a fontlist and return true if any are in the set bool ContainsUserFontSetFonts(const mozilla::FontFamilyList& aFontList) const; - // Lookup a font entry for a given style, returns null if not loaded. - // aFamily must be a family returned by our LookupFamily method. - // (only used by gfxPangoFontGroup for now) - gfxUserFontEntry* FindUserFontEntryAndLoad(gfxFontFamily* aFamily, - const gfxFontStyle& aFontStyle, - bool& aNeedsBold, - bool& aWaitForUserFont); - // check whether the given source is allowed to be loaded; // returns the Principal (for use in the key when caching the loaded font), // and whether the load should bypass the cache (force-reload). diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 7ad26449ae19..1410fb040298 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1217,6 +1217,14 @@ gfxWindowsPlatform::SetupClearTypeParams() } } + if (GetDefaultContentBackend() == BackendType::SKIA) { + // Skia doesn't support a contrast value outside of 0-1, so default to 1.0 + if (contrast < 0.0 || contrast > 1.0) { + NS_WARNING("Custom dwrite contrast not supported in Skia. Defaulting to 1.0."); + contrast = 1.0; + } + } + // For parameters that have not been explicitly set, // we copy values from default params (or our overridden value for contrast) if (gamma < 1.0 || gamma > 2.2) { diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index a08aa27b1b7c..f51288fcbd11 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -110,8 +110,6 @@ elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: ] SOURCES += [ 'gfxFcPlatformFontList.cpp', - 'gfxFontconfigFonts.cpp', - 'gfxFontconfigUtils.cpp', 'gfxFT2FontBase.cpp', 'gfxFT2Utils.cpp', 'gfxGdkNativeRenderer.cpp', diff --git a/gfx/webrender_bindings/webrender_ffi.h b/gfx/webrender_bindings/webrender_ffi.h index b4f5a3c009d4..b662785c0d58 100644 --- a/gfx/webrender_bindings/webrender_ffi.h +++ b/gfx/webrender_bindings/webrender_ffi.h @@ -452,7 +452,7 @@ struct WrVecU8 { // an error and causes the build to fail. So for wr_* functions called by // destructors in C++ classes, use WR_DESTRUCTOR_SAFE_FUNC instead, which omits // the unreachable annotation. -#ifdef MOZ_ENABLE_WEBRENDER +#ifdef MOZ_BUILD_WEBRENDER # define WR_INLINE # define WR_FUNC # define WR_DESTRUCTOR_SAFE_FUNC diff --git a/image/FrameAnimator.cpp b/image/FrameAnimator.cpp index a3ed0a4a69e2..736d722d7a04 100644 --- a/image/FrameAnimator.cpp +++ b/image/FrameAnimator.cpp @@ -141,28 +141,33 @@ AnimationState::LoopLength() const // FrameAnimator implementation. /////////////////////////////////////////////////////////////////////////////// -TimeStamp +Maybe FrameAnimator::GetCurrentImgFrameEndTime(AnimationState& aState) const { TimeStamp currentFrameTime = aState.mCurrentAnimationFrameTime; - FrameTimeout timeout = GetTimeoutForFrame(aState.mCurrentAnimationFrameIndex); + Maybe timeout = GetTimeoutForFrame(aState, aState.mCurrentAnimationFrameIndex); - if (timeout == FrameTimeout::Forever()) { + if (timeout.isNothing()) { + MOZ_ASSERT(aState.GetHasBeenDecoded() && !aState.GetIsCurrentlyDecoded()); + return Nothing(); + } + + if (*timeout == FrameTimeout::Forever()) { // We need to return a sentinel value in this case, because our logic // doesn't work correctly if we have an infinitely long timeout. We use one // year in the future as the sentinel because it works with the loop in // RequestRefresh() below. // XXX(seth): It'd be preferable to make our logic work correctly with // infinitely long timeouts. - return TimeStamp::NowLoRes() + - TimeDuration::FromMilliseconds(31536000.0); + return Some(TimeStamp::NowLoRes() + + TimeDuration::FromMilliseconds(31536000.0)); } TimeDuration durationOfTimeout = - TimeDuration::FromMilliseconds(double(timeout.AsMilliseconds())); + TimeDuration::FromMilliseconds(double(timeout->AsMilliseconds())); TimeStamp currentFrameEndTime = currentFrameTime + durationOfTimeout; - return currentFrameEndTime; + return Some(currentFrameEndTime); } RefreshResult @@ -238,7 +243,11 @@ FrameAnimator::AdvanceFrame(AnimationState& aState, TimeStamp aTime) return ret; } - if (GetTimeoutForFrame(nextFrameIndex) == FrameTimeout::Forever()) { + Maybe nextFrameTimeout = GetTimeoutForFrame(aState, nextFrameIndex); + // GetTimeoutForFrame can only return none if frame doesn't exist, + // but we just got it above. + MOZ_ASSERT(nextFrameTimeout.isSome()); + if (*nextFrameTimeout == FrameTimeout::Forever()) { ret.mAnimationFinished = true; } @@ -252,7 +261,9 @@ FrameAnimator::AdvanceFrame(AnimationState& aState, TimeStamp aTime) // something went wrong, move on to next NS_WARNING("FrameAnimator::AdvanceFrame(): Compositing of frame failed"); nextFrame->SetCompositingFailed(true); - aState.mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(aState); + Maybe currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + MOZ_ASSERT(currentFrameEndTime.isSome()); + aState.mCurrentAnimationFrameTime = *currentFrameEndTime; aState.mCurrentAnimationFrameIndex = nextFrameIndex; return ret; @@ -261,7 +272,9 @@ FrameAnimator::AdvanceFrame(AnimationState& aState, TimeStamp aTime) nextFrame->SetCompositingFailed(false); } - aState.mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(aState); + Maybe currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + MOZ_ASSERT(currentFrameEndTime.isSome()); + aState.mCurrentAnimationFrameTime = *currentFrameEndTime; // If we can get closer to the current time by a multiple of the image's loop // time, we should. We can only do this if we're done decoding; otherwise, we @@ -301,10 +314,18 @@ FrameAnimator::RequestRefresh(AnimationState& aState, const TimeStamp& aTime) // only advance the frame if the current time is greater than or // equal to the current frame's end time. - TimeStamp currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + Maybe currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + if (currentFrameEndTime.isNothing()) { + MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable()); + MOZ_ASSERT(aState.GetHasBeenDecoded() && !aState.GetIsCurrentlyDecoded()); + MOZ_ASSERT(aState.mCompositedFrameInvalid); + // Nothing we can do but wait for our previous current frame to be decoded + // again so we can determine what to do next. + return ret; + } - while (currentFrameEndTime <= aTime) { - TimeStamp oldFrameEndTime = currentFrameEndTime; + while (*currentFrameEndTime <= aTime) { + TimeStamp oldFrameEndTime = *currentFrameEndTime; RefreshResult frameRes = AdvanceFrame(aState, aTime); @@ -312,17 +333,19 @@ FrameAnimator::RequestRefresh(AnimationState& aState, const TimeStamp& aTime) ret.Accumulate(frameRes); currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + // AdvanceFrame can't advance to a frame that doesn't exist yet. + MOZ_ASSERT(currentFrameEndTime.isSome()); // If we didn't advance a frame, and our frame end time didn't change, // then we need to break out of this loop & wait for the frame(s) // to finish downloading. - if (!frameRes.mFrameAdvanced && (currentFrameEndTime == oldFrameEndTime)) { + if (!frameRes.mFrameAdvanced && (*currentFrameEndTime == oldFrameEndTime)) { break; } } // Advanced to the correct frame, the composited frame is now valid to be drawn. - if (currentFrameEndTime > aTime) { + if (*currentFrameEndTime > aTime) { aState.mCompositedFrameInvalid = false; } @@ -371,17 +394,18 @@ FrameAnimator::GetCompositedFrame(AnimationState& aState) return result; } -FrameTimeout -FrameAnimator::GetTimeoutForFrame(uint32_t aFrameNum) const +Maybe +FrameAnimator::GetTimeoutForFrame(AnimationState& aState, + uint32_t aFrameNum) const { RawAccessFrameRef frame = GetRawFrame(aFrameNum); if (frame) { AnimationData data = frame->GetAnimationData(); - return data.mTimeout; + return Some(data.mTimeout); } - NS_WARNING("No frame; called GetTimeoutForFrame too early?"); - return FrameTimeout::FromRawMilliseconds(100); + MOZ_ASSERT(aState.mHasBeenDecoded && !aState.mIsCurrentlyDecoded); + return Nothing(); } static void diff --git a/image/FrameAnimator.h b/image/FrameAnimator.h index 998a79f66db3..2f1cbe9eacca 100644 --- a/image/FrameAnimator.h +++ b/image/FrameAnimator.h @@ -312,15 +312,17 @@ private: // methods */ RawAccessFrameRef GetRawFrame(uint32_t aFrameNum) const; - /// @return the given frame's timeout. - FrameTimeout GetTimeoutForFrame(uint32_t aFrameNum) const; + /// @return the given frame's timeout if it is available + Maybe GetTimeoutForFrame(AnimationState& aState, + uint32_t aFrameNum) const; /** * Get the time the frame we're currently displaying is supposed to end. * - * In the error case, returns an "infinity" timestamp. + * In the error case (like if the requested frame is not currently + * decoded), returns None(). */ - TimeStamp GetCurrentImgFrameEndTime(AnimationState& aState) const; + Maybe GetCurrentImgFrameEndTime(AnimationState& aState) const; bool DoBlend(gfx::IntRect* aDirtyRect, uint32_t aPrevFrameIndex, diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index e2c28f773f6f..3796041881b1 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -107,6 +107,9 @@ RasterImage::~RasterImage() // Record Telemetry. Telemetry::Accumulate(Telemetry::IMAGE_DECODE_COUNT, mDecodeCount); + if (mAnimationState) { + Telemetry::Accumulate(Telemetry::IMAGE_ANIMATED_DECODE_COUNT, mDecodeCount); + } } nsresult @@ -1428,6 +1431,11 @@ RasterImage::Draw(gfxContext* aContext, TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime; Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, int32_t(drawLatency.ToMicroseconds())); + if (mAnimationState) { + Telemetry::Accumulate(Telemetry::IMAGE_ANIMATED_DECODE_ON_DRAW_LATENCY, + int32_t(drawLatency.ToMicroseconds())); + + } mDrawStartTime = TimeStamp(); } @@ -1677,6 +1685,11 @@ RasterImage::NotifyDecodeComplete(const DecoderFinalStatus& aStatus, Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME, int32_t(aTelemetry.mDecodeTime.ToMicroseconds())); + if (mAnimationState) { + Telemetry::Accumulate(Telemetry::IMAGE_ANIMATED_DECODE_TIME, + int32_t(aTelemetry.mDecodeTime.ToMicroseconds())); + } + if (aTelemetry.mSpeedHistogram) { Telemetry::Accumulate(*aTelemetry.mSpeedHistogram, aTelemetry.Speed()); } diff --git a/image/decoders/icon/android/nsIconChannel.cpp b/image/decoders/icon/android/nsIconChannel.cpp index 5670bf2f9540..11d58ea20a89 100644 --- a/image/decoders/icon/android/nsIconChannel.cpp +++ b/image/decoders/icon/android/nsIconChannel.cpp @@ -13,7 +13,7 @@ #include "nsIStringStream.h" #include "nsNetUtil.h" #include "nsComponentManagerUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" NS_IMPL_ISUPPORTS(nsIconChannel, nsIRequest, @@ -115,7 +115,7 @@ moz_icon_to_channel(nsIURI* aURI, const nsACString& aFileExt, // nsIconProtocolHandler::NewChannel2 will provide the correct loadInfo for // this iconChannel. Use the most restrictive security settings for the // temporary loadInfo to make sure the channel can not be openend. - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); return NS_NewInputStreamChannel(aChannel, aURI, stream, diff --git a/image/decoders/icon/gtk/nsIconChannel.cpp b/image/decoders/icon/gtk/nsIconChannel.cpp index 3d3820e72465..c050a37ce93d 100644 --- a/image/decoders/icon/gtk/nsIconChannel.cpp +++ b/image/decoders/icon/gtk/nsIconChannel.cpp @@ -27,7 +27,7 @@ #include "nsComponentManagerUtils.h" #include "nsIStringStream.h" #include "nsServiceManagerUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIURL.h" #include "prlink.h" @@ -107,7 +107,7 @@ moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIURI* aURI, // nsIconProtocolHandler::NewChannel2 will provide the correct loadInfo for // this iconChannel. Use the most restrictive security settings for the // temporary loadInfo to make sure the channel can not be openend. - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); return NS_NewInputStreamChannel(aChannel, aURI, stream, diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index 8d6014e4749f..d7a99677b47e 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -11,13 +11,13 @@ #include "mozilla/BasePrincipal.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/net/NeckoChannelParams.h" -#include "nsExpandedPrincipal.h" -#include "nsPrincipal.h" +#include "ExpandedPrincipal.h" #include "nsIScriptSecurityManager.h" #include "nsIURI.h" #include "nsNetUtil.h" #include "mozilla/LoadInfo.h" -#include "nsNullPrincipal.h" +#include "ContentPrincipal.h" +#include "NullPrincipal.h" #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsTArray.h" @@ -70,7 +70,7 @@ PrincipalInfoToPrincipal(const PrincipalInfo& aPrincipalInfo, return nullptr; } - principal = nsNullPrincipal::Create(info.attrs(), uri); + principal = NullPrincipal::Create(info.attrs(), uri); return principal.forget(); } @@ -124,8 +124,8 @@ PrincipalInfoToPrincipal(const PrincipalInfo& aPrincipalInfo, whitelist.AppendElement(wlPrincipal); } - RefPtr expandedPrincipal = - nsExpandedPrincipal::Create(whitelist, info.attrs()); + RefPtr expandedPrincipal = + ExpandedPrincipal::Create(whitelist, info.attrs()); if (!expandedPrincipal) { NS_WARNING("could not instantiate expanded principal"); return nullptr; diff --git a/ipc/glue/URIUtils.cpp b/ipc/glue/URIUtils.cpp index ec7656d74e8c..b961310d33bb 100644 --- a/ipc/glue/URIUtils.cpp +++ b/ipc/glue/URIUtils.cpp @@ -16,7 +16,7 @@ #include "nsJARURI.h" #include "nsIIconURI.h" #include "nsHostObjectURI.h" -#include "nsNullPrincipalURI.h" +#include "NullPrincipalURI.h" #include "nsJSProtocolHandler.h" #include "nsNetCID.h" #include "nsSimpleNestedURI.h" @@ -100,7 +100,7 @@ DeserializeURI(const URIParams& aParams) break; case URIParams::TNullPrincipalURIParams: - serializable = new nsNullPrincipalURI(); + serializable = new NullPrincipalURI(); break; case URIParams::TSimpleNestedURIParams: diff --git a/ipc/ipdl/ipdl.py b/ipc/ipdl/ipdl.py index d94e8536b8a6..de0132168996 100755 --- a/ipc/ipdl/ipdl.py +++ b/ipc/ipdl/ipdl.py @@ -151,7 +151,9 @@ for f in files: log(3, ' pretty printed code:') ipdl.genipdl(ast, codedir) -ipdl.checkFixedSyncMessages(parser) +if not ipdl.checkFixedSyncMessages(parser): + # Errors have alraedy been printed to stderr, just exit + sys.exit(1) # Second pass: generate code for f in files: diff --git a/ipc/ipdl/ipdl/checker.py b/ipc/ipdl/ipdl/checker.py index df836e9bcc00..114380035625 100644 --- a/ipc/ipdl/ipdl/checker.py +++ b/ipc/ipdl/ipdl/checker.py @@ -55,6 +55,7 @@ def checkSyncMessage(tu, syncMsgList, errout=sys.stderr): def checkFixedSyncMessages(config, errout=sys.stderr): fixed = SyncMessageChecker.getFixedSyncMessages() + error_free = True for item in fixed: protocol = item.split('::')[0] # Ignore things like sync messages in test protocols we didn't compile. @@ -63,3 +64,5 @@ def checkFixedSyncMessages(config, errout=sys.stderr): 'platform' not in config.options(item): print >>errout, 'Error: Sync IPC message %s not found, it appears to be fixed.\n' \ 'Please remove it from sync-messages.ini.' % item + error_free = False + return error_free diff --git a/ipc/ipdl/sync-messages.ini b/ipc/ipdl/sync-messages.ini index 46ef0984c0d8..ac446f695ca9 100644 --- a/ipc/ipdl/sync-messages.ini +++ b/ipc/ipdl/sync-messages.ini @@ -233,244 +233,364 @@ description = # A11y code [PDocAccessible::State] description = +platform = notwin [PDocAccessible::NativeState] description = +platform = notwin [PDocAccessible::Name] description = +platform = notwin [PDocAccessible::Value] description = +platform = notwin [PDocAccessible::Help] description = +platform = notwin [PDocAccessible::Description] description = +platform = notwin [PDocAccessible::Attributes] description = +platform = notwin [PDocAccessible::RelationByType] description = +platform = notwin [PDocAccessible::Relations] description = +platform = notwin [PDocAccessible::IsSearchbox] description = +platform = notwin [PDocAccessible::LandmarkRole] description = +platform = notwin [PDocAccessible::ARIARoleAtom] description = +platform = notwin [PDocAccessible::GetLevelInternal] description = +platform = notwin [PDocAccessible::CaretLineNumber] description = +platform = notwin [PDocAccessible::CaretOffset] description = +platform = notwin [PDocAccessible::CharacterCount] description = +platform = notwin [PDocAccessible::SelectionCount] description = +platform = notwin [PDocAccessible::TextSubstring] description = +platform = notwin [PDocAccessible::GetTextAfterOffset] description = +platform = notwin [PDocAccessible::GetTextAtOffset] description = +platform = notwin [PDocAccessible::GetTextBeforeOffset] description = +platform = notwin [PDocAccessible::CharAt] description = +platform = notwin [PDocAccessible::TextAttributes] description = +platform = notwin [PDocAccessible::DefaultTextAttributes] description = +platform = notwin [PDocAccessible::TextBounds] description = +platform = notwin [PDocAccessible::CharBounds] description = +platform = notwin [PDocAccessible::OffsetAtPoint] description = +platform = notwin [PDocAccessible::SelectionBoundsAt] description = +platform = notwin [PDocAccessible::SetSelectionBoundsAt] description = +platform = notwin [PDocAccessible::AddToSelection] description = +platform = notwin [PDocAccessible::RemoveFromSelection] description = +platform = notwin [PDocAccessible::Text] description = +platform = notwin [PDocAccessible::ReplaceText] description = +platform = notwin [PDocAccessible::InsertText] description = +platform = notwin [PDocAccessible::CopyText] description = +platform = notwin [PDocAccessible::CutText] description = +platform = notwin [PDocAccessible::DeleteText] description = +platform = notwin [PDocAccessible::PasteText] description = +platform = notwin [PDocAccessible::ImagePosition] description = +platform = notwin [PDocAccessible::ImageSize] description = +platform = notwin [PDocAccessible::StartOffset] description = +platform = notwin [PDocAccessible::EndOffset] description = +platform = notwin [PDocAccessible::IsLinkValid] description = +platform = notwin [PDocAccessible::AnchorCount] description = +platform = notwin [PDocAccessible::AnchorURIAt] description = +platform = notwin [PDocAccessible::AnchorAt] description = +platform = notwin [PDocAccessible::LinkCount] description = +platform = notwin [PDocAccessible::LinkAt] description = +platform = notwin [PDocAccessible::LinkIndexOf] description = +platform = notwin [PDocAccessible::LinkIndexAtOffset] description = +platform = notwin [PDocAccessible::TableOfACell] description = +platform = notwin [PDocAccessible::ColIdx] description = +platform = notwin [PDocAccessible::RowIdx] description = +platform = notwin [PDocAccessible::GetPosition] description = +platform = notwin [PDocAccessible::ColExtent] description = +platform = notwin [PDocAccessible::RowExtent] description = +platform = notwin [PDocAccessible::GetColRowExtents] description = +platform = notwin [PDocAccessible::ColHeaderCells] description = +platform = notwin [PDocAccessible::RowHeaderCells] description = +platform = notwin [PDocAccessible::IsCellSelected] description = +platform = notwin [PDocAccessible::TableCaption] description = +platform = notwin [PDocAccessible::TableSummary] description = +platform = notwin [PDocAccessible::TableColumnCount] description = +platform = notwin [PDocAccessible::TableRowCount] description = +platform = notwin [PDocAccessible::TableCellAt] description = +platform = notwin [PDocAccessible::TableCellIndexAt] description = +platform = notwin [PDocAccessible::TableColumnIndexAt] description = +platform = notwin [PDocAccessible::TableRowIndexAt] description = +platform = notwin [PDocAccessible::TableRowAndColumnIndicesAt] description = +platform = notwin [PDocAccessible::TableColumnExtentAt] description = +platform = notwin [PDocAccessible::TableRowExtentAt] description = +platform = notwin [PDocAccessible::TableColumnDescription] description = +platform = notwin [PDocAccessible::TableRowDescription] description = +platform = notwin [PDocAccessible::TableColumnSelected] description = +platform = notwin [PDocAccessible::TableRowSelected] description = +platform = notwin [PDocAccessible::TableCellSelected] description = +platform = notwin [PDocAccessible::TableSelectedCellCount] description = +platform = notwin [PDocAccessible::TableSelectedColumnCount] description = +platform = notwin [PDocAccessible::TableSelectedRowCount] description = +platform = notwin [PDocAccessible::TableSelectedCells] description = +platform = notwin [PDocAccessible::TableSelectedCellIndices] description = +platform = notwin [PDocAccessible::TableSelectedColumnIndices] description = +platform = notwin [PDocAccessible::TableSelectedRowIndices] description = +platform = notwin [PDocAccessible::TableSelectColumn] description = +platform = notwin [PDocAccessible::TableSelectRow] description = +platform = notwin [PDocAccessible::TableUnselectColumn] description = +platform = notwin [PDocAccessible::TableUnselectRow] description = +platform = notwin [PDocAccessible::TableIsProbablyForLayout] description = +platform = notwin [PDocAccessible::AtkTableColumnHeader] description = +platform = notwin [PDocAccessible::AtkTableRowHeader] description = +platform = notwin [PDocAccessible::SelectedItems] description = +platform = notwin [PDocAccessible::SelectedItemCount] description = +platform = notwin [PDocAccessible::GetSelectedItem] description = +platform = notwin [PDocAccessible::IsItemSelected] description = +platform = notwin [PDocAccessible::AddItemToSelection] description = +platform = notwin [PDocAccessible::RemoveItemFromSelection] description = +platform = notwin [PDocAccessible::SelectAll] description = +platform = notwin [PDocAccessible::UnselectAll] description = +platform = notwin [PDocAccessible::DoAction] description = +platform = notwin [PDocAccessible::ActionCount] description = +platform = notwin [PDocAccessible::ActionDescriptionAt] description = +platform = notwin [PDocAccessible::ActionNameAt] description = +platform = notwin [PDocAccessible::AccessKey] description = +platform = notwin [PDocAccessible::KeyboardShortcut] description = +platform = notwin [PDocAccessible::AtkKeyBinding] description = +platform = notwin [PDocAccessible::CurValue] description = +platform = notwin [PDocAccessible::SetCurValue] description = +platform = notwin [PDocAccessible::MinValue] description = +platform = notwin [PDocAccessible::MaxValue] description = +platform = notwin [PDocAccessible::Step] description = +platform = notwin [PDocAccessible::FocusedChild] description = +platform = notwin [PDocAccessible::Language] description = +platform = notwin [PDocAccessible::DocType] description = +platform = notwin [PDocAccessible::Title] description = +platform = notwin [PDocAccessible::URL] description = +platform = notwin [PDocAccessible::MimeType] description = +platform = notwin [PDocAccessible::URLDocTypeMimeType] description = +platform = notwin [PDocAccessible::AccessibleAtPoint] description = +platform = notwin [PDocAccessible::Extents] description = +platform = notwin [PDocAccessible::DOMNodeID] description = +platform = notwin [PDocAccessible::GetWindowedPluginIAccessible] description = platform = win diff --git a/js/ipc/JavaScriptChild.cpp b/js/ipc/JavaScriptChild.cpp index 69bc8ded243f..fecdcd060a1b 100644 --- a/js/ipc/JavaScriptChild.cpp +++ b/js/ipc/JavaScriptChild.cpp @@ -35,7 +35,7 @@ TraceChild(JSTracer* trc, void* data) JavaScriptChild::~JavaScriptChild() { JSContext* cx = dom::danger::GetJSContext(); - JS_RemoveWeakPointerZoneGroupCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup); + JS_RemoveWeakPointerZonesCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup); JS_RemoveExtraGCRootsTracer(cx, TraceChild, this); } @@ -48,7 +48,7 @@ JavaScriptChild::init() return false; JSContext* cx = dom::danger::GetJSContext(); - JS_AddWeakPointerZoneGroupCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup, this); + JS_AddWeakPointerZonesCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup, this); JS_AddExtraGCRootsTracer(cx, TraceChild, this); return true; } diff --git a/js/public/ProfilingFrameIterator.h b/js/public/ProfilingFrameIterator.h index e769c269a339..550ac518a193 100644 --- a/js/public/ProfilingFrameIterator.h +++ b/js/public/ProfilingFrameIterator.h @@ -93,9 +93,10 @@ class MOZ_NON_PARAM JS_PUBLIC_API(ProfilingFrameIterator) public: struct RegisterState { - RegisterState() : pc(nullptr), sp(nullptr), lr(nullptr) {} + RegisterState() : pc(nullptr), sp(nullptr), fp(nullptr), lr(nullptr) {} void* pc; void* sp; + void* fp; void* lr; }; diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index f8a8777ad380..5e90f60e48f0 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -788,9 +788,9 @@ class GCRuntime void callObjectsTenuredCallback(); MOZ_MUST_USE bool addFinalizeCallback(JSFinalizeCallback callback, void* data); void removeFinalizeCallback(JSFinalizeCallback func); - MOZ_MUST_USE bool addWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback, + MOZ_MUST_USE bool addWeakPointerZonesCallback(JSWeakPointerZonesCallback callback, void* data); - void removeWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback); + void removeWeakPointerZonesCallback(JSWeakPointerZonesCallback callback); MOZ_MUST_USE bool addWeakPointerCompartmentCallback(JSWeakPointerCompartmentCallback callback, void* data); void removeWeakPointerCompartmentCallback(JSWeakPointerCompartmentCallback callback); @@ -802,7 +802,7 @@ class GCRuntime void setFullCompartmentChecks(bool enable); - JS::Zone* getCurrentZoneGroup() { return currentZoneGroup; } + JS::Zone* getCurrentSweepGroup() { return currentSweepGroup; } void setFoundBlackGrayEdges(TenuredCell& target) { AutoEnterOOMUnsafeRegion oomUnsafe; if (!foundBlackGrayEdges.ref().append(&target)) @@ -978,13 +978,13 @@ class GCRuntime void markAllGrayReferences(gcstats::Phase phase); void beginSweepPhase(bool lastGC, AutoLockForExclusiveAccess& lock); - void findZoneGroups(AutoLockForExclusiveAccess& lock); + void groupZonesForSweeping(AutoLockForExclusiveAccess& lock); MOZ_MUST_USE bool findInterZoneEdges(); - void getNextZoneGroup(); - void endMarkingZoneGroup(); - void beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock); + void getNextSweepGroup(); + void endMarkingSweepGroup(); + void beginSweepingSweepGroup(AutoLockForExclusiveAccess& lock); bool shouldReleaseObservedTypes(); - void endSweepingZoneGroup(); + void endSweepingSweepGroup(); IncrementalProgress sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock); void endSweepPhase(bool lastGC, AutoLockForExclusiveAccess& lock); bool allCCVisibleZonesWereCollected() const; @@ -1024,7 +1024,7 @@ class GCRuntime #endif void callFinalizeCallbacks(FreeOp* fop, JSFinalizeStatus status) const; - void callWeakPointerZoneGroupCallbacks() const; + void callWeakPointerZonesCallbacks() const; void callWeakPointerCompartmentCallbacks(JSCompartment* comp) const; public: @@ -1196,14 +1196,14 @@ class GCRuntime ActiveThreadOrGCTaskData blocksToFreeAfterSweeping; private: - /* Index of current zone group (for stats). */ - ActiveThreadData zoneGroupIndex; + /* Index of current sweep group (for stats). */ + ActiveThreadData sweepGroupIndex; /* * Incremental sweep state. */ - ActiveThreadData zoneGroups; - ActiveThreadOrGCTaskData currentZoneGroup; + ActiveThreadData sweepGroups; + ActiveThreadOrGCTaskData currentSweepGroup; ActiveThreadData sweepingTypes; ActiveThreadData finalizePhase; ActiveThreadData sweepZone; @@ -1295,7 +1295,7 @@ class GCRuntime Callback gcDoCycleCollectionCallback; Callback tenuredCallback; CallbackVector finalizeCallbacks; - CallbackVector updateWeakPointerZoneGroupCallbacks; + CallbackVector updateWeakPointerZonesCallbacks; CallbackVector updateWeakPointerCompartmentCallbacks; MemoryCounter mallocCounter; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 70b6419f2aee..22839c291ce4 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2451,7 +2451,7 @@ GCMarker::enterWeakMarkingMode() if (weakMapAction() == ExpandWeakMaps) { tag_ = TracerKindTag::WeakMarking; - for (GCZoneGroupIter zone(runtime()); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(runtime()); !zone.done(); zone.next()) { for (WeakMapBase* m : zone->gcWeakMapList()) { if (m->marked) (void) m->markIteratively(this); diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index d7905a97f92a..c41825be8d55 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -330,6 +330,7 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM // Trace active interpreter and JIT stack roots. TraceInterpreterActivations(cx, target, trc); jit::TraceJitActivations(cx, target, trc); + wasm::TraceActivations(cx, target, trc); // Trace legacy C stack roots. AutoGCRooter::traceAll(target, trc); diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 519c393aa6d1..8065fdc8b7a4 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -164,7 +164,7 @@ static const PhaseInfo phases[] = { { PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK, 15 }, { PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK, 16 }, { PHASE_FINALIZE_START, "Finalize Start Callbacks", PHASE_SWEEP, 17 }, - { PHASE_WEAK_ZONEGROUP_CALLBACK, "Per-Slice Weak Callback", PHASE_FINALIZE_START, 57 }, + { PHASE_WEAK_ZONES_CALLBACK, "Per-Slice Weak Callback", PHASE_FINALIZE_START, 57 }, { PHASE_WEAK_COMPARTMENT_CALLBACK, "Per-Compartment Weak Callback", PHASE_FINALIZE_START, 58 }, { PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP, 18 }, { PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments", PHASE_SWEEP, 20 }, diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index 9af2245ba901..4957b9c26561 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -49,7 +49,7 @@ enum Phase : uint8_t { PHASE_SWEEP_MARK_GRAY, PHASE_SWEEP_MARK_GRAY_WEAK, PHASE_FINALIZE_START, - PHASE_WEAK_ZONEGROUP_CALLBACK, + PHASE_WEAK_ZONES_CALLBACK, PHASE_WEAK_COMPARTMENT_CALLBACK, PHASE_SWEEP_ATOMS, PHASE_SWEEP_COMPARTMENTS, diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 67030ea4d7ca..b8dade6039e8 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -37,7 +37,7 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group) gcWeakRefs_(group), weakCaches_(group), gcWeakKeys_(group, SystemAllocPolicy(), rt->randomHashCodeScrambler()), - gcZoneGroupEdges_(group), + gcSweepGroupEdges_(group), hasDeadProxies_(group), typeDescrObjects_(group, this, SystemAllocPolicy()), markedAtoms_(group), @@ -50,7 +50,7 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group) data(group, nullptr), isSystem(group, false), #ifdef DEBUG - gcLastZoneGroupIndex(group, 0), + gcLastSweepGroupIndex(group, 0), #endif jitZone_(group, nullptr), gcState_(NoGC), @@ -90,7 +90,7 @@ bool Zone::init(bool isSystemArg) { isSystem = isSystemArg; return uniqueIds().init() && - gcZoneGroupEdges().init() && + gcSweepGroupEdges().init() && gcWeakKeys().init() && typeDescrObjects().init() && markedAtoms().init(); @@ -159,8 +159,8 @@ Zone::sweepBreakpoints(FreeOp* fop) GCPtrNativeObject& dbgobj = bp->debugger->toJSObjectRef(); // If we are sweeping, then we expect the script and the - // debugger object to be swept in the same zone group, except if - // the breakpoint was added after we computed the zone + // debugger object to be swept in the same sweep group, except + // if the breakpoint was added after we computed the sweep // groups. In this case both script and debugger object must be // live. MOZ_ASSERT_IF(isGCSweeping() && dbgobj->zone()->isCollecting(), diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index c9874caa86d5..7b6b87e7954a 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -270,9 +270,9 @@ struct Zone : public JS::shadow::Zone, void prepareForCompacting(); #ifdef DEBUG - // For testing purposes, return the index of the zone group which this zone + // For testing purposes, return the index of the sweep group which this zone // was swept in in the last GC. - unsigned lastZoneGroupIndex() { return gcLastZoneGroupIndex; } + unsigned lastSweepGroupIndex() { return gcLastSweepGroupIndex; } #endif using DebuggerVector = js::Vector; @@ -348,7 +348,7 @@ struct Zone : public JS::shadow::Zone, WeakEdges& gcWeakRefs() { return gcWeakRefs_.ref(); } private: - // List of non-ephemeron weak containers to sweep during beginSweepingZoneGroup. + // List of non-ephemeron weak containers to sweep during beginSweepingSweepGroup. js::ZoneGroupData>> weakCaches_; public: mozilla::LinkedList>& weakCaches() { return weakCaches_.ref(); } @@ -368,16 +368,16 @@ struct Zone : public JS::shadow::Zone, private: // A set of edges from this zone to other zones. // - // This is used during GC while calculating zone groups to record edges that - // can't be determined by examining this zone by itself. - js::ZoneGroupData gcZoneGroupEdges_; + // This is used during GC while calculating sweep groups to record edges + // that can't be determined by examining this zone by itself. + js::ZoneGroupData gcSweepGroupEdges_; // Zones with dead proxies require an extra scan through the wrapper map, // so track whether any dead proxies are known to exist. js::ZoneGroupData hasDeadProxies_; public: - ZoneSet& gcZoneGroupEdges() { return gcZoneGroupEdges_.ref(); } + ZoneSet& gcSweepGroupEdges() { return gcSweepGroupEdges_.ref(); } bool hasDeadProxies() { return hasDeadProxies_; } void setHasDeadProxies(bool b) { hasDeadProxies_ = b; } @@ -485,7 +485,7 @@ struct Zone : public JS::shadow::Zone, } #ifdef DEBUG - js::ZoneGroupData gcLastZoneGroupIndex; + js::ZoneGroupData gcLastSweepGroupIndex; #endif static js::HashNumber UniqueIdToHash(uint64_t uid) { diff --git a/js/src/jit-test/tests/asm.js/testAtomics.js b/js/src/jit-test/tests/asm.js/testAtomics.js index 5b30fb622034..89582fe686f7 100644 --- a/js/src/jit-test/tests/asm.js/testAtomics.js +++ b/js/src/jit-test/tests/asm.js/testAtomics.js @@ -1872,15 +1872,51 @@ setARMHwCapFlags('vfp'); asmCompile('stdlib', 'ffi', 'heap', USE_ASM + ` + var atomic_cmpxchg = stdlib.Atomics.compareExchange; var atomic_exchange = stdlib.Atomics.exchange; + var atomic_add = stdlib.Atomics.add; + var atomic_sub = stdlib.Atomics.sub; + var atomic_and = stdlib.Atomics.and; + var atomic_or = stdlib.Atomics.or; + var atomic_xor = stdlib.Atomics.xor; var i8a = new stdlib.Int8Array(heap); + function do_cas() { + var v = 0; + v = atomic_cmpxchg(i8a, 100, 0, -1); + return v|0; + } function do_xchg() { var v = 0; v = atomic_exchange(i8a, 200, 37); return v|0; } + function do_add() { + var v = 0; + v = atomic_add(i8a, 10, 37); + return v|0; + } + function do_sub() { + var v = 0; + v = atomic_sub(i8a, 10, 37); + return v|0; + } + function do_and() { + var v = 0; + v = atomic_and(i8a, 10, 37); + return v|0; + } + function do_or() { + var v = 0; + v = atomic_or(i8a, 10, 37); + return v|0; + } + function do_xor() { + var v = 0; + v = atomic_xor(i8a, 10, 37); + return v|0; + } - return { xchg: do_xchg } + return { cas:do_cas, xchg: do_xchg, add: do_add, sub: do_sub, and: do_and, or: do_or, xor: do_xor } `); diff --git a/js/src/jit-test/tests/asm.js/testProfiling.js b/js/src/jit-test/tests/asm.js/testProfiling.js index 7c3f348e8b20..1c47da213bf2 100644 --- a/js/src/jit-test/tests/asm.js/testProfiling.js +++ b/js/src/jit-test/tests/asm.js/testProfiling.js @@ -69,7 +69,7 @@ var f = asmLink(asmCompile('global','ffis',USE_ASM + "var ffi=ffis.ffi; function f(0); assertStackContainsSeq(stacks, ""); f(+1); -assertStackContainsSeq(stacks, ""); +assertStackContainsSeq(stacks, "<,g,f,>"); f(0); assertStackContainsSeq(stacks, "<,g,f,>"); f(-1); @@ -112,7 +112,7 @@ function testBuiltinD2D(name) { enableSingleStepProfiling(); assertEq(f(.1), eval("Math." + name + "(.1)")); var stacks = disableSingleStepProfiling(); - assertStackContainsSeq(stacks, ">,f,>,native call,>,f,>,>"); + assertStackContainsSeq(stacks, ">,f,>,f,>,>"); } } for (name of ['sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'ceil', 'floor', 'exp', 'log']) @@ -125,7 +125,7 @@ function testBuiltinF2F(name) { enableSingleStepProfiling(); assertEq(f(.1), eval("Math.fround(Math." + name + "(Math.fround(.1)))")); var stacks = disableSingleStepProfiling(); - assertStackContainsSeq(stacks, ">,f,>,native call,>,f,>,>"); + assertStackContainsSeq(stacks, ">,f,>,f,>,>"); } } for (name of ['ceil', 'floor']) @@ -138,7 +138,7 @@ function testBuiltinDD2D(name) { enableSingleStepProfiling(); assertEq(f(.1, .2), eval("Math." + name + "(.1, .2)")); var stacks = disableSingleStepProfiling(); - assertStackContainsSeq(stacks, ">,f,>,native call,>,f,>,>"); + assertStackContainsSeq(stacks, ">,f,>,f,>,>"); } } for (name of ['atan2', 'pow']) diff --git a/js/src/jit-test/tests/debug/wasm-onExceptionUnwind-gc.js b/js/src/jit-test/tests/debug/wasm-onExceptionUnwind-gc.js new file mode 100644 index 000000000000..ca191ea0f772 --- /dev/null +++ b/js/src/jit-test/tests/debug/wasm-onExceptionUnwind-gc.js @@ -0,0 +1,50 @@ + +if (!wasmIsSupported()) + quit(); + +var sandbox = newGlobal(); +var dbg = new Debugger(sandbox); +var counter = 0; +dbg.onExceptionUnwind = (frame, value) => { + if (frame.type !== "wasmcall") + return; + if (++counter != 2) + return; + gc(); +}; + +sandbox.innerCode = wasmTextToBinary(`(module + (import "imports" "tbl" (table 1 anyfunc)) + (import $setNull "imports" "setNull" (func)) + (func $trap + call $setNull + unreachable + ) + (elem (i32.const 0) $trap) +)`); +sandbox.outerCode = wasmTextToBinary(`(module + (import "imports" "tbl" (table 1 anyfunc)) + (type $v2v (func)) + (func (export "run") + i32.const 0 + call_indirect $v2v + ) +)`); + +sandbox.eval(` +(function() { + +var tbl = new WebAssembly.Table({initial:1, element:"anyfunc"}); +function setNull() { tbl.set(0, null) } +new WebAssembly.Instance(new WebAssembly.Module(innerCode), {imports:{tbl,setNull}}); +var outer = new WebAssembly.Instance(new WebAssembly.Module(outerCode), {imports:{tbl}}); +var caught; +try { + outer.exports.run(); +} catch (e) { + caught = e; +} +assertEq(caught instanceof WebAssembly.RuntimeError, true); + +})(); +`); diff --git a/js/src/jit-test/tests/ion/bug1331058.js b/js/src/jit-test/tests/ion/bug1331058.js new file mode 100644 index 000000000000..ffb8f29196d5 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1331058.js @@ -0,0 +1,29 @@ +function foo(o, trigger) { + bar = function() { return o.getY(); }; + if (trigger) + assertEq(bar(), undefined); + return 1; +} +function O(o, trigger) { + this.a1 = 1; + this.a2 = 2; + this.a3 = 3; + this.a4 = 4; + this.x = foo(this, trigger); +} +O.prototype.getY = function() { + return this.x; +} +function test() { + with(this) {}; // No Ion. + var arr = []; + for (var i=0; i<100; i++) + arr.push(new O({y: i}, false)); + + for (var i=0; i<100; i++) + bar(); + + for (var i=0; i<300; i++) + arr.push(new O({y: i}, true)); +} +test(); diff --git a/js/src/jit-test/tests/wasm/profiling.js b/js/src/jit-test/tests/wasm/profiling.js index 108c3c5d978e..45b169e70b40 100644 --- a/js/src/jit-test/tests/wasm/profiling.js +++ b/js/src/jit-test/tests/wasm/profiling.js @@ -125,7 +125,7 @@ testError( (func (export "") (call $foo)) )`, WebAssembly.RuntimeError, -["", ">", "1,>", "0,1,>", "trap handling,0,1,>", "inline stub,0,1,>", "trap handling,0,1,>", ""]); +["", ">", "1,>", "0,1,>", "interstitial,0,1,>", "trap handling,0,1,>", ""]); testError( `(module @@ -140,7 +140,7 @@ WebAssembly.RuntimeError, // Technically we have this one *one-instruction* interval where // the caller is lost (the stack with "1,>"). It's annoying to fix and shouldn't // mess up profiles in practice so we ignore it. -["", ">", "0,>", "1,0,>", "1,>", "trap handling,0,>", "inline stub,0,>", "trap handling,0,>", ""]); +["", ">", "0,>", "1,0,>", "1,>", "trap handling,0,>", ""]); (function() { var e = wasmEvalText(` diff --git a/js/src/jit-test/tests/wasm/timeout/1.js b/js/src/jit-test/tests/wasm/timeout/1.js new file mode 100644 index 000000000000..3bcbf8034963 --- /dev/null +++ b/js/src/jit-test/tests/wasm/timeout/1.js @@ -0,0 +1,17 @@ +// |jit-test| exitstatus: 6; + +// Don't include wasm.js in timeout tests: when wasm isn't supported, it will +// quit(0) which will cause the test to fail. +if (!wasmIsSupported()) + quit(6); + +var code = wasmTextToBinary(`(module + (func (export "iloop") + (loop $top br $top) + ) +)`); + +var i = new WebAssembly.Instance(new WebAssembly.Module(code)); +timeout(1); +i.exports.iloop(); +assertEq(true, false); diff --git a/js/src/jit-test/tests/wasm/timeout/2.js b/js/src/jit-test/tests/wasm/timeout/2.js new file mode 100644 index 000000000000..ef84b00470d7 --- /dev/null +++ b/js/src/jit-test/tests/wasm/timeout/2.js @@ -0,0 +1,31 @@ +// |jit-test| exitstatus: 6; + +// Don't include wasm.js in timeout tests: when wasm isn't supported, it will +// quit(0) which will cause the test to fail. +if (!wasmIsSupported()) + quit(6); + +var tbl = new WebAssembly.Table({initial:1, element:"anyfunc"}); + +new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`(module + (func $iloop + loop $top + br $top + end + ) + (import "imports" "tbl" (table 1 anyfunc)) + (elem (i32.const 0) $iloop) +)`)), {imports:{tbl}}); + +var outer = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`(module + (import "imports" "tbl" (table 1 anyfunc)) + (type $v2v (func)) + (func (export "run") + i32.const 0 + call_indirect $v2v + ) +)`)), {imports:{tbl}}); + +timeout(1, () => { tbl.set(0, null); gc() }); +outer.exports.run(); +assertEq(true, false); diff --git a/js/src/jit-test/tests/wasm/timeout/directives.txt b/js/src/jit-test/tests/wasm/timeout/directives.txt new file mode 100644 index 000000000000..8262f0bbae1f --- /dev/null +++ b/js/src/jit-test/tests/wasm/timeout/directives.txt @@ -0,0 +1,2 @@ +|jit-test| test-also-wasm-baseline + diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 461e0d46e653..240ed55f0ab1 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1206,7 +1206,7 @@ PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Re } // Check for a linear input string. - masm.branchIfRope(input, failure); + masm.branchIfRopeOrExternal(input, temp1, failure); // Get the RegExpShared for the RegExp. masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp1); @@ -7608,10 +7608,7 @@ CodeGenerator::visitSubstr(LSubstr* lir) // Use slow path for ropes. masm.bind(&nonZero); - static_assert(JSString::ROPE_FLAGS == 0, - "rope flags must be zero for (flags & TYPE_FLAGS_MASK) == 0 " - "to be a valid is-rope check"); - masm.branchTest32(Assembler::Zero, stringFlags, Imm32(JSString::TYPE_FLAGS_MASK), slowPath); + masm.branchIfRopeOrExternal(string, temp, slowPath); // Handle inlined strings by creating a FatInlineString. masm.branchTest32(Assembler::Zero, stringFlags, Imm32(JSString::INLINE_CHARS_BIT), ¬Inline); diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h index a73677c14d54..92210679e092 100644 --- a/js/src/jit/CompileInfo.h +++ b/js/src/jit/CompileInfo.h @@ -447,14 +447,18 @@ class CompileInfo // the frame is active on the stack. This implies that these definitions // would have to be executed and that they cannot be removed even if they // are unused. - bool isObservableSlot(uint32_t slot) const { - if (isObservableFrameSlot(slot)) - return true; + inline bool isObservableSlot(uint32_t slot) const { + if (slot >= firstLocalSlot()) { + // The |this| slot for a derived class constructor is a local slot. + if (thisSlotForDerivedClassConstructor_) + return *thisSlotForDerivedClassConstructor_ == slot; + return false; + } - if (isObservableArgumentSlot(slot)) - return true; + if (slot < firstArgSlot()) + return isObservableFrameSlot(slot); - return false; + return isObservableArgumentSlot(slot); } bool isObservableFrameSlot(uint32_t slot) const { diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index d7a51b51083b..df992177e6a3 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1861,6 +1861,17 @@ OptimizeMIR(MIRGenerator* mir) return false; } + // BCE marks bounds checks as dead, so do BCE before DCE. + if (mir->compilingWasm() && !JitOptions.wasmAlwaysCheckBounds) { + if (!EliminateBoundsChecks(mir, graph)) + return false; + gs.spewPass("Redundant Bounds Check Elimination"); + AssertGraphCoherency(graph); + + if (mir->shouldCancel("BCE")) + return false; + } + { AutoTraceLog log(logger, TraceLogger_EliminateDeadCode); if (!EliminateDeadCode(mir, graph)) @@ -1933,13 +1944,6 @@ OptimizeMIR(MIRGenerator* mir) AssertGraphCoherency(graph); } - if (mir->compilingWasm()) { - if (!EliminateBoundsChecks(mir, graph)) - return false; - gs.spewPass("Redundant Bounds Check Elimination"); - AssertGraphCoherency(graph); - } - AssertGraphCoherency(graph, /* force = */ true); DumpMIRExpressions(graph); diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 7de6715b4398..28c5460c8a05 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -196,6 +196,8 @@ FlagPhiInputsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block, MBasicBl static bool FlagAllOperandsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block) { + const CompileInfo& info = block->info(); + // Flag all instructions operands as having removed uses. MInstructionIterator end = block->end(); for (MInstructionIterator it = block->begin(); it != end; it++) { @@ -210,8 +212,10 @@ FlagAllOperandsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block) if (MResumePoint* rp = ins->resumePoint()) { // Note: no need to iterate over the caller's of the resume point as // this is the same as the entry resume point. - for (size_t i = 0, e = rp->numOperands(); i < e; i++) - rp->getOperand(i)->setUseRemovedUnchecked(); + for (size_t i = 0, e = rp->numOperands(); i < e; i++) { + if (info.isObservableSlot(i)) + rp->getOperand(i)->setUseRemovedUnchecked(); + } } } @@ -221,8 +225,10 @@ FlagAllOperandsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block) if (mir->shouldCancel("FlagAllOperandsAsHavingRemovedUses loop 2")) return false; - for (size_t i = 0, e = rp->numOperands(); i < e; i++) - rp->getOperand(i)->setUseRemovedUnchecked(); + for (size_t i = 0, e = rp->numOperands(); i < e; i++) { + if (info.isObservableSlot(i)) + rp->getOperand(i)->setUseRemovedUnchecked(); + } rp = rp->caller(); } diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index f93603c6ab84..7c090b6f9cd5 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4278,10 +4278,7 @@ LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) #ifdef WASM_HUGE_MEMORY MOZ_CRASH("No bounds checking on huge memory"); #else - if (ins->isRedundant()) { - if (MOZ_LIKELY(!JitOptions.wasmAlwaysCheckBounds)) - return; - } + MOZ_ASSERT(!ins->isRedundant()); MDefinition* index = ins->index(); MOZ_ASSERT(index->type() == MIRType::Int32); @@ -4369,13 +4366,7 @@ LIRGenerator::visitWasmReturn(MWasmReturn* ins) MDefinition* rval = ins->getOperand(0); if (rval->type() == MIRType::Int64) { - LWasmReturnI64* lir = new(alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64)); - - // Preserve the TLS pointer we were passed in `WasmTlsReg`. - MDefinition* tlsPtr = ins->getOperand(1); - lir->setOperand(INT64_PIECES, useFixed(tlsPtr, WasmTlsReg)); - - add(lir); + add(new(alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64))); return; } @@ -4391,23 +4382,13 @@ LIRGenerator::visitWasmReturn(MWasmReturn* ins) else MOZ_CRASH("Unexpected wasm return type"); - // Preserve the TLS pointer we were passed in `WasmTlsReg`. - MDefinition* tlsPtr = ins->getOperand(1); - lir->setOperand(1, useFixed(tlsPtr, WasmTlsReg)); - add(lir); } void LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid* ins) { - auto* lir = new(alloc()) LWasmReturnVoid; - - // Preserve the TLS pointer we were passed in `WasmTlsReg`. - MDefinition* tlsPtr = ins->getOperand(0); - lir->setOperand(0, useFixed(tlsPtr, WasmTlsReg)); - - add(lir); + add(new(alloc()) LWasmReturnVoid); } void diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 44e8c026fe47..02ee711a89e6 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -3171,7 +3171,8 @@ MBinaryArithInstruction::foldsTo(TempAllocator& alloc) if (isTruncated()) { if (!folded->block()) block()->insertBefore(this, folded); - return MTruncateToInt32::New(alloc, folded); + if (folded->type() != MIRType::Int32) + return MTruncateToInt32::New(alloc, folded); } return folded; } @@ -5700,10 +5701,9 @@ MWasmUnsignedToFloat32::foldsTo(TempAllocator& alloc) MWasmCall* MWasmCall::New(TempAllocator& alloc, const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee, - const Args& args, MIRType resultType, uint32_t spIncrement, uint32_t tlsStackOffset, - MDefinition* tableIndex) + const Args& args, MIRType resultType, uint32_t spIncrement, MDefinition* tableIndex) { - MWasmCall* call = new(alloc) MWasmCall(desc, callee, spIncrement, tlsStackOffset); + MWasmCall* call = new(alloc) MWasmCall(desc, callee, spIncrement); call->setResultType(resultType); if (!call->argRegs_.init(alloc, args.length())) @@ -5729,12 +5729,10 @@ MWasmCall::NewBuiltinInstanceMethodCall(TempAllocator& alloc, const ABIArg& instanceArg, const Args& args, MIRType resultType, - uint32_t spIncrement, - uint32_t tlsStackOffset) + uint32_t spIncrement) { auto callee = wasm::CalleeDesc::builtinInstanceMethod(builtin); - MWasmCall* call = MWasmCall::New(alloc, desc, callee, args, resultType, spIncrement, - tlsStackOffset, nullptr); + MWasmCall* call = MWasmCall::New(alloc, desc, callee, args, resultType, spIncrement, nullptr); if (!call) return nullptr; diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 596ff609460d..1b67d16d56df 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -13718,15 +13718,14 @@ class MWasmBoundsCheck : public MBinaryInstruction, public NoTypePolicy::Data { - bool redundant_; wasm::TrapOffset trapOffset_; explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit, wasm::TrapOffset trapOffset) : MBinaryInstruction(index, boundsCheckLimit), - redundant_(false), trapOffset_(trapOffset) { - setGuard(); // Effectful: throws for OOB. + // Bounds check is effectful: it throws for OOB. + setGuard(); } public: @@ -13739,11 +13738,11 @@ class MWasmBoundsCheck } bool isRedundant() const { - return redundant_; + return !isGuard(); } - void setRedundant(bool val) { - redundant_ = val; + void setRedundant() { + setNotGuard(); } wasm::TrapOffset trapOffset() const { @@ -14247,12 +14246,11 @@ class MWasmParameter : public MNullaryInstruction }; class MWasmReturn - : public MAryControlInstruction<2, 0>, + : public MAryControlInstruction<1, 0>, public NoTypePolicy::Data { - explicit MWasmReturn(MDefinition* ins, MDefinition* tlsPtr) { + explicit MWasmReturn(MDefinition* ins) { initOperand(0, ins); - initOperand(1, tlsPtr); } public: @@ -14261,13 +14259,9 @@ class MWasmReturn }; class MWasmReturnVoid - : public MAryControlInstruction<1, 0>, + : public MAryControlInstruction<0, 0>, public NoTypePolicy::Data { - explicit MWasmReturnVoid(MDefinition* tlsPtr) { - initOperand(0, tlsPtr); - } - public: INSTRUCTION_HEADER(WasmReturnVoid) TRIVIAL_NEW_WRAPPERS @@ -14305,15 +14299,12 @@ class MWasmCall final wasm::CalleeDesc callee_; FixedList argRegs_; uint32_t spIncrement_; - uint32_t tlsStackOffset_; ABIArg instanceArg_; - MWasmCall(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee, uint32_t spIncrement, - uint32_t tlsStackOffset) + MWasmCall(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee, uint32_t spIncrement) : desc_(desc), callee_(callee), - spIncrement_(spIncrement), - tlsStackOffset_(tlsStackOffset) + spIncrement_(spIncrement) { } public: @@ -14326,15 +14317,12 @@ class MWasmCall final }; typedef Vector Args; - static const uint32_t DontSaveTls = UINT32_MAX; - static MWasmCall* New(TempAllocator& alloc, const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee, const Args& args, MIRType resultType, uint32_t spIncrement, - uint32_t tlsStackOffset, MDefinition* tableIndex = nullptr); static MWasmCall* NewBuiltinInstanceMethodCall(TempAllocator& alloc, @@ -14343,8 +14331,7 @@ class MWasmCall final const ABIArg& instanceArg, const Args& args, MIRType resultType, - uint32_t spIncrement, - uint32_t tlsStackOffset); + uint32_t spIncrement); size_t numArgs() const { return argRegs_.length(); @@ -14362,13 +14349,6 @@ class MWasmCall final uint32_t spIncrement() const { return spIncrement_; } - bool saveTls() const { - return tlsStackOffset_ != DontSaveTls; - } - uint32_t tlsStackOffset() const { - MOZ_ASSERT(saveTls()); - return tlsStackOffset_; - } bool possiblyCalls() const override { return true; diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index d089c32f2295..0ec15f179384 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -84,21 +84,21 @@ void MacroAssembler::call(const wasm::CallSiteDesc& desc, const Register reg) { CodeOffset l = call(reg); - append(desc, l, framePushed()); + append(desc, l); } void MacroAssembler::call(const wasm::CallSiteDesc& desc, uint32_t funcDefIndex) { CodeOffset l = callWithPatch(); - append(desc, l, framePushed(), funcDefIndex); + append(desc, l, funcDefIndex); } void MacroAssembler::call(const wasm::CallSiteDesc& desc, wasm::Trap trap) { CodeOffset l = callWithPatch(); - append(desc, l, framePushed(), trap); + append(desc, l, trap); } // =============================================================== @@ -395,6 +395,19 @@ MacroAssembler::branchIfRope(Register str, Label* label) branchTest32(Assembler::Zero, flags, Imm32(JSString::TYPE_FLAGS_MASK), label); } +void +MacroAssembler::branchIfRopeOrExternal(Register str, Register temp, Label* label) +{ + Address flags(str, JSString::offsetOfFlags()); + move32(Imm32(JSString::TYPE_FLAGS_MASK), temp); + and32(flags, temp); + + static_assert(JSString::ROPE_FLAGS == 0, "Rope type flags must be 0"); + branchTest32(Assembler::Zero, temp, temp, label); + + branch32(Assembler::Equal, temp, Imm32(JSString::EXTERNAL_FLAGS), label); +} + void MacroAssembler::branchLatin1String(Register string, Label* label) { diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 813fc13de2fa..72723f337bdb 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -2931,6 +2931,14 @@ MacroAssembler::wasmEmitTrapOutOfLineCode() if (size_t dec = StackDecrementForCall(ABIStackAlignment, alreadyPushed, toPush)) reserveStack(dec); + // To call the trap handler function, we must have the WasmTlsReg + // filled since this is the normal calling ABI. To avoid requiring + // every trapping operation to have the TLS register filled for the + // rare case that it takes a trap, we restore it from the frame on + // the out-of-line path. However, there are millions of out-of-line + // paths (viz. for loads/stores), so the load is factored out into + // the shared FarJumpIsland generated by patchCallSites. + // Call the trap's exit, using the bytecode offset of the trap site. // Note that this code is inside the same CodeRange::Function as the // trap site so it's as if the trapping instruction called the @@ -2955,8 +2963,34 @@ MacroAssembler::wasmEmitTrapOutOfLineCode() clearTrapSites(); } +void +MacroAssembler::wasmAssertNonExitInvariants(Register activation) +{ +#ifdef DEBUG + // WasmActivation.exitFP should be null when outside any exit frame. + Label ok; + Address exitFP(activation, WasmActivation::offsetOfExitFP()); + branchPtr(Assembler::Equal, exitFP, ImmWord(0), &ok); + breakpoint(); + bind(&ok); +#endif +} + //}}} check_macroassembler_style +void +MacroAssembler::loadWasmActivationFromTls(Register dest) +{ + loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, cx)), dest); + loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest); +} + +void +MacroAssembler::loadWasmTlsRegFromFrame(Register dest) +{ + loadPtr(Address(getStackPointer(), framePushed() + offsetof(wasm::Frame, tls)), dest); +} + void MacroAssembler::BranchType::emit(MacroAssembler& masm) { diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index e6189bde6e01..55c7ab071108 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -447,6 +447,7 @@ class MacroAssembler : public MacroAssemblerSpecific void Push(const ImmPtr imm) PER_SHARED_ARCH; void Push(const ImmGCPtr ptr) PER_SHARED_ARCH; void Push(FloatRegister reg) PER_SHARED_ARCH; + void PushFlags() DEFINED_ON(x86_shared); void Push(jsid id, Register scratchReg); void Push(TypedOrValueRegister v); void Push(const ConstantOrRegister& v); @@ -462,6 +463,7 @@ class MacroAssembler : public MacroAssemblerSpecific void Pop(Register reg) PER_SHARED_ARCH; void Pop(FloatRegister t) PER_SHARED_ARCH; void Pop(const ValueOperand& val) PER_SHARED_ARCH; + void PopFlags() DEFINED_ON(x86_shared); void popRooted(VMFunction::RootType rootType, Register cellReg, const ValueOperand& valueReg); // Move the stack pointer based on the requested amount. @@ -1113,6 +1115,7 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branchIfTrueBool(Register reg, Label* label); inline void branchIfRope(Register str, Label* label); + inline void branchIfRopeOrExternal(Register str, Register temp, Label* label); inline void branchLatin1String(Register string, Label* label); inline void branchTwoByteString(Register string, Label* label); @@ -1461,6 +1464,9 @@ class MacroAssembler : public MacroAssemblerSpecific // including "normal" OutOfLineCode. void wasmEmitTrapOutOfLineCode(); + // Assert invariants that should be true within any non-exit-stub wasm code. + void wasmAssertNonExitInvariants(Register activation); + public: // ======================================================================== // Clamping functions. @@ -1516,15 +1522,9 @@ class MacroAssembler : public MacroAssemblerSpecific loadJSContext(dest); loadPtr(Address(dest, offsetof(JSContext, activation_)), dest); } - void loadWasmActivationFromTls(Register dest) { - loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, cx)), dest); - loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest); - } - void loadWasmActivationFromSymbolicAddress(Register dest) { - movePtr(wasm::SymbolicAddress::ContextPtr, dest); - loadPtr(Address(dest, 0), dest); - loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest); - } + + void loadWasmActivationFromTls(Register dest); + void loadWasmTlsRegFromFrame(Register dest = WasmTlsReg); template void loadTypedOrValue(const T& src, TypedOrValueRegister dest) { diff --git a/js/src/jit/RegisterAllocator.h b/js/src/jit/RegisterAllocator.h index d5b4110d5bd6..bcc3915d9983 100644 --- a/js/src/jit/RegisterAllocator.h +++ b/js/src/jit/RegisterAllocator.h @@ -288,9 +288,12 @@ class RegisterAllocator allRegisters_.take(AnyRegister(HeapReg)); allRegisters_.take(AnyRegister(HeapLenReg)); #endif + allRegisters_.take(FramePointer); } else { - if (FramePointer != InvalidReg && mir->instrumentedProfiling()) +#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM64) + if (mir->instrumentedProfiling()) allRegisters_.take(AnyRegister(FramePointer)); +#endif } } diff --git a/js/src/jit/WasmBCE.cpp b/js/src/jit/WasmBCE.cpp index aac362738572..20739a5de059 100644 --- a/js/src/jit/WasmBCE.cpp +++ b/js/src/jit/WasmBCE.cpp @@ -6,6 +6,7 @@ #include "jit/WasmBCE.h" #include "jit/MIRGenerator.h" #include "jit/MIRGraph.h" +#include "wasm/WasmTypes.h" using namespace js; using namespace js::jit; @@ -42,15 +43,34 @@ jit::EliminateBoundsChecks(MIRGenerator* mir, MIRGraph& graph) switch (def->op()) { case MDefinition::Op_WasmBoundsCheck: { MWasmBoundsCheck* bc = def->toWasmBoundsCheck(); - MDefinition* addr = def->getOperand(0); + MDefinition* addr = bc->index(); - LastSeenMap::AddPtr ptr = lastSeen.lookupForAdd(addr->id()); - if (ptr) { - if (ptr->value()->block()->dominates(block)) - bc->setRedundant(true); - } else { - if (!lastSeen.add(ptr, addr->id(), def)) - return false; + // Eliminate constant-address bounds checks to addresses below + // the heap minimum. + // + // The payload of the MConstant will be Double if the constant + // result is above 2^31-1, but we don't care about that for BCE. + +#ifndef WASM_HUGE_MEMORY + MOZ_ASSERT(wasm::MaxMemoryAccessSize < wasm::GuardSize, + "Guard page handles partial out-of-bounds"); +#endif + + if (addr->isConstant() && addr->toConstant()->type() == MIRType::Int32 && + uint32_t(addr->toConstant()->toInt32()) < mir->minWasmHeapLength()) + { + bc->setRedundant(); + } + else + { + LastSeenMap::AddPtr ptr = lastSeen.lookupForAdd(addr->id()); + if (ptr) { + if (ptr->value()->block()->dominates(block)) + bc->setRedundant(); + } else { + if (!lastSeen.add(ptr, addr->id(), def)) + return false; + } } break; } diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 71043b2e1ae2..0bdc2768c511 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -73,7 +73,7 @@ static constexpr Register IntArgReg0 = r0; static constexpr Register IntArgReg1 = r1; static constexpr Register IntArgReg2 = r2; static constexpr Register IntArgReg3 = r3; -static constexpr Register HeapReg = r11; +static constexpr Register HeapReg = r10; static constexpr Register CallTempNonArgRegs[] = { r5, r6, r7, r8 }; static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonArgRegs); @@ -134,7 +134,7 @@ static constexpr FloatRegister InvalidFloatReg; static constexpr Register JSReturnReg_Type = r3; static constexpr Register JSReturnReg_Data = r2; static constexpr Register StackPointer = sp; -static constexpr Register FramePointer = InvalidReg; +static constexpr Register FramePointer = r11; static constexpr Register ReturnReg = r0; static constexpr Register64 ReturnReg64(r1, r0); static constexpr FloatRegister ReturnFloat32Reg = { FloatRegisters::d0, VFPRegister::Single }; @@ -168,6 +168,7 @@ static constexpr Register WasmIonExitRegE1 = r1; // None of these may be the second scratch register (lr). static constexpr Register WasmIonExitRegReturnData = r2; static constexpr Register WasmIonExitRegReturnType = r3; +static constexpr Register WasmIonExitTlsReg = r9; static constexpr Register WasmIonExitRegD0 = r0; static constexpr Register WasmIonExitRegD1 = r1; static constexpr Register WasmIonExitRegD2 = r4; diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp index 9b9e09cf5523..c488394da0bd 100644 --- a/js/src/jit/arm/Lowering-arm.cpp +++ b/js/src/jit/arm/Lowering-arm.cpp @@ -893,11 +893,12 @@ LIRGeneratorARM::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins) if (byteSize(ins->access().type()) != 4 && !HasLDSTREXBHD()) { LAsmJSCompareExchangeCallout* lir = - new(alloc()) LAsmJSCompareExchangeCallout(useRegisterAtStart(base), - useRegisterAtStart(ins->oldValue()), - useRegisterAtStart(ins->newValue()), - useFixed(ins->tls(), WasmTlsReg), - temp(), temp()); + new(alloc()) LAsmJSCompareExchangeCallout(useFixedAtStart(base, IntArgReg2), + useFixedAtStart(ins->oldValue(), IntArgReg3), + useFixedAtStart(ins->newValue(), CallTempReg0), + useFixedAtStart(ins->tls(), WasmTlsReg), + tempFixed(IntArgReg0), + tempFixed(IntArgReg1)); defineReturn(lir, ins); return; } @@ -917,17 +918,18 @@ LIRGeneratorARM::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins) MOZ_ASSERT(ins->access().type() < Scalar::Float32); MOZ_ASSERT(ins->access().offset() == 0); - const LAllocation base = useRegisterAtStart(ins->base()); - const LAllocation value = useRegisterAtStart(ins->value()); - if (byteSize(ins->access().type()) < 4 && !HasLDSTREXBHD()) { // Call out on ARMv6. - defineReturn(new(alloc()) LAsmJSAtomicExchangeCallout(base, value, - useFixed(ins->tls(), WasmTlsReg), - temp(), temp()), ins); + defineReturn(new(alloc()) LAsmJSAtomicExchangeCallout(useFixedAtStart(ins->base(), IntArgReg2), + useFixedAtStart(ins->value(), IntArgReg3), + useFixedAtStart(ins->tls(), WasmTlsReg), + tempFixed(IntArgReg0), + tempFixed(IntArgReg1)), ins); return; } + const LAllocation base = useRegisterAtStart(ins->base()); + const LAllocation value = useRegisterAtStart(ins->value()); define(new(alloc()) LAsmJSAtomicExchangeHeap(base, value), ins); } @@ -942,10 +944,11 @@ LIRGeneratorARM::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins) if (byteSize(ins->access().type()) != 4 && !HasLDSTREXBHD()) { LAsmJSAtomicBinopCallout* lir = - new(alloc()) LAsmJSAtomicBinopCallout(useRegisterAtStart(base), - useRegisterAtStart(ins->value()), - useFixed(ins->tls(), WasmTlsReg), - temp(), temp()); + new(alloc()) LAsmJSAtomicBinopCallout(useFixedAtStart(base, IntArgReg2), + useFixedAtStart(ins->value(), IntArgReg3), + useFixedAtStart(ins->tls(), WasmTlsReg), + tempFixed(IntArgReg0), + tempFixed(IntArgReg1)); defineReturn(lir, ins); return; } diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index 8fa1d70cf279..99dc9a1dfec8 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -5138,7 +5138,7 @@ MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc) { CodeOffset offset(currentOffset()); ma_nop(); - append(desc, CodeOffset(currentOffset()), framePushed()); + append(desc, CodeOffset(currentOffset())); return offset; } diff --git a/js/src/jit/arm/Simulator-arm.h b/js/src/jit/arm/Simulator-arm.h index 0259e776ce9e..606261c9c603 100644 --- a/js/src/jit/arm/Simulator-arm.h +++ b/js/src/jit/arm/Simulator-arm.h @@ -81,6 +81,8 @@ class Simulator r0 = 0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, num_registers, + fp = 11, + ip = 12, sp = 13, lr = 14, pc = 15, diff --git a/js/src/jit/arm64/Assembler-arm64.h b/js/src/jit/arm64/Assembler-arm64.h index 276c6b9eea58..ba6367421682 100644 --- a/js/src/jit/arm64/Assembler-arm64.h +++ b/js/src/jit/arm64/Assembler-arm64.h @@ -126,6 +126,7 @@ static constexpr Register WasmIonExitRegE1 = r1; // None of these may be the second scratch register. static constexpr Register WasmIonExitRegReturnData = r2; static constexpr Register WasmIonExitRegReturnType = r3; +static constexpr Register WasmIonExitTlsReg = r17; static constexpr Register WasmIonExitRegD0 = r0; static constexpr Register WasmIonExitRegD1 = r1; static constexpr Register WasmIonExitRegD2 = r4; diff --git a/js/src/jit/mips32/Assembler-mips32.h b/js/src/jit/mips32/Assembler-mips32.h index 3c8a6ffafbe0..dd3fa38f44db 100644 --- a/js/src/jit/mips32/Assembler-mips32.h +++ b/js/src/jit/mips32/Assembler-mips32.h @@ -77,6 +77,7 @@ static constexpr FloatRegister SecondScratchDoubleReg = { FloatRegisters::f16, F // None of these may be the second scratch register (t8). static constexpr Register WasmIonExitRegReturnData = JSReturnReg_Data; static constexpr Register WasmIonExitRegReturnType = JSReturnReg_Type; +static constexpr Register WasmIonExitTlsReg = s5; static constexpr FloatRegister f0 = { FloatRegisters::f0, FloatRegister::Double }; static constexpr FloatRegister f2 = { FloatRegisters::f2, FloatRegister::Double }; diff --git a/js/src/jit/mips64/Assembler-mips64.h b/js/src/jit/mips64/Assembler-mips64.h index eed15b133a09..f9884b9e5063 100644 --- a/js/src/jit/mips64/Assembler-mips64.h +++ b/js/src/jit/mips64/Assembler-mips64.h @@ -71,6 +71,7 @@ static constexpr FloatRegister SecondScratchDoubleReg = { FloatRegisters::f21, F // None of these may be the second scratch register (t8). static constexpr Register WasmIonExitRegReturnData = JSReturnReg_Data; static constexpr Register WasmIonExitRegReturnType = JSReturnReg_Type; +static constexpr Register WasmIonExitTlsReg = s5; static constexpr FloatRegister f0 = { FloatRegisters::f0, FloatRegisters::Double }; static constexpr FloatRegister f1 = { FloatRegisters::f1, FloatRegisters::Double }; diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index 1795fd869cf1..cb13d834e9f1 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -48,6 +48,7 @@ static constexpr Register WasmIonExitRegE1 { Registers::invalid_reg }; static constexpr Register WasmIonExitRegReturnData { Registers::invalid_reg }; static constexpr Register WasmIonExitRegReturnType { Registers::invalid_reg }; +static constexpr Register WasmIonExitTlsReg = { Registers::invalid_reg }; static constexpr Register WasmIonExitRegD0 { Registers::invalid_reg }; static constexpr Register WasmIonExitRegD1 { Registers::invalid_reg }; static constexpr Register WasmIonExitRegD2 { Registers::invalid_reg }; @@ -415,7 +416,6 @@ class MacroAssemblerNone : public Assembler bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); } void loadWasmGlobalPtr(uint32_t, Register) { MOZ_CRASH(); } void loadWasmActivationFromTls(Register) { MOZ_CRASH(); } - void loadWasmActivationFromSymbolicAddress(Register) { MOZ_CRASH(); } void loadWasmPinnedRegsFromTls() { MOZ_CRASH(); } void setPrinter(Sprinter*) { MOZ_CRASH(); } diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h index 19f80e609b05..0c8a1cf3d39a 100644 --- a/js/src/jit/shared/Assembler-shared.h +++ b/js/src/jit/shared/Assembler-shared.h @@ -749,6 +749,25 @@ struct GlobalAccess typedef Vector GlobalAccessVector; +// A CallFarJump records the offset of a jump that needs to be patched to a +// call at the end of the module when all calls have been emitted. + +struct CallFarJump +{ + uint32_t funcIndex; + jit::CodeOffset jump; + + CallFarJump(uint32_t funcIndex, jit::CodeOffset jump) + : funcIndex(funcIndex), jump(jump) + {} + + void offsetBy(size_t delta) { + jump.offsetBy(delta); + } +}; + +typedef Vector CallFarJumpVector; + // The TrapDesc struct describes a wasm trap that is about to be emitted. This // includes the logical wasm bytecode offset to report, the kind of instruction // causing the trap, and the stack depth right before control is transferred to @@ -808,6 +827,7 @@ namespace jit { class AssemblerShared { wasm::CallSiteAndTargetVector callSites_; + wasm::CallFarJumpVector callFarJumps_; wasm::TrapSiteVector trapSites_; wasm::TrapFarJumpVector trapFarJumps_; wasm::MemoryAccessVector memoryAccesses_; @@ -842,16 +862,18 @@ class AssemblerShared } template - void append(const wasm::CallSiteDesc& desc, CodeOffset retAddr, size_t framePushed, - Args&&... args) + void append(const wasm::CallSiteDesc& desc, CodeOffset retAddr, Args&&... args) { - // framePushed does not include sizeof(wasm:Frame), so add it in explicitly when - // setting the CallSite::stackDepth. - wasm::CallSite cs(desc, retAddr.offset(), framePushed + sizeof(wasm::Frame)); + wasm::CallSite cs(desc, retAddr.offset()); enoughMemory_ &= callSites_.emplaceBack(cs, mozilla::Forward(args)...); } wasm::CallSiteAndTargetVector& callSites() { return callSites_; } + void append(wasm::CallFarJump jmp) { + enoughMemory_ &= callFarJumps_.append(jmp); + } + const wasm::CallFarJumpVector& callFarJumps() const { return callFarJumps_; } + void append(wasm::TrapSite trapSite) { enoughMemory_ &= trapSites_.append(trapSite); } @@ -911,6 +933,11 @@ class AssemblerShared MOZ_ASSERT(other.trapSites_.empty(), "should have been cleared by wasmEmitTrapOutOfLineCode"); + i = callFarJumps_.length(); + enoughMemory_ &= callFarJumps_.appendAll(other.callFarJumps_); + for (; i < callFarJumps_.length(); i++) + callFarJumps_[i].offsetBy(delta); + i = trapFarJumps_.length(); enoughMemory_ &= trapFarJumps_.appendAll(other.trapFarJumps_); for (; i < trapFarJumps_.length(); i++) diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index b32e1c3fc6c3..7922d16490f2 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -1499,35 +1499,37 @@ CodeGeneratorShared::emitWasmCallBase(LWasmCallBase* ins) masm.bind(&ok); #endif - // Save the caller's TLS register in a reserved stack slot (below the - // call's stack arguments) for retrieval after the call. - if (mir->saveTls()) - masm.storePtr(WasmTlsReg, Address(masm.getStackPointer(), mir->tlsStackOffset())); + // LWasmCallBase::isCallPreserved() assumes that all MWasmCalls preserve the + // TLS and pinned regs. The only case where where we don't have to reload + // the TLS and pinned regs is when the callee preserves them. + bool reloadRegs = true; const wasm::CallSiteDesc& desc = mir->desc(); const wasm::CalleeDesc& callee = mir->callee(); switch (callee.which()) { case wasm::CalleeDesc::Func: masm.call(desc, callee.funcIndex()); + reloadRegs = false; break; case wasm::CalleeDesc::Import: masm.wasmCallImport(desc, callee); break; - case wasm::CalleeDesc::WasmTable: case wasm::CalleeDesc::AsmJSTable: + case wasm::CalleeDesc::WasmTable: masm.wasmCallIndirect(desc, callee, ins->needsBoundsCheck()); + reloadRegs = callee.which() == wasm::CalleeDesc::WasmTable && callee.wasmTableIsExternal(); break; case wasm::CalleeDesc::Builtin: masm.call(callee.builtin()); + reloadRegs = false; break; case wasm::CalleeDesc::BuiltinInstanceMethod: masm.wasmCallBuiltinInstanceMethod(mir->instanceArg(), callee.builtin()); break; } - // After return, restore the caller's TLS and pinned registers. - if (mir->saveTls()) { - masm.loadPtr(Address(masm.getStackPointer(), mir->tlsStackOffset()), WasmTlsReg); + if (reloadRegs) { + masm.loadWasmTlsRegFromFrame(); masm.loadWasmPinnedRegsFromTls(); } diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 0c632201ec06..c67a8e814cc8 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -8605,13 +8605,13 @@ class LWasmParameterI64 : public LInstructionHelper LIR_HEADER(WasmParameterI64); }; -class LWasmReturn : public LInstructionHelper<0, 2, 0> +class LWasmReturn : public LInstructionHelper<0, 1, 0> { public: LIR_HEADER(WasmReturn); }; -class LWasmReturnI64 : public LInstructionHelper<0, INT64_PIECES + 1, 0> +class LWasmReturnI64 : public LInstructionHelper<0, INT64_PIECES, 0> { public: LIR_HEADER(WasmReturnI64) @@ -8621,7 +8621,7 @@ class LWasmReturnI64 : public LInstructionHelper<0, INT64_PIECES + 1, 0> } }; -class LWasmReturnVoid : public LInstructionHelper<0, 1, 0> +class LWasmReturnVoid : public LInstructionHelper<0, 0, 0> { public: LIR_HEADER(WasmReturnVoid); @@ -8683,6 +8683,7 @@ class LWasmCallBase : public LInstruction // - internal/indirect calls do by the internal wasm ABI // - import calls do by explicitly saving/restoring at the callsite // - builtin calls do because the TLS reg is non-volatile + // See also CodeGeneratorShared::emitWasmCallBase. return !reg.isFloat() && reg.gpr() == WasmTlsReg; } diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h index e2900770f02c..1b13a7f68417 100644 --- a/js/src/jit/shared/Lowering-shared-inl.h +++ b/js/src/jit/shared/Lowering-shared-inl.h @@ -817,6 +817,12 @@ LIRGeneratorShared::useInt64Fixed(MDefinition* mir, Register64 regs, bool useAtS #endif } +LInt64Allocation +LIRGeneratorShared::useInt64FixedAtStart(MDefinition* mir, Register64 regs) +{ + return useInt64Fixed(mir, regs, true); +} + LInt64Allocation LIRGeneratorShared::useInt64(MDefinition* mir, bool useAtStart) { diff --git a/js/src/jit/shared/Lowering-shared.h b/js/src/jit/shared/Lowering-shared.h index 4247e8ba069d..b3ecd6e9be0f 100644 --- a/js/src/jit/shared/Lowering-shared.h +++ b/js/src/jit/shared/Lowering-shared.h @@ -208,6 +208,7 @@ class LIRGeneratorShared : public MDefinitionVisitor inline LInt64Allocation useInt64Register(MDefinition* mir, bool useAtStart = false); inline LInt64Allocation useInt64RegisterOrConstant(MDefinition* mir, bool useAtStart = false); inline LInt64Allocation useInt64Fixed(MDefinition* mir, Register64 regs, bool useAtStart = false); + inline LInt64Allocation useInt64FixedAtStart(MDefinition* mir, Register64 regs); LInt64Allocation useInt64RegisterAtStart(MDefinition* mir) { return useInt64Register(mir, /* useAtStart = */ true); diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h index 2fb167dbc061..cf6c5afbc460 100644 --- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -157,6 +157,7 @@ static constexpr Register WasmIonExitRegE1 = rdi; // Registers used in the GenerateFFIIonExit Disable Activation block. static constexpr Register WasmIonExitRegReturnData = ecx; static constexpr Register WasmIonExitRegReturnType = ecx; +static constexpr Register WasmIonExitTlsReg = r14; static constexpr Register WasmIonExitRegD0 = rax; static constexpr Register WasmIonExitRegD1 = rdi; static constexpr Register WasmIonExitRegD2 = rbx; diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 5eedd508fba9..352ba8043d4c 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -474,9 +474,8 @@ MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromWasm) stackForCall += ComputeByteAlignment(stackForCall + sizeof(intptr_t), ABIStackAlignment); } else { - static_assert(sizeof(wasm::Frame) % ABIStackAlignment == 0, - "wasm::Frame should be part of the stack alignment."); - stackForCall += ComputeByteAlignment(stackForCall + framePushed(), + uint32_t alignmentAtPrologue = callFromWasm ? sizeof(wasm::Frame) : 0; + stackForCall += ComputeByteAlignment(stackForCall + framePushed() + alignmentAtPrologue, ABIStackAlignment); } diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp index 1359bb1aaa4b..8ecc66428649 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp @@ -600,6 +600,13 @@ MacroAssembler::Push(FloatRegister t) adjustFrame(sizeof(double)); } +void +MacroAssembler::PushFlags() +{ + pushFlags(); + adjustFrame(sizeof(intptr_t)); +} + void MacroAssembler::Pop(const Operand op) { @@ -628,6 +635,13 @@ MacroAssembler::Pop(const ValueOperand& val) implicitPop(sizeof(Value)); } +void +MacroAssembler::PopFlags() +{ + popFlags(); + implicitPop(sizeof(intptr_t)); +} + // =============================================================== // Simple call functions. @@ -741,7 +755,7 @@ MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc) { CodeOffset offset(currentOffset()); masm.nop_five(); - append(desc, CodeOffset(currentOffset()), framePushed()); + append(desc, CodeOffset(currentOffset())); MOZ_ASSERT_IF(!oom(), size() - offset.offset() == ToggledCallSize(nullptr)); return offset; } diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index 2fe4ae90c882..c1a9e5a1fc38 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -112,9 +112,10 @@ static constexpr Register WasmIonExitRegE1 = eax; // Registers used in the GenerateFFIIonExit Disable Activation block. static constexpr Register WasmIonExitRegReturnData = edx; static constexpr Register WasmIonExitRegReturnType = ecx; +static constexpr Register WasmIonExitTlsReg = esi; static constexpr Register WasmIonExitRegD0 = edi; static constexpr Register WasmIonExitRegD1 = eax; -static constexpr Register WasmIonExitRegD2 = esi; +static constexpr Register WasmIonExitRegD2 = ebx; // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand). static constexpr Register RegExpMatcherRegExpReg = CallTempReg0; diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index dea148125724..ce1880d51fe6 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -949,20 +949,11 @@ CodeGeneratorX86::visitDivOrModI64(LDivOrModI64* lir) { Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs)); Register64 rhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Rhs)); + Register temp = ToRegister(lir->temp()); Register64 output = ToOutRegister64(lir); MOZ_ASSERT(output == ReturnReg64); - // We are free to clobber all registers, since this is a call instruction. - AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); - regs.take(lhs.low); - regs.take(lhs.high); - if (lhs != rhs) { - regs.take(rhs.low); - regs.take(rhs.high); - } - Register temp = regs.takeAny(); - Label done; // Handle divide by zero. @@ -1006,20 +997,11 @@ CodeGeneratorX86::visitUDivOrModI64(LUDivOrModI64* lir) { Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs)); Register64 rhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Rhs)); + Register temp = ToRegister(lir->temp()); Register64 output = ToOutRegister64(lir); MOZ_ASSERT(output == ReturnReg64); - // We are free to clobber all registers, since this is a call instruction. - AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All()); - regs.take(lhs.low); - regs.take(lhs.high); - if (lhs != rhs) { - regs.take(rhs.low); - regs.take(rhs.high); - } - Register temp = regs.takeAny(); - // Prevent divide by zero. if (lir->canBeDivideByZero()) masm.branchTest64(Assembler::Zero, rhs, rhs, temp, trap(lir, wasm::Trap::IntegerDivideByZero)); diff --git a/js/src/jit/x86/LIR-x86.h b/js/src/jit/x86/LIR-x86.h index f49ec7b87667..0c36494eac41 100644 --- a/js/src/jit/x86/LIR-x86.h +++ b/js/src/jit/x86/LIR-x86.h @@ -109,7 +109,7 @@ class LWasmUint32ToFloat32: public LInstructionHelper<1, 1, 1> } }; -class LDivOrModI64 : public LCallInstructionHelper +class LDivOrModI64 : public LCallInstructionHelper { public: LIR_HEADER(DivOrModI64) @@ -117,10 +117,11 @@ class LDivOrModI64 : public LCallInstructionHelpertoMod()->trapOffset(); return mir_->toDiv()->trapOffset(); } + const LDefinition* temp() { + return getTemp(0); + } }; -class LUDivOrModI64 : public LCallInstructionHelper +class LUDivOrModI64 : public LCallInstructionHelper { public: LIR_HEADER(UDivOrModI64) @@ -153,10 +157,11 @@ class LUDivOrModI64 : public LCallInstructionHelpertoMod()->trapOffset(); return mir_->toDiv()->trapOffset(); } + const LDefinition* temp() { + return getTemp(0); + } }; class LWasmTruncateToInt64 : public LInstructionHelper diff --git a/js/src/jit/x86/Lowering-x86.cpp b/js/src/jit/x86/Lowering-x86.cpp index 5c11bac16555..337b165a56ed 100644 --- a/js/src/jit/x86/Lowering-x86.cpp +++ b/js/src/jit/x86/Lowering-x86.cpp @@ -618,8 +618,9 @@ LIRGeneratorX86::lowerDivI64(MDiv* div) return; } - LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(div->lhs()), - useInt64RegisterAtStart(div->rhs())); + LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64FixedAtStart(div->lhs(), Register64(eax, ebx)), + useInt64FixedAtStart(div->rhs(), Register64(ecx, edx)), + tempFixed(esi)); defineReturn(lir, div); } @@ -631,24 +632,27 @@ LIRGeneratorX86::lowerModI64(MMod* mod) return; } - LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(mod->lhs()), - useInt64RegisterAtStart(mod->rhs())); + LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64FixedAtStart(mod->lhs(), Register64(eax, ebx)), + useInt64FixedAtStart(mod->rhs(), Register64(ecx, edx)), + tempFixed(esi)); defineReturn(lir, mod); } void LIRGeneratorX86::lowerUDivI64(MDiv* div) { - LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(div->lhs()), - useInt64RegisterAtStart(div->rhs())); + LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64FixedAtStart(div->lhs(), Register64(eax, ebx)), + useInt64FixedAtStart(div->rhs(), Register64(ecx, edx)), + tempFixed(esi)); defineReturn(lir, div); } void LIRGeneratorX86::lowerUModI64(MMod* mod) { - LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(mod->lhs()), - useInt64RegisterAtStart(mod->rhs())); + LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64FixedAtStart(mod->lhs(), Register64(eax, ebx)), + useInt64FixedAtStart(mod->rhs(), Register64(ecx, edx)), + tempFixed(esi)); defineReturn(lir, mod); } diff --git a/js/src/jsapi-tests/testGCFinalizeCallback.cpp b/js/src/jsapi-tests/testGCFinalizeCallback.cpp index 95fac3d59959..1826487bef32 100644 --- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp +++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp @@ -175,7 +175,7 @@ bool checkMultipleGroups() bool checkFinalizeStatus() { /* - * The finalize callback should be called twice for each zone group + * The finalize callback should be called twice for each sweep group * finalized, with status JSFINALIZE_GROUP_START and JSFINALIZE_GROUP_END, * and then once more with JSFINALIZE_COLLECTION_END. */ diff --git a/js/src/jsapi-tests/testWeakMap.cpp b/js/src/jsapi-tests/testWeakMap.cpp index 37a272817df4..a4540c11535d 100644 --- a/js/src/jsapi-tests/testWeakMap.cpp +++ b/js/src/jsapi-tests/testWeakMap.cpp @@ -102,7 +102,7 @@ BEGIN_TEST(testWeakMap_keyDelegates) while (JS::IsIncrementalGCInProgress(cx)) cx->runtime()->gc.debugGCSlice(budget); #ifdef DEBUG - CHECK(map->zone()->lastZoneGroupIndex() < delegateRoot->zone()->lastZoneGroupIndex()); + CHECK(map->zone()->lastSweepGroupIndex() < delegateRoot->zone()->lastSweepGroupIndex()); #endif /* Add our entry to the weakmap. */ @@ -124,7 +124,7 @@ BEGIN_TEST(testWeakMap_keyDelegates) * necessary because of the presence of the delegate and the CCW. */ #ifdef DEBUG - CHECK(map->zone()->lastZoneGroupIndex() == delegateRoot->zone()->lastZoneGroupIndex()); + CHECK(map->zone()->lastSweepGroupIndex() == delegateRoot->zone()->lastSweepGroupIndex()); #endif /* Check that when the delegate becomes unreachable the entry is removed. */ diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 7b8278820e79..80484310e513 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1382,16 +1382,16 @@ JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb) } JS_PUBLIC_API(bool) -JS_AddWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb, void* data) +JS_AddWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb, void* data) { AssertHeapIsIdle(); - return cx->runtime()->gc.addWeakPointerZoneGroupCallback(cb, data); + return cx->runtime()->gc.addWeakPointerZonesCallback(cb, data); } JS_PUBLIC_API(void) -JS_RemoveWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb) +JS_RemoveWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb) { - cx->runtime()->gc.removeWeakPointerZoneGroupCallback(cb); + cx->runtime()->gc.removeWeakPointerZonesCallback(cb); } JS_PUBLIC_API(bool) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 411aaf3bb9f5..bfbd82d0961f 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -585,7 +585,7 @@ typedef void (* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, bool isZoneGC, void* data); typedef void -(* JSWeakPointerZoneGroupCallback)(JSContext* cx, void* data); +(* JSWeakPointerZonesCallback)(JSContext* cx, void* data); typedef void (* JSWeakPointerCompartmentCallback)(JSContext* cx, JSCompartment* comp, void* data); @@ -1720,7 +1720,7 @@ JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb); * about. * * Since sweeping is incremental, we have several callbacks to avoid repeatedly - * having to visit all embedder structures. The WeakPointerZoneGroupCallback is + * having to visit all embedder structures. The WeakPointerZonesCallback is * called once for each strongly connected group of zones, whereas the * WeakPointerCompartmentCallback is called once for each compartment that is * visited while sweeping. Structures that cannot contain references in more @@ -1739,10 +1739,10 @@ JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb); */ extern JS_PUBLIC_API(bool) -JS_AddWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb, void* data); +JS_AddWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb, void* data); extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb); +JS_RemoveWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb); extern JS_PUBLIC_API(bool) JS_AddWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb, diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 0989b942fb39..356ff8597c66 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -378,6 +378,12 @@ js::AssertSameCompartment(JSContext* cx, JSObject* obj) assertSameCompartment(cx, obj); } +JS_FRIEND_API(void) +js::AssertSameCompartment(JSContext* cx, JS::HandleValue v) +{ + assertSameCompartment(cx, v); +} + #ifdef DEBUG JS_FRIEND_API(void) js::AssertSameCompartment(JSObject* objA, JSObject* objB) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 76745822486e..41f7c0cae7b7 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -653,6 +653,9 @@ GetPrototypeNoProxy(JSObject* obj); JS_FRIEND_API(void) AssertSameCompartment(JSContext* cx, JSObject* obj); +JS_FRIEND_API(void) +AssertSameCompartment(JSContext* cx, JS::HandleValue v); + #ifdef JS_DEBUG JS_FRIEND_API(void) AssertSameCompartment(JSObject* objA, JSObject* objB); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 9d8bde656774..7257455193ce 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -80,12 +80,12 @@ * * Slice n+1: Sweep: Mark objects in unswept zones that were newly * identified as alive (see below). Then sweep more zone - * groups. + * sweep groups. * * ... JS code runs ... * * Slice n+2: Sweep: Mark objects in unswept zones that were newly - * identified as alive. Then sweep more zone groups. + * identified as alive. Then sweep more zones. * * ... JS code runs ... * @@ -161,7 +161,7 @@ * conditions to change such that incremental collection is no longer safe. In * this case, the collection is 'reset' by ResetIncrementalGC(). If we are in * the mark state, this just stops marking, but if we have started sweeping - * already, we continue until we have swept the current zone group. Following a + * already, we continue until we have swept the current sweep group. Following a * reset, a new non-incremental collection is started. * * Compacting GC @@ -838,9 +838,9 @@ GCRuntime::GCRuntime(JSRuntime* rt) : lastMarkSlice(false), sweepOnBackgroundThread(false), blocksToFreeAfterSweeping((size_t) JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), - zoneGroupIndex(0), - zoneGroups(nullptr), - currentZoneGroup(nullptr), + sweepGroupIndex(0), + sweepGroups(nullptr), + currentSweepGroup(nullptr), sweepZone(nullptr), sweepKind(AllocKind::FIRST), abortSweepAfterCurrentGroup(false), @@ -1420,27 +1420,27 @@ GCRuntime::callFinalizeCallbacks(FreeOp* fop, JSFinalizeStatus status) const } bool -GCRuntime::addWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback, void* data) +GCRuntime::addWeakPointerZonesCallback(JSWeakPointerZonesCallback callback, void* data) { - return updateWeakPointerZoneGroupCallbacks.ref().append( - Callback(callback, data)); + return updateWeakPointerZonesCallbacks.ref().append( + Callback(callback, data)); } void -GCRuntime::removeWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback) +GCRuntime::removeWeakPointerZonesCallback(JSWeakPointerZonesCallback callback) { - for (auto& p : updateWeakPointerZoneGroupCallbacks.ref()) { + for (auto& p : updateWeakPointerZonesCallbacks.ref()) { if (p.op == callback) { - updateWeakPointerZoneGroupCallbacks.ref().erase(&p); + updateWeakPointerZonesCallbacks.ref().erase(&p); break; } } } void -GCRuntime::callWeakPointerZoneGroupCallbacks() const +GCRuntime::callWeakPointerZonesCallbacks() const { - for (auto const& p : updateWeakPointerZoneGroupCallbacks.ref()) + for (auto const& p : updateWeakPointerZonesCallbacks.ref()) p.op(TlsContext.get(), p.data); } @@ -2561,7 +2561,7 @@ GCRuntime::updateRuntimePointersToRelocatedCells(AutoLockForExclusiveAccess& loc blocksToFreeAfterSweeping.ref().freeAll(); // Call callbacks to get the rest of the system to fixup other untraced pointers. - callWeakPointerZoneGroupCallbacks(); + callWeakPointerZonesCallbacks(); } void @@ -4057,7 +4057,7 @@ GCRuntime::markWeakReferences(gcstats::Phase phase) void GCRuntime::markWeakReferencesInCurrentGroup(gcstats::Phase phase) { - markWeakReferences(phase); + markWeakReferences(phase); } template @@ -4080,7 +4080,7 @@ GCRuntime::markGrayReferences(gcstats::Phase phase) void GCRuntime::markGrayReferencesInCurrentGroup(gcstats::Phase phase) { - markGrayReferences(phase); + markGrayReferences(phase); } void @@ -4466,7 +4466,7 @@ JSCompartment::findDeadProxyZoneEdges(bool* foundAny) if (IsDeadProxyObject(&value.toObject())) { *foundAny = true; CrossCompartmentKey& key = e.front().mutableKey(); - if (!key.as()->zone()->gcZoneGroupEdges().put(zone())) + if (!key.as()->zone()->gcSweepGroupEdges().put(zone())) return false; } } @@ -4490,7 +4490,7 @@ Zone::findOutgoingEdges(ZoneComponentFinder& finder) for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next()) comp->findOutgoingEdges(finder); - for (ZoneSet::Range r = gcZoneGroupEdges().all(); !r.empty(); r.popFront()) { + for (ZoneSet::Range r = gcSweepGroupEdges().all(); !r.empty(); r.popFront()) { if (r.front()->isGCMarking()) finder.addEdgeTo(r.front()); } @@ -4534,11 +4534,11 @@ GCRuntime::findInterZoneEdges() } void -GCRuntime::findZoneGroups(AutoLockForExclusiveAccess& lock) +GCRuntime::groupZonesForSweeping(AutoLockForExclusiveAccess& lock) { #ifdef DEBUG for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) - MOZ_ASSERT(zone->gcZoneGroupEdges().empty()); + MOZ_ASSERT(zone->gcSweepGroupEdges().empty()); #endif JSContext* cx = TlsContext.get(); @@ -4550,22 +4550,22 @@ GCRuntime::findZoneGroups(AutoLockForExclusiveAccess& lock) MOZ_ASSERT(zone->isGCMarking()); finder.addNode(zone); } - zoneGroups = finder.getResultsList(); - currentZoneGroup = zoneGroups; - zoneGroupIndex = 0; + sweepGroups = finder.getResultsList(); + currentSweepGroup = sweepGroups; + sweepGroupIndex = 0; for (GCZonesIter zone(rt); !zone.done(); zone.next()) - zone->gcZoneGroupEdges().clear(); + zone->gcSweepGroupEdges().clear(); #ifdef DEBUG - for (Zone* head = currentZoneGroup; head; head = head->nextGroup()) { + for (Zone* head = currentSweepGroup; head; head = head->nextGroup()) { for (Zone* zone = head; zone; zone = zone->nextNodeInGroup()) MOZ_ASSERT(zone->isGCMarking()); } - MOZ_ASSERT_IF(!isIncremental, !currentZoneGroup->nextGroup()); + MOZ_ASSERT_IF(!isIncremental, !currentSweepGroup->nextGroup()); for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) - MOZ_ASSERT(zone->gcZoneGroupEdges().empty()); + MOZ_ASSERT(zone->gcSweepGroupEdges().empty()); #endif } @@ -4573,26 +4573,26 @@ static void ResetGrayList(JSCompartment* comp); void -GCRuntime::getNextZoneGroup() +GCRuntime::getNextSweepGroup() { - currentZoneGroup = currentZoneGroup->nextGroup(); - ++zoneGroupIndex; - if (!currentZoneGroup) { + currentSweepGroup = currentSweepGroup->nextGroup(); + ++sweepGroupIndex; + if (!currentSweepGroup) { abortSweepAfterCurrentGroup = false; return; } - for (Zone* zone = currentZoneGroup; zone; zone = zone->nextNodeInGroup()) { + for (Zone* zone = currentSweepGroup; zone; zone = zone->nextNodeInGroup()) { MOZ_ASSERT(zone->isGCMarking()); MOZ_ASSERT(!zone->isQueuedForBackgroundSweep()); } if (!isIncremental) - ZoneComponentFinder::mergeGroups(currentZoneGroup); + ZoneComponentFinder::mergeGroups(currentSweepGroup); if (abortSweepAfterCurrentGroup) { MOZ_ASSERT(!isIncremental); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(!zone->gcNextGraphComponent); MOZ_ASSERT(zone->isGCMarking()); zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit); @@ -4604,7 +4604,7 @@ GCRuntime::getNextZoneGroup() ResetGrayList(comp); abortSweepAfterCurrentGroup = false; - currentZoneGroup = nullptr; + currentSweepGroup = nullptr; } } @@ -4853,7 +4853,7 @@ js::NotifyGCPostSwap(JSObject* a, JSObject* b, unsigned removedFlags) } void -GCRuntime::endMarkingZoneGroup() +GCRuntime::endMarkingSweepGroup() { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_MARK); @@ -4871,7 +4871,7 @@ GCRuntime::endMarkingZoneGroup() * these will be marked through, as they are not marked with * MarkCrossCompartmentXXX. */ - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(zone->isGCMarkingBlack()); zone->setGCState(Zone::MarkGray); } @@ -4885,7 +4885,7 @@ GCRuntime::endMarkingZoneGroup() markWeakReferencesInCurrentGroup(gcstats::PHASE_SWEEP_MARK_GRAY_WEAK); /* Restore marking state. */ - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(zone->isGCMarkingGray()); zone->setGCState(Zone::Mark); } @@ -5010,7 +5010,7 @@ using WeakCacheTaskVector = mozilla::Vector* cache : zone->weakCaches()) { SweepWeakCacheTask task(rt, *cache); task.runFromActiveCooperatingThread(rt); @@ -5022,7 +5022,7 @@ static WeakCacheTaskVector PrepareWeakCacheTasks(JSRuntime* rt) { WeakCacheTaskVector out; - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { for (JS::WeakCache* cache : zone->weakCaches()) { if (!out.append(SweepWeakCacheTask(rt, *cache))) { SweepWeakCachesFromActiveCooperatingThread(rt); @@ -5034,15 +5034,15 @@ PrepareWeakCacheTasks(JSRuntime* rt) } void -GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) +GCRuntime::beginSweepingSweepGroup(AutoLockForExclusiveAccess& lock) { /* - * Begin sweeping the group of zones in gcCurrentZoneGroup, - * performing actions that must be done before yielding to caller. + * Begin sweeping the group of zones in currentSweepGroup, performing + * actions that must be done before yielding to caller. */ bool sweepingAtoms = false; - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { /* Set the GC state to sweeping. */ MOZ_ASSERT(zone->isGCMarking()); zone->setGCState(Zone::Sweep); @@ -5057,7 +5057,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) rt->sweepZoneCallback(zone); #ifdef DEBUG - zone->gcLastZoneGroupIndex = zoneGroupIndex; + zone->gcLastSweepGroupIndex = sweepGroupIndex; #endif } @@ -5071,7 +5071,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) SweepMiscTask sweepMiscTask(rt); WeakCacheTaskVector sweepCacheTasks = PrepareWeakCacheTasks(rt); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { /* Clear all weakrefs that point to unmarked things. */ for (auto edge : zone->gcWeakRefs()) { /* Edges may be present multiple times, so may already be nulled. */ @@ -5080,22 +5080,22 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) } zone->gcWeakRefs().clear(); - /* No need to look up any more weakmap keys from this zone group. */ + /* No need to look up any more weakmap keys from this sweep group. */ AutoEnterOOMUnsafeRegion oomUnsafe; if (!zone->gcWeakKeys().clear()) - oomUnsafe.crash("clearing weak keys in beginSweepingZoneGroup()"); + oomUnsafe.crash("clearing weak keys in beginSweepingSweepGroup()"); } { gcstats::AutoPhase ap(stats(), gcstats::PHASE_FINALIZE_START); callFinalizeCallbacks(&fop, JSFINALIZE_GROUP_START); { - gcstats::AutoPhase ap2(stats(), gcstats::PHASE_WEAK_ZONEGROUP_CALLBACK); - callWeakPointerZoneGroupCallbacks(); + gcstats::AutoPhase ap2(stats(), gcstats::PHASE_WEAK_ZONES_CALLBACK); + callWeakPointerZonesCallbacks(); } { gcstats::AutoPhase ap2(stats(), gcstats::PHASE_WEAK_COMPARTMENT_CALLBACK); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) callWeakPointerCompartmentCallbacks(comp); } @@ -5109,7 +5109,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_COMPARTMENTS); - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + gcstats::AutoSCC scc(stats(), sweepGroupIndex); { AutoLockHelperThreadState helperLock; @@ -5136,7 +5136,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) c->sweepTemplateObjects(); } - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->sweepWeakMaps(); // Bug 1071218: the following two methods have not yet been @@ -5159,26 +5159,26 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) { gcstats::AutoPhase apdc(stats(), gcstats::PHASE_SWEEP_DISCARD_CODE); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->discardJitCode(&fop); } { gcstats::AutoPhase ap1(stats(), gcstats::PHASE_SWEEP_TYPES); gcstats::AutoPhase ap2(stats(), gcstats::PHASE_SWEEP_TYPES_BEGIN); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->beginSweepTypes(&fop, releaseObservedTypes && !zone->isPreservingCode()); } { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_BREAKPOINT); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->sweepBreakpoints(&fop); } { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_BREAKPOINT); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->sweepUniqueIds(&fop); } } @@ -5191,7 +5191,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_COMPARTMENTS); - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + gcstats::AutoSCC scc(stats(), sweepGroupIndex); AutoLockHelperThreadState helperLock; joinTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER, helperLock); @@ -5211,29 +5211,29 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) * Objects are finalized immediately but this may change in the future. */ - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { + gcstats::AutoSCC scc(stats(), sweepGroupIndex); zone->arenas.queueForegroundObjectsForSweep(&fop); } - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { + gcstats::AutoSCC scc(stats(), sweepGroupIndex); for (unsigned i = 0; i < ArrayLength(IncrementalFinalizePhases); ++i) zone->arenas.queueForForegroundSweep(&fop, IncrementalFinalizePhases[i]); } - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { + gcstats::AutoSCC scc(stats(), sweepGroupIndex); for (unsigned i = 0; i < ArrayLength(BackgroundFinalizePhases); ++i) zone->arenas.queueForBackgroundSweep(&fop, BackgroundFinalizePhases[i]); } - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { + gcstats::AutoSCC scc(stats(), sweepGroupIndex); zone->arenas.queueForegroundThingsForSweep(&fop); } sweepingTypes = true; finalizePhase = 0; - sweepZone = currentZoneGroup; + sweepZone = currentSweepGroup; sweepKind = AllocKind::FIRST; { @@ -5243,10 +5243,10 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) } void -GCRuntime::endSweepingZoneGroup() +GCRuntime::endSweepingSweepGroup() { /* Update the GC state for zones we have swept. */ - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(zone->isGCSweeping()); AutoLockGC lock(rt); zone->setGCState(Zone::Finished); @@ -5256,7 +5256,7 @@ GCRuntime::endSweepingZoneGroup() /* Start background thread to sweep zones if required. */ ZoneList zones; - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zones.append(zone); if (sweepOnBackgroundThread) queueZonesForBackgroundSweep(zones); @@ -5299,9 +5299,9 @@ GCRuntime::beginSweepPhase(bool destroyingRuntime, AutoLockForExclusiveAccess& l AssertNoWrappersInGrayList(rt); DropStringWrappers(rt); - findZoneGroups(lock); - endMarkingZoneGroup(); - beginSweepingZoneGroup(lock); + groupZonesForSweeping(lock); + endMarkingSweepGroup(); + beginSweepingSweepGroup(lock); } bool @@ -5391,10 +5391,10 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock // Sweep dead type information stored in scripts and object groups, but // don't finalize them yet. We have to sweep dead information from both // live and dead scripts and object groups, so that no dead references - // remain in them. Type inference can end up crawling these zones - // again, such as for TypeCompartment::markSetsUnknown, and if this - // happens after sweeping for the zone group finishes we won't be able - // to determine which things in the zone are live. + // remain in them. Type inference can end up crawling these zones again, + // such as for TypeCompartment::markSetsUnknown, and if this happens + // after sweeping for the sweep group finishes we won't be able to + // determine which things in the zone are live. if (sweepingTypes) { gcstats::AutoPhase ap1(stats(), gcstats::PHASE_SWEEP_COMPARTMENTS); gcstats::AutoPhase ap2(stats(), gcstats::PHASE_SWEEP_TYPES); @@ -5425,7 +5425,7 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock al.mergeForegroundSweptObjectArenas(); } - sweepZone = currentZoneGroup; + sweepZone = currentSweepGroup; sweepingTypes = false; } @@ -5456,7 +5456,7 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock } sweepKind = AllocKind::FIRST; } - sweepZone = currentZoneGroup; + sweepZone = currentSweepGroup; } /* Remove dead shapes from the shape tree, but don't finalize them yet. */ @@ -5474,13 +5474,13 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock } } - endSweepingZoneGroup(); - getNextZoneGroup(); - if (!currentZoneGroup) + endSweepingSweepGroup(); + getNextSweepGroup(); + if (!currentSweepGroup) return Finished; - endMarkingZoneGroup(); - beginSweepingZoneGroup(lock); + endMarkingSweepGroup(); + beginSweepingSweepGroup(lock); } } @@ -5807,7 +5807,7 @@ GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoLockForExclusiveAccess for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) c->scheduledForDestruction = false; - /* Finish sweeping the current zone group, then abort. */ + /* Finish sweeping the current sweep group, then abort. */ abortSweepAfterCurrentGroup = true; /* Don't perform any compaction after sweeping. */ diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index 612c854b734d..9024985af073 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -445,15 +445,15 @@ class GCZonesIter typedef CompartmentsIterT GCCompartmentsIter; -/* Iterates over all zones in the current zone group. */ -class GCZoneGroupIter { +/* Iterates over all zones in the current sweep group. */ +class GCSweepGroupIter { private: JS::Zone* current; public: - explicit GCZoneGroupIter(JSRuntime* rt) { + explicit GCSweepGroupIter(JSRuntime* rt) { MOZ_ASSERT(CurrentThreadIsPerformingGC()); - current = rt->gc.getCurrentZoneGroup(); + current = rt->gc.getCurrentSweepGroup(); } bool done() const { return !current; } @@ -472,7 +472,7 @@ class GCZoneGroupIter { JS::Zone* operator->() const { return get(); } }; -typedef CompartmentsIterT GCCompartmentGroupIter; +typedef CompartmentsIterT GCCompartmentGroupIter; inline void RelocationOverlay::forwardTo(Cell* cell) diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index 349c0fbb3c42..9764af9c1a3c 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -147,7 +147,7 @@ ObjectValueMap::findZoneEdges() Zone* delegateZone = delegate->zone(); if (delegateZone == zone() || !delegateZone->isGCMarking()) continue; - if (!delegateZone->gcZoneGroupEdges().put(key->zone())) + if (!delegateZone->gcSweepGroupEdges().put(key->zone())) return false; } return true; diff --git a/js/src/moz.build b/js/src/moz.build index 8b11432f99bc..32459181050e 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -381,7 +381,6 @@ UNIFIED_SOURCES += [ 'wasm/WasmCode.cpp', 'wasm/WasmCompartment.cpp', 'wasm/WasmCompile.cpp', - 'wasm/WasmDebugFrame.cpp', 'wasm/WasmFrameIterator.cpp', 'wasm/WasmGenerator.cpp', 'wasm/WasmInstance.cpp', diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 93966b5d68a6..5e0a70e4aeec 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -5274,9 +5274,11 @@ SingleStepCallback(void* arg, jit::Simulator* sim, void* pc) #if defined(JS_SIMULATOR_ARM) state.sp = (void*)sim->get_register(jit::Simulator::sp); state.lr = (void*)sim->get_register(jit::Simulator::lr); + state.fp = (void*)sim->get_register(jit::Simulator::fp); #elif defined(JS_SIMULATOR_MIPS64) state.sp = (void*)sim->getRegister(jit::Simulator::sp); state.lr = (void*)sim->getRegister(jit::Simulator::ra); + state.fp = (void*)sim->getRegister(jit::Simulator::fp); #else # error "NYI: Single-step profiling support" #endif diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 8bb44714a4c2..be3db0cc80bb 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -2549,7 +2549,7 @@ Debugger::updateExecutionObservabilityOfFrames(JSContext* cx, const ExecutionObs oldestEnabledFrame.setIsDebuggee(); } if (iter.abstractFramePtr().isWasmDebugFrame()) - iter.abstractFramePtr().asWasmDebugFrame()->observeFrame(cx); + iter.abstractFramePtr().asWasmDebugFrame()->observe(cx); } else { #ifdef DEBUG // Debugger.Frame lifetimes are managed by the debug epilogue, diff --git a/js/src/vm/GeckoProfiler.cpp b/js/src/vm/GeckoProfiler.cpp index 86fdcc003617..fdd1cf07fc88 100644 --- a/js/src/vm/GeckoProfiler.cpp +++ b/js/src/vm/GeckoProfiler.cpp @@ -141,6 +141,12 @@ GeckoProfiler::enable(bool enabled) } } + // WebAssembly code does not need to be released, but profiling string + // labels have to be generated so that they are available during async + // profiling stack iteration. + for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) + c->wasm.ensureProfilingLabels(enabled); + return true; } diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 250819b3e26d..3dc4109817bd 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -561,7 +561,7 @@ struct JSRuntime : public js::MallocProvider } private: - // List of non-ephemeron weak containers to sweep during beginSweepingZoneGroup. + // List of non-ephemeron weak containers to sweep during beginSweepingSweepGroup. js::ActiveThreadData>> weakCaches_; public: mozilla::LinkedList>& weakCaches() { return weakCaches_.ref(); } diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 8679d6fb7af9..85fc08249574 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -19,7 +19,6 @@ #include "js/Debug.h" #include "vm/EnvironmentObject.h" #include "vm/GeneratorObject.h" -#include "wasm/WasmDebugFrame.h" #include "wasm/WasmInstance.h" #include "jsobjinlines.h" @@ -455,7 +454,7 @@ AbstractFramePtr::environmentChain() const if (isBaselineFrame()) return asBaselineFrame()->environmentChain(); if (isWasmDebugFrame()) - return asWasmDebugFrame()->environmentChain(); + return &global()->lexicalEnvironment(); return asRematerializedFrame()->environmentChain(); } diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 8e5fe3060610..70150b556b52 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -17,7 +17,6 @@ #include "js/GCAPI.h" #include "vm/Debugger.h" #include "vm/Opcodes.h" -#include "wasm/WasmDebugFrame.h" #include "jit/JitFrameIterator-inl.h" #include "vm/EnvironmentObject-inl.h" @@ -1647,7 +1646,7 @@ WasmActivation::WasmActivation(JSContext* cx) : Activation(cx, Wasm), entrySP_(nullptr), resumePC_(nullptr), - fp_(nullptr), + exitFP_(nullptr), exitReason_(wasm::ExitReason::None) { (void) entrySP_; // silence "unused private member" warning @@ -1655,8 +1654,6 @@ WasmActivation::WasmActivation(JSContext* cx) prevWasm_ = cx->wasmActivationStack_; cx->wasmActivationStack_ = this; - cx->compartment()->wasm.activationCount_++; - // Now that the WasmActivation is fully initialized, make it visible to // asynchronous profiling. registerProfiling(); @@ -1667,13 +1664,11 @@ WasmActivation::~WasmActivation() // Hide this activation from the profiler before is is destroyed. unregisterProfiling(); - MOZ_ASSERT(fp_ == nullptr); + MOZ_ASSERT(exitFP_ == nullptr); + MOZ_ASSERT(exitReason_ == wasm::ExitReason::None); MOZ_ASSERT(cx_->wasmActivationStack_ == this); cx_->wasmActivationStack_ = prevWasm_; - - MOZ_ASSERT(cx_->compartment()->wasm.activationCount_ > 0); - cx_->compartment()->wasm.activationCount_--; } InterpreterFrameIterator& diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 582a4da128db..5655b5f76291 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -25,6 +25,7 @@ #include "vm/ArgumentsObject.h" #include "vm/SavedFrame.h" #include "wasm/WasmFrameIterator.h" +#include "wasm/WasmTypes.h" struct JSCompartment; @@ -166,6 +167,7 @@ class AbstractFramePtr MOZ_IMPLICIT AbstractFramePtr(wasm::DebugFrame* fp) : ptr_(fp ? uintptr_t(fp) | Tag_WasmDebugFrame : 0) { + static_assert(wasm::DebugFrame::Alignment >= TagMask, "aligned"); MOZ_ASSERT_IF(fp, asWasmDebugFrame() == fp); } @@ -1733,7 +1735,7 @@ class WasmActivation : public Activation WasmActivation* prevWasm_; void* entrySP_; void* resumePC_; - uint8_t* fp_; + uint8_t* exitFP_; wasm::ExitReason exitReason_; public: @@ -1746,20 +1748,16 @@ class WasmActivation : public Activation return true; } - // Returns a pointer to the base of the innermost stack frame of wasm code - // in this activation. - uint8_t* fp() const { return fp_; } + // Returns null or the final wasm::Frame* when wasm exited this + // WasmActivation. + uint8_t* exitFP() const { return exitFP_; } // Returns the reason why wasm code called out of wasm code. wasm::ExitReason exitReason() const { return exitReason_; } - // Read by JIT code: - static unsigned offsetOfContext() { return offsetof(WasmActivation, cx_); } - static unsigned offsetOfResumePC() { return offsetof(WasmActivation, resumePC_); } - // Written by JIT code: static unsigned offsetOfEntrySP() { return offsetof(WasmActivation, entrySP_); } - static unsigned offsetOfFP() { return offsetof(WasmActivation, fp_); } + static unsigned offsetOfExitFP() { return offsetof(WasmActivation, exitFP_); } static unsigned offsetOfExitReason() { return offsetof(WasmActivation, exitReason_); } // Read/written from SIGSEGV handler: @@ -1767,7 +1765,7 @@ class WasmActivation : public Activation void* resumePC() const { return resumePC_; } // Used by wasm::FrameIterator during stack unwinding. - void unwindFP(uint8_t* fp) { fp_ = fp; } + void unwindExitFP(uint8_t* exitFP) { exitFP_ = exitFP; exitReason_ = wasm::ExitReason::None; } }; // A FrameIter walks over a context's stack of JS script activations, diff --git a/js/src/vm/String-inl.h b/js/src/vm/String-inl.h index 7dc628d02117..ff98dcc1d319 100644 --- a/js/src/vm/String-inl.h +++ b/js/src/vm/String-inl.h @@ -181,6 +181,9 @@ JSDependentString::new_(JSContext* cx, JSLinearString* baseArg, size_t start, : js::NewInlineString(cx, base, start, length); } + if (baseArg->isExternal() && !baseArg->ensureFlat(cx)) + return nullptr; + JSDependentString* str = static_cast(js::Allocate(cx)); if (str) { str->init(cx, baseArg, start, length); diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index 4a1ec1d3f9dc..67ddee95ca01 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -928,6 +928,9 @@ AutoStableStringChars::init(JSContext* cx, JSString* s) MOZ_ASSERT(state_ == Uninitialized); + if (linearString->isExternal() && !linearString->ensureFlat(cx)) + return false; + // If the chars are inline then we need to copy them since they may be moved // by a compacting GC. if (baseIsInline(linearString)) { @@ -959,6 +962,9 @@ AutoStableStringChars::initTwoByte(JSContext* cx, JSString* s) if (linearString->hasLatin1Chars()) return copyAndInflateLatin1Chars(cx, linearString); + if (linearString->isExternal() && !linearString->ensureFlat(cx)) + return false; + // If the chars are inline then we need to copy them since they may be moved // by a compacting GC. if (baseIsInline(linearString)) diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp index cd6ab32fd434..c367bfa573d8 100644 --- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -97,7 +97,6 @@ #endif #include "wasm/WasmBinaryIterator.h" -#include "wasm/WasmDebugFrame.h" #include "wasm/WasmGenerator.h" #include "wasm/WasmSignalHandlers.h" #include "wasm/WasmValidate.h" @@ -199,31 +198,19 @@ static constexpr int32_t TlsSlotSize = sizeof(void*); static constexpr int32_t TlsSlotOffset = TlsSlotSize; BaseLocalIter::BaseLocalIter(const ValTypeVector& locals, - size_t argsLength, - bool debugEnabled) + size_t argsLength, + bool debugEnabled) : locals_(locals), argsLength_(argsLength), argsRange_(locals.begin(), argsLength), argsIter_(argsRange_), index_(0), - localSize_(0), + localSize_(debugEnabled ? DebugFrame::offsetOfFrame() : 0), + reservedSize_(localSize_), done_(false) { MOZ_ASSERT(argsLength <= locals.length()); - // Reserve a stack slot for the TLS pointer outside the locals range so it - // isn't zero-filled like the normal locals. - DebugOnly tlsSlotOffset = pushLocal(TlsSlotSize); - MOZ_ASSERT(tlsSlotOffset == TlsSlotOffset); - if (debugEnabled) { - // If debug information is generated, constructing DebugFrame record: - // reserving some data before TLS pointer. The TLS pointer allocated - // above and regular wasm::Frame data starts after locals. - localSize_ += DebugFrame::offsetOfTlsData(); - MOZ_ASSERT(DebugFrame::offsetOfFrame() == localSize_); - } - reservedSize_ = localSize_; - settle(); } @@ -628,10 +615,6 @@ class BaseCompiler Vector localInfo_; Vector outOfLine_; - // Index into localInfo_ of the special local used for saving the TLS - // pointer. This follows the function's real arguments and locals. - uint32_t tlsSlot_; - // On specific platforms we sometimes need to use specific registers. #ifdef JS_CODEGEN_X64 @@ -2229,9 +2212,6 @@ class BaseCompiler maxFramePushed_ = localSize_; - // The TLS pointer is always passed as a hidden argument in WasmTlsReg. - // Save it into its assigned local slot. - storeToFramePtr(WasmTlsReg, localInfo_[tlsSlot_].offs()); if (debugEnabled_) { // Initialize funcIndex and flag fields of DebugFrame. size_t debugFrame = masm.framePushed() - DebugFrame::offsetOfFrame(); @@ -2361,8 +2341,9 @@ class BaseCompiler masm.breakpoint(); // Patch the add in the prologue so that it checks against the correct - // frame size. + // frame size. Flush the constant pool in case it needs to be patched. MOZ_ASSERT(maxFramePushed_ >= localSize_); + masm.flush(); masm.patchAdd32ToPtr(stackAddOffset_, Imm32(-int32_t(maxFramePushed_ - localSize_))); // Since we just overflowed the stack, to be on the safe side, pop the @@ -2390,9 +2371,6 @@ class BaseCompiler restoreResult(); } - // Restore the TLS register in case it was overwritten by the function. - loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); - GenerateFunctionEpilogue(masm, localSize_, &offsets_); #if defined(JS_ION_PERF) @@ -2481,7 +2459,7 @@ class BaseCompiler // On x86 there are no pinned registers, so don't waste time // reloading the Tls. #ifndef JS_CODEGEN_X86 - loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(); masm.loadWasmPinnedRegsFromTls(); #endif } @@ -2678,7 +2656,7 @@ class BaseCompiler const FunctionCall& call) { // Builtin method calls assume the TLS register has been set. - loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(); CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::Symbolic); masm.wasmCallBuiltinInstanceMethod(instanceArg, builtin); @@ -3317,56 +3295,56 @@ class BaseCompiler void loadGlobalVarI32(unsigned globalDataOffset, RegI32 r) { ScratchI32 tmp(*this); - loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(tmp); masm.load32(Address(tmp, globalToTlsOffset(globalDataOffset)), r); } void loadGlobalVarI64(unsigned globalDataOffset, RegI64 r) { ScratchI32 tmp(*this); - loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(tmp); masm.load64(Address(tmp, globalToTlsOffset(globalDataOffset)), r); } void loadGlobalVarF32(unsigned globalDataOffset, RegF32 r) { ScratchI32 tmp(*this); - loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(tmp); masm.loadFloat32(Address(tmp, globalToTlsOffset(globalDataOffset)), r); } void loadGlobalVarF64(unsigned globalDataOffset, RegF64 r) { ScratchI32 tmp(*this); - loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(tmp); masm.loadDouble(Address(tmp, globalToTlsOffset(globalDataOffset)), r); } void storeGlobalVarI32(unsigned globalDataOffset, RegI32 r) { ScratchI32 tmp(*this); - loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(tmp); masm.store32(r, Address(tmp, globalToTlsOffset(globalDataOffset))); } void storeGlobalVarI64(unsigned globalDataOffset, RegI64 r) { ScratchI32 tmp(*this); - loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(tmp); masm.store64(r, Address(tmp, globalToTlsOffset(globalDataOffset))); } void storeGlobalVarF32(unsigned globalDataOffset, RegF32 r) { ScratchI32 tmp(*this); - loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(tmp); masm.storeFloat32(r, Address(tmp, globalToTlsOffset(globalDataOffset))); } void storeGlobalVarF64(unsigned globalDataOffset, RegF64 r) { ScratchI32 tmp(*this); - loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(tmp); masm.storeDouble(r, Address(tmp, globalToTlsOffset(globalDataOffset))); } @@ -5187,8 +5165,15 @@ BaseCompiler::sniffConditionalControlCmp(Cond compareOp, ValType operandType) MOZ_ASSERT(latentOp_ == LatentOp::None, "Latent comparison state not properly reset"); switch (iter_.peekOp()) { - case uint16_t(Op::BrIf): case uint16_t(Op::Select): +#ifdef JS_CODEGEN_X86 + // On x86, with only 5 available registers, a latent i64 binary + // comparison takes 4 leaving only 1 which is not enough for select. + if (operandType == ValType::I64) + return false; +#endif + MOZ_FALLTHROUGH; + case uint16_t(Op::BrIf): case uint16_t(Op::If): setLatentCompare(compareOp, operandType); return true; @@ -5804,11 +5789,8 @@ BaseCompiler::emitCallArgs(const ValTypeVector& argTypes, FunctionCall& baseline for (size_t i = 0; i < numArgs; ++i) passArg(baselineCall, argTypes[i], peek(numArgs - 1 - i)); - // Pass the TLS pointer as a hidden argument in WasmTlsReg. Load - // it directly out if its stack slot so we don't interfere with - // the stk_. if (baselineCall.loadTlsBefore) - loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(); return true; } @@ -6450,7 +6432,7 @@ BaseCompiler::maybeLoadTlsForAccess(bool omitBoundsCheck) RegI32 tls = invalidI32(); if (needTlsForAccess(omitBoundsCheck)) { tls = needI32(); - loadFromFramePtr(tls, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer)); + masm.loadWasmTlsRegFromFrame(tls); } return tls; } @@ -7473,7 +7455,6 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env, #ifdef DEBUG scratchRegisterTaken_(false), #endif - tlsSlot_(0), #ifdef JS_CODEGEN_X64 specific_rax(RegI64(Register64(rax))), specific_rcx(RegI64(Register64(rcx))), @@ -7511,6 +7492,7 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env, #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) availGPR_.take(HeapReg); #endif + availGPR_.take(FramePointer); #ifdef DEBUG setupRegisterLeakCheck(); @@ -7533,15 +7515,9 @@ BaseCompiler::init() const ValTypeVector& args = func_.sig().args(); - // localInfo_ contains an entry for every local in locals_, followed by - // entries for special locals. Currently the only special local is the TLS - // pointer. - tlsSlot_ = locals_.length(); - if (!localInfo_.resize(locals_.length() + 1)) + if (!localInfo_.resize(locals_.length())) return false; - localInfo_[tlsSlot_].init(MIRType::Pointer, TlsSlotOffset); - BaseLocalIter i(locals_, args.length(), debugEnabled_); varLow_ = i.reservedSize(); for (; !i.done() && i.index() < args.length(); i++) { diff --git a/js/src/wasm/WasmCode.cpp b/js/src/wasm/WasmCode.cpp index 4d928ceaeda3..697390e2b384 100644 --- a/js/src/wasm/WasmCode.cpp +++ b/js/src/wasm/WasmCode.cpp @@ -111,7 +111,7 @@ StaticallyLink(CodeSegment& cs, const LinkData& linkData, JSContext* cx) const Uint32Vector& offsets = linkData.symbolicLinks[imm]; for (size_t i = 0; i < offsets.length(); i++) { uint8_t* patchAt = cs.base() + offsets[i]; - void* target = AddressOf(imm, cx); + void* target = AddressOf(imm); Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt), PatchedImmPtr(target), PatchedImmPtr((void*)-1)); @@ -299,60 +299,44 @@ FuncImport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const CodeRange::CodeRange(Kind kind, Offsets offsets) : begin_(offsets.begin), - profilingReturn_(0), + ret_(0), end_(offsets.end), funcIndex_(0), funcLineOrBytecode_(0), - funcBeginToTableEntry_(0), - funcBeginToTableProfilingJump_(0), - funcBeginToNonProfilingEntry_(0), - funcProfilingJumpToProfilingReturn_(0), - funcProfilingEpilogueToProfilingReturn_(0), + funcBeginToNormalEntry_(0), kind_(kind) { MOZ_ASSERT(begin_ <= end_); - MOZ_ASSERT(kind_ == Entry || kind_ == Inline || + MOZ_ASSERT(kind_ == Entry || kind_ == Inline || kind_ == Throw || kind_ == FarJumpIsland || kind_ == DebugTrap); } -CodeRange::CodeRange(Kind kind, ProfilingOffsets offsets) +CodeRange::CodeRange(Kind kind, CallableOffsets offsets) : begin_(offsets.begin), - profilingReturn_(offsets.profilingReturn), + ret_(offsets.ret), end_(offsets.end), funcIndex_(0), funcLineOrBytecode_(0), - funcBeginToTableEntry_(0), - funcBeginToTableProfilingJump_(0), - funcBeginToNonProfilingEntry_(0), - funcProfilingJumpToProfilingReturn_(0), - funcProfilingEpilogueToProfilingReturn_(0), + funcBeginToNormalEntry_(0), kind_(kind) { - MOZ_ASSERT(begin_ < profilingReturn_); - MOZ_ASSERT(profilingReturn_ < end_); + MOZ_ASSERT(begin_ < ret_); + MOZ_ASSERT(ret_ < end_); MOZ_ASSERT(kind_ == ImportJitExit || kind_ == ImportInterpExit || kind_ == TrapExit); } CodeRange::CodeRange(uint32_t funcIndex, uint32_t funcLineOrBytecode, FuncOffsets offsets) : begin_(offsets.begin), - profilingReturn_(offsets.profilingReturn), + ret_(offsets.ret), end_(offsets.end), funcIndex_(funcIndex), funcLineOrBytecode_(funcLineOrBytecode), - funcBeginToTableEntry_(offsets.tableEntry - begin_), - funcBeginToTableProfilingJump_(offsets.tableProfilingJump - begin_), - funcBeginToNonProfilingEntry_(offsets.nonProfilingEntry - begin_), - funcProfilingJumpToProfilingReturn_(profilingReturn_ - offsets.profilingJump), - funcProfilingEpilogueToProfilingReturn_(profilingReturn_ - offsets.profilingEpilogue), + funcBeginToNormalEntry_(offsets.normalEntry - begin_), kind_(Function) { - MOZ_ASSERT(begin_ < profilingReturn_); - MOZ_ASSERT(profilingReturn_ < end_); - MOZ_ASSERT(offsets.tableEntry - begin_ <= UINT8_MAX); - MOZ_ASSERT(offsets.tableProfilingJump - begin_ <= UINT8_MAX); - MOZ_ASSERT(offsets.nonProfilingEntry - begin_ <= UINT8_MAX); - MOZ_ASSERT(profilingReturn_ - offsets.profilingJump <= UINT8_MAX); - MOZ_ASSERT(profilingReturn_ - offsets.profilingEpilogue <= UINT8_MAX); + MOZ_ASSERT(begin_ < ret_); + MOZ_ASSERT(ret_ < end_); + MOZ_ASSERT(offsets.normalEntry - begin_ <= UINT8_MAX); } static size_t @@ -413,7 +397,6 @@ Metadata::serializedSize() const SerializedPodVectorSize(memoryAccesses) + SerializedPodVectorSize(codeRanges) + SerializedPodVectorSize(callSites) + - SerializedPodVectorSize(callThunks) + SerializedPodVectorSize(funcNames) + SerializedPodVectorSize(customSections) + filename.serializedSize(); @@ -434,7 +417,6 @@ Metadata::serialize(uint8_t* cursor) const cursor = SerializePodVector(cursor, memoryAccesses); cursor = SerializePodVector(cursor, codeRanges); cursor = SerializePodVector(cursor, callSites); - cursor = SerializePodVector(cursor, callThunks); cursor = SerializePodVector(cursor, funcNames); cursor = SerializePodVector(cursor, customSections); cursor = filename.serialize(cursor); @@ -453,7 +435,6 @@ Metadata::deserialize(const uint8_t* cursor) (cursor = DeserializePodVector(cursor, &memoryAccesses)) && (cursor = DeserializePodVector(cursor, &codeRanges)) && (cursor = DeserializePodVector(cursor, &callSites)) && - (cursor = DeserializePodVector(cursor, &callThunks)) && (cursor = DeserializePodVector(cursor, &funcNames)) && (cursor = DeserializePodVector(cursor, &customSections)) && (cursor = filename.deserialize(cursor)); @@ -476,7 +457,6 @@ Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const memoryAccesses.sizeOfExcludingThis(mallocSizeOf) + codeRanges.sizeOfExcludingThis(mallocSizeOf) + callSites.sizeOfExcludingThis(mallocSizeOf) + - callThunks.sizeOfExcludingThis(mallocSizeOf) + funcNames.sizeOfExcludingThis(mallocSizeOf) + customSections.sizeOfExcludingThis(mallocSizeOf) + filename.sizeOfExcludingThis(mallocSizeOf); @@ -578,7 +558,6 @@ Code::Code(UniqueCodeSegment segment, : segment_(Move(segment)), metadata_(&metadata), maybeBytecode_(maybeBytecode), - profilingEnabled_(false), enterAndLeaveFrameTrapsCounter_(0) { MOZ_ASSERT_IF(metadata_->debugEnabled, maybeBytecode); @@ -986,77 +965,67 @@ Code::clearBreakpointsIn(JSContext* cx, WasmInstanceObject* instance, js::Debugg } -bool -Code::ensureProfilingState(JSRuntime* rt, bool newProfilingEnabled) +// When enabled, generate profiling labels for every name in funcNames_ that is +// the name of some Function CodeRange. This involves malloc() so do it now +// since, once we start sampling, we'll be in a signal-handing context where we +// cannot malloc. +void +Code::ensureProfilingLabels(bool profilingEnabled) { - if (profilingEnabled_ == newProfilingEnabled) - return true; + if (!profilingEnabled) { + profilingLabels_.clear(); + return; + } - // When enabled, generate profiling labels for every name in funcNames_ - // that is the name of some Function CodeRange. This involves malloc() so - // do it now since, once we start sampling, we'll be in a signal-handing - // context where we cannot malloc. - if (newProfilingEnabled) { - for (const CodeRange& codeRange : metadata_->codeRanges) { - if (!codeRange.isFunction()) - continue; + if (!profilingLabels_.empty()) + return; - ToCStringBuf cbuf; - const char* bytecodeStr = NumberToCString(nullptr, &cbuf, codeRange.funcLineOrBytecode()); - MOZ_ASSERT(bytecodeStr); + for (const CodeRange& codeRange : metadata_->codeRanges) { + if (!codeRange.isFunction()) + continue; - UTF8Bytes name; - if (!getFuncName(codeRange.funcIndex(), &name) || !name.append(" (", 2)) - return false; + ToCStringBuf cbuf; + const char* bytecodeStr = NumberToCString(nullptr, &cbuf, codeRange.funcLineOrBytecode()); + MOZ_ASSERT(bytecodeStr); - if (const char* filename = metadata_->filename.get()) { - if (!name.append(filename, strlen(filename))) - return false; - } else { - if (!name.append('?')) - return false; - } + UTF8Bytes name; + if (!getFuncName(codeRange.funcIndex(), &name) || !name.append(" (", 2)) + return; - if (!name.append(':') || - !name.append(bytecodeStr, strlen(bytecodeStr)) || - !name.append(")\0", 2)) - { - return false; - } - - UniqueChars label(name.extractOrCopyRawBuffer()); - if (!label) - return false; - - if (codeRange.funcIndex() >= funcLabels_.length()) { - if (!funcLabels_.resize(codeRange.funcIndex() + 1)) - return false; - } - - funcLabels_[codeRange.funcIndex()] = Move(label); + if (const char* filename = metadata_->filename.get()) { + if (!name.append(filename, strlen(filename))) + return; + } else { + if (!name.append('?')) + return; } - } else { - funcLabels_.clear(); + + if (!name.append(':') || + !name.append(bytecodeStr, strlen(bytecodeStr)) || + !name.append(")\0", 2)) + { + return; + } + + UniqueChars label(name.extractOrCopyRawBuffer()); + if (!label) + return; + + if (codeRange.funcIndex() >= profilingLabels_.length()) { + if (!profilingLabels_.resize(codeRange.funcIndex() + 1)) + return; + } + + profilingLabels_[codeRange.funcIndex()] = Move(label); } +} - // Only mutate the code after the fallible operations are complete to avoid - // the need to rollback. - profilingEnabled_ = newProfilingEnabled; - - { - AutoWritableJitCode awjc(segment_->base(), segment_->length()); - AutoFlushICache afc("Code::ensureProfilingState"); - AutoFlushICache::setRange(uintptr_t(segment_->base()), segment_->length()); - - for (const CallSite& callSite : metadata_->callSites) - ToggleProfiling(*this, callSite, newProfilingEnabled); - for (const CallThunk& callThunk : metadata_->callThunks) - ToggleProfiling(*this, callThunk, newProfilingEnabled); - for (const CodeRange& codeRange : metadata_->codeRanges) - ToggleProfiling(*this, codeRange, newProfilingEnabled); - } - - return true; +const char* +Code::profilingLabel(uint32_t funcIndex) const +{ + if (funcIndex >= profilingLabels_.length() || !profilingLabels_[funcIndex]) + return "?"; + return profilingLabels_[funcIndex].get(); } void diff --git a/js/src/wasm/WasmCode.h b/js/src/wasm/WasmCode.h index 6c26ec8043a6..0acb8c3f3c9d 100644 --- a/js/src/wasm/WasmCode.h +++ b/js/src/wasm/WasmCode.h @@ -57,9 +57,6 @@ class CodeSegment uint8_t* outOfBoundsCode_; uint8_t* unalignedAccessCode_; - // The profiling mode may be changed dynamically. - bool profilingEnabled_; - public: #ifdef MOZ_VTUNE unsigned vtune_method_id_; // Zero if unset. @@ -242,28 +239,24 @@ class CodeRange DebugTrap, // calls C++ to handle debug event such as // enter/leave frame or breakpoint FarJumpIsland, // inserted to connect otherwise out-of-range insns - Inline // stub that is jumped-to, not called, and thus - // replaces/loses preceding innermost frame + Inline, // stub that is jumped-to within prologue/epilogue + Throw // special stack-unwinding stub }; private: // All fields are treated as cacheable POD: uint32_t begin_; - uint32_t profilingReturn_; + uint32_t ret_; uint32_t end_; uint32_t funcIndex_; uint32_t funcLineOrBytecode_; - uint8_t funcBeginToTableEntry_; - uint8_t funcBeginToTableProfilingJump_; - uint8_t funcBeginToNonProfilingEntry_; - uint8_t funcProfilingJumpToProfilingReturn_; - uint8_t funcProfilingEpilogueToProfilingReturn_; + uint8_t funcBeginToNormalEntry_; Kind kind_ : 8; public: CodeRange() = default; CodeRange(Kind kind, Offsets offsets); - CodeRange(Kind kind, ProfilingOffsets offsets); + CodeRange(Kind kind, CallableOffsets offsets); CodeRange(uint32_t funcIndex, uint32_t lineOrBytecode, FuncOffsets offsets); // All CodeRanges have a begin and end. @@ -293,41 +286,30 @@ class CodeRange bool isInline() const { return kind() == Inline; } + bool isThunk() const { + return kind() == FarJumpIsland; + } - // Every CodeRange except entry and inline stubs has a profiling return - // which is used for asynchronous profiling to determine the frame pointer. + // Every CodeRange except entry and inline stubs are callable and have a + // return statement. Asynchronous frame iteration needs to know the offset + // of the return instruction to calculate the frame pointer. - uint32_t profilingReturn() const { + uint32_t ret() const { MOZ_ASSERT(isFunction() || isImportExit() || isTrapExit()); - return profilingReturn_; + return ret_; } - // Functions have offsets which allow patching to selectively execute - // profiling prologues/epilogues. + // Function CodeRanges have two entry points: one for normal calls (with a + // known signature) and one for table calls (which involves dynamic + // signature checking). - uint32_t funcProfilingEntry() const { - MOZ_ASSERT(isFunction()); - return begin(); - } uint32_t funcTableEntry() const { MOZ_ASSERT(isFunction()); - return begin_ + funcBeginToTableEntry_; + return begin_; } - uint32_t funcTableProfilingJump() const { + uint32_t funcNormalEntry() const { MOZ_ASSERT(isFunction()); - return begin_ + funcBeginToTableProfilingJump_; - } - uint32_t funcNonProfilingEntry() const { - MOZ_ASSERT(isFunction()); - return begin_ + funcBeginToNonProfilingEntry_; - } - uint32_t funcProfilingJump() const { - MOZ_ASSERT(isFunction()); - return profilingReturn_ - funcProfilingJumpToProfilingReturn_; - } - uint32_t funcProfilingEpilogue() const { - MOZ_ASSERT(isFunction()); - return profilingReturn_ - funcProfilingEpilogueToProfilingReturn_; + return begin_ + funcBeginToNormalEntry_; } uint32_t funcIndex() const { MOZ_ASSERT(isFunction()); @@ -354,25 +336,6 @@ class CodeRange WASM_DECLARE_POD_VECTOR(CodeRange, CodeRangeVector) -// A CallThunk describes the offset and target of thunks so that they may be -// patched at runtime when profiling is toggled. Thunks are emitted to connect -// callsites that are too far away from callees to fit in a single call -// instruction's relative offset. - -struct CallThunk -{ - uint32_t offset; - union { - uint32_t funcIndex; - uint32_t codeRangeIndex; - } u; - - CallThunk(uint32_t offset, uint32_t funcIndex) : offset(offset) { u.funcIndex = funcIndex; } - CallThunk() = default; -}; - -WASM_DECLARE_POD_VECTOR(CallThunk, CallThunkVector) - // A wasm module can either use no memory, a unshared memory (ArrayBuffer) or // shared memory (SharedArrayBuffer). @@ -463,7 +426,6 @@ struct Metadata : ShareableBase, MetadataCacheablePod MemoryAccessVector memoryAccesses; CodeRangeVector codeRanges; CallSiteVector callSites; - CallThunkVector callThunks; NameInBytecodeVector funcNames; CustomSectionVector customSections; CacheableChars filename; @@ -560,8 +522,9 @@ class Code const SharedMetadata metadata_; const SharedBytes maybeBytecode_; UniqueGeneratedSourceMap maybeSourceMap_; - CacheableCharsVector funcLabels_; - bool profilingEnabled_; + + // Mutated at runtime: + CacheableCharsVector profilingLabels_; // State maintained when debugging is enabled: @@ -602,15 +565,11 @@ class Code bool getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, size_t* lineno, size_t* column); bool totalSourceLines(JSContext* cx, uint32_t* count); - // Each Code has a profiling mode that is updated to match the runtime's - // profiling mode when there are no other activations of the code live on - // the stack. Once in profiling mode, ProfilingFrameIterator can be used to - // asynchronously walk the stack. Otherwise, the ProfilingFrameIterator will - // skip any activations of this code. + // To save memory, profilingLabels_ are generated lazily when profiling mode + // is enabled. - MOZ_MUST_USE bool ensureProfilingState(JSRuntime* rt, bool enabled); - bool profilingEnabled() const { return profilingEnabled_; } - const char* profilingLabel(uint32_t funcIndex) const { return funcLabels_[funcIndex].get(); } + void ensureProfilingLabels(bool profilingEnabled); + const char* profilingLabel(uint32_t funcIndex) const; // The Code can track enter/leave frame events. Any such event triggers // debug trap. The enter/leave frame events enabled or disabled across diff --git a/js/src/wasm/WasmCompartment.cpp b/js/src/wasm/WasmCompartment.cpp index 60a1b566f2bd..7c6279a053c2 100644 --- a/js/src/wasm/WasmCompartment.cpp +++ b/js/src/wasm/WasmCompartment.cpp @@ -29,13 +29,12 @@ using namespace wasm; Compartment::Compartment(Zone* zone) : mutatingInstances_(false), - activationCount_(0), - profilingEnabled_(false) + interruptedCount_(0) {} Compartment::~Compartment() { - MOZ_ASSERT(activationCount_ == 0); + MOZ_ASSERT(interruptedCount_ == 0); MOZ_ASSERT(instances_.empty()); MOZ_ASSERT(!mutatingInstances_); } @@ -58,10 +57,14 @@ void Compartment::trace(JSTracer* trc) { // A WasmInstanceObject that was initially reachable when called can become - // unreachable while executing on the stack. Since wasm does not otherwise - // scan the stack during GC to identify live instances, we mark all instance - // objects live if there is any running wasm in the compartment. - if (activationCount_) { + // unreachable while executing on the stack. When execution in a compartment + // is interrupted inside wasm code, wasm::TraceActivations() may miss frames + // due to its use of FrameIterator which assumes wasm has exited through an + // exit stub. This could be fixed by changing wasm::TraceActivations() to + // use a ProfilingFrameIterator, which inspects register state, but for now + // just mark everything in the compartment in this super-rare case. + + if (interruptedCount_) { for (Instance* i : instances_) i->trace(trc); } @@ -73,8 +76,7 @@ Compartment::registerInstance(JSContext* cx, HandleWasmInstanceObject instanceOb Instance& instance = instanceObj->instance(); MOZ_ASSERT(this == &instance.compartment()->wasm); - if (!instance.ensureProfilingState(cx, profilingEnabled_)) - return false; + instance.code().ensureProfilingLabels(cx->runtime()->geckoProfiler().enabled()); size_t index; if (BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index)) @@ -139,38 +141,22 @@ Compartment::lookupInstanceDeprecated(const void* pc) const return instances_[index]; } -bool -Compartment::ensureProfilingState(JSContext* cx) +void +Compartment::setInterrupted(bool interrupted) { - bool newProfilingEnabled = cx->runtime()->geckoProfiler().enabled(); - if (profilingEnabled_ == newProfilingEnabled) - return true; - - // Since one Instance can call another Instance in the same compartment - // directly without calling through Instance::callExport(), when profiling - // is enabled, enable it for the entire compartment at once. It is only safe - // to enable profiling when the wasm is not on the stack, so delay enabling - // profiling until there are no live WasmActivations in this compartment. - - if (activationCount_ > 0) - return true; - - for (Instance* instance : instances_) { - if (!instance->ensureProfilingState(cx, newProfilingEnabled)) - return false; + if (interrupted) { + interruptedCount_++; + } else { + MOZ_ASSERT(interruptedCount_ > 0); + interruptedCount_--; } - - profilingEnabled_ = newProfilingEnabled; - return true; } -bool -Compartment::profilingEnabled() const +void +Compartment::ensureProfilingLabels(bool profilingEnabled) { - // Profiling can asynchronously interrupt the mutation of the instances_ - // vector which is used by lookupCode() during stack-walking. To handle - // this rare case, disable profiling during mutation. - return profilingEnabled_ && !mutatingInstances_; + for (Instance* instance : instances_) + instance->code().ensureProfilingLabels(profilingEnabled); } void diff --git a/js/src/wasm/WasmCompartment.h b/js/src/wasm/WasmCompartment.h index dcdd75d0c317..3ef43f12dedd 100644 --- a/js/src/wasm/WasmCompartment.h +++ b/js/src/wasm/WasmCompartment.h @@ -39,8 +39,7 @@ class Compartment { InstanceVector instances_; volatile bool mutatingInstances_; - size_t activationCount_; - bool profilingEnabled_; + size_t interruptedCount_; friend class js::WasmActivation; @@ -89,12 +88,14 @@ class Compartment Instance* lookupInstanceDeprecated(const void* pc) const; - // To ensure profiling is enabled (so that wasm frames are not lost in - // profiling callstacks), ensureProfilingState must be called before calling - // the first wasm function in a compartment. + // The wasm::Compartment must be notified when execution is interrupted + // while executing in wasm code in this compartment. - bool ensureProfilingState(JSContext* cx); - bool profilingEnabled() const; + void setInterrupted(bool interrupted); + + // Ensure all Instances in this JSCompartment have profiling labels created. + + void ensureProfilingLabels(bool profilingEnabled); // about:memory reporting diff --git a/js/src/wasm/WasmDebugFrame.cpp b/js/src/wasm/WasmDebugFrame.cpp deleted file mode 100644 index 274677d92068..000000000000 --- a/js/src/wasm/WasmDebugFrame.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright 2016 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "wasm/WasmDebugFrame.h" - -#include "vm/EnvironmentObject.h" -#include "wasm/WasmBaselineCompile.h" -#include "wasm/WasmInstance.h" - -#include "jsobjinlines.h" - -using namespace js; -using namespace js::wasm; - -Instance* -DebugFrame::instance() const -{ - return tlsData_->instance; -} - -GlobalObject* -DebugFrame::global() const -{ - return &instance()->object()->global(); -} - -JSObject* -DebugFrame::environmentChain() const -{ - return &global()->lexicalEnvironment(); -} - -void -DebugFrame::observeFrame(JSContext* cx) -{ - if (observing_) - return; - - instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ true); - observing_ = true; -} - -void -DebugFrame::leaveFrame(JSContext* cx) -{ - if (!observing_) - return; - - instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ false); - observing_ = false; -} - -void -DebugFrame::clearReturnJSValue() -{ - hasCachedReturnJSValue_ = true; - cachedReturnJSValue_.setUndefined(); -} - -void -DebugFrame::updateReturnJSValue() -{ - hasCachedReturnJSValue_ = true; - ExprType returnType = instance()->code().debugGetResultType(funcIndex()); - switch (returnType) { - case ExprType::Void: - cachedReturnJSValue_.setUndefined(); - break; - case ExprType::I32: - cachedReturnJSValue_.setInt32(resultI32_); - break; - case ExprType::I64: - // Just display as a Number; it's ok if we lose some precision - cachedReturnJSValue_.setDouble((double)resultI64_); - break; - case ExprType::F32: - cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF32_)); - break; - case ExprType::F64: - cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF64_)); - break; - default: - MOZ_CRASH("result type"); - } -} - -bool -DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp) -{ - ValTypeVector locals; - size_t argsLength; - if (!instance()->code().debugGetLocalTypes(funcIndex(), &locals, &argsLength)) - return false; - - BaseLocalIter iter(locals, argsLength, /* debugEnabled = */ true); - while (!iter.done() && iter.index() < localIndex) - iter++; - MOZ_ALWAYS_TRUE(!iter.done()); - - uint8_t* frame = static_cast((void*)this) + offsetOfFrame(); - void* dataPtr = frame - iter.frameOffset(); - switch (iter.mirType()) { - case jit::MIRType::Int32: - vp.set(Int32Value(*static_cast(dataPtr))); - break; - case jit::MIRType::Int64: - // Just display as a Number; it's ok if we lose some precision - vp.set(NumberValue((double)*static_cast(dataPtr))); - break; - case jit::MIRType::Float32: - vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast(dataPtr)))); - break; - case jit::MIRType::Double: - vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast(dataPtr)))); - break; - default: - MOZ_CRASH("local type"); - } - return true; -} - diff --git a/js/src/wasm/WasmDebugFrame.h b/js/src/wasm/WasmDebugFrame.h deleted file mode 100644 index 963f54026365..000000000000 --- a/js/src/wasm/WasmDebugFrame.h +++ /dev/null @@ -1,127 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sts=4 et sw=4 tw=99: - * - * Copyright 2016 Mozilla Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef wasmdebugframe_js_h -#define wasmdebugframe_js_h - -#include "gc/Barrier.h" -#include "js/RootingAPI.h" -#include "js/TracingAPI.h" -#include "wasm/WasmTypes.h" - -namespace js { - -class WasmFunctionCallObject; - -namespace wasm { - -class DebugFrame -{ - union - { - int32_t resultI32_; - int64_t resultI64_; - float resultF32_; - double resultF64_; - }; - - js::Value cachedReturnJSValue_; - - // The fields below are initialized by the baseline compiler. - uint32_t funcIndex_; - uint32_t reserved0_; - - union - { - struct - { - bool observing_ : 1; - bool isDebuggee_ : 1; - bool prevUpToDate_ : 1; - bool hasCachedSavedFrame_ : 1; - bool hasCachedReturnJSValue_ : 1; - }; - void* reserved1_; - }; - - TlsData* tlsData_; - Frame frame_; - - explicit DebugFrame() {} - - void StaticAsserts() { - // VS2017 doesn't consider offsetOfResults() etc. to be constexpr, so we have to use - // offsetof directly. These asserts can't be at class-level because the type is incomplete. - static_assert(offsetof(DebugFrame, resultI32_) == 0, "results shall be at offset 0"); - static_assert(offsetof(DebugFrame, tlsData_) + sizeof(TlsData*) == - offsetof(DebugFrame, frame_), - "TLS pointer must be a field just before the wasm frame"); - static_assert(sizeof(DebugFrame) % 8 == 0 && offsetof(DebugFrame, frame_) % 8 == 0, - "DebugFrame and its portion is 8-bytes aligned for AbstractFramePtr"); - } - - public: - inline uint32_t funcIndex() const { return funcIndex_; } - inline TlsData* tlsData() const { return tlsData_; } - inline Frame& frame() { return frame_; } - - Instance* instance() const; - GlobalObject* global() const; - - JSObject* environmentChain() const; - - void observeFrame(JSContext* cx); - void leaveFrame(JSContext* cx); - - void trace(JSTracer* trc); - - // These are opaque boolean flags used by the debugger and - // saved-frame-chains code. - inline bool isDebuggee() const { return isDebuggee_; } - inline void setIsDebuggee() { isDebuggee_ = true; } - inline void unsetIsDebuggee() { isDebuggee_ = false; } - - inline bool prevUpToDate() const { return prevUpToDate_; } - inline void setPrevUpToDate() { prevUpToDate_ = true; } - inline void unsetPrevUpToDate() { prevUpToDate_ = false; } - - inline bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; } - inline void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; } - - inline void* resultsPtr() { return &resultI32_; } - - inline HandleValue returnValue() const { - MOZ_ASSERT(hasCachedReturnJSValue_); - return HandleValue::fromMarkedLocation(&cachedReturnJSValue_); - } - void updateReturnJSValue(); - void clearReturnJSValue(); - - bool getLocal(uint32_t localIndex, MutableHandleValue vp); - - static constexpr size_t offsetOfResults() { return offsetof(DebugFrame, resultI32_); } - static constexpr size_t offsetOfFlagsWord() { return offsetof(DebugFrame, reserved1_); } - static constexpr size_t offsetOfFuncIndex() { return offsetof(DebugFrame, funcIndex_); } - static constexpr size_t offsetOfTlsData() { return offsetof(DebugFrame, tlsData_); } - static constexpr size_t offsetOfFrame() { return offsetof(DebugFrame, frame_); } -}; - -} // namespace wasm -} // namespace js - -#endif // wasmdebugframe_js_h diff --git a/js/src/wasm/WasmFrameIterator.cpp b/js/src/wasm/WasmFrameIterator.cpp index 232774966aac..35dde46a53a7 100644 --- a/js/src/wasm/WasmFrameIterator.cpp +++ b/js/src/wasm/WasmFrameIterator.cpp @@ -18,7 +18,6 @@ #include "wasm/WasmFrameIterator.h" -#include "wasm/WasmDebugFrame.h" #include "wasm/WasmInstance.h" #include "jit/MacroAssembler-inl.h" @@ -45,11 +44,10 @@ CallerFPFromFP(void* fp) return reinterpret_cast(fp)->callerFP; } -static TlsData* -TlsDataFromFP(void *fp) +static DebugFrame* +FrameToDebugFrame(void* fp) { - void* debugFrame = (uint8_t*)fp - DebugFrame::offsetOfFrame(); - return reinterpret_cast(debugFrame)->tlsData(); + return reinterpret_cast((uint8_t*)fp - DebugFrame::offsetOfFrame()); } FrameIterator::FrameIterator() @@ -69,33 +67,30 @@ FrameIterator::FrameIterator(WasmActivation* activation, Unwind unwind) code_(nullptr), callsite_(nullptr), codeRange_(nullptr), - fp_(activation->fp()), + fp_(nullptr), unwind_(unwind), missingFrameMessage_(false) { - if (fp_) { - settle(); + // When execution is interrupted, the embedding may capture a stack trace. + // Since we've lost all the register state, we can't unwind the full stack + // like ProfilingFrameIterator does. However, we can recover the interrupted + // function via the resumePC and at least print that frame. + if (void* resumePC = activation->resumePC()) { + code_ = activation->compartment()->wasm.lookupCode(resumePC); + codeRange_ = code_->lookupRange(resumePC); + MOZ_ASSERT(codeRange_->kind() == CodeRange::Function); + MOZ_ASSERT(!done()); return; } - void* pc = activation_->resumePC(); - if (!pc) { + fp_ = activation->exitFP(); + + if (!fp_) { MOZ_ASSERT(done()); return; } - code_ = activation_->compartment()->wasm.lookupCode(pc); - MOZ_ASSERT(code_); - - const CodeRange* codeRange = code_->lookupRange(pc); - MOZ_ASSERT(codeRange); - - if (codeRange->kind() == CodeRange::Function) - codeRange_ = codeRange; - else - missingFrameMessage_ = true; - - MOZ_ASSERT(!done()); + settle(); } bool @@ -123,38 +118,33 @@ void FrameIterator::settle() { if (unwind_ == Unwind::True) - activation_->unwindFP(fp_); + activation_->unwindExitFP(fp_); void* returnAddress = ReturnAddressFromFP(fp_); - code_ = activation_->compartment()->wasm.lookupCode(returnAddress); - MOZ_ASSERT(code_); + fp_ = CallerFPFromFP(fp_); - codeRange_ = code_->lookupRange(returnAddress); - MOZ_ASSERT(codeRange_); - - if (codeRange_->kind() == CodeRange::Entry) { - fp_ = nullptr; + if (!fp_) { code_ = nullptr; codeRange_ = nullptr; callsite_ = nullptr; if (unwind_ == Unwind::True) - activation_->unwindFP(nullptr); + activation_->unwindExitFP(nullptr); MOZ_ASSERT(done()); return; } - MOZ_RELEASE_ASSERT(codeRange_->kind() == CodeRange::Function); + code_ = activation_->compartment()->wasm.lookupCode(returnAddress); + MOZ_ASSERT(code_); + + codeRange_ = code_->lookupRange(returnAddress); + MOZ_ASSERT(codeRange_->kind() == CodeRange::Function); callsite_ = code_->lookupCallSite(returnAddress); MOZ_ASSERT(callsite_); - DebugOnly oldfp = fp_; - fp_ += callsite_->stackDepth(); - MOZ_ASSERT_IF(code_->profilingEnabled(), fp_ == CallerFPFromFP(oldfp)); - MOZ_ASSERT(!done()); } @@ -187,8 +177,7 @@ FrameIterator::functionDisplayAtom() const JSContext* cx = activation_->cx(); if (missingFrameMessage_) { - const char* msg = "asm.js/wasm frames may be missing; enable the profiler before running " - "to see all frames"; + const char* msg = "asm.js/wasm frames may be missing below this one"; JSAtom* atom = Atomize(cx, msg, strlen(msg)); if (!atom) { cx->clearPendingException(); @@ -217,11 +206,19 @@ FrameIterator::lineOrBytecode() const : (codeRange_ ? codeRange_->funcLineOrBytecode() : 0); } +bool +FrameIterator::hasInstance() const +{ + MOZ_ASSERT(!done()); + return !!fp_; +} + Instance* FrameIterator::instance() const { - MOZ_ASSERT(!done() && debugEnabled()); - return TlsDataFromFP(fp_)->instance; + MOZ_ASSERT(!done()); + MOZ_ASSERT(hasInstance()); + return FrameToDebugFrame(fp_)->instance(); } bool @@ -238,9 +235,7 @@ DebugFrame* FrameIterator::debugFrame() const { MOZ_ASSERT(!done() && debugEnabled()); - // The fp() points to wasm::Frame. - void* buf = static_cast(fp_) - DebugFrame::offsetOfFrame(); - return static_cast(buf); + return FrameToDebugFrame(fp_); } const CallSite* @@ -255,70 +250,64 @@ FrameIterator::debugTrapCallsite() const /*****************************************************************************/ // Prologue/epilogue code generation -// These constants reflect statically-determined offsets in the profiling +// These constants reflect statically-determined offsets in the // prologue/epilogue. The offsets are dynamically asserted during code // generation. #if defined(JS_CODEGEN_X64) -# if defined(DEBUG) static const unsigned PushedRetAddr = 0; -static const unsigned PostStorePrePopFP = 0; -# endif -static const unsigned PushedFP = 26; -static const unsigned StoredFP = 33; +static const unsigned PushedFP = 1; +static const unsigned PushedTLS = 3; +static const unsigned PoppedTLS = 1; #elif defined(JS_CODEGEN_X86) -# if defined(DEBUG) static const unsigned PushedRetAddr = 0; -static const unsigned PostStorePrePopFP = 0; -# endif -static const unsigned PushedFP = 16; -static const unsigned StoredFP = 19; +static const unsigned PushedFP = 1; +static const unsigned PushedTLS = 2; +static const unsigned PoppedTLS = 1; #elif defined(JS_CODEGEN_ARM) +static const unsigned BeforePushRetAddr = 0; static const unsigned PushedRetAddr = 4; -static const unsigned PushedFP = 28; -static const unsigned StoredFP = 32; -static const unsigned PostStorePrePopFP = 4; +static const unsigned PushedFP = 8; +static const unsigned PushedTLS = 12; +static const unsigned PoppedTLS = 4; #elif defined(JS_CODEGEN_ARM64) +static const unsigned BeforePushRetAddr = 0; static const unsigned PushedRetAddr = 0; static const unsigned PushedFP = 0; -static const unsigned StoredFP = 0; -static const unsigned PostStorePrePopFP = 0; +static const unsigned PushedTLS = 0; +static const unsigned PoppedTLS = 0; #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) -static const unsigned PushedRetAddr = 8; -static const unsigned PushedFP = 36; -static const unsigned StoredFP = 40; -static const unsigned PostStorePrePopFP = 4; +static const unsigned BeforePushRetAddr = 0; +static const unsigned PushedRetAddr = 4; +static const unsigned PushedFP = 8; +static const unsigned PushedTLS = 12; +static const unsigned PoppedTLS = 4; #elif defined(JS_CODEGEN_NONE) -# if defined(DEBUG) static const unsigned PushedRetAddr = 0; -static const unsigned PostStorePrePopFP = 0; -# endif -static const unsigned PushedFP = 1; -static const unsigned StoredFP = 1; +static const unsigned PushedFP = 0; +static const unsigned PushedTLS = 0; +static const unsigned PoppedTLS = 0; #else # error "Unknown architecture!" #endif static void -PushRetAddr(MacroAssembler& masm) +PushRetAddr(MacroAssembler& masm, unsigned entry) { #if defined(JS_CODEGEN_ARM) + MOZ_ASSERT(masm.currentOffset() - entry == BeforePushRetAddr); masm.push(lr); #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) + MOZ_ASSERT(masm.currentOffset() - entry == BeforePushRetAddr); masm.push(ra); #else // The x86/x64 call instruction pushes the return address. #endif } -// Generate a prologue that maintains WasmActivation::fp as the virtual frame -// pointer so that ProfilingFrameIterator can walk the stack at any pc in -// generated code. static void -GenerateProfilingPrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason, - ProfilingOffsets* offsets) +GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason, + uint32_t* entry) { - Register scratch = ABINonArgReg0; - // ProfilingFrameIterator needs to know the offsets of several key // instructions from entry. To save space, we make these offsets static // constants and assert that they match the actual codegen below. On ARM, @@ -329,102 +318,75 @@ GenerateProfilingPrologue(MacroAssembler& masm, unsigned framePushed, ExitReason AutoForbidPools afp(&masm, /* number of instructions in scope = */ 8); #endif - offsets->begin = masm.currentOffset(); + *entry = masm.currentOffset(); - PushRetAddr(masm); - MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - offsets->begin); - - masm.loadWasmActivationFromSymbolicAddress(scratch); - masm.push(Address(scratch, WasmActivation::offsetOfFP())); - MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - offsets->begin); - - masm.storePtr(masm.getStackPointer(), Address(scratch, WasmActivation::offsetOfFP())); - MOZ_ASSERT_IF(!masm.oom(), StoredFP == masm.currentOffset() - offsets->begin); + PushRetAddr(masm, *entry); + MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - *entry); + masm.push(FramePointer); + MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - *entry); + masm.push(WasmTlsReg); + MOZ_ASSERT_IF(!masm.oom(), PushedTLS == masm.currentOffset() - *entry); + masm.moveStackPtrTo(FramePointer); } - if (reason != ExitReason::None) - masm.store32(Imm32(int32_t(reason)), Address(scratch, WasmActivation::offsetOfExitReason())); + if (reason != ExitReason::None) { + Register scratch = ABINonArgReg0; + masm.loadWasmActivationFromTls(scratch); + masm.wasmAssertNonExitInvariants(scratch); + Address exitReason(scratch, WasmActivation::offsetOfExitReason()); + masm.store32(Imm32(int32_t(reason)), exitReason); + Address exitFP(scratch, WasmActivation::offsetOfExitFP()); + masm.storePtr(FramePointer, exitFP); + } if (framePushed) masm.subFromStackPtr(Imm32(framePushed)); } -// Generate the inverse of GenerateProfilingPrologue. static void -GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason reason, - ProfilingOffsets* offsets) +GenerateCallableEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason reason, + uint32_t* ret) { - Register scratch = ABINonArgReturnReg0; -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ - defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) - Register scratch2 = ABINonArgReturnReg1; -#endif - if (framePushed) masm.addToStackPtr(Imm32(framePushed)); - masm.loadWasmActivationFromSymbolicAddress(scratch); if (reason != ExitReason::None) { - masm.store32(Imm32(int32_t(ExitReason::None)), - Address(scratch, WasmActivation::offsetOfExitReason())); + Register scratch = ABINonArgReturnReg0; + masm.loadWasmActivationFromTls(scratch); + Address exitFP(scratch, WasmActivation::offsetOfExitFP()); + masm.storePtr(ImmWord(0), exitFP); + Address exitReason(scratch, WasmActivation::offsetOfExitReason()); + masm.store32(Imm32(int32_t(ExitReason::None)), exitReason); } - // ProfilingFrameIterator assumes fixed offsets of the last few - // instructions from profilingReturn, so AutoForbidPools to ensure that - // unintended instructions are not automatically inserted. - { + // Forbid pools for the same reason as described in GenerateCallablePrologue. #if defined(JS_CODEGEN_ARM) - AutoForbidPools afp(&masm, /* number of instructions in scope = */ 4); + AutoForbidPools afp(&masm, /* number of instructions in scope = */ 3); #endif - // sp protects the stack from clobber via asynchronous signal handlers - // and the async interrupt exit. Since activation.fp can be read at any - // time and still points to the current frame, be careful to only update - // sp after activation.fp has been repointed to the caller's frame. -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \ - defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) - masm.loadPtr(Address(masm.getStackPointer(), 0), scratch2); - masm.storePtr(scratch2, Address(scratch, WasmActivation::offsetOfFP())); - DebugOnly prePop = masm.currentOffset(); - masm.addToStackPtr(Imm32(sizeof(void *))); - MOZ_ASSERT_IF(!masm.oom(), PostStorePrePopFP == masm.currentOffset() - prePop); -#else - masm.pop(Address(scratch, WasmActivation::offsetOfFP())); - MOZ_ASSERT(PostStorePrePopFP == 0); -#endif - - offsets->profilingReturn = masm.currentOffset(); - masm.ret(); - } + masm.pop(WasmTlsReg); + DebugOnly poppedTLS = masm.currentOffset(); + masm.pop(FramePointer); + *ret = masm.currentOffset(); + masm.ret(); + MOZ_ASSERT_IF(!masm.oom(), PoppedTLS == *ret - poppedTLS); } -// In profiling mode, we need to maintain fp so that we can unwind the stack at -// any pc. In non-profiling mode, the only way to observe WasmActivation::fp is -// to call out to C++ so, as an optimization, we don't update fp. To avoid -// recompilation when the profiling mode is toggled, we generate both prologues -// a priori and switch between prologues when the profiling mode is toggled. -// Specifically, ToggleProfiling patches all callsites to either call the -// profiling or non-profiling entry point. void wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId, FuncOffsets* offsets) { #if defined(JS_CODEGEN_ARM) // Flush pending pools so they do not get dumped between the 'begin' and - // 'entry' offsets since the difference must be less than UINT8_MAX. + // 'normalEntry' offsets since the difference must be less than UINT8_MAX + // to be stored in CodeRange::funcBeginToNormalEntry_. masm.flushBuffer(); #endif - masm.haltingAlign(CodeAlignment); - GenerateProfilingPrologue(masm, framePushed, ExitReason::None, offsets); - Label body; - masm.jump(&body); - - // Generate table entry thunk: - masm.haltingAlign(CodeAlignment); - offsets->tableEntry = masm.currentOffset(); + // Generate table entry: + offsets->begin = masm.currentOffset(); TrapOffset trapOffset(0); // ignored by masm.wasmEmitTrapOutOfLineCode TrapDesc trap(trapOffset, Trap::IndirectCallBadSig, masm.framePushed()); switch (sigId.kind()) { @@ -440,66 +402,38 @@ wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, const case SigIdDesc::Kind::None: break; } - offsets->tableProfilingJump = masm.nopPatchableToNearJump().offset(); - // Generate normal prologue: + // Generate normal entry: masm.nopAlign(CodeAlignment); - offsets->nonProfilingEntry = masm.currentOffset(); - PushRetAddr(masm); - masm.subFromStackPtr(Imm32(framePushed + FrameBytesAfterReturnAddress)); + GenerateCallablePrologue(masm, framePushed, ExitReason::None, &offsets->normalEntry); - // Prologue join point, body begin: - masm.bind(&body); masm.setFramePushed(framePushed); } -// Similar to GenerateFunctionPrologue (see comment), we generate both a -// profiling and non-profiling epilogue a priori. When the profiling mode is -// toggled, ToggleProfiling patches the 'profiling jump' to either be a nop -// (falling through to the normal prologue) or a jump (jumping to the profiling -// epilogue). void wasm::GenerateFunctionEpilogue(MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets) { MOZ_ASSERT(masm.framePushed() == framePushed); - -#if defined(JS_CODEGEN_ARM) - // Flush pending pools so they do not get dumped between the profilingReturn - // and profilingJump/profilingEpilogue offsets since the difference must be - // less than UINT8_MAX. - masm.flushBuffer(); -#endif - - // Generate a nop that is overwritten by a jump to the profiling epilogue - // when profiling is enabled. - offsets->profilingJump = masm.nopPatchableToNearJump().offset(); - - // Normal epilogue: - masm.addToStackPtr(Imm32(framePushed + FrameBytesAfterReturnAddress)); - masm.ret(); + GenerateCallableEpilogue(masm, framePushed, ExitReason::None, &offsets->ret); masm.setFramePushed(0); - - // Profiling epilogue: - offsets->profilingEpilogue = masm.currentOffset(); - GenerateProfilingEpilogue(masm, framePushed, ExitReason::None, offsets); } void wasm::GenerateExitPrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason, - ProfilingOffsets* offsets) + CallableOffsets* offsets) { masm.haltingAlign(CodeAlignment); - GenerateProfilingPrologue(masm, framePushed, reason, offsets); + GenerateCallablePrologue(masm, framePushed, reason, &offsets->begin); masm.setFramePushed(framePushed); } void wasm::GenerateExitEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason reason, - ProfilingOffsets* offsets) + CallableOffsets* offsets) { // Inverse of GenerateExitPrologue: MOZ_ASSERT(masm.framePushed() == framePushed); - GenerateProfilingEpilogue(masm, framePushed, reason, offsets); + GenerateCallableEpilogue(masm, framePushed, reason, &offsets->ret); masm.setFramePushed(0); } @@ -527,21 +461,11 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation) stackAddress_(nullptr), exitReason_(ExitReason::None) { - // If profiling hasn't been enabled for this instance, then CallerFPFromFP - // will be trash, so ignore the entire activation. In practice, this only - // happens if profiling is enabled while the instance is on the stack (in - // which case profiling will be enabled when the instance becomes inactive - // and gets called again). - if (!activation_->compartment()->wasm.profilingEnabled()) { - MOZ_ASSERT(done()); - return; - } - - initFromFP(); + initFromExitFP(); } static inline void -AssertMatchesCallSite(const WasmActivation& activation, void* callerPC, void* callerFP, void* fp) +AssertMatchesCallSite(const WasmActivation& activation, void* callerPC, void* callerFP) { #ifdef DEBUG Code* code = activation.compartment()->wasm.lookupCode(callerPC); @@ -557,15 +481,13 @@ AssertMatchesCallSite(const WasmActivation& activation, void* callerPC, void* ca const CallSite* callsite = code->lookupCallSite(callerPC); MOZ_ASSERT(callsite); - - MOZ_ASSERT(callerFP == (uint8_t*)fp + callsite->stackDepth()); #endif } void -ProfilingFrameIterator::initFromFP() +ProfilingFrameIterator::initFromExitFP() { - uint8_t* fp = activation_->fp(); + uint8_t* fp = activation_->exitFP(); stackAddress_ = fp; // If a signal was handled while entering an activation, the frame will @@ -600,13 +522,14 @@ ProfilingFrameIterator::initFromFP() fp = CallerFPFromFP(fp); callerPC_ = ReturnAddressFromFP(fp); callerFP_ = CallerFPFromFP(fp); - AssertMatchesCallSite(*activation_, callerPC_, callerFP_, fp); + AssertMatchesCallSite(*activation_, callerPC_, callerFP_); break; case CodeRange::ImportJitExit: case CodeRange::ImportInterpExit: case CodeRange::TrapExit: case CodeRange::DebugTrap: case CodeRange::Inline: + case CodeRange::Throw: case CodeRange::FarJumpIsland: MOZ_CRASH("Unexpected CodeRange kind"); } @@ -615,28 +538,11 @@ ProfilingFrameIterator::initFromFP() // This allows the variety of exit reasons to show up in the callstack. exitReason_ = activation_->exitReason(); - // In the case of calls to builtins or asynchronous interrupts, no exit path - // is taken so the exitReason is None. Coerce these to the Native exit - // reason so that self-time is accounted for. - if (exitReason_ == ExitReason::None) - exitReason_ = ExitReason::Native; - MOZ_ASSERT(!done()); } typedef JS::ProfilingFrameIterator::RegisterState RegisterState; -static bool -InThunk(const CodeRange& codeRange, uint32_t offsetInModule) -{ - if (codeRange.kind() == CodeRange::FarJumpIsland) - return true; - - return codeRange.isFunction() && - offsetInModule >= codeRange.funcTableEntry() && - offsetInModule < codeRange.funcNonProfilingEntry(); -} - ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation, const RegisterState& state) : activation_(&activation), @@ -647,13 +553,10 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation, stackAddress_(nullptr), exitReason_(ExitReason::None) { - // If profiling hasn't been enabled for this instance, then CallerFPFromFP - // will be trash, so ignore the entire activation. In practice, this only - // happens if profiling is enabled while the instance is on the stack (in - // which case profiling will be enabled when the instance becomes inactive - // and gets called again). - if (!activation_->compartment()->wasm.profilingEnabled()) { - MOZ_ASSERT(done()); + // In the case of ImportJitExit, the fp register may be temporarily + // clobbered on return from Ion so always use activation.fp when it is set. + if (activation.exitFP()) { + initFromExitFP(); return; } @@ -661,87 +564,98 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation, // exit trampoline or signal handler. code_ = activation_->compartment()->wasm.lookupCode(state.pc); if (!code_) { - initFromFP(); + MOZ_ASSERT(done()); return; } - // Note: fp may be null while entering and leaving the activation. - uint8_t* fp = activation.fp(); + // When the pc is inside the prologue/epilogue, the innermost call's Frame + // is not complete and thus fp points to the second-to-innermost call's + // Frame. Since fp can only tell you about its caller, naively unwinding + // while pc is in the prologue/epilogue would skip the second-to-innermost + // call. To avoid this problem, we use the static structure of the code in + // the prologue and epilogue to do the Right Thing. + uint8_t* fp = (uint8_t*)state.fp; + uint8_t* pc = (uint8_t*)state.pc; + void** sp = (void**)state.sp; + + const CodeRange* codeRange = code_->lookupRange(pc); + uint32_t offsetInModule = pc - code_->segment().base(); + MOZ_ASSERT(offsetInModule >= codeRange->begin()); + MOZ_ASSERT(offsetInModule < codeRange->end()); + + // Compute the offset of the pc from the (normal) entry of the code range. + // The stack state of the pc for the entire table-entry is equivalent to + // that of the first pc of the normal-entry. Thus, we can simplify the below + // case analysis by redirecting all pc-in-table-entry cases to the + // pc-at-normal-entry case. + uint32_t offsetFromEntry; + if (codeRange->isFunction()) { + if (offsetInModule < codeRange->funcNormalEntry()) + offsetFromEntry = 0; + else + offsetFromEntry = offsetInModule - codeRange->funcNormalEntry(); + } else { + offsetFromEntry = offsetInModule - codeRange->begin(); + } - const CodeRange* codeRange = code_->lookupRange(state.pc); switch (codeRange->kind()) { case CodeRange::Function: case CodeRange::FarJumpIsland: case CodeRange::ImportJitExit: case CodeRange::ImportInterpExit: - case CodeRange::TrapExit: { - // When the pc is inside the prologue/epilogue, the innermost call's - // Frame is not complete and thus fp points to the second-to-innermost - // call's Frame. Since fp can only tell you about its caller (via - // ReturnAddressFromFP(fp)), naively unwinding while pc is in the - // prologue/epilogue would skip the second-to- innermost call. To avoid - // this problem, we use the static structure of the code in the prologue - // and epilogue to do the Right Thing. - uint32_t offsetInModule = (uint8_t*)state.pc - code_->segment().base(); - MOZ_ASSERT(offsetInModule >= codeRange->begin()); - MOZ_ASSERT(offsetInModule < codeRange->end()); - uint32_t offsetInCodeRange = offsetInModule - codeRange->begin(); - void** sp = (void**)state.sp; -#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) - if (offsetInCodeRange < PushedRetAddr || InThunk(*codeRange, offsetInModule)) { - // First instruction of the ARM/MIPS function; the return address is - // still in lr and fp still holds the caller's fp. + case CodeRange::TrapExit: +#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) + if (offsetFromEntry == BeforePushRetAddr || codeRange->isThunk()) { + // The return address is still in lr and fp holds the caller's fp. callerPC_ = state.lr; callerFP_ = fp; - AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp - 2); - } else if (offsetInModule == codeRange->profilingReturn() - PostStorePrePopFP) { - // Second-to-last instruction of the ARM/MIPS function; fp points to - // the caller's fp; have not yet popped Frame. - callerPC_ = ReturnAddressFromFP(sp); - callerFP_ = CallerFPFromFP(sp); - AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp); + AssertMatchesCallSite(*activation_, callerPC_, callerFP_); } else #endif - if (offsetInCodeRange < PushedFP || offsetInModule == codeRange->profilingReturn() || - InThunk(*codeRange, offsetInModule)) - { - // The return address has been pushed on the stack but not fp; fp - // still points to the caller's fp. - callerPC_ = *sp; + if (offsetFromEntry == PushedRetAddr || codeRange->isThunk()) { + // The return address has been pushed on the stack but fp still + // points to the caller's fp. + callerPC_ = sp[0]; callerFP_ = fp; - AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp - 1); - } else if (offsetInCodeRange < StoredFP) { - // The full Frame has been pushed; fp still points to the caller's - // frame. + AssertMatchesCallSite(*activation_, callerPC_, callerFP_); + } else if (offsetFromEntry == PushedFP) { + // The return address and caller's fp have been pushed on the stack; fp + // is still the caller's fp. + callerPC_ = sp[1]; + callerFP_ = sp[0]; + AssertMatchesCallSite(*activation_, callerPC_, callerFP_); + } else if (offsetFromEntry == PushedTLS) { + // The full Frame has been pushed; fp is still the caller's fp. MOZ_ASSERT(fp == CallerFPFromFP(sp)); callerPC_ = ReturnAddressFromFP(sp); - callerFP_ = CallerFPFromFP(sp); - AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp); + callerFP_ = fp; + AssertMatchesCallSite(*activation_, callerPC_, callerFP_); + } else if (offsetInModule == codeRange->ret() - PoppedTLS) { + // The TLS field of the Frame has been popped. + callerPC_ = sp[1]; + callerFP_ = sp[0]; + } else if (offsetInModule == codeRange->ret()) { + // Both the TLS and callerFP fields have been popped and fp now + // points to the caller's frame. + callerPC_ = sp[0]; + callerFP_ = fp; + AssertMatchesCallSite(*activation_, callerPC_, callerFP_); } else { // Not in the prologue/epilogue. callerPC_ = ReturnAddressFromFP(fp); callerFP_ = CallerFPFromFP(fp); - AssertMatchesCallSite(*activation_, callerPC_, callerFP_, fp); + AssertMatchesCallSite(*activation_, callerPC_, callerFP_); } break; - } - case CodeRange::Entry: { + case CodeRange::Entry: // The entry trampoline is the final frame in an WasmActivation. The entry // trampoline also doesn't GeneratePrologue/Epilogue so we can't use // the general unwinding logic above. - MOZ_ASSERT(!fp); callerPC_ = nullptr; callerFP_ = nullptr; break; - } case CodeRange::DebugTrap: - case CodeRange::Inline: { - // The throw stub clears WasmActivation::fp on it's way out. - if (!fp) { - MOZ_ASSERT(done()); - return; - } - + case CodeRange::Inline: // Most inline code stubs execute after the prologue/epilogue have // completed so we can simply unwind based on fp. The only exception is // the async interrupt stub, since it can be executed at any time. @@ -749,13 +663,18 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation, // skipped frames. Thus, we use simply unwind based on fp. callerPC_ = ReturnAddressFromFP(fp); callerFP_ = CallerFPFromFP(fp); - AssertMatchesCallSite(*activation_, callerPC_, callerFP_, fp); + AssertMatchesCallSite(*activation_, callerPC_, callerFP_); break; - } + case CodeRange::Throw: + // The throw stub executes a small number of instructions before popping + // the entire activation. To simplify testing, we simply pretend throw + // stubs have already popped the entire stack. + MOZ_ASSERT(done()); + return; } codeRange_ = codeRange; - stackAddress_ = state.sp; + stackAddress_ = sp; MOZ_ASSERT(!done()); } @@ -784,6 +703,7 @@ ProfilingFrameIterator::operator++() switch (codeRange_->kind()) { case CodeRange::Entry: + case CodeRange::Throw: MOZ_ASSERT(callerFP_ == nullptr); callerPC_ = nullptr; break; @@ -796,7 +716,7 @@ ProfilingFrameIterator::operator++() case CodeRange::FarJumpIsland: stackAddress_ = callerFP_; callerPC_ = ReturnAddressFromFP(callerFP_); - AssertMatchesCallSite(*activation_, callerPC_, CallerFPFromFP(callerFP_), callerFP_); + AssertMatchesCallSite(*activation_, callerPC_, CallerFPFromFP(callerFP_)); callerFP_ = CallerFPFromFP(callerFP_); break; } @@ -816,7 +736,6 @@ ProfilingFrameIterator::label() const // devtools/client/performance/modules/logic/frame-utils.js const char* importJitDescription = "fast FFI trampoline (in asm.js)"; const char* importInterpDescription = "slow FFI trampoline (in asm.js)"; - const char* nativeDescription = "native call (in asm.js)"; const char* trapDescription = "trap handling (in asm.js)"; const char* debugTrapDescription = "debug trap handling (in asm.js)"; @@ -827,8 +746,6 @@ ProfilingFrameIterator::label() const return importJitDescription; case ExitReason::ImportInterp: return importInterpDescription; - case ExitReason::Native: - return nativeDescription; case ExitReason::Trap: return trapDescription; case ExitReason::DebugTrap: @@ -844,99 +761,21 @@ ProfilingFrameIterator::label() const case CodeRange::DebugTrap: return debugTrapDescription; case CodeRange::Inline: return "inline stub (in asm.js)"; case CodeRange::FarJumpIsland: return "interstitial (in asm.js)"; + case CodeRange::Throw: MOZ_CRASH("no frame for throw stubs"); } MOZ_CRASH("bad code range kind"); } -/*****************************************************************************/ -// Runtime patching to enable/disable profiling - void -wasm::ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled) +wasm::TraceActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc) { - if (callSite.kind() != CallSite::Func) - return; - - uint8_t* callerRetAddr = code.segment().base() + callSite.returnAddressOffset(); - -#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) - void* callee = X86Encoding::GetRel32Target(callerRetAddr); -#elif defined(JS_CODEGEN_ARM) - uint8_t* caller = callerRetAddr - 4; - Instruction* callerInsn = reinterpret_cast(caller); - BOffImm calleeOffset; - callerInsn->as()->extractImm(&calleeOffset); - void* callee = calleeOffset.getDest(callerInsn); -#elif defined(JS_CODEGEN_ARM64) - MOZ_CRASH(); - void* callee = nullptr; - (void)callerRetAddr; -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) - uint8_t* caller = callerRetAddr - 2 * sizeof(uint32_t); - InstImm* callerInsn = reinterpret_cast(caller); - BOffImm16 calleeOffset; - callerInsn->extractImm16(&calleeOffset); - void* callee = calleeOffset.getDest(reinterpret_cast(caller)); -#elif defined(JS_CODEGEN_NONE) - MOZ_CRASH(); - void* callee = nullptr; -#else -# error "Missing architecture" -#endif - - const CodeRange* codeRange = code.lookupRange(callee); - if (!codeRange->isFunction()) - return; - - uint8_t* from = code.segment().base() + codeRange->funcNonProfilingEntry(); - uint8_t* to = code.segment().base() + codeRange->funcProfilingEntry(); - if (!enabled) - Swap(from, to); - - MOZ_ASSERT(callee == from); - -#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) - X86Encoding::SetRel32(callerRetAddr, to); -#elif defined(JS_CODEGEN_ARM) - new (caller) InstBLImm(BOffImm(to - caller), Assembler::Always); -#elif defined(JS_CODEGEN_ARM64) - (void)to; - MOZ_CRASH(); -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) - new (caller) InstImm(op_regimm, zero, rt_bgezal, BOffImm16(to - caller)); -#elif defined(JS_CODEGEN_NONE) - MOZ_CRASH(); -#else -# error "Missing architecture" -#endif -} - -void -wasm::ToggleProfiling(const Code& code, const CallThunk& callThunk, bool enabled) -{ - const CodeRange& cr = code.metadata().codeRanges[callThunk.u.codeRangeIndex]; - uint32_t calleeOffset = enabled ? cr.funcProfilingEntry() : cr.funcNonProfilingEntry(); - MacroAssembler::repatchFarJump(code.segment().base(), callThunk.offset, calleeOffset); -} - -void -wasm::ToggleProfiling(const Code& code, const CodeRange& codeRange, bool enabled) -{ - if (!codeRange.isFunction()) - return; - - uint8_t* codeBase = code.segment().base(); - uint8_t* profilingEntry = codeBase + codeRange.funcProfilingEntry(); - uint8_t* tableProfilingJump = codeBase + codeRange.funcTableProfilingJump(); - uint8_t* profilingJump = codeBase + codeRange.funcProfilingJump(); - uint8_t* profilingEpilogue = codeBase + codeRange.funcProfilingEpilogue(); - - if (enabled) { - MacroAssembler::patchNopToNearJump(tableProfilingJump, profilingEntry); - MacroAssembler::patchNopToNearJump(profilingJump, profilingEpilogue); - } else { - MacroAssembler::patchNearJumpToNop(tableProfilingJump); - MacroAssembler::patchNearJumpToNop(profilingJump); + for (ActivationIterator iter(cx, target); !iter.done(); ++iter) { + if (iter.activation()->isWasm()) { + for (FrameIterator fi(iter.activation()->asWasm()); !fi.done(); ++fi) { + if (fi.hasInstance()) + fi.instance()->trace(trc); + } + } } } diff --git a/js/src/wasm/WasmFrameIterator.h b/js/src/wasm/WasmFrameIterator.h index 7c8e440b61cc..1f780c73ef96 100644 --- a/js/src/wasm/WasmFrameIterator.h +++ b/js/src/wasm/WasmFrameIterator.h @@ -36,9 +36,8 @@ class CodeRange; class DebugFrame; class Instance; class SigIdDesc; -struct CallThunk; struct FuncOffsets; -struct ProfilingOffsets; +struct CallableOffsets; struct TrapOffset; // Iterates over the frames of a single WasmActivation, called synchronously @@ -76,6 +75,7 @@ class FrameIterator JSAtom* functionDisplayAtom() const; unsigned lineOrBytecode() const; const CodeRange* codeRange() const { return codeRange_; } + bool hasInstance() const; Instance* instance() const; bool debugEnabled() const; DebugFrame* debugFrame() const; @@ -89,25 +89,23 @@ enum class ExitReason : uint32_t None, // default state, the pc is in wasm code ImportJit, // fast-path call directly into JIT code ImportInterp, // slow-path call into C++ Invoke() - Native, // call to native C++ code (e.g., Math.sin, ToInt32(), interrupt) Trap, // call to trap handler for the trap in WasmActivation::trap DebugTrap // call to debug trap handler }; // Iterates over the frames of a single WasmActivation, given an -// asynchrously-interrupted thread's state. If the activation's -// module is not in profiling mode, the activation is skipped. +// asynchronously-interrupted thread's state. class ProfilingFrameIterator { const WasmActivation* activation_; const Code* code_; const CodeRange* codeRange_; - uint8_t* callerFP_; + void* callerFP_; void* callerPC_; void* stackAddress_; ExitReason exitReason_; - void initFromFP(); + void initFromExitFP(); public: ProfilingFrameIterator(); @@ -125,26 +123,20 @@ class ProfilingFrameIterator void GenerateExitPrologue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason, - ProfilingOffsets* offsets); + CallableOffsets* offsets); void GenerateExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason, - ProfilingOffsets* offsets); + CallableOffsets* offsets); void GenerateFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId, FuncOffsets* offsets); void GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets); -// Runtime patching to enable/disable profiling +// Mark all instance objects live on the stack. void -ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled); - -void -ToggleProfiling(const Code& code, const CallThunk& callThunk, bool enabled); - -void -ToggleProfiling(const Code& code, const CodeRange& codeRange, bool enabled); +TraceActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc); } // namespace wasm } // namespace js diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp index e1f3a7639d17..9cb645c91270 100644 --- a/js/src/wasm/WasmGenerator.cpp +++ b/js/src/wasm/WasmGenerator.cpp @@ -309,7 +309,7 @@ JumpRange() typedef HashMap, SystemAllocPolicy> OffsetMap; bool -ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits) +ModuleGenerator::patchCallSites() { masm_.haltingAlign(CodeAlignment); @@ -338,7 +338,7 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits) break; case CallSiteDesc::Func: { if (funcIsCompiled(cs.funcIndex())) { - uint32_t calleeOffset = funcCodeRange(cs.funcIndex()).funcNonProfilingEntry(); + uint32_t calleeOffset = funcCodeRange(cs.funcIndex()).funcNormalEntry(); MOZ_RELEASE_ASSERT(calleeOffset < INT32_MAX); if (uint32_t(abs(int32_t(calleeOffset) - int32_t(callerOffset))) < JumpRange()) { @@ -351,7 +351,7 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits) if (!p) { Offsets offsets; offsets.begin = masm_.currentOffset(); - uint32_t jumpOffset = masm_.farJumpWithPatch().offset(); + masm_.append(CallFarJump(cs.funcIndex(), masm_.farJumpWithPatch())); offsets.end = masm_.currentOffset(); if (masm_.oom()) return false; @@ -360,30 +360,18 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits) return false; if (!existingCallFarJumps.add(p, cs.funcIndex(), offsets.begin)) return false; - - // Record calls' far jumps in metadata since they must be - // repatched at runtime when profiling mode is toggled. - if (!metadata_->callThunks.emplaceBack(jumpOffset, cs.funcIndex())) - return false; } masm_.patchCall(callerOffset, p->value()); break; } case CallSiteDesc::TrapExit: { - if (maybeTrapExits) { - uint32_t calleeOffset = (*maybeTrapExits)[cs.trap()].begin; - MOZ_RELEASE_ASSERT(calleeOffset < INT32_MAX); - - if (uint32_t(abs(int32_t(calleeOffset) - int32_t(callerOffset))) < JumpRange()) { - masm_.patchCall(callerOffset, calleeOffset); - break; - } - } - if (!existingTrapFarJumps[cs.trap()]) { + // See MacroAssembler::wasmEmitTrapOutOfLineCode for why we must + // reload the TLS register on this path. Offsets offsets; offsets.begin = masm_.currentOffset(); + masm_.loadPtr(Address(FramePointer, offsetof(Frame, tls)), WasmTlsReg); masm_.append(TrapFarJump(cs.trap(), masm_.farJumpWithPatch())); offsets.end = masm_.currentOffset(); if (masm_.oom()) @@ -429,12 +417,8 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits) bool ModuleGenerator::patchFarJumps(const TrapExitOffsetArray& trapExits, const Offsets& debugTrapStub) { - for (CallThunk& callThunk : metadata_->callThunks) { - uint32_t funcIndex = callThunk.u.funcIndex; - callThunk.u.codeRangeIndex = funcToCodeRange_[funcIndex]; - CodeOffset farJump(callThunk.offset); - masm_.patchFarJump(farJump, funcCodeRange(funcIndex).funcNonProfilingEntry()); - } + for (const CallFarJump& farJump : masm_.callFarJumps()) + masm_.patchFarJump(farJump.jump, funcCodeRange(farJump.funcIndex).funcNormalEntry()); for (const TrapFarJump& farJump : masm_.trapFarJumps()) masm_.patchFarJump(farJump.jump, trapExits[farJump.trap].begin); @@ -534,7 +518,7 @@ ModuleGenerator::finishFuncExports() } typedef Vector OffsetVector; -typedef Vector ProfilingOffsetVector; +typedef Vector CallableOffsetVector; bool ModuleGenerator::finishCodegen() @@ -550,8 +534,8 @@ ModuleGenerator::finishCodegen() // due to the large absolute offsets temporarily stored by Label::bind(). OffsetVector entries; - ProfilingOffsetVector interpExits; - ProfilingOffsetVector jitExits; + CallableOffsetVector interpExits; + CallableOffsetVector jitExits; TrapExitOffsetArray trapExits; Offsets outOfBoundsExit; Offsets unalignedAccessExit; @@ -632,7 +616,7 @@ ModuleGenerator::finishCodegen() return false; throwStub.offsetBy(offsetInWhole); - if (!metadata_->codeRanges.emplaceBack(CodeRange::Inline, throwStub)) + if (!metadata_->codeRanges.emplaceBack(CodeRange::Throw, throwStub)) return false; debugTrapStub.offsetBy(offsetInWhole); @@ -649,7 +633,7 @@ ModuleGenerator::finishCodegen() // then far jumps. Patching callsites can generate far jumps so there is an // ordering dependency. - if (!patchCallSites(&trapExits)) + if (!patchCallSites()) return false; if (!patchFarJumps(trapExits, debugTrapStub)) @@ -1168,7 +1152,6 @@ ModuleGenerator::finish(const ShareableBytes& bytecode) metadata_->memoryAccesses.podResizeToFit(); metadata_->codeRanges.podResizeToFit(); metadata_->callSites.podResizeToFit(); - metadata_->callThunks.podResizeToFit(); metadata_->debugTrapFarJumpOffsets.podResizeToFit(); metadata_->debugFuncToCodeRange.podResizeToFit(); diff --git a/js/src/wasm/WasmGenerator.h b/js/src/wasm/WasmGenerator.h index b7a1630a55d6..6a820525b27a 100644 --- a/js/src/wasm/WasmGenerator.h +++ b/js/src/wasm/WasmGenerator.h @@ -212,7 +212,7 @@ class MOZ_STACK_CLASS ModuleGenerator typedef HashSet, SystemAllocPolicy> Uint32Set; typedef Vector CompileTaskVector; typedef Vector CompileTaskPtrVector; - typedef EnumeratedArray TrapExitOffsetArray; + typedef EnumeratedArray TrapExitOffsetArray; // Constant parameters CompileMode compileMode_; @@ -257,7 +257,7 @@ class MOZ_STACK_CLASS ModuleGenerator bool funcIsCompiled(uint32_t funcIndex) const; const CodeRange& funcCodeRange(uint32_t funcIndex) const; uint32_t numFuncImports() const; - MOZ_MUST_USE bool patchCallSites(TrapExitOffsetArray* maybeTrapExits = nullptr); + MOZ_MUST_USE bool patchCallSites(); MOZ_MUST_USE bool patchFarJumps(const TrapExitOffsetArray& trapExits, const Offsets& debugTrapStub); MOZ_MUST_USE bool finishTask(CompileTask* task); MOZ_MUST_USE bool finishOutstandingTask(); diff --git a/js/src/wasm/WasmInstance.cpp b/js/src/wasm/WasmInstance.cpp index ba8e759008b5..019bd1239648 100644 --- a/js/src/wasm/WasmInstance.cpp +++ b/js/src/wasm/WasmInstance.cpp @@ -352,7 +352,7 @@ Instance::Instance(JSContext* cx, const CodeRange& codeRange = calleeInstanceObj->getExportedFunctionCodeRange(f); Instance& calleeInstance = calleeInstanceObj->instance(); import.tls = calleeInstance.tlsData(); - import.code = calleeInstance.codeSegment().base() + codeRange.funcNonProfilingEntry(); + import.code = calleeInstance.codeSegment().base() + codeRange.funcNormalEntry(); import.baselineScript = nullptr; import.obj = calleeInstanceObj; } else { @@ -538,9 +538,6 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args) // If there has been a moving grow, this Instance should have been notified. MOZ_RELEASE_ASSERT(!memory_ || tlsData()->memoryBase == memory_->buffer().dataPointerEither()); - if (!cx->compartment()->wasm.ensureProfilingState(cx)) - return false; - const FuncExport& func = metadata().lookupFuncExport(funcIndex); // The calling convention for an external call into wasm is to pass an @@ -782,61 +779,6 @@ Instance::deoptimizeImportExit(uint32_t funcImportIndex) import.baselineScript = nullptr; } -static void -UpdateEntry(const Code& code, bool profilingEnabled, void** entry) -{ - const CodeRange& codeRange = *code.lookupRange(*entry); - void* from = code.segment().base() + codeRange.funcNonProfilingEntry(); - void* to = code.segment().base() + codeRange.funcProfilingEntry(); - - if (!profilingEnabled) - Swap(from, to); - - MOZ_ASSERT(*entry == from); - *entry = to; -} - -bool -Instance::ensureProfilingState(JSContext* cx, bool newProfilingEnabled) -{ - if (code_->profilingEnabled() == newProfilingEnabled) - return true; - - if (!code_->ensureProfilingState(cx->runtime(), newProfilingEnabled)) - return false; - - // Imported wasm functions and typed function tables point directly to - // either the profiling or non-profiling prologue and must therefore be - // updated when the profiling mode is toggled. - - for (const FuncImport& fi : metadata().funcImports) { - FuncImportTls& import = funcImportTls(fi); - if (import.obj && import.obj->is()) { - Code& code = import.obj->as().instance().code(); - UpdateEntry(code, newProfilingEnabled, &import.code); - } - } - - for (const SharedTable& table : tables_) { - if (!table->isTypedFunction()) - continue; - - // This logic will have to be generalized to match the import logic - // above if wasm can create typed function tables since a single table - // can contain elements from multiple instances. - MOZ_ASSERT(metadata().kind == ModuleKind::AsmJS); - - void** array = table->internalArray(); - uint32_t length = table->length(); - for (size_t i = 0; i < length; i++) { - if (array[i]) - UpdateEntry(*code_, newProfilingEnabled, &array[i]); - } - } - - return true; -} - void Instance::ensureEnterFrameTrapsState(JSContext* cx, bool enabled) { diff --git a/js/src/wasm/WasmInstance.h b/js/src/wasm/WasmInstance.h index 753e89560b45..46b8a622154f 100644 --- a/js/src/wasm/WasmInstance.h +++ b/js/src/wasm/WasmInstance.h @@ -78,7 +78,7 @@ class Instance TableTls& tableTls(const TableDesc& td) const; // Import call slow paths which are called directly from wasm code. - friend void* AddressOf(SymbolicAddress, JSContext*); + friend void* AddressOf(SymbolicAddress); static int32_t callImport_void(Instance*, int32_t, int32_t, uint64_t*); static int32_t callImport_i32(Instance*, int32_t, int32_t, uint64_t*); static int32_t callImport_i64(Instance*, int32_t, int32_t, uint64_t*); @@ -152,10 +152,6 @@ class Instance void onMovingGrowMemory(uint8_t* prevMemoryBase); void onMovingGrowTable(); - // See Code::ensureProfilingState comment. - - MOZ_MUST_USE bool ensureProfilingState(JSContext* cx, bool enabled); - // Debug support: bool debugEnabled() const { return code_->metadata().debugEnabled; } bool enterFrameTrapsEnabled() const { return enterFrameTrapsEnabled_; } diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp index 66d1c788f64d..7938395974cc 100644 --- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -55,22 +55,6 @@ typedef OpIter IonOpIter; class FunctionCompiler; -// TlsUsage describes how the TLS register is used during a function call. - -enum class TlsUsage -{ - Unused, // No particular action is taken with respect to the TLS register. - Need, // The TLS register must be reloaded just before the call. - CallerSaved // Same, plus space must be allocated to save/restore the TLS - // register. -}; - -static bool -NeedsTls(TlsUsage usage) -{ - return usage == TlsUsage::Need || usage == TlsUsage::CallerSaved; -} - // CallCompileState describes a call that is being compiled. Due to expression // nesting, multiple calls can be in the middle of compilation at the same time // and these are tracked in a stack by FunctionCompiler. @@ -93,11 +77,6 @@ class CallCompileState // FunctionCompiler::startCall() comment below. uint32_t spIncrement_; - // Set by FunctionCompiler::finishCall(), tells a potentially-inter-module - // call the offset of the reserved space in which it can save the caller's - // WasmTlsReg. - uint32_t tlsStackOffset_; - // Accumulates the register arguments while compiling arguments. MWasmCall::Args regArgs_; @@ -123,7 +102,6 @@ class CallCompileState : lineOrBytecode_(lineOrBytecode), maxChildStackBytes_(0), spIncrement_(0), - tlsStackOffset_(MWasmCall::DontSaveTls), childClobbers_(false) { } }; @@ -995,7 +973,7 @@ class FunctionCompiler outer->childClobbers_ = true; } - bool finishCall(CallCompileState* call, TlsUsage tls) + bool finishCall(CallCompileState* call) { MOZ_ALWAYS_TRUE(callStack_.popCopy() == call); @@ -1004,22 +982,10 @@ class FunctionCompiler return true; } - if (NeedsTls(tls)) { - if (!call->regArgs_.append(MWasmCall::Arg(AnyRegister(WasmTlsReg), tlsPointer_))) - return false; - } + if (!call->regArgs_.append(MWasmCall::Arg(AnyRegister(WasmTlsReg), tlsPointer_))) + return false; uint32_t stackBytes = call->abi_.stackBytesConsumedSoFar(); - - // If this is a potentially-inter-module call, allocate an extra word of - // stack space to save/restore the caller's WasmTlsReg during the call. - // Record the stack offset before including spIncrement since MWasmCall - // will use this offset after having bumped the stack pointer. - if (tls == TlsUsage::CallerSaved) { - call->tlsStackOffset_ = stackBytes; - stackBytes += sizeof(void*); - } - if (call->childClobbers_) { call->spIncrement_ = AlignBytes(call->maxChildStackBytes_, WasmStackAlignment); for (MWasmStackArg* stackArg : call->stackArgs_) @@ -1052,8 +1018,7 @@ class FunctionCompiler CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Func); MIRType ret = ToMIRType(sig.ret()); auto callee = CalleeDesc::function(funcIndex); - auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ret, - call.spIncrement_, MWasmCall::DontSaveTls); + auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ret, call.spIncrement_); if (!ins) return false; @@ -1078,7 +1043,6 @@ class FunctionCompiler const TableDesc& table = env_.tables[env_.asmJSSigToTableIndex[sigIndex]]; MOZ_ASSERT(IsPowerOfTwo(table.limits.initial)); MOZ_ASSERT(!table.external); - MOZ_ASSERT(call.tlsStackOffset_ == MWasmCall::DontSaveTls); MConstant* mask = MConstant::New(alloc(), Int32Value(table.limits.initial - 1)); curBlock_->add(mask); @@ -1091,14 +1055,12 @@ class FunctionCompiler MOZ_ASSERT(sig.id.kind() != SigIdDesc::Kind::None); MOZ_ASSERT(env_.tables.length() == 1); const TableDesc& table = env_.tables[0]; - MOZ_ASSERT(table.external == (call.tlsStackOffset_ != MWasmCall::DontSaveTls)); - callee = CalleeDesc::wasmTable(table, sig.id); } CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Dynamic); auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(sig.ret()), - call.spIncrement_, call.tlsStackOffset_, index); + call.spIncrement_, index); if (!ins) return false; @@ -1115,12 +1077,10 @@ class FunctionCompiler return true; } - MOZ_ASSERT(call.tlsStackOffset_ != MWasmCall::DontSaveTls); - CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Dynamic); auto callee = CalleeDesc::import(globalDataOffset); auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(ret), - call.spIncrement_, call.tlsStackOffset_); + call.spIncrement_); if (!ins) return false; @@ -1140,7 +1100,7 @@ class FunctionCompiler CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Symbolic); auto callee = CalleeDesc::builtin(builtin); auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(ret), - call.spIncrement_, MWasmCall::DontSaveTls); + call.spIncrement_); if (!ins) return false; @@ -1160,8 +1120,7 @@ class FunctionCompiler CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Symbolic); auto* ins = MWasmCall::NewBuiltinInstanceMethodCall(alloc(), desc, builtin, call.instanceArg_, call.regArgs_, - ToMIRType(ret), call.spIncrement_, - call.tlsStackOffset_); + ToMIRType(ret), call.spIncrement_); if (!ins) return false; @@ -1181,7 +1140,7 @@ class FunctionCompiler if (inDeadCode()) return; - MWasmReturn* ins = MWasmReturn::New(alloc(), operand, tlsPointer_); + MWasmReturn* ins = MWasmReturn::New(alloc(), operand); curBlock_->end(ins); curBlock_ = nullptr; } @@ -1191,7 +1150,7 @@ class FunctionCompiler if (inDeadCode()) return; - MWasmReturnVoid* ins = MWasmReturnVoid::New(alloc(), tlsPointer_); + MWasmReturnVoid* ins = MWasmReturnVoid::New(alloc()); curBlock_->end(ins); curBlock_ = nullptr; } @@ -2018,11 +1977,8 @@ EmitUnreachable(FunctionCompiler& f) typedef IonOpIter::ValueVector DefVector; static bool -EmitCallArgs(FunctionCompiler& f, const Sig& sig, const DefVector& args, TlsUsage tls, - CallCompileState* call) +EmitCallArgs(FunctionCompiler& f, const Sig& sig, const DefVector& args, CallCompileState* call) { - MOZ_ASSERT(NeedsTls(tls)); - if (!f.startCall(call)) return false; @@ -2031,7 +1987,7 @@ EmitCallArgs(FunctionCompiler& f, const Sig& sig, const DefVector& args, TlsUsag return false; } - return f.finishCall(call, tls); + return f.finishCall(call); } static bool @@ -2048,15 +2004,13 @@ EmitCall(FunctionCompiler& f) return true; const Sig& sig = *f.env().funcSigs[funcIndex]; - bool import = f.env().funcIsImport(funcIndex); - TlsUsage tls = import ? TlsUsage::CallerSaved : TlsUsage::Need; CallCompileState call(f, lineOrBytecode); - if (!EmitCallArgs(f, sig, args, tls, &call)) + if (!EmitCallArgs(f, sig, args, &call)) return false; MDefinition* def; - if (import) { + if (f.env().funcIsImport(funcIndex)) { uint32_t globalDataOffset = f.env().funcImportGlobalDataOffsets[funcIndex]; if (!f.callImport(globalDataOffset, call, sig.ret(), &def)) return false; @@ -2093,12 +2047,8 @@ EmitCallIndirect(FunctionCompiler& f, bool oldStyle) const Sig& sig = f.env().sigs[sigIndex]; - TlsUsage tls = !f.env().isAsmJS() && f.env().tables[0].external - ? TlsUsage::CallerSaved - : TlsUsage::Need; - CallCompileState call(f, lineOrBytecode); - if (!EmitCallArgs(f, sig, args, tls, &call)) + if (!EmitCallArgs(f, sig, args, &call)) return false; MDefinition* def; @@ -2581,7 +2531,7 @@ EmitUnaryMathBuiltinCall(FunctionCompiler& f, SymbolicAddress callee, ValType op if (!f.passArg(input, operandType, &call)) return false; - if (!f.finishCall(&call, TlsUsage::Unused)) + if (!f.finishCall(&call)) return false; MDefinition* def; @@ -2612,7 +2562,7 @@ EmitBinaryMathBuiltinCall(FunctionCompiler& f, SymbolicAddress callee, ValType o if (!f.passArg(rhs, operandType, &call)) return false; - if (!f.finishCall(&call, TlsUsage::Unused)) + if (!f.finishCall(&call)) return false; MDefinition* def; @@ -3217,10 +3167,7 @@ EmitGrowMemory(FunctionCompiler& f) if (!f.passArg(delta, ValType::I32, &args)) return false; - // As a short-cut, pretend this is an inter-module call so that any pinned - // heap pointer will be reloaded after the call. This hack will go away once - // we can stop pinning registers. - f.finishCall(&args, TlsUsage::CallerSaved); + f.finishCall(&args); MDefinition* ret; if (!f.builtinInstanceMethodCall(SymbolicAddress::GrowMemory, args, ValType::I32, &ret)) @@ -3246,7 +3193,7 @@ EmitCurrentMemory(FunctionCompiler& f) if (!f.passInstance(&args)) return false; - f.finishCall(&args, TlsUsage::Need); + f.finishCall(&args); MDefinition* ret; if (!f.builtinInstanceMethodCall(SymbolicAddress::CurrentMemory, args, ValType::I32, &ret)) diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 1bbf5e336d3c..7bd49a7fbf42 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -65,13 +65,6 @@ wasm::HasCompilerSupport(JSContext* cx) if (!wasm::HaveSignalHandlers()) return false; -#if defined(JS_CODEGEN_ARM) - // movw/t are required for the loadWasmActivationFromSymbolicAddress in - // GenerateProfilingPrologue/Epilogue to avoid using the constant pool. - if (!HasMOVWT()) - return false; -#endif - #if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64) return false; #else diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp index bbf926a2ebe1..b4c65082941d 100644 --- a/js/src/wasm/WasmModule.cpp +++ b/js/src/wasm/WasmModule.cpp @@ -440,11 +440,11 @@ Module::extractCode(JSContext* cx, MutableHandleValue vp) if (!JS_DefineProperty(cx, segment, "funcIndex", value, JSPROP_ENUMERATE)) return false; - value.setNumber((uint32_t)p.funcNonProfilingEntry()); + value.setNumber((uint32_t)p.funcNormalEntry()); if (!JS_DefineProperty(cx, segment, "funcBodyBegin", value, JSPROP_ENUMERATE)) return false; - value.setNumber((uint32_t)p.funcProfilingEpilogue()); + value.setNumber((uint32_t)p.end()); if (!JS_DefineProperty(cx, segment, "funcBodyEnd", value, JSPROP_ENUMERATE)) return false; } @@ -521,7 +521,6 @@ Module::initSegments(JSContext* cx, for (const ElemSegment& seg : elemSegments_) { Table& table = *tables[seg.tableIndex]; uint32_t offset = EvaluateInitExpr(globalImports, seg.offset); - bool profilingEnabled = instance.code().profilingEnabled(); const CodeRangeVector& codeRanges = metadata().codeRanges; uint8_t* codeBase = instance.codeBase(); @@ -539,9 +538,7 @@ Module::initSegments(JSContext* cx, } else { const CodeRange& cr = codeRanges[seg.elemCodeRangeIndices[i]]; uint32_t entryOffset = table.isTypedFunction() - ? profilingEnabled - ? cr.funcProfilingEntry() - : cr.funcNonProfilingEntry() + ? cr.funcNormalEntry() : cr.funcTableEntry(); table.set(offset + i, codeBase + entryOffset, instance); } diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp index ebe446a7eeb9..8c28d98981ac 100644 --- a/js/src/wasm/WasmStubs.cpp +++ b/js/src/wasm/WasmStubs.cpp @@ -122,7 +122,7 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) Register scratch = ABINonArgReturnReg1; // Read the arguments of wasm::ExportFuncPtr according to the native ABI. - // The entry stub's frame is only 1 word, not the usual 2 for wasm::Frame. + // The entry stub's frame is 1 word. const unsigned argBase = sizeof(void*) + masm.framePushed(); ABIArgGenerator abi; ABIArg arg; @@ -262,12 +262,25 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) } } + // Set the FramePointer to null for the benefit of debugging. + masm.movePtr(ImmWord(0), FramePointer); + // Call into the real function. masm.assertStackAlignment(WasmStackAlignment); masm.call(CallSiteDesc(CallSiteDesc::Func), fe.funcIndex()); + masm.assertStackAlignment(WasmStackAlignment); + +#ifdef DEBUG + // Assert FramePointer was returned to null by the callee. + Label ok; + masm.branchTestPtr(Assembler::Zero, FramePointer, FramePointer, &ok); + masm.breakpoint(); + masm.bind(&ok); +#endif // Recover the stack pointer value before dynamic alignment. masm.loadWasmActivationFromTls(scratch); + masm.wasmAssertNonExitInvariants(scratch); masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP())); masm.setFramePushed(FramePushedForEntrySP); @@ -445,15 +458,14 @@ FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argO // normal wasm function for the purposes of exports and table calls. In // particular, the wrapper function provides: // - a table entry, so JS imports can be put into tables -// - normal (non-)profiling entries, so that, if the import is re-exported, -// an entry stub can be generated and called without any special cases +// - normal entries, so that, if the import is re-exported, an entry stub can +// be generated and called without any special cases FuncOffsets wasm::GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, SigIdDesc sigId) { masm.setFramePushed(0); - unsigned tlsBytes = sizeof(void*); - unsigned framePushed = StackDecrementForCall(masm, WasmStackAlignment, fi.sig().args(), tlsBytes); + unsigned framePushed = StackDecrementForCall(masm, WasmStackAlignment, fi.sig().args()); FuncOffsets offsets; GenerateFunctionPrologue(masm, framePushed, sigId, &offsets); @@ -474,16 +486,12 @@ wasm::GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, Si StackCopy(masm, i.mirType(), scratch, src, dst); } - // Save the TLS register so it can be restored later. - uint32_t tlsStackOffset = i.stackBytesConsumedSoFar(); - masm.storePtr(WasmTlsReg, Address(masm.getStackPointer(), tlsStackOffset)); - // Call the import exit stub. CallSiteDesc desc(CallSiteDesc::Dynamic); masm.wasmCallImport(desc, CalleeDesc::import(fi.tlsDataOffset())); // Restore the TLS register and pinned regs, per wasm function ABI. - masm.loadPtr(Address(masm.getStackPointer(), tlsStackOffset), WasmTlsReg); + masm.loadWasmTlsRegFromFrame(); masm.loadWasmPinnedRegsFromTls(); GenerateFunctionEpilogue(masm, framePushed, &offsets); @@ -497,7 +505,7 @@ wasm::GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, Si // Generate a stub that is called via the internal ABI derived from the // signature of the import and calls into an appropriate callImport C++ // function, having boxed all the ABI arguments into a homogeneous Value array. -ProfilingOffsets +CallableOffsets wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint32_t funcImportIndex, Label* throwLabel) { @@ -519,7 +527,7 @@ wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint3 unsigned argBytes = Max(1, fi.sig().args().length()) * sizeof(Value); unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, argOffset + argBytes); - ProfilingOffsets offsets; + CallableOffsets offsets; GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, &offsets); // Fill the argument array. @@ -621,12 +629,10 @@ wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint3 return offsets; } -static const unsigned SavedTlsReg = sizeof(void*); - // Generate a stub that is called via the internal ABI derived from the // signature of the import and calls into a compatible JIT function, // having boxed all the ABI arguments into the JIT stack frame layout. -ProfilingOffsets +CallableOffsets wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLabel) { masm.setFramePushed(0); @@ -640,11 +646,11 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t static_assert(WasmStackAlignment >= JitStackAlignment, "subsumes"); unsigned sizeOfRetAddr = sizeof(void*); unsigned jitFrameBytes = 3 * sizeof(void*) + (1 + fi.sig().args().length()) * sizeof(Value); - unsigned totalJitFrameBytes = sizeOfRetAddr + jitFrameBytes + SavedTlsReg; + unsigned totalJitFrameBytes = sizeOfRetAddr + jitFrameBytes; unsigned jitFramePushed = StackDecrementForCall(masm, JitStackAlignment, totalJitFrameBytes) - sizeOfRetAddr; - ProfilingOffsets offsets; + CallableOffsets offsets; GenerateExitPrologue(masm, jitFramePushed, ExitReason::ImportJit, &offsets); // 1. Descriptor @@ -684,12 +690,6 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t argOffset += fi.sig().args().length() * sizeof(Value); MOZ_ASSERT(argOffset == jitFrameBytes); - // 6. Jit code will clobber all registers, even non-volatiles. WasmTlsReg - // must be kept live for the benefit of the epilogue, so push it on the - // stack so that it can be restored before the epilogue. - static_assert(SavedTlsReg == sizeof(void*), "stack frame accounting"); - masm.storePtr(WasmTlsReg, Address(masm.getStackPointer(), jitFrameBytes)); - { // Enable Activation. // @@ -700,8 +700,7 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t Register act = WasmIonExitRegE1; // JitActivation* act = cx->activation(); - masm.movePtr(SymbolicAddress::ContextPtr, cx); - masm.loadPtr(Address(cx, 0), cx); + masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, cx)), cx); masm.loadPtr(Address(cx, JSContext::offsetOfActivation()), act); // act.active_ = true; @@ -718,20 +717,26 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t masm.callJitNoProfiler(callee); AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr); + // The JIT callee clobbers all registers, including WasmTlsReg and + // FrameRegister, so restore those here. + masm.loadWasmTlsRegFromFrame(); + masm.moveStackPtrTo(FramePointer); + masm.addPtr(Imm32(masm.framePushed()), FramePointer); + { // Disable Activation. // - // This sequence needs three registers, and must preserve the JSReturnReg_Data and - // JSReturnReg_Type, so there are five live registers. + // This sequence needs three registers and must preserve WasmTlsReg, + // JSReturnReg_Data and JSReturnReg_Type. MOZ_ASSERT(JSReturnReg_Data == WasmIonExitRegReturnData); MOZ_ASSERT(JSReturnReg_Type == WasmIonExitRegReturnType); + MOZ_ASSERT(WasmTlsReg == WasmIonExitTlsReg); Register cx = WasmIonExitRegD0; Register act = WasmIonExitRegD1; Register tmp = WasmIonExitRegD2; // JitActivation* act = cx->activation(); - masm.movePtr(SymbolicAddress::ContextPtr, cx); - masm.loadPtr(Address(cx, 0), cx); + masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, cx)), cx); masm.loadPtr(Address(cx, JSContext::offsetOfActivation()), act); // cx->jitTop = act->prevJitTop_; @@ -795,12 +800,6 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t Label done; masm.bind(&done); - // Ion code does not respect the system ABI's callee-saved register - // conventions so reload any assumed-non-volatile registers. Note that the - // reserveStack(sizeOfRetAddr) above means that the stack pointer is at a - // different offset than when WasmTlsReg was stored. - masm.loadPtr(Address(masm.getStackPointer(), jitFrameBytes + sizeOfRetAddr), WasmTlsReg); - GenerateExitEpilogue(masm, masm.framePushed(), ExitReason::ImportJit, &offsets); if (oolConvert.used()) { @@ -864,10 +863,10 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t } // Generate a stub that calls into ReportTrap with the right trap reason. -// This stub is called with ABIStackAlignment by a trap out-of-line path. A -// profiling prologue/epilogue is used so that stack unwinding picks up the +// This stub is called with ABIStackAlignment by a trap out-of-line path. An +// exit prologue/epilogue is used so that stack unwinding picks up the // current WasmActivation. Unwinding will begin at the caller of this trap exit. -ProfilingOffsets +CallableOffsets wasm::GenerateTrapExit(MacroAssembler& masm, Trap trap, Label* throwLabel) { masm.haltingAlign(CodeAlignment); @@ -879,7 +878,7 @@ wasm::GenerateTrapExit(MacroAssembler& masm, Trap trap, Label* throwLabel) uint32_t framePushed = StackDecrementForCall(masm, ABIStackAlignment, args); - ProfilingOffsets offsets; + CallableOffsets offsets; GenerateExitPrologue(masm, framePushed, ExitReason::Trap, &offsets); ABIArgMIRTypeIter i(args); @@ -904,11 +903,11 @@ wasm::GenerateTrapExit(MacroAssembler& masm, Trap trap, Label* throwLabel) // Generate a stub which is only used by the signal handlers to handle out of // bounds access by experimental SIMD.js and Atomics and unaligned accesses on // ARM. This stub is executed by direct PC transfer from the faulting memory -// access and thus the stack depth is unknown. Since WasmActivation::fp is not -// set before calling the error reporter, the current wasm activation will be -// lost. This stub should be removed when SIMD.js and Atomics are moved to wasm -// and given proper traps and when we use a non-faulting strategy for unaligned -// ARM access. +// access and thus the stack depth is unknown. Since WasmActivation::exitFP is +// not set before calling the error reporter, the current wasm activation will +// be lost. This stub should be removed when SIMD.js and Atomics are moved to +// wasm and given proper traps and when we use a non-faulting strategy for +// unaligned ARM access. static Offsets GenerateGenericMemoryAccessTrap(MacroAssembler& masm, SymbolicAddress reporter, Label* throwLabel) { @@ -943,13 +942,17 @@ wasm::GenerateUnalignedExit(MacroAssembler& masm, Label* throwLabel) return GenerateGenericMemoryAccessTrap(masm, SymbolicAddress::ReportUnalignedAccess, throwLabel); } +#if defined(JS_CODEGEN_ARM) +static const LiveRegisterSet AllRegsExceptPCSP( + GeneralRegisterSet(Registers::AllMask & ~((uint32_t(1) << Registers::sp) | + (uint32_t(1) << Registers::pc))), + FloatRegisterSet(FloatRegisters::AllDoubleMask)); +static_assert(!SupportsSimd, "high lanes of SIMD registers need to be saved too."); +#else static const LiveRegisterSet AllRegsExceptSP( GeneralRegisterSet(Registers::AllMask & ~(uint32_t(1) << Registers::StackPointer)), FloatRegisterSet(FloatRegisters::AllMask)); - -static const LiveRegisterSet AllAllocatableRegs = LiveRegisterSet( - GeneralRegisterSet(Registers::AllocatableMask), - FloatRegisterSet(FloatRegisters::AllMask)); +#endif // The async interrupt-callback exit is called from arbitrarily-interrupted wasm // code. That means we must first save *all* registers and restore *all* @@ -971,18 +974,11 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel) // Be very careful here not to perturb the machine state before saving it // to the stack. In particular, add/sub instructions may set conditions in // the flags register. - masm.push(Imm32(0)); // space for resumePC - masm.pushFlags(); // after this we are safe to use sub - masm.setFramePushed(0); // set to zero so we can use masm.framePushed() below + masm.push(Imm32(0)); // space used as return address, updated below + masm.setFramePushed(0); // set to 0 now so that framePushed is offset of return address + masm.PushFlags(); // after this we are safe to use sub masm.PushRegsInMask(AllRegsExceptSP); // save all GP/FP registers (except SP) - Register scratch = ABINonArgReturnReg0; - - // Store resumePC into the reserved space. - masm.loadWasmActivationFromSymbolicAddress(scratch); - masm.loadPtr(Address(scratch, WasmActivation::offsetOfResumePC()), scratch); - masm.storePtr(scratch, Address(masm.getStackPointer(), masm.framePushed() + sizeof(void*))); - // We know that StackPointer is word-aligned, but not necessarily // stack-aligned, so we need to align it dynamically. masm.moveStackPtrTo(ABINonVolatileReg); @@ -990,18 +986,27 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel) if (ShadowStackSpace) masm.subFromStackPtr(Imm32(ShadowStackSpace)); + // Make the call to C++, which preserves ABINonVolatileReg. masm.assertStackAlignment(ABIStackAlignment); masm.call(SymbolicAddress::HandleExecutionInterrupt); - masm.branchIfFalseBool(ReturnReg, throwLabel); + // HandleExecutionInterrupt returns null if execution is interrupted and + // the resumption pc otherwise. + masm.branchTestPtr(Assembler::Zero, ReturnReg, ReturnReg, throwLabel); - // Restore the StackPointer to its position before the call. + // Restore the stack pointer then store resumePC into the stack slow that + // will be popped by the 'ret' below. masm.moveToStackPtr(ABINonVolatileReg); + masm.storePtr(ReturnReg, Address(StackPointer, masm.framePushed())); - // Restore the machine state to before the interrupt. - masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP) - masm.popFlags(); // after this, nothing that sets conditions - masm.ret(); // pop resumePC into PC + // Restore the machine state to before the interrupt. After popping flags, + // no instructions can be executed which set flags. + masm.PopRegsInMask(AllRegsExceptSP); + masm.PopFlags(); + + // Return to the resumePC stored into this stack slot above. + MOZ_ASSERT(masm.framePushed() == 0); + masm.ret(); #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) // Reserve space to store resumePC and HeapReg. masm.subFromStackPtr(Imm32(2 * sizeof(intptr_t))); @@ -1049,61 +1054,40 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel) masm.as_jr(HeapReg); masm.loadPtr(Address(StackPointer, -sizeof(intptr_t)), HeapReg); #elif defined(JS_CODEGEN_ARM) - masm.setFramePushed(0); // set to zero so we can use masm.framePushed() below + masm.push(Imm32(0)); // space used as return address, updated below + masm.setFramePushed(0); // set to 0 now so that framePushed is offset of return address + masm.PushRegsInMask(AllRegsExceptPCSP); // save all GP/FP registers (except PC and SP) - // Save all GPR, except the stack pointer. - masm.PushRegsInMask(LiveRegisterSet( - GeneralRegisterSet(Registers::AllMask & ~(1< Maybe maximum() const { return maximum_; } uint8_t* base() const { return array_.get(); } - // All updates must go through a set() function with the exception of - // (profiling) updates to the callee pointer that do not change which - // logical function is being called. + // All table updates must go through set() or setNull(). void** internalArray() const; ExternalTableElem* externalArray() const; diff --git a/js/src/wasm/WasmTypes.cpp b/js/src/wasm/WasmTypes.cpp index 6347f00a56fb..b117f65a530c 100644 --- a/js/src/wasm/WasmTypes.cpp +++ b/js/src/wasm/WasmTypes.cpp @@ -28,6 +28,7 @@ #include "jit/MacroAssembler.h" #include "js/Conversions.h" #include "vm/Interpreter.h" +#include "wasm/WasmBaselineCompile.h" #include "wasm/WasmInstance.h" #include "wasm/WasmSerialize.h" #include "wasm/WasmSignalHandlers.h" @@ -78,25 +79,26 @@ __aeabi_uidivmod(int, int); } #endif -static void -WasmReportOverRecursed() -{ - ReportOverRecursed(JSContext::innermostWasmActivation()->cx()); -} - -static bool +static void* WasmHandleExecutionInterrupt() { WasmActivation* activation = JSContext::innermostWasmActivation(); + + // wasm::Compartment requires notification when execution is interrupted in + // the compartment. Only the innermost compartment has been interrupted; + // enclosing compartments necessarily exited through an exit stub. + activation->compartment()->wasm.setInterrupted(true); bool success = CheckForInterrupt(activation->cx()); + activation->compartment()->wasm.setInterrupted(false); // Preserve the invariant that having a non-null resumePC means that we are - // handling an interrupt. Note that resumePC has already been copied onto - // the stack by the interrupt stub, so we can clear it before returning - // to the stub. + // handling an interrupt. + void* resumePC = activation->resumePC(); activation->setResumePC(nullptr); - return success; + // Return the resumePC if execution can continue or null if execution should + // jump to the throw stub. + return success ? resumePC : nullptr; } static bool @@ -115,7 +117,7 @@ WasmHandleDebugTrap() return true; DebugFrame* frame = iter.debugFrame(); frame->setIsDebuggee(); - frame->observeFrame(cx); + frame->observe(cx); // TODO call onEnterFrame JSTrapStatus status = Debugger::onEnterFrame(cx, frame); if (status == JSTRAP_RETURN) { @@ -131,7 +133,7 @@ WasmHandleDebugTrap() DebugFrame* frame = iter.debugFrame(); frame->updateReturnJSValue(); bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true); - frame->leaveFrame(cx); + frame->leave(cx); return ok; } @@ -163,14 +165,36 @@ WasmHandleDebugTrap() return true; } -static void +static WasmActivation* WasmHandleThrow() { - WasmActivation* activation = JSContext::innermostWasmActivation(); - MOZ_ASSERT(activation); - JSContext* cx = activation->cx(); + JSContext* cx = TlsContext.get(); - for (FrameIterator iter(activation, FrameIterator::Unwind::True); !iter.done(); ++iter) { + WasmActivation* activation = cx->wasmActivationStack(); + MOZ_ASSERT(activation); + + // FrameIterator iterates down wasm frames in the activation starting at + // WasmActivation::exitFP. Pass Unwind::True to pop WasmActivation::exitFP + // once each time FrameIterator is incremented, ultimately leaving exitFP + // null when the FrameIterator is done(). This is necessary to prevent a + // DebugFrame from being observed again after we just called onLeaveFrame + // (which would lead to the frame being re-added to the map of live frames, + // right as it becomes trash). + FrameIterator iter(activation, FrameIterator::Unwind::True); + if (iter.done()) + return activation; + + // Live wasm code on the stack is kept alive (in wasm::TraceActivations) by + // marking the instance of every wasm::Frame found by FrameIterator. + // However, as explained above, we're popping frames while iterating which + // means that a GC during this loop could collect the code of frames whose + // code is still on the stack. This is actually mostly fine: as soon as we + // return to the throw stub, the entire stack will be popped as a whole, + // returning to the C++ caller. However, we must keep the throw stub alive + // itself which is owned by the innermost instance. + RootedWasmInstanceObject keepAlive(cx, iter.instance()->object()); + + for (; !iter.done(); ++iter) { if (!iter.debugEnabled()) continue; @@ -196,8 +220,10 @@ WasmHandleThrow() // TODO properly handle success and resume wasm execution. JS_ReportErrorASCII(cx, "Unexpected success from onLeaveFrame"); } - frame->leaveFrame(cx); + frame->leave(cx); } + + return activation; } static void @@ -407,13 +433,9 @@ wasm::IsRoundingFunction(SymbolicAddress callee, jit::RoundingMode* mode) } void* -wasm::AddressOf(SymbolicAddress imm, JSContext* cx) +wasm::AddressOf(SymbolicAddress imm) { switch (imm) { - case SymbolicAddress::ContextPtr: - return cx->zone()->group()->addressOfOwnerContext(); - case SymbolicAddress::ReportOverRecursed: - return FuncCast(WasmReportOverRecursed, Args_General0); case SymbolicAddress::HandleExecutionInterrupt: return FuncCast(WasmHandleExecutionInterrupt, Args_General0); case SymbolicAddress::HandleDebugTrap: @@ -998,3 +1020,122 @@ wasm::ComputeMappedSize(uint32_t maxSize) } #endif // WASM_HUGE_MEMORY + +void +DebugFrame::alignmentStaticAsserts() +{ + // VS2017 doesn't consider offsetOfFrame() to be a constexpr, so we have + // to use offsetof directly. These asserts can't be at class-level + // because the type is incomplete. + + static_assert(WasmStackAlignment >= Alignment, + "Aligned by ABI before pushing DebugFrame"); + static_assert((offsetof(DebugFrame, frame_) + sizeof(Frame)) % Alignment == 0, + "Aligned after pushing DebugFrame"); +} + +GlobalObject* +DebugFrame::global() const +{ + return &instance()->object()->global(); +} + +JSObject* +DebugFrame::environmentChain() const +{ + return &global()->lexicalEnvironment(); +} + +bool +DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp) +{ + ValTypeVector locals; + size_t argsLength; + if (!instance()->code().debugGetLocalTypes(funcIndex(), &locals, &argsLength)) + return false; + + BaseLocalIter iter(locals, argsLength, /* debugEnabled = */ true); + while (!iter.done() && iter.index() < localIndex) + iter++; + MOZ_ALWAYS_TRUE(!iter.done()); + + uint8_t* frame = static_cast((void*)this) + offsetOfFrame(); + void* dataPtr = frame - iter.frameOffset(); + switch (iter.mirType()) { + case jit::MIRType::Int32: + vp.set(Int32Value(*static_cast(dataPtr))); + break; + case jit::MIRType::Int64: + // Just display as a Number; it's ok if we lose some precision + vp.set(NumberValue((double)*static_cast(dataPtr))); + break; + case jit::MIRType::Float32: + vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast(dataPtr)))); + break; + case jit::MIRType::Double: + vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast(dataPtr)))); + break; + default: + MOZ_CRASH("local type"); + } + return true; +} + +void +DebugFrame::updateReturnJSValue() +{ + hasCachedReturnJSValue_ = true; + ExprType returnType = instance()->code().debugGetResultType(funcIndex()); + switch (returnType) { + case ExprType::Void: + cachedReturnJSValue_.setUndefined(); + break; + case ExprType::I32: + cachedReturnJSValue_.setInt32(resultI32_); + break; + case ExprType::I64: + // Just display as a Number; it's ok if we lose some precision + cachedReturnJSValue_.setDouble((double)resultI64_); + break; + case ExprType::F32: + cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF32_)); + break; + case ExprType::F64: + cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF64_)); + break; + default: + MOZ_CRASH("result type"); + } +} + +HandleValue +DebugFrame::returnValue() const +{ + MOZ_ASSERT(hasCachedReturnJSValue_); + return HandleValue::fromMarkedLocation(&cachedReturnJSValue_); +} + +void +DebugFrame::clearReturnJSValue() +{ + hasCachedReturnJSValue_ = true; + cachedReturnJSValue_.setUndefined(); +} + +void +DebugFrame::observe(JSContext* cx) +{ + if (!observing_) { + instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ true); + observing_ = true; + } +} + +void +DebugFrame::leave(JSContext* cx) +{ + if (observing_) { + instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ false); + observing_ = false; + } +} diff --git a/js/src/wasm/WasmTypes.h b/js/src/wasm/WasmTypes.h index 910b8d9aaa55..899c6ae23fbb 100644 --- a/js/src/wasm/WasmTypes.h +++ b/js/src/wasm/WasmTypes.h @@ -41,6 +41,8 @@ namespace js { class PropertyName; +class WasmActivation; +class WasmFunctionCallObject; namespace jit { struct BaselineScript; enum class RoundingMode; @@ -762,7 +764,7 @@ struct SigWithId : Sig typedef Vector SigWithIdVector; typedef Vector SigWithIdPtrVector; -// The (,Profiling,Func)Offsets classes are used to record the offsets of +// The (,Callable,Func)Offsets classes are used to record the offsets of // different key points in a CodeRange during compilation. struct Offsets @@ -782,62 +784,39 @@ struct Offsets } }; -struct ProfilingOffsets : Offsets +struct CallableOffsets : Offsets { - MOZ_IMPLICIT ProfilingOffsets(uint32_t profilingReturn = 0) - : Offsets(), profilingReturn(profilingReturn) + MOZ_IMPLICIT CallableOffsets(uint32_t ret = 0) + : Offsets(), ret(ret) {} - // For CodeRanges with ProfilingOffsets, 'begin' is the offset of the - // profiling entry. - uint32_t profilingEntry() const { return begin; } - - // The profiling return is the offset of the return instruction, which - // precedes the 'end' by a variable number of instructions due to - // out-of-line codegen. - uint32_t profilingReturn; + // The offset of the return instruction precedes 'end' by a variable number + // of instructions due to out-of-line codegen. + uint32_t ret; void offsetBy(uint32_t offset) { Offsets::offsetBy(offset); - profilingReturn += offset; + ret += offset; } }; -struct FuncOffsets : ProfilingOffsets +struct FuncOffsets : CallableOffsets { MOZ_IMPLICIT FuncOffsets() - : ProfilingOffsets(), - tableEntry(0), - tableProfilingJump(0), - nonProfilingEntry(0), - profilingJump(0), - profilingEpilogue(0) + : CallableOffsets(), + normalEntry(0) {} // Function CodeRanges have a table entry which takes an extra signature // argument which is checked against the callee's signature before falling - // through to the normal prologue. When profiling is enabled, a nop on the - // fallthrough is patched to instead jump to the profiling epilogue. - uint32_t tableEntry; - uint32_t tableProfilingJump; - - // Function CodeRanges have an additional non-profiling entry that comes - // after the profiling entry and a non-profiling epilogue that comes before - // the profiling epilogue. - uint32_t nonProfilingEntry; - - // When profiling is enabled, the 'nop' at offset 'profilingJump' is - // overwritten to be a jump to 'profilingEpilogue'. - uint32_t profilingJump; - uint32_t profilingEpilogue; + // through to the normal prologue. The table entry is thus at the beginning + // of the CodeRange and the normal entry is at some offset after the table + // entry. + uint32_t normalEntry; void offsetBy(uint32_t offset) { - ProfilingOffsets::offsetBy(offset); - tableEntry += offset; - tableProfilingJump += offset; - nonProfilingEntry += offset; - profilingJump += offset; - profilingEpilogue += offset; + CallableOffsets::offsetBy(offset); + normalEntry += offset; } }; @@ -926,26 +905,18 @@ class CallSiteDesc class CallSite : public CallSiteDesc { uint32_t returnAddressOffset_; - uint32_t stackDepth_; public: CallSite() {} - CallSite(CallSiteDesc desc, uint32_t returnAddressOffset, uint32_t stackDepth) + CallSite(CallSiteDesc desc, uint32_t returnAddressOffset) : CallSiteDesc(desc), - returnAddressOffset_(returnAddressOffset), - stackDepth_(stackDepth) + returnAddressOffset_(returnAddressOffset) { } void setReturnAddressOffset(uint32_t r) { returnAddressOffset_ = r; } void offsetReturnAddressBy(int32_t o) { returnAddressOffset_ += o; } uint32_t returnAddressOffset() const { return returnAddressOffset_; } - - // The stackDepth measures the amount of stack space pushed since the - // function was called. In particular, this includes the pushed return - // address on all archs (whether or not the call instruction pushes the - // return address (x86/x64) or the prologue does (ARM/MIPS)). - uint32_t stackDepth() const { return stackDepth_; } }; WASM_DECLARE_POD_VECTOR(CallSite, CallSiteVector) @@ -978,12 +949,12 @@ class CallSiteAndTarget : public CallSite typedef Vector CallSiteAndTargetVector; -// A wasm::SymbolicAddress represents a pointer to a well-known function or -// object that is embedded in wasm code. Since wasm code is serialized and -// later deserialized into a different address space, symbolic addresses must be -// used for *all* pointers into the address space. The MacroAssembler records a -// list of all SymbolicAddresses and the offsets of their use in the code for -// later patching during static linking. +// A wasm::SymbolicAddress represents a pointer to a well-known function that is +// embedded in wasm code. Since wasm code is serialized and later deserialized +// into a different address space, symbolic addresses must be used for *all* +// pointers into the address space. The MacroAssembler records a list of all +// SymbolicAddresses and the offsets of their use in the code for later patching +// during static linking. enum class SymbolicAddress { @@ -1018,8 +989,6 @@ enum class SymbolicAddress LogD, PowD, ATan2D, - ContextPtr, - ReportOverRecursed, HandleExecutionInterrupt, HandleDebugTrap, HandleThrow, @@ -1051,7 +1020,7 @@ bool IsRoundingFunction(SymbolicAddress callee, jit::RoundingMode* mode); void* -AddressOf(SymbolicAddress imm, JSContext* cx); +AddressOf(SymbolicAddress imm); // Assumptions captures ambient state that must be the same when compiling and // deserializing a module for the compiled code to be valid. If it's not, then @@ -1485,19 +1454,127 @@ WASM_DECLARE_POD_VECTOR(MemoryAccess, MemoryAccessVector) struct Frame { - // The caller's saved frame pointer. In non-profiling mode, internal - // wasm-to-wasm calls don't update fp and thus don't save the caller's - // frame pointer; the space is reserved, however, so that profiling mode can - // reuse the same function body without recompiling. + // The saved value of WasmTlsReg on entry to the function. This is + // effectively the callee's instance. + TlsData* tls; + + // The caller's Frame*. uint8_t* callerFP; // The return address pushed by the call (in the case of ARM/MIPS the return // address is pushed by the first instruction of the prologue). void* returnAddress; + + // Helper functions: + + Instance* instance() const { return tls->instance; } }; -static_assert(sizeof(Frame) == 2 * sizeof(void*), "?!"); -static const uint32_t FrameBytesAfterReturnAddress = sizeof(void*); +// A DebugFrame is a Frame with additional fields that are added after the +// normal function prologue by the baseline compiler. If a Module is compiled +// with debugging enabled, then all its code creates DebugFrames on the stack +// instead of just Frames. These extra fields are used by the Debugger API. + +class DebugFrame +{ + // The results field left uninitialized and only used during the baseline + // compiler's return sequence to allow the debugger to inspect and modify + // the return value of a frame being debugged. + union + { + int32_t resultI32_; + int64_t resultI64_; + float resultF32_; + double resultF64_; + }; + + // The returnValue() method returns a HandleValue pointing to this field. + js::Value cachedReturnJSValue_; + + // The function index of this frame. Technically, this could be derived + // given a PC into this frame (which could lookup the CodeRange which has + // the function index), but this isn't always readily available. + uint32_t funcIndex_; + + // Flags whose meaning are described below. + union + { + struct + { + bool observing_ : 1; + bool isDebuggee_ : 1; + bool prevUpToDate_ : 1; + bool hasCachedSavedFrame_ : 1; + bool hasCachedReturnJSValue_ : 1; + }; + void* flagsWord_; + }; + + // Padding so that DebugFrame has Alignment. +#if JS_BITS_PER_WORD == 32 + void* padding_; +#endif + + // The Frame goes at the end since the stack grows down. + Frame frame_; + + public: + Frame& frame() { return frame_; } + uint32_t funcIndex() const { return funcIndex_; } + Instance* instance() const { return frame_.instance(); } + GlobalObject* global() const; + JSObject* environmentChain() const; + bool getLocal(uint32_t localIndex, MutableHandleValue vp); + + // The return value must be written from the unboxed representation in the + // results union into cachedReturnJSValue_ by updateReturnJSValue() before + // returnValue() can return a Handle to it. + + void updateReturnJSValue(); + HandleValue returnValue() const; + void clearReturnJSValue(); + + // Once the debugger observes a frame, it must be notified via + // onLeaveFrame() before the frame is popped. Calling observe() ensures the + // leave frame traps are enabled. Both methods are idempotent so the caller + // doesn't have to worry about calling them more than once. + + void observe(JSContext* cx); + void leave(JSContext* cx); + + // The 'isDebugge' bit is initialized to false and set by the WebAssembly + // runtime right before a frame is exposed to the debugger, as required by + // the Debugger API. The bit is then used for Debugger-internal purposes + // afterwards. + + bool isDebuggee() const { return isDebuggee_; } + void setIsDebuggee() { isDebuggee_ = true; } + void unsetIsDebuggee() { isDebuggee_ = false; } + + // These are opaque boolean flags used by the debugger to implement + // AbstractFramePtr. They are initialized to false and not otherwise read or + // written by wasm code or runtime. + + bool prevUpToDate() const { return prevUpToDate_; } + void setPrevUpToDate() { prevUpToDate_ = true; } + void unsetPrevUpToDate() { prevUpToDate_ = false; } + + bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; } + void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; } + + // DebugFrame is accessed directly by JIT code. + + static constexpr size_t offsetOfResults() { return offsetof(DebugFrame, resultI32_); } + static constexpr size_t offsetOfFlagsWord() { return offsetof(DebugFrame, flagsWord_); } + static constexpr size_t offsetOfFuncIndex() { return offsetof(DebugFrame, funcIndex_); } + static constexpr size_t offsetOfFrame() { return offsetof(DebugFrame, frame_); } + + // DebugFrames are aligned to 8-byte aligned, allowing them to be placed in + // an AbstractFramePtr. + + static const unsigned Alignment = 8; + static void alignmentStaticAsserts(); +}; } // namespace wasm } // namespace js diff --git a/js/xpconnect/idl/xpccomponents.idl b/js/xpconnect/idl/xpccomponents.idl index 711ea4c64238..10c0537c801c 100644 --- a/js/xpconnect/idl/xpccomponents.idl +++ b/js/xpconnect/idl/xpccomponents.idl @@ -693,7 +693,7 @@ interface nsIXPCComponents_Utils : nsISupports * Interface for the 'Components' object. * * The first interface contains things that are available to non-chrome XBL code -* that runs in a scope with an nsExpandedPrincipal. The second interface +* that runs in a scope with an ExpandedPrincipal. The second interface * includes members that are only exposed to chrome. */ diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index d52c408660bc..4c1d884c3725 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -19,8 +19,8 @@ #include "nsIURI.h" #include "nsJSUtils.h" #include "nsNetUtil.h" -#include "nsNullPrincipal.h" -#include "nsExpandedPrincipal.h" +#include "NullPrincipal.h" +#include "ExpandedPrincipal.h" #include "WrapperFactory.h" #include "xpcprivate.h" #include "xpc_make_class.h" @@ -1049,7 +1049,7 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin if (sop) { principal = sop->GetPrincipal(); } else { - RefPtr nullPrin = nsNullPrincipal::Create(); + RefPtr nullPrin = NullPrincipal::Create(); principal = nullPrin; } } @@ -1439,8 +1439,8 @@ GetExpandedPrincipal(JSContext* cx, HandleObject arrayObj, } } - RefPtr result = - nsExpandedPrincipal::Create(allowedDomains, attrs.ref()); + RefPtr result = + ExpandedPrincipal::Create(allowedDomains, attrs.ref()); result.forget(out); return true; } @@ -1784,7 +1784,7 @@ nsXPCComponents_utils_Sandbox::CallOrConstruct(nsIXPConnectWrappedNative* wrappe } } else if (args[0].isNull()) { // Null means that we just pass prinOrSop = nullptr, and get an - // nsNullPrincipal. + // NullPrincipal. ok = true; } diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index ed33f230a735..81536d9b57b6 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -342,7 +342,7 @@ PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal) if (nsXPConnect::SecurityManager()->IsSystemPrincipal(aPrincipal)) return true; - // nsExpandedPrincipal gets a free pass. + // ExpandedPrincipal gets a free pass. nsCOMPtr ep = do_QueryInterface(aPrincipal); if (ep) return true; @@ -888,7 +888,7 @@ XPCJSContext::FinalizeCallback(JSFreeOp* fop, } /* static */ void -XPCJSContext::WeakPointerZoneGroupCallback(JSContext* cx, void* data) +XPCJSContext::WeakPointerZonesCallback(JSContext* cx, void* data) { // Called before each sweeping slice -- after processing any final marking // triggered by barriers -- to clear out any references to things that are @@ -1582,7 +1582,7 @@ XPCJSContext::~XPCJSContext() // callbacks if we aren't careful. Null out the relevant callbacks. js::SetActivityCallback(Context(), nullptr, nullptr); JS_RemoveFinalizeCallback(Context(), FinalizeCallback); - JS_RemoveWeakPointerZoneGroupCallback(Context(), WeakPointerZoneGroupCallback); + JS_RemoveWeakPointerZonesCallback(Context(), WeakPointerZonesCallback); JS_RemoveWeakPointerCompartmentCallback(Context(), WeakPointerCompartmentCallback); // Clear any pending exception. It might be an XPCWrappedJS, and if we try @@ -3502,7 +3502,7 @@ XPCJSContext::Initialize() mPrevDoCycleCollectionCallback = JS::SetDoCycleCollectionCallback(cx, DoCycleCollectionCallback); JS_AddFinalizeCallback(cx, FinalizeCallback, nullptr); - JS_AddWeakPointerZoneGroupCallback(cx, WeakPointerZoneGroupCallback, this); + JS_AddWeakPointerZonesCallback(cx, WeakPointerZonesCallback, this); JS_AddWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback, this); JS_SetWrapObjectCallbacks(cx, &WrapObjectCallbacks); js::SetPreserveWrapperCallback(cx, PreserveWrapper); diff --git a/js/xpconnect/src/XPCWrappedNativeScope.cpp b/js/xpconnect/src/XPCWrappedNativeScope.cpp index c3c87d76a795..be86e0878158 100644 --- a/js/xpconnect/src/XPCWrappedNativeScope.cpp +++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp @@ -10,7 +10,7 @@ #include "XPCWrapper.h" #include "nsContentUtils.h" #include "nsCycleCollectionNoteRootCallback.h" -#include "nsExpandedPrincipal.h" +#include "ExpandedPrincipal.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Preferences.h" #include "nsIAddonInterposition.h" @@ -290,14 +290,14 @@ XPCWrappedNativeScope::EnsureContentXBLScope(JSContext* cx) options.proto = global; options.sameZoneAs = global; - // Use an nsExpandedPrincipal to create asymmetric security. + // Use an ExpandedPrincipal to create asymmetric security. nsIPrincipal* principal = GetPrincipal(); MOZ_ASSERT(!nsContentUtils::IsExpandedPrincipal(principal)); nsTArray> principalAsArray(1); principalAsArray.AppendElement(principal); - RefPtr ep = - nsExpandedPrincipal::Create(principalAsArray, - principal->OriginAttributesRef()); + RefPtr ep = + ExpandedPrincipal::Create(principalAsArray, + principal->OriginAttributesRef()); // Create the sandbox. RootedValue v(cx); diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index b9145d73495d..9f2dbe04c208 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -538,7 +538,7 @@ public: JSFinalizeStatus status, bool isZoneGC, void* data); - static void WeakPointerZoneGroupCallback(JSContext* cx, void* data); + static void WeakPointerZonesCallback(JSContext* cx, void* data); static void WeakPointerCompartmentCallback(JSContext* cx, JSCompartment* comp, void* data); inline void AddVariantRoot(XPCTraceableVariant* variant); diff --git a/js/xpconnect/tests/chrome/test_bug996069.xul b/js/xpconnect/tests/chrome/test_bug996069.xul index f61003bb1baa..52e33c2ec10f 100644 --- a/js/xpconnect/tests/chrome/test_bug996069.xul +++ b/js/xpconnect/tests/chrome/test_bug996069.xul @@ -28,15 +28,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=996069 ifr.wrappedJSObject.finishTest = function() { // If we got here we did not hit the NS_ReleaseAssert... - ok(true, "nsExpandedPrincipal should not be inherited by content windows"); + ok(true, "ExpandedPrincipal should not be inherited by content windows"); // But let's be sure that the new window does not have nsEP newWin.wrappedJSObject.obj = Cu.evalInSandbox("var obj = { foo: 'bar' }; obj", sb); try { newWin.eval("obj.foo"); - ok(false, "newWin should not have access to object from a scope with nsExpandedPrincipal"); + ok(false, "newWin should not have access to object from a scope with ExpandedPrincipal"); } catch (e) { - ok(/Permission denied/.exec(e.message), "newWin should not have access to object from a scope with nsExpandedPrincipal"); + ok(/Permission denied/.exec(e.message), "newWin should not have access to object from a scope with ExpandedPrincipal"); } newWin.close(); SimpleTest.finish(); diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index a59b8f956911..0d516ccea7cc 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -82,11 +82,6 @@ #include "mozilla/dom/PerformanceTiming.h" #include "mozilla/layers/APZThreadUtils.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - - // Needed for Start/Stop of Image Animation #include "imgIContainer.h" #include "nsIImageLoadingContent.h" @@ -2230,19 +2225,12 @@ nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) if (!mShell) return; - bool usePlatformFontList = true; -#if defined(MOZ_WIDGET_GTK) - usePlatformFontList = gfxPlatformGtk::UseFcFontList(); -#endif - - // xxx - until the Linux platform font list is always used, use full - // restyle to force updates with gfxPangoFontGroup usage // Note: this method is called without a font when rules in the userfont set // are updated, which may occur during reflow as a result of the lazy // initialization of the userfont set. It would be better to avoid a full // restyle but until this method is only called outside of reflow, schedule a // full restyle in these cases. - if (!usePlatformFontList || !aUpdatedFont) { + if (!aUpdatedFont) { PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, eRestyle_ForceDescendants); return; } diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 064a0a2e184d..d6413ace24ea 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -131,9 +131,9 @@ using mozilla::dom::AudioChannelAgent; #include "nsTextServicesCID.h" #include "nsScriptSecurityManager.h" -#include "nsPrincipal.h" -#include "nsSystemPrincipal.h" -#include "nsNullPrincipal.h" +#include "ContentPrincipal.h" +#include "SystemPrincipal.h" +#include "NullPrincipal.h" #include "nsNetCID.h" #ifndef MOZ_WIDGET_GONK #if defined(MOZ_WIDGET_ANDROID) @@ -590,10 +590,10 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsCSPContext) NS_GENERIC_FACTORY_CONSTRUCTOR(CSPService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMixedContentBlocker) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsPrincipal) -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemPrincipal, +NS_GENERIC_FACTORY_CONSTRUCTOR(ContentPrincipal) +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemPrincipal, nsScriptSecurityManager::SystemPrincipalSingletonConstructor) -NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNullPrincipal, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NullPrincipal, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsStructuredCloneContainer) NS_GENERIC_FACTORY_CONSTRUCTOR(OSFileConstantsService) @@ -1027,9 +1027,9 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kNS_PARENTPROCESSMESSAGEMANAGER_CID, false, nullptr, CreateParentMessageManager }, { &kNS_CHILDPROCESSMESSAGEMANAGER_CID, false, nullptr, CreateChildMessageManager }, { &kNS_SCRIPTSECURITYMANAGER_CID, false, nullptr, Construct_nsIScriptSecurityManager }, - { &kNS_PRINCIPAL_CID, false, nullptr, nsPrincipalConstructor }, - { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, nsSystemPrincipalConstructor }, - { &kNS_NULLPRINCIPAL_CID, false, nullptr, nsNullPrincipalConstructor }, + { &kNS_PRINCIPAL_CID, false, nullptr, ContentPrincipalConstructor }, + { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, SystemPrincipalConstructor }, + { &kNS_NULLPRINCIPAL_CID, false, nullptr, NullPrincipalConstructor }, { &kNS_DEVICE_SENSORS_CID, false, nullptr, nsDeviceSensorsConstructor }, #ifndef MOZ_WIDGET_GONK #if defined(ANDROID) diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 3247ed29bb8e..e8e4826efb52 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -32,7 +32,7 @@ #include "nsImageFrame.h" #include "nsLayoutStylesheetCache.h" #include "mozilla/RuleProcessorCache.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "nsRange.h" #include "nsRegion.h" #include "nsRepeatService.h" @@ -270,7 +270,7 @@ nsLayoutStatics::Initialize() nsLayoutUtils::Initialize(); nsIPresShell::InitializeStatics(); TouchManager::InitializeStatics(); - nsPrincipal::InitializeStatics(); + ContentPrincipal::InitializeStatics(); nsCORSListenerProxy::Startup(); diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index a716601df3b9..ba49c928543e 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -838,9 +838,30 @@ public: nsIFrame* aSubFrame) const; /** - * Bounding rect of the frame. The values are in app units, and the origin is - * relative to the upper-left of the geometric parent. The size includes the - * content area, borders, and padding. + * Bounding rect of the frame. + * + * For frames that are laid out according to CSS box model rules the values + * are in app units, and the origin is relative to the upper-left of the + * geometric parent. The size includes the content area, borders, and + * padding. + * + * Frames that are laid out according to SVG's coordinate space based rules + * (frames with the NS_FRAME_SVG_LAYOUT bit set, which *excludes* + * nsSVGOuterSVGFrame) are different. Many frames of this type do not set or + * use mRect, in which case the frame rect is undefined. The exceptions are: + * + * - nsSVGInnerSVGFrame + * - SVGGeometryFrame (used for , , etc.) + * - nsSVGImageFrame + * - nsSVGForeignObjectFrame + * + * For these frames the frame rect contains the frame's element's userspace + * bounds including fill, stroke and markers, but converted to app units + * rather than being in user units (CSS px). In the SVG code "userspace" is + * defined to be the coordinate system for the attributes that define an + * element's geometry (such as the 'cx' attribute for ). For more + * precise details see these frames' implementations of the ReflowSVG method + * where mRect is set. * * Note: moving or sizing the frame does not affect the view's size or * position. diff --git a/layout/style/CSSStyleSheet.cpp b/layout/style/CSSStyleSheet.cpp index 84d0f7c9f476..6b1444c9e7d7 100644 --- a/layout/style/CSSStyleSheet.cpp +++ b/layout/style/CSSStyleSheet.cpp @@ -43,7 +43,7 @@ #include "nsDOMClassInfoID.h" #include "mozilla/Likely.h" #include "nsComponentManagerUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/RuleProcessorCache.h" #include "nsIStyleSheetLinkingElement.h" #include "nsDOMWindowUtils.h" diff --git a/layout/style/StyleSheet.cpp b/layout/style/StyleSheet.cpp index fdb901eb2e80..c0cc593b51dc 100644 --- a/layout/style/StyleSheet.cpp +++ b/layout/style/StyleSheet.cpp @@ -15,7 +15,7 @@ #include "mozAutoDocUpdate.h" #include "nsMediaList.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" namespace mozilla { @@ -202,7 +202,7 @@ StyleSheet::SetEnabled(bool aEnabled) StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy, const dom::SRIMetadata& aIntegrity) - : mPrincipal(nsNullPrincipal::Create()) + : mPrincipal(NullPrincipal::Create()) , mCORSMode(aCORSMode) , mReferrerPolicy(aReferrerPolicy) , mIntegrity(aIntegrity) @@ -212,7 +212,7 @@ StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode, #endif { if (!mPrincipal) { - NS_RUNTIMEABORT("nsNullPrincipal::Init failed"); + NS_RUNTIMEABORT("NullPrincipal::Init failed"); } } diff --git a/layout/svg/nsSVGFilterFrame.cpp b/layout/svg/nsSVGFilterFrame.cpp index 13ce16993d78..60817bd7d050 100644 --- a/layout/svg/nsSVGFilterFrame.cpp +++ b/layout/svg/nsSVGFilterFrame.cpp @@ -7,6 +7,7 @@ #include "nsSVGFilterFrame.h" // Keep others in (case-insensitive) order: +#include "AutoReferenceChainGuard.h" #include "gfxUtils.h" #include "nsGkAtoms.h" #include "nsSVGEffects.h" @@ -17,6 +18,7 @@ #include "nsSVGUtils.h" #include "nsContentUtils.h" +using namespace mozilla; using namespace mozilla::dom; nsIFrame* @@ -27,26 +29,6 @@ NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) NS_IMPL_FRAMEARENA_HELPERS(nsSVGFilterFrame) -class MOZ_RAII nsSVGFilterFrame::AutoFilterReferencer -{ -public: - explicit AutoFilterReferencer(nsSVGFilterFrame *aFrame MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mFrame(aFrame) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - // Reference loops should normally be detected in advance and handled, so - // we're not expecting to encounter them here - MOZ_ASSERT(!mFrame->mLoopFlag, "Undetected reference loop!"); - mFrame->mLoopFlag = true; - } - ~AutoFilterReferencer() { - mFrame->mLoopFlag = false; - } -private: - nsSVGFilterFrame *mFrame; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - uint16_t nsSVGFilterFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault) { @@ -56,12 +38,22 @@ nsSVGFilterFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault) if (thisEnum.IsExplicitlySet()) return thisEnum.GetAnimValue(); - AutoFilterReferencer filterRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return static_cast(aDefault)-> + mEnumAttributes[aIndex].GetAnimValue(); + } - nsSVGFilterFrame *next = GetReferencedFilterIfNotInUse(); - return next ? next->GetEnumValue(aIndex, aDefault) : - static_cast(aDefault)-> - mEnumAttributes[aIndex].GetAnimValue(); + nsSVGFilterFrame *next = GetReferencedFilter(); + + return next ? next->GetEnumValue(aIndex, aDefault) + : static_cast(aDefault)-> + mEnumAttributes[aIndex].GetAnimValue(); } const nsSVGLength2 * @@ -73,11 +65,20 @@ nsSVGFilterFrame::GetLengthValue(uint32_t aIndex, nsIContent *aDefault) if (thisLength->IsExplicitlySet()) return thisLength; - AutoFilterReferencer filterRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return &static_cast(aDefault)->mLengthAttributes[aIndex]; + } - nsSVGFilterFrame *next = GetReferencedFilterIfNotInUse(); - return next ? next->GetLengthValue(aIndex, aDefault) : - &static_cast(aDefault)->mLengthAttributes[aIndex]; + nsSVGFilterFrame *next = GetReferencedFilter(); + + return next ? next->GetLengthValue(aIndex, aDefault) + : &static_cast(aDefault)->mLengthAttributes[aIndex]; } const SVGFilterElement * @@ -93,11 +94,20 @@ nsSVGFilterFrame::GetFilterContent(nsIContent *aDefault) } } - AutoFilterReferencer filterRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return static_cast(aDefault); + } - nsSVGFilterFrame *next = GetReferencedFilterIfNotInUse(); - return next ? next->GetFilterContent(aDefault) : - static_cast(aDefault); + nsSVGFilterFrame *next = GetReferencedFilter(); + + return next ? next->GetFilterContent(aDefault) + : static_cast(aDefault); } nsSVGFilterFrame * @@ -150,22 +160,6 @@ nsSVGFilterFrame::GetReferencedFilter() return static_cast(result); } -nsSVGFilterFrame * -nsSVGFilterFrame::GetReferencedFilterIfNotInUse() -{ - nsSVGFilterFrame *referenced = GetReferencedFilter(); - if (!referenced) - return nullptr; - - if (referenced->mLoopFlag) { - // XXXjwatt: we should really send an error to the JavaScript Console here: - NS_WARNING("Filter reference loop detected while inheriting attribute!"); - return nullptr; - } - - return referenced; -} - nsresult nsSVGFilterFrame::AttributeChanged(int32_t aNameSpaceID, nsIAtom* aAttribute, diff --git a/layout/svg/nsSVGFilterFrame.h b/layout/svg/nsSVGFilterFrame.h index 223c787f6e85..eac06ce7c9ec 100644 --- a/layout/svg/nsSVGFilterFrame.h +++ b/layout/svg/nsSVGFilterFrame.h @@ -69,10 +69,8 @@ private: // Parse our xlink:href and set up our nsSVGPaintingProperty if we // reference another filter and we don't have a property. Return // the referenced filter's frame if available, null otherwise. - class AutoFilterReferencer; friend class nsSVGFilterInstance; nsSVGFilterFrame* GetReferencedFilter(); - nsSVGFilterFrame* GetReferencedFilterIfNotInUse(); // Accessors to lookup filter attributes uint16_t GetEnumValue(uint32_t aIndex, nsIContent *aDefault); diff --git a/layout/svg/nsSVGGradientFrame.cpp b/layout/svg/nsSVGGradientFrame.cpp index e3b627ea102c..f6eaf174a986 100644 --- a/layout/svg/nsSVGGradientFrame.cpp +++ b/layout/svg/nsSVGGradientFrame.cpp @@ -8,6 +8,7 @@ #include // Keep others in (case-insensitive) order: +#include "AutoReferenceChainGuard.h" #include "gfxPattern.h" #include "mozilla/dom/SVGGradientElement.h" #include "mozilla/dom/SVGStopElement.h" @@ -21,30 +22,6 @@ using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::gfx; -//---------------------------------------------------------------------- -// Helper classes - -class MOZ_RAII nsSVGGradientFrame::AutoGradientReferencer -{ -public: - explicit AutoGradientReferencer(nsSVGGradientFrame *aFrame - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mFrame(aFrame) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - // Reference loops should normally be detected in advance and handled, so - // we're not expecting to encounter them here - MOZ_ASSERT(!mFrame->mLoopFlag, "Undetected reference loop!"); - mFrame->mLoopFlag = true; - } - ~AutoGradientReferencer() { - mFrame->mLoopFlag = false; - } -private: - nsSVGGradientFrame *mFrame; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - //---------------------------------------------------------------------- // Implementation @@ -93,12 +70,22 @@ nsSVGGradientFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault) if (thisEnum.IsExplicitlySet()) return thisEnum.GetAnimValue(); - AutoGradientReferencer gradientRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return static_cast(aDefault)-> + mEnumAttributes[aIndex].GetAnimValue(); + } - nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse(); - return next ? next->GetEnumValue(aIndex, aDefault) : - static_cast(aDefault)-> - mEnumAttributes[aIndex].GetAnimValue(); + nsSVGGradientFrame *next = GetReferencedGradient(); + + return next ? next->GetEnumValue(aIndex, aDefault) + : static_cast(aDefault)-> + mEnumAttributes[aIndex].GetAnimValue(); } uint16_t @@ -123,12 +110,22 @@ nsSVGGradientFrame::GetGradientTransformList(nsIContent* aDefault) if (thisTransformList && thisTransformList->IsExplicitlySet()) return thisTransformList; - AutoGradientReferencer gradientRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return static_cast(aDefault)-> + mGradientTransform.get(); + } - nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse(); - return next ? next->GetGradientTransformList(aDefault) : - static_cast(aDefault) - ->mGradientTransform.get(); + nsSVGGradientFrame *next = GetReferencedGradient(); + + return next ? next->GetGradientTransformList(aDefault) + : static_cast(aDefault)-> + mGradientTransform.get(); } gfxMatrix @@ -167,9 +164,17 @@ nsSVGGradientFrame::GetLinearGradientWithLength(uint32_t aIndex, // already found it in nsSVGLinearGradientFrame::GetLinearGradientWithLength. // Since we didn't find the length, continue looking down the chain. - AutoGradientReferencer gradientRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return aDefault; + } - nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse(); + nsSVGGradientFrame *next = GetReferencedGradient(); return next ? next->GetLinearGradientWithLength(aIndex, aDefault) : aDefault; } @@ -181,9 +186,17 @@ nsSVGGradientFrame::GetRadialGradientWithLength(uint32_t aIndex, // already found it in nsSVGRadialGradientFrame::GetRadialGradientWithLength. // Since we didn't find the length, continue looking down the chain. - AutoGradientReferencer gradientRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return aDefault; + } - nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse(); + nsSVGGradientFrame *next = GetReferencedGradient(); return next ? next->GetRadialGradientWithLength(aIndex, aDefault) : aDefault; } @@ -362,22 +375,6 @@ nsSVGGradientFrame::GetReferencedGradient() return static_cast(result); } -nsSVGGradientFrame * -nsSVGGradientFrame::GetReferencedGradientIfNotInUse() -{ - nsSVGGradientFrame *referenced = GetReferencedGradient(); - if (!referenced) - return nullptr; - - if (referenced->mLoopFlag) { - // XXXjwatt: we should really send an error to the JavaScript Console here: - NS_WARNING("gradient reference loop detected while inheriting attribute!"); - return nullptr; - } - - return referenced; -} - void nsSVGGradientFrame::GetStopFrames(nsTArray* aStopFrames) { @@ -394,13 +391,20 @@ nsSVGGradientFrame::GetStopFrames(nsTArray* aStopFrames) // Our gradient element doesn't have stops - try to "inherit" them - AutoGradientReferencer gradientRef(this); - nsSVGGradientFrame* next = GetReferencedGradientIfNotInUse(); - if (!next) { + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain return; } - return next->GetStopFrames(aStopFrames); + nsSVGGradientFrame* next = GetReferencedGradient(); + if (next) { + next->GetStopFrames(aStopFrames); + } } // ------------------------------------------------------------------------- diff --git a/layout/svg/nsSVGGradientFrame.h b/layout/svg/nsSVGGradientFrame.h index f12b132533a3..c9bc6c2ca5d4 100644 --- a/layout/svg/nsSVGGradientFrame.h +++ b/layout/svg/nsSVGGradientFrame.h @@ -86,10 +86,6 @@ protected: virtual bool GradientVectorLengthIsZero() = 0; virtual already_AddRefed CreateGradient() = 0; - // Internal methods for handling referenced gradients - class AutoGradientReferencer; - nsSVGGradientFrame* GetReferencedGradientIfNotInUse(); - // Accessors to lookup gradient attributes uint16_t GetEnumValue(uint32_t aIndex, nsIContent *aDefault); uint16_t GetEnumValue(uint32_t aIndex) diff --git a/layout/svg/nsSVGMaskFrame.cpp b/layout/svg/nsSVGMaskFrame.cpp index a9887e57348c..47346d0f5ecd 100644 --- a/layout/svg/nsSVGMaskFrame.cpp +++ b/layout/svg/nsSVGMaskFrame.cpp @@ -7,6 +7,7 @@ #include "nsSVGMaskFrame.h" // Keep others in (case-insensitive) order: +#include "AutoReferenceChainGuard.h" #include "gfx2DGlue.h" #include "gfxContext.h" #include "mozilla/gfx/2D.h" @@ -204,14 +205,14 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSVGMaskFrame) mozilla::Pair> nsSVGMaskFrame::GetMaskForMaskedFrame(MaskParams& aParams) { - // If the flag is set when we get here, it means this mask frame - // has already been used painting the current mask, and the document - // has a mask reference loop. - if (mInUse) { - NS_WARNING("Mask loop detected!"); + // Make sure we break reference loops and over long reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mInUse, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain return MakePair(DrawResult::SUCCESS, RefPtr()); } - AutoMaskReferencer maskRef(this); gfxRect maskArea = GetMaskArea(aParams.maskedFrame); gfxContext* context = aParams.ctx; diff --git a/layout/svg/nsSVGMaskFrame.h b/layout/svg/nsSVGMaskFrame.h index 40ba0b555af0..32c23ad083d9 100644 --- a/layout/svg/nsSVGMaskFrame.h +++ b/layout/svg/nsSVGMaskFrame.h @@ -111,28 +111,6 @@ private: */ gfxMatrix GetMaskTransform(nsIFrame* aMaskedFrame); - // A helper class to allow us to paint masks safely. The helper - // automatically sets and clears the mInUse flag on the mask frame - // (to prevent nasty reference loops). It's easy to mess this up - // and break things, so this helper makes the code far more robust. - class MOZ_RAII AutoMaskReferencer - { - public: - explicit AutoMaskReferencer(nsSVGMaskFrame *aFrame - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mFrame(aFrame) { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - NS_ASSERTION(!mFrame->mInUse, "reference loop!"); - mFrame->mInUse = true; - } - ~AutoMaskReferencer() { - mFrame->mInUse = false; - } - private: - nsSVGMaskFrame *mFrame; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER - }; - gfxMatrix mMatrixForChildren; // recursion prevention flag bool mInUse; diff --git a/layout/svg/nsSVGPatternFrame.cpp b/layout/svg/nsSVGPatternFrame.cpp index 67f0abf8bc68..68cf1fd775e8 100644 --- a/layout/svg/nsSVGPatternFrame.cpp +++ b/layout/svg/nsSVGPatternFrame.cpp @@ -7,6 +7,7 @@ #include "nsSVGPatternFrame.h" // Keep others in (case-insensitive) order: +#include "AutoReferenceChainGuard.h" #include "gfx2DGlue.h" #include "gfxContext.h" #include "gfxMatrix.h" @@ -29,30 +30,6 @@ using namespace mozilla::dom; using namespace mozilla::gfx; using namespace mozilla::image; -//---------------------------------------------------------------------- -// Helper classes - -class MOZ_RAII nsSVGPatternFrame::AutoPatternReferencer -{ -public: - explicit AutoPatternReferencer(nsSVGPatternFrame *aFrame - MOZ_GUARD_OBJECT_NOTIFIER_PARAM) - : mFrame(aFrame) - { - MOZ_GUARD_OBJECT_NOTIFIER_INIT; - // Reference loops should normally be detected in advance and handled, so - // we're not expecting to encounter them here - MOZ_ASSERT(!mFrame->mLoopFlag, "Undetected reference loop!"); - mFrame->mLoopFlag = true; - } - ~AutoPatternReferencer() { - mFrame->mLoopFlag = false; - } -private: - nsSVGPatternFrame *mFrame; - MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER -}; - //---------------------------------------------------------------------- // Implementation @@ -443,9 +420,18 @@ nsSVGPatternFrame::GetPatternWithChildren() return this; // No, see if we chain to someone who does - AutoPatternReferencer patternRef(this); - nsSVGPatternFrame* next = GetReferencedPatternIfNotInUse(); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return nullptr; + } + + nsSVGPatternFrame* next = GetReferencedPattern(); if (!next) return nullptr; @@ -461,12 +447,21 @@ nsSVGPatternFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault) if (thisEnum.IsExplicitlySet()) return thisEnum.GetAnimValue(); - AutoPatternReferencer patternRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return static_cast(aDefault)-> + mEnumAttributes[aIndex].GetAnimValue(); + } - nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse(); - return next ? next->GetEnumValue(aIndex, aDefault) : - static_cast(aDefault)-> - mEnumAttributes[aIndex].GetAnimValue(); + nsSVGPatternFrame *next = GetReferencedPattern(); + return next ? next->GetEnumValue(aIndex, aDefault) + : static_cast(aDefault)-> + mEnumAttributes[aIndex].GetAnimValue(); } nsSVGAnimatedTransformList* @@ -478,11 +473,19 @@ nsSVGPatternFrame::GetPatternTransformList(nsIContent* aDefault) if (thisTransformList && thisTransformList->IsExplicitlySet()) return thisTransformList; - AutoPatternReferencer patternRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return static_cast(aDefault)->mPatternTransform.get(); + } - nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse(); - return next ? next->GetPatternTransformList(aDefault) : - static_cast(aDefault)->mPatternTransform.get(); + nsSVGPatternFrame *next = GetReferencedPattern(); + return next ? next->GetPatternTransformList(aDefault) + : static_cast(aDefault)->mPatternTransform.get(); } gfxMatrix @@ -505,11 +508,19 @@ nsSVGPatternFrame::GetViewBox(nsIContent* aDefault) if (thisViewBox.IsExplicitlySet()) return thisViewBox; - AutoPatternReferencer patternRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return static_cast(aDefault)->mViewBox; + } - nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse(); - return next ? next->GetViewBox(aDefault) : - static_cast(aDefault)->mViewBox; + nsSVGPatternFrame *next = GetReferencedPattern(); + return next ? next->GetViewBox(aDefault) + : static_cast(aDefault)->mViewBox; } const SVGAnimatedPreserveAspectRatio & @@ -521,11 +532,19 @@ nsSVGPatternFrame::GetPreserveAspectRatio(nsIContent *aDefault) if (thisPar.IsExplicitlySet()) return thisPar; - AutoPatternReferencer patternRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return static_cast(aDefault)->mPreserveAspectRatio; + } - nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse(); - return next ? next->GetPreserveAspectRatio(aDefault) : - static_cast(aDefault)->mPreserveAspectRatio; + nsSVGPatternFrame *next = GetReferencedPattern(); + return next ? next->GetPreserveAspectRatio(aDefault) + : static_cast(aDefault)->mPreserveAspectRatio; } const nsSVGLength2 * @@ -537,11 +556,19 @@ nsSVGPatternFrame::GetLengthValue(uint32_t aIndex, nsIContent *aDefault) if (thisLength->IsExplicitlySet()) return thisLength; - AutoPatternReferencer patternRef(this); + // Before we recurse, make sure we'll break reference loops and over long + // reference chains: + static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain; + AutoReferenceChainGuard refChainGuard(this, &mLoopFlag, + &sRefChainLengthCounter); + if (MOZ_UNLIKELY(!refChainGuard.Reference())) { + // Break reference chain + return &static_cast(aDefault)->mLengthAttributes[aIndex]; + } - nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse(); - return next ? next->GetLengthValue(aIndex, aDefault) : - &static_cast(aDefault)->mLengthAttributes[aIndex]; + nsSVGPatternFrame *next = GetReferencedPattern(); + return next ? next->GetLengthValue(aIndex, aDefault) + : &static_cast(aDefault)->mLengthAttributes[aIndex]; } // Private (helper) methods @@ -595,22 +622,6 @@ nsSVGPatternFrame::GetReferencedPattern() return static_cast(result); } -nsSVGPatternFrame * -nsSVGPatternFrame::GetReferencedPatternIfNotInUse() -{ - nsSVGPatternFrame *referenced = GetReferencedPattern(); - if (!referenced) - return nullptr; - - if (referenced->mLoopFlag) { - // XXXjwatt: we should really send an error to the JavaScript Console here: - NS_WARNING("pattern reference loop detected while inheriting attribute!"); - return nullptr; - } - - return referenced; -} - gfxRect nsSVGPatternFrame::GetPatternRect(uint16_t aPatternUnits, const gfxRect &aTargetBBox, diff --git a/layout/svg/nsSVGPatternFrame.h b/layout/svg/nsSVGPatternFrame.h index 5182e55385eb..3443d630f3c7 100644 --- a/layout/svg/nsSVGPatternFrame.h +++ b/layout/svg/nsSVGPatternFrame.h @@ -81,9 +81,7 @@ public: protected: // Internal methods for handling referenced patterns - class AutoPatternReferencer; nsSVGPatternFrame* GetReferencedPattern(); - nsSVGPatternFrame* GetReferencedPatternIfNotInUse(); // Accessors to lookup pattern attributes uint16_t GetEnumValue(uint32_t aIndex, nsIContent *aDefault); diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index 2ee486e90188..d65ceda2ec6b 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -74,7 +74,7 @@ #include "nsIURLParser.h" #include "nsIDOMDataChannel.h" #include "nsIDOMLocation.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/PeerIdentity.h" #include "mozilla/dom/RTCCertificate.h" #include "mozilla/dom/RTCConfigurationBinding.h" @@ -1877,7 +1877,7 @@ PeerConnectionImpl::CreateNewRemoteTracks(RefPtr& aPco) } else { // we're either certain that we need isolation for the streams, OR // we're not sure and we can fix the stream in SetDtlsConnected - principal = nsNullPrincipal::CreateWithInheritedAttributes(doc->NodePrincipal()); + principal = NullPrincipal::CreateWithInheritedAttributes(doc->NodePrincipal()); } // We need to select unique ids, just use max + 1 diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java index 7bf6aac376c9..42db038390f4 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java @@ -1157,6 +1157,10 @@ public abstract class GeckoApp enableStrictMode(); } + // Mozglue should already be loaded by BrowserApp.onCreate() in Fennec, but in + // custom tabs it may not be. + GeckoLoader.loadMozGlue(getApplicationContext()); + if (!HardwareUtils.isSupportedSystem() || !GeckoLoader.neonCompatible()) { // This build does not support the Android version of the device: Show an error and finish the app. mIsAbortingAppLaunch = true; diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index edeea402fe3f..da28a1d79860 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -818,7 +818,11 @@ pref("gfx.logging.peak-texture-usage.enabled", false); pref("gfx.ycbcr.accurate-conversion", false); +#ifdef MOZ_ENABLE_WEBRENDER pref("gfx.webrender.enabled", true); +#else +pref("gfx.webrender.enabled", false); +#endif pref("accessibility.browsewithcaret", false); pref("accessibility.warn_on_browsewithcaret", true); @@ -4204,13 +4208,7 @@ pref("intl.ime.use_simple_context_on_password_field", true); pref("intl.ime.use_simple_context_on_password_field", false); #endif -# enable new platform fontlist for linux on GTK platforms -# temporary pref to allow flipping back to the existing -# gfxPangoFontGroup/gfxFontconfigUtils code for handling system fonts - #ifdef MOZ_WIDGET_GTK -pref("gfx.font_rendering.fontconfig.fontlist.enabled", true); - // maximum number of fonts to substitute for a generic pref("gfx.font_rendering.fontconfig.max_generic_substitutions", 3); #endif diff --git a/modules/libpref/moz.build b/modules/libpref/moz.build index cd8b526bc93e..4cfa17fb8a9d 100644 --- a/modules/libpref/moz.build +++ b/modules/libpref/moz.build @@ -45,6 +45,8 @@ FINAL_LIBRARY = 'xul' DEFINES['OS_ARCH'] = CONFIG['OS_ARCH'] DEFINES['MOZ_WIDGET_TOOLKIT'] = CONFIG['MOZ_WIDGET_TOOLKIT'] +if CONFIG['MOZ_ENABLE_WEBRENDER']: + DEFINES['MOZ_ENABLE_WEBRENDER'] = True FINAL_TARGET_PP_FILES += [ 'greprefs.js', diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index a11a35c3c314..c9992f812346 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -21,7 +21,7 @@ #include "nsContentUtils.h" #include "nsDocShell.h" #include "nsGlobalWindow.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" using namespace mozilla::dom; @@ -465,10 +465,10 @@ LoadInfo::GetSandboxedLoadingPrincipal(nsIPrincipal** aPrincipal) if (!mSandboxedLoadingPrincipal) { if (mLoadingPrincipal) { mSandboxedLoadingPrincipal = - nsNullPrincipal::CreateWithInheritedAttributes(mLoadingPrincipal); + NullPrincipal::CreateWithInheritedAttributes(mLoadingPrincipal); } else { OriginAttributes attrs(mOriginAttributes); - mSandboxedLoadingPrincipal = nsNullPrincipal::Create(attrs); + mSandboxedLoadingPrincipal = NullPrincipal::Create(attrs); } } MOZ_ASSERT(mSandboxedLoadingPrincipal); @@ -717,7 +717,7 @@ LoadInfo::ResetPrincipalsToNullPrincipal() // take the originAttributes from the LoadInfo and create // a new NullPrincipal using those origin attributes. nsCOMPtr newNullPrincipal = - nsNullPrincipal::Create(mOriginAttributes); + NullPrincipal::Create(mOriginAttributes); MOZ_ASSERT(mInternalContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT || !mLoadingPrincipal, diff --git a/netwerk/base/nsIURI.idl b/netwerk/base/nsIURI.idl index ef163813aa37..2b903141921e 100644 --- a/netwerk/base/nsIURI.idl +++ b/netwerk/base/nsIURI.idl @@ -63,7 +63,7 @@ * old (pre-gecko6) nsIURI IID and swap in the current IID instead, in order * for sessionstore to work after an upgrade. If this IID is revved further, * we will need to add additional checks there for all intermediate IIDs, until - * nsPrincipal is fixed to serialize its URIs as nsISupports (bug 662693). + * ContentPrincipal is fixed to serialize its URIs as nsISupports (bug 662693). */ [scriptable, uuid(92073a54-6d78-4f30-913a-b871813208c6)] interface nsIURI : nsISupports diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index 07a1da5f824c..2c8e98e2ae39 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -41,7 +41,7 @@ #include "SerializedLoadContext.h" #include "nsAuthInformationHolder.h" #include "nsIAuthPromptCallback.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "nsINetworkPredictor.h" #include "nsINetworkPredictorVerifier.h" #include "nsISpeculativeConnect.h" diff --git a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp index 61c9d7fc1b1f..d120890338a1 100644 --- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp +++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp @@ -41,7 +41,7 @@ #include "nsISocketTransportService.h" #include "nsIURI.h" #include "nsILoadInfo.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIAuthPrompt2.h" #include "nsIFTPChannelParentInternal.h" diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index d6579e14858e..69e61bbbcc41 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -39,7 +39,7 @@ #include "nsIDOMWindowUtils.h" #include "nsIDOMWindow.h" #include "nsINetworkInterceptController.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsICorsPreflightCallback.h" #include "nsISupportsImpl.h" #include "mozilla/LoadInfo.h" @@ -762,7 +762,7 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel, if (NS_SUCCEEDED(rv) && !equal) { // Spec says to set our source origin to a unique origin. mOriginHeaderPrincipal = - nsNullPrincipal::CreateWithInheritedAttributes(oldChannelPrincipal); + NullPrincipal::CreateWithInheritedAttributes(oldChannelPrincipal); } } diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index f6ce07f4d8ac..3d466d63799b 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -92,7 +92,7 @@ #include "nsIHttpPushListener.h" #include "nsIX509Cert.h" #include "ScopedNSSTypes.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIDeprecationWarner.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" diff --git a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp index 324aae069e5a..cfa4eceff625 100644 --- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp +++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp @@ -11,7 +11,7 @@ #include "nsContentUtils.h" #include "nsIHttpHeaderVisitor.h" #include "nsContentSecurityManager.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsServiceManagerUtils.h" #include "nsIInputStreamChannel.h" #include "mozilla/DebugOnly.h" @@ -67,7 +67,7 @@ nsViewSourceChannel::Init(nsIURI* uri) // Until then we follow the principal of least privilege and use // nullPrincipal as the loadingPrincipal and the least permissive // securityflag. - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); rv = pService->NewChannel2(path, nullptr, // aOriginCharset diff --git a/parser/html/nsParserUtils.cpp b/parser/html/nsParserUtils.cpp index 6e9b9c296fb0..bf4ca6546b6f 100644 --- a/parser/html/nsParserUtils.cpp +++ b/parser/html/nsParserUtils.cpp @@ -36,7 +36,7 @@ #include "nsTreeSanitizer.h" #include "nsHtml5Module.h" #include "mozilla/dom/DocumentFragment.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #define XHTML_DIV_TAG "div xmlns=\"http://www.w3.org/1999/xhtml\"" @@ -76,7 +76,7 @@ nsParserUtils::Sanitize(const nsAString& aFromStr, { nsCOMPtr uri; NS_NewURI(getter_AddRefs(uri), "about:blank"); - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); nsCOMPtr domDocument; nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument), EmptyString(), diff --git a/parser/htmlparser/nsExpatDriver.cpp b/parser/htmlparser/nsExpatDriver.cpp index df4bfbb96052..eb3e16ce83ec 100644 --- a/parser/htmlparser/nsExpatDriver.cpp +++ b/parser/htmlparser/nsExpatDriver.cpp @@ -27,7 +27,7 @@ #include "nsXPCOMCIDInternal.h" #include "nsUnicharInputStream.h" #include "nsContentUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/Logging.h" #include "mozilla/SizePrintfMacros.h" @@ -793,7 +793,7 @@ nsExpatDriver::OpenInputStreamFromExternalDTD(const char16_t* aFPIStr, } } if (!loadingPrincipal) { - loadingPrincipal = nsNullPrincipal::Create(); + loadingPrincipal = NullPrincipal::Create(); } rv = NS_NewChannel(getter_AddRefs(channel), uri, diff --git a/parser/xml/nsSAXXMLReader.cpp b/parser/xml/nsSAXXMLReader.cpp index a84e0d63ba91..363f7bfea2e2 100644 --- a/parser/xml/nsSAXXMLReader.cpp +++ b/parser/xml/nsSAXXMLReader.cpp @@ -6,7 +6,7 @@ #include "nsIInputStream.h" #include "nsNetCID.h" #include "nsNetUtil.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIParser.h" #include "nsParserCIID.h" #include "nsStreamUtils.h" @@ -496,7 +496,7 @@ nsSAXXMLReader::ParseFromStream(nsIInputStream *aStream, rv = EnsureBaseURI(); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); // The following channel is never openend, so it does not matter what // securityFlags we pass; let's follow the principle of least privilege. diff --git a/python/mozbuild/mozbuild/mach_commands.py b/python/mozbuild/mozbuild/mach_commands.py index 4ae31ba3d79d..6f9323be70fa 100644 --- a/python/mozbuild/mozbuild/mach_commands.py +++ b/python/mozbuild/mozbuild/mach_commands.py @@ -210,6 +210,8 @@ class BuildOutputManager(LoggingMixin): # TODO convert terminal footer to config file setting. if not terminal or os.environ.get('MACH_NO_TERMINAL_FOOTER', None): return + if os.environ.get('INSIDE_EMACS', None): + return self.t = terminal self.footer = BuildProgressFooter(terminal, monitor) diff --git a/rdf/base/nsRDFXMLParser.cpp b/rdf/base/nsRDFXMLParser.cpp index f8237356bd3b..6975522ef0c4 100644 --- a/rdf/base/nsRDFXMLParser.cpp +++ b/rdf/base/nsRDFXMLParser.cpp @@ -13,7 +13,7 @@ #include "nsParserCIID.h" #include "nsStringStream.h" #include "nsNetUtil.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" static NS_DEFINE_CID(kParserCID, NS_PARSER_CID); @@ -113,7 +113,7 @@ nsRDFXMLParser::ParseString(nsIRDFDataSource* aSink, nsIURI* aBaseURI, const nsA rv = NS_NewCStringInputStream(getter_AddRefs(stream), aString); if (NS_FAILED(rv)) return rv; - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); // The following channel is never openend, so it does not matter what // securityFlags we pass; let's follow the principle of least privilege. diff --git a/testing/mozbase/mozprofile/mozprofile/permissions.py b/testing/mozbase/mozprofile/mozprofile/permissions.py index ea13d96f021c..2a0754c1be0a 100644 --- a/testing/mozbase/mozprofile/mozprofile/permissions.py +++ b/testing/mozbase/mozprofile/mozprofile/permissions.py @@ -274,9 +274,10 @@ class Permissions(object): permission_type = 2 if using_origin: - # This is a crude approximation of the origin generation logic from - # nsPrincipal and nsStandardURL. It should suffice for the permissions - # which the test runners will want to insert into the system. + # This is a crude approximation of the origin generation + # logic from ContentPrincipal and nsStandardURL. It should + # suffice for the permissions which the test runners will + # want to insert into the system. origin = location.scheme + "://" + location.host if (location.scheme != 'http' or location.port != '80') and \ (location.scheme != 'https' or location.port != '443'): diff --git a/testing/web-platform/tests/XMLHttpRequest/event-readystatechange-loaded.htm b/testing/web-platform/tests/XMLHttpRequest/event-readystatechange-loaded.htm index de6debe6babc..452efafae9f7 100644 --- a/testing/web-platform/tests/XMLHttpRequest/event-readystatechange-loaded.htm +++ b/testing/web-platform/tests/XMLHttpRequest/event-readystatechange-loaded.htm @@ -24,7 +24,7 @@ test.step(function() { } if (client.readyState === 4) { - assert_equals(countedLoading, 10, "LOADING state change may be emitted multiple times"); + assert_greater_than(countedLoading, 1, "LOADING state change may be emitted multiple times"); test.done(); } diff --git a/toolkit/components/places/nsFaviconService.cpp b/toolkit/components/places/nsFaviconService.cpp index 42526b285724..2bf6672d17c4 100644 --- a/toolkit/components/places/nsFaviconService.cpp +++ b/toolkit/components/places/nsFaviconService.cpp @@ -31,7 +31,7 @@ #include "nsILoadInfo.h" #include "nsIContentPolicy.h" #include "nsContentUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" // For large favicons optimization. #include "imgITools.h" @@ -240,7 +240,7 @@ nsFaviconService::SetAndFetchFaviconForPage(nsIURI* aPageURI, nsContentUtils::eNECKO_PROPERTIES, "APIDeprecationWarning", params, ArrayLength(params)); - loadingPrincipal = nsNullPrincipal::Create(); + loadingPrincipal = NullPrincipal::Create(); } NS_ENSURE_TRUE(loadingPrincipal, NS_ERROR_FAILURE); @@ -402,7 +402,7 @@ nsFaviconService::ReplaceFaviconDataFromDataURL(nsIURI* aFaviconURI, "APIDeprecationWarning", params, ArrayLength(params)); - loadingPrincipal = nsNullPrincipal::Create(); + loadingPrincipal = NullPrincipal::Create(); } NS_ENSURE_TRUE(loadingPrincipal, NS_ERROR_FAILURE); diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index d47990c02011..a507af218cfd 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -1444,6 +1444,16 @@ "n_buckets": 100, "description": "Time spent decoding an image (us)" }, + "IMAGE_ANIMATED_DECODE_TIME": { + "alert_emails": ["gfx-telemetry-alerts@mozilla.com"], + "bug_numbers": [1347302], + "expires_in_version": "57", + "kind": "exponential", + "low": 50, + "high": 50000000, + "n_buckets": 100, + "description": "Time spent decoding an animated image (us)" + }, "IMAGE_DECODE_ON_DRAW_LATENCY": { "expires_in_version": "never", "kind": "exponential", @@ -1452,6 +1462,16 @@ "n_buckets": 100, "description": "Time from starting a decode to it showing up on the screen (us)" }, + "IMAGE_ANIMATED_DECODE_ON_DRAW_LATENCY": { + "alert_emails": ["gfx-telemetry-alerts@mozilla.com"], + "bug_numbers": [1347302], + "expires_in_version": "57", + "kind": "exponential", + "low": 50, + "high": 50000000, + "n_buckets": 100, + "description": "Time from starting a decode of an animated image to it showing up on the screen (us)" + }, "IMAGE_DECODE_CHUNKS": { "expires_in_version": "never", "kind": "exponential", @@ -1466,6 +1486,15 @@ "n_buckets": 50, "description": "Decode count" }, + "IMAGE_ANIMATED_DECODE_COUNT": { + "alert_emails": ["gfx-telemetry-alerts@mozilla.com"], + "bug_numbers": [1347302], + "expires_in_version": "57", + "kind": "exponential", + "high": 500, + "n_buckets": 50, + "description": "Decode count of animated images" + }, "IMAGE_DECODE_SPEED_JPEG": { "expires_in_version": "never", "kind": "exponential", diff --git a/toolkit/components/telemetry/TelemetrySession.jsm b/toolkit/components/telemetry/TelemetrySession.jsm index f9542729f715..42bd06448097 100644 --- a/toolkit/components/telemetry/TelemetrySession.jsm +++ b/toolkit/components/telemetry/TelemetrySession.jsm @@ -17,7 +17,6 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); Cu.import("resource://gre/modules/Promise.jsm", this); Cu.import("resource://gre/modules/DeferredTask.jsm", this); Cu.import("resource://gre/modules/Preferences.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/Timer.jsm"); Cu.import("resource://gre/modules/TelemetrySend.jsm", this); Cu.import("resource://gre/modules/TelemetryUtils.jsm", this); @@ -1529,14 +1528,14 @@ var Impl = { delayedInit() { this._log.trace("delayedInit"); - this._delayedInitTask = Task.spawn(function* () { + this._delayedInitTask = (async function() { try { this._initialized = true; - yield this._loadSessionData(); + await this._loadSessionData(); // Update the session data to keep track of new subsessions created before // the initialization. - yield TelemetryStorage.saveSessionData(this._getSessionDataObject()); + await TelemetryStorage.saveSessionData(this._getSessionDataObject()); this.attachObservers(); this.gatherMemory(); @@ -1548,18 +1547,18 @@ var Impl = { Telemetry.asyncFetchTelemetryData(function() {}); // Update the crash annotation with the proper client ID. - annotateCrashReport(this._sessionId, yield ClientID.getClientID(), + annotateCrashReport(this._sessionId, await ClientID.getClientID(), Preferences.get(PREF_SERVER, undefined)); if (IS_UNIFIED_TELEMETRY) { // Check for a previously written aborted session ping. - yield TelemetryController.checkAbortedSessionPing(); + await TelemetryController.checkAbortedSessionPing(); // Write the first aborted-session ping as early as possible. Just do that // if we are not testing, since calling Telemetry.reset() will make a previous // aborted ping a pending ping. if (!this._testing) { - yield this._saveAbortedSessionPing(); + await this._saveAbortedSessionPing(); } // The last change date for the environment, used to throttle environment changes. @@ -1578,7 +1577,7 @@ var Impl = { this._delayedInitTask = null; throw e; } - }.bind(this)); + }.bind(this))(); return this._delayedInitTask; }, @@ -1988,15 +1987,15 @@ var Impl = { this._initialized = false; }; - return Task.spawn(function*() { - yield this.saveShutdownPings(); + return (async function() { + await this.saveShutdownPings(); if (IS_UNIFIED_TELEMETRY) { - yield TelemetryController.removeAbortedSessionPing(); + await TelemetryController.removeAbortedSessionPing(); } reset(); - }.bind(this)); + }.bind(this))(); }; // We can be in one the following states here: @@ -2049,8 +2048,8 @@ var Impl = { * @return {Promise} A promise which is resolved with an object when * loading has completed, with null otherwise. */ - _loadSessionData: Task.async(function* () { - let data = yield TelemetryStorage.loadSessionData(); + async _loadSessionData() { + let data = await TelemetryStorage.loadSessionData(); if (!data) { return null; @@ -2072,7 +2071,7 @@ var Impl = { this._profileSubsessionCounter = data.profileSubsessionCounter + this._subsessionCounter; return data; - }), + }, /** * Get the session data object to serialise to disk. diff --git a/toolkit/components/url-classifier/tests/mochitest/chrome.ini b/toolkit/components/url-classifier/tests/mochitest/chrome.ini index 01dcf697d7b8..a6fe2539623c 100644 --- a/toolkit/components/url-classifier/tests/mochitest/chrome.ini +++ b/toolkit/components/url-classifier/tests/mochitest/chrome.ini @@ -9,11 +9,12 @@ support-files = gethash.sjs classifierCommon.js classifierHelper.js + head.js [test_lookup_system_principal.html] [test_classified_annotations.html] tags = trackingprotection -skip-if = os == 'linux' && asan # Bug 1202548 +skip-if = os == 'linux' && asan # Bug 1202548 [test_allowlisted_annotations.html] tags = trackingprotection [test_privatebrowsing_trackingprotection.html] diff --git a/toolkit/components/url-classifier/tests/mochitest/head.js b/toolkit/components/url-classifier/tests/mochitest/head.js new file mode 100644 index 000000000000..897dff87fac9 --- /dev/null +++ b/toolkit/components/url-classifier/tests/mochitest/head.js @@ -0,0 +1,36 @@ +// calculate the fullhash and send it to gethash server +function addCompletionToServer(list, url, mochitestUrl) { + return new Promise(function(resolve, reject) { + var listParam = "list=" + list; + var fullhashParam = "fullhash=" + hash(url); + + var xhr = new XMLHttpRequest; + xhr.open("PUT", mochitestUrl + "?" + listParam + "&" + fullhashParam, true); + xhr.setRequestHeader("Content-Type", "text/plain"); + xhr.onreadystatechange = function() { + if (this.readyState == this.DONE) { + resolve(); + } + }; + xhr.send(); + }); +} + +function hash(str) { + function bytesFromString(str) { + var converter = + SpecialPowers.Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(SpecialPowers.Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + return converter.convertToByteArray(str); + } + + var hasher = SpecialPowers.Cc["@mozilla.org/security/hash;1"] + .createInstance(SpecialPowers.Ci.nsICryptoHash); + + var data = bytesFromString(str); + hasher.init(hasher.SHA256); + hasher.update(data, data.length); + + return hasher.finish(true); +} diff --git a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini index 27671fad5958..303308c55397 100644 --- a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini +++ b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini @@ -6,6 +6,7 @@ support-files = classifierHelper.js cleanWorker.js good.js + head.js evil.css evil.css^headers^ evil.js diff --git a/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html b/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html index 1c149406ace9..d8a86e81dd0b 100644 --- a/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html +++ b/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html @@ -13,6 +13,7 @@
 
+