Bug 1340710 - Part 7: Add a fast path for nsIPrincipal::Equals() and nsIPrincipal::EqualsConsideringDomain(); r=bholley
authorEhsan Akhgari <ehsan@mozilla.com>
Fri, 24 Feb 2017 18:05:44 -0500
changeset 346290 512a7e6dfe6b1bbe1e494a3139dd6a0e2d244a0f
parent 346289 c798f52cc53e130a8afe0f8f47be71ce60582888
child 346291 c9bf97b0dd70b4559367fa91fc4dcdabd8c3660b
push id31460
push usercbook@mozilla.com
push dateTue, 07 Mar 2017 14:14:00 +0000
treeherdermozilla-central@47e5c929a487 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1340710
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1340710 - Part 7: Add a fast path for nsIPrincipal::Equals() and nsIPrincipal::EqualsConsideringDomain(); r=bholley
caps/BasePrincipal.cpp
caps/BasePrincipal.h
--- a/caps/BasePrincipal.cpp
+++ b/caps/BasePrincipal.cpp
@@ -328,38 +328,92 @@ BasePrincipal::Subsumes(nsIPrincipal* aO
   if (Kind() == eCodebasePrincipal &&
       OriginAttributesRef() != Cast(aOther)->OriginAttributesRef()) {
     return false;
   }
 
   return SubsumesInternal(aOther, aConsideration);
 }
 
+bool
+BasePrincipal::FastEquals(nsIPrincipal* aOther)
+{
+  auto other = Cast(aOther);
+  if (Kind() != other->Kind()) {
+    // Principals of different kinds can't be equal.
+    return false;
+  }
+
+  // Two principals are considered to be equal if their origins are the same.
+  // If the two principals are codebase principals, their origin attributes
+  // (aka the origin suffix) must also match.
+  // If the two principals are null principals, they're only equal if they're
+  // the same object.
+  if (Kind() == eNullPrincipal || Kind() == eSystemPrincipal) {
+    return this == other;
+  }
+
+  if (mOriginNoSuffix) {
+    if (Kind() == eCodebasePrincipal) {
+      return mOriginNoSuffix == other->mOriginNoSuffix &&
+             mOriginSuffix == other->mOriginSuffix;
+    }
+
+    MOZ_ASSERT(Kind() == eExpandedPrincipal);
+    return mOriginNoSuffix == other->mOriginNoSuffix;
+  }
+
+  // If mOriginNoSuffix is null on one of our principals, we must fall back
+  // to the slow path.
+  return Subsumes(aOther, DontConsiderDocumentDomain) &&
+         other->Subsumes(this, DontConsiderDocumentDomain);
+}
+
 NS_IMETHODIMP
 BasePrincipal::Equals(nsIPrincipal *aOther, bool *aResult)
 {
   NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
-  *aResult = Subsumes(aOther, DontConsiderDocumentDomain) &&
-             Cast(aOther)->Subsumes(this, DontConsiderDocumentDomain);
+
+  *aResult = FastEquals(aOther);
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::EqualsConsideringDomain(nsIPrincipal *aOther, bool *aResult)
 {
   NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
   *aResult = Subsumes(aOther, ConsiderDocumentDomain) &&
              Cast(aOther)->Subsumes(this, ConsiderDocumentDomain);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::Subsumes(nsIPrincipal *aOther, bool *aResult)
 {
   NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
+
+  // If two principals are equal, then they both subsume each other.
+  // We deal with two special cases first:
+  // Null principals only subsume each other if they are equal, and are only
+  // equal if they're the same object.
+  // Also, if mOriginNoSuffix is null, FastEquals falls back to the slow path
+  // using Subsumes, so we don't want to use it in that case to avoid an
+  // infinite recursion.
+  auto other = Cast(aOther);
+  if (Kind() == eNullPrincipal && other->Kind() == eNullPrincipal) {
+    *aResult = (this == other);
+    return NS_OK;
+  }
+  if (mOriginNoSuffix && FastEquals(aOther)) {
+    *aResult = true;
+    return NS_OK;
+  }
+
+  // Otherwise, fall back to the slow path.
   *aResult = Subsumes(aOther, DontConsiderDocumentDomain);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 BasePrincipal::SubsumesConsideringDomain(nsIPrincipal *aOther, bool *aResult)
 {
   NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG);
--- a/caps/BasePrincipal.h
+++ b/caps/BasePrincipal.h
@@ -260,16 +260,19 @@ public:
 
   already_AddRefed<BasePrincipal> CloneStrippingUserContextIdAndFirstPartyDomain();
 
   // Helper to check whether this principal is associated with an addon that
   // allows unprivileged code to load aURI.  aExplicit == true will prevent
   // use of all_urls permission, requiring the domain in its permissions.
   bool AddonAllowsLoad(nsIURI* aURI, bool aExplicit = false);
 
+  // Call this instead of Equals to avoid the cost of virtual dispatch.
+  bool FastEquals(nsIPrincipal* aOther);
+
 protected:
   virtual ~BasePrincipal();
 
   virtual nsresult GetOriginInternal(nsACString& aOrigin) = 0;
   // Note that this does not check OriginAttributes. Callers that depend on
   // those must call Subsumes instead.
   virtual bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsider) = 0;