Bug 1149280 part 1. Make nullprincipal creation faster. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 31 Mar 2015 13:11:00 -0400
changeset 266729 60d47f6038172abe1291384867198b18fd6a517e
parent 266728 538a0b9c118c8ff08066013be4c4adc701c03647
child 266730 c39ec40cb4e181df6b8be94c75da1d68a0945ade
push id4830
push userjlund@mozilla.com
push dateMon, 29 Jun 2015 20:18:48 +0000
treeherdermozilla-beta@4c2175bb0420 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1149280
milestone40.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 1149280 part 1. Make nullprincipal creation faster. r=smaug
caps/nsNullPrincipal.cpp
caps/nsNullPrincipal.h
caps/nsNullPrincipalURI.cpp
caps/nsNullPrincipalURI.h
caps/nsScriptSecurityManager.cpp
dom/base/nsContentUtils.cpp
js/xpconnect/src/Sandbox.cpp
xpcom/build/ServiceList.h
--- a/caps/nsNullPrincipal.cpp
+++ b/caps/nsNullPrincipal.cpp
@@ -10,18 +10,16 @@
  * same-origin with anything but themselves.
  */
 
 #include "mozilla/ArrayUtils.h"
 
 #include "nsNullPrincipal.h"
 #include "nsNullPrincipalURI.h"
 #include "nsMemory.h"
-#include "nsIUUIDGenerator.h"
-#include "nsID.h"
 #include "nsNetUtil.h"
 #include "nsIClassInfoImpl.h"
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
 #include "nsNetCID.h"
 #include "nsError.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsPrincipal.h"
@@ -73,74 +71,45 @@ nsNullPrincipal::~nsNullPrincipal()
 nsNullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom)
 {
   nsRefPtr<nsNullPrincipal> nullPrin = new nsNullPrincipal();
   nsresult rv = nullPrin->Init(aInheritFrom->GetAppId(),
                                aInheritFrom->GetIsInBrowserElement());
   return NS_SUCCEEDED(rv) ? nullPrin.forget() : nullptr;
 }
 
-#define NS_NULLPRINCIPAL_PREFIX NS_NULLPRINCIPAL_SCHEME ":"
+/* static */ already_AddRefed<nsNullPrincipal>
+nsNullPrincipal::Create(uint32_t aAppId, bool aInMozBrowser)
+{
+  nsRefPtr<nsNullPrincipal> nullPrin = new nsNullPrincipal();
+  nsresult rv = nullPrin->Init(aAppId, aInMozBrowser);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  return nullPrin.forget();
+}
 
 nsresult
 nsNullPrincipal::Init(uint32_t aAppId, bool aInMozBrowser)
 {
   MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
   mAppId = aAppId;
   mInMozBrowser = aInMozBrowser;
 
-  nsCString str;
-  nsresult rv = GenerateNullPrincipalURI(str);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mURI = new nsNullPrincipalURI(str);
+  mURI = nsNullPrincipalURI::Create();
+  NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_AVAILABLE);
 
   return NS_OK;
 }
 
 void
 nsNullPrincipal::GetScriptLocation(nsACString &aStr)
 {
   mURI->GetSpec(aStr);
 }
 
-nsresult
-nsNullPrincipal::GenerateNullPrincipalURI(nsACString &aStr)
-{
-  // FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant.
-  nsresult rv;
-  nsCOMPtr<nsIUUIDGenerator> uuidgen =
-    do_GetService("@mozilla.org/uuid-generator;1", &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsID id;
-  rv = uuidgen->GenerateUUIDInPlace(&id);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  char chars[NSID_LENGTH];
-  id.ToProvidedString(chars);
-
-  uint32_t suffixLen = NSID_LENGTH - 1;
-  uint32_t prefixLen = ArrayLength(NS_NULLPRINCIPAL_PREFIX) - 1;
-
-  // Use an nsCString so we only do the allocation once here and then share
-  // with nsJSPrincipals
-  aStr.SetCapacity(prefixLen + suffixLen);
-
-  aStr.Append(NS_NULLPRINCIPAL_PREFIX);
-  aStr.Append(chars);
-
-  if (aStr.Length() != prefixLen + suffixLen) {
-    NS_WARNING("Out of memory allocating null-principal URI");
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
-
-  return NS_OK;
-}
-
 #ifdef DEBUG
 void nsNullPrincipal::dumpImpl()
 {
   nsAutoCString str;
   mURI->GetSpec(str);
   fprintf(stderr, "nsNullPrincipal (%p) = %s\n", this, str.get());
 }
 #endif 
--- a/caps/nsNullPrincipal.h
+++ b/caps/nsNullPrincipal.h
@@ -25,37 +25,44 @@ class nsIURI;
   { 0x93, 0x42, 0x90, 0xbf, 0xc9, 0xb7, 0xa1, 0xab } }
 #define NS_NULLPRINCIPAL_CONTRACTID "@mozilla.org/nullprincipal;1"
 
 #define NS_NULLPRINCIPAL_SCHEME "moz-nullprincipal"
 
 class nsNullPrincipal final : public nsJSPrincipals
 {
 public:
+  // This should only be used by deserialization, and the factory constructor.
+  // Other consumers should use the Create and CreateWithInheritedAttributes
+  // methods.
   nsNullPrincipal();
 
   // Our refcount is managed by nsJSPrincipals.  Use this macro to avoid an
   // extra refcount member.
 
   // FIXME: bug 327245 -- I sorta wish there were a clean way to share the
   // nsJSPrincipals munging code between the various principal classes without
   // giving up the NS_DECL_NSIPRINCIPAL goodness.
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIPRINCIPAL
   NS_DECL_NSISERIALIZABLE
 
+  // Returns null on failure.
   static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIPrincipal *aInheritFrom);
 
+  // Returns null on failure.
+  static already_AddRefed<nsNullPrincipal>
+    Create(uint32_t aAppId = nsIScriptSecurityManager::NO_APP_ID,
+           bool aInMozBrowser = false);
+
   nsresult Init(uint32_t aAppId = nsIScriptSecurityManager::NO_APP_ID,
                 bool aInMozBrowser = false);
 
   virtual void GetScriptLocation(nsACString &aStr) override;
 
-  static nsresult GenerateNullPrincipalURI(nsACString &aStr);
-
 #ifdef DEBUG
   virtual void dumpImpl() override;
 #endif 
 
  protected:
   virtual ~nsNullPrincipal();
 
   nsCOMPtr<nsIURI> mURI;
--- a/caps/nsNullPrincipalURI.cpp
+++ b/caps/nsNullPrincipalURI.cpp
@@ -9,39 +9,63 @@
 #include "mozilla/DebugOnly.h"
 #include "mozilla/MemoryReporting.h"
 
 #include "mozilla/ipc/URIParams.h"
 
 #include "nsNetUtil.h"
 #include "nsEscape.h"
 #include "nsCRT.h"
+#include "nsIUUIDGenerator.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsNullPrincipalURI
 
-nsNullPrincipalURI::nsNullPrincipalURI(const nsCString &aSpec)
+nsNullPrincipalURI::nsNullPrincipalURI()
+  : mScheme(NS_NULLPRINCIPAL_SCHEME),
+    mPath(mPathBytes, ArrayLength(mPathBytes), ArrayLength(mPathBytes) - 1)
 {
-  InitializeFromSpec(aSpec);
+}
+
+nsNullPrincipalURI::nsNullPrincipalURI(const nsNullPrincipalURI& aOther)
+  : mScheme(NS_NULLPRINCIPAL_SCHEME),
+    mPath(mPathBytes, ArrayLength(mPathBytes), ArrayLength(mPathBytes) - 1)
+{
+  mPath.Assign(aOther.mPath);
 }
 
-void
-nsNullPrincipalURI::InitializeFromSpec(const nsCString &aSpec)
+nsresult
+nsNullPrincipalURI::Init()
 {
-  int32_t dividerPosition = aSpec.FindChar(':');
-  NS_ASSERTION(dividerPosition != -1, "Malformed URI!");
+  // FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant.
+  nsCOMPtr<nsIUUIDGenerator> uuidgen = services::GetUUIDGenerator();
+  NS_ENSURE_TRUE(uuidgen, NS_ERROR_NOT_AVAILABLE);
+
+  nsID id;
+  nsresult rv = uuidgen->GenerateUUIDInPlace(&id);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  MOZ_ASSERT(mPathBytes == mPath.BeginWriting());
+
+  id.ToProvidedString(mPathBytes);
 
-  mozilla::DebugOnly<int32_t> n = aSpec.Left(mScheme, dividerPosition);
-  NS_ASSERTION(n == dividerPosition, "Storing the scheme failed!");
+  MOZ_ASSERT(mPath.Length() == NSID_LENGTH - 1);
+  MOZ_ASSERT(strlen(mPath.get()) == NSID_LENGTH - 1);
+
+  return NS_OK;
+}
 
-  int32_t count = aSpec.Length() - dividerPosition - 1;
-  n = aSpec.Mid(mPath, dividerPosition + 1, count);
-  NS_ASSERTION(n == count, "Storing the path failed!");
-
-  ToLowerCase(mScheme);
+/* static */
+already_AddRefed<nsNullPrincipalURI>
+nsNullPrincipalURI::Create()
+{
+  nsRefPtr<nsNullPrincipalURI> uri = new nsNullPrincipalURI();
+  nsresult rv = uri->Init();
+  NS_ENSURE_SUCCESS(rv, nullptr);
+  return uri.forget();
 }
 
 static NS_DEFINE_CID(kNullPrincipalURIImplementationCID,
                      NS_NULLPRINCIPALURI_IMPLEMENTATION_CID);
 
 NS_IMPL_ADDREF(nsNullPrincipalURI)
 NS_IMPL_RELEASE(nsNullPrincipalURI)
 
@@ -225,18 +249,17 @@ NS_IMETHODIMP
 nsNullPrincipalURI::SetUserPass(const nsACString &aUserPass)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsNullPrincipalURI::Clone(nsIURI **_newURI)
 {
-  nsCOMPtr<nsIURI> uri =
-    new nsNullPrincipalURI(mScheme + NS_LITERAL_CSTRING(":") + mPath);
+  nsCOMPtr<nsIURI> uri = new nsNullPrincipalURI(*this);
   uri.forget(_newURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNullPrincipalURI::CloneIgnoringRef(nsIURI **_newURI)
 {
   // GetRef/SetRef not supported by nsNullPrincipalURI, so
@@ -293,21 +316,19 @@ nsNullPrincipalURI::Serialize(mozilla::i
 bool
 nsNullPrincipalURI::Deserialize(const mozilla::ipc::URIParams &aParams)
 {
   if (aParams.type() != mozilla::ipc::URIParams::TNullPrincipalURIParams) {
     MOZ_ASSERT_UNREACHABLE("unexpected URIParams type");
     return false;
   }
 
-  nsCString str;
-  nsresult rv = nsNullPrincipal::GenerateNullPrincipalURI(str);
+  nsresult rv = Init();
   NS_ENSURE_SUCCESS(rv, false);
 
-  InitializeFromSpec(str);
   return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsISizeOf
 
 size_t
 nsNullPrincipalURI::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
--- a/caps/nsNullPrincipalURI.h
+++ b/caps/nsNullPrincipalURI.h
@@ -13,16 +13,18 @@
 
 #include "nsIURI.h"
 #include "nsISizeOf.h"
 #include "nsAutoPtr.h"
 #include "nsString.h"
 #include "mozilla/Attributes.h"
 #include "nsIIPCSerializableURI.h"
 #include "mozilla/MemoryReporting.h"
+#include "nsNullPrincipal.h"
+#include "nsID.h"
 
 // {51fcd543-3b52-41f7-b91b-6b54102236e6}
 #define NS_NULLPRINCIPALURI_IMPLEMENTATION_CID \
   {0x51fcd543, 0x3b52, 0x41f7, \
     {0xb9, 0x1b, 0x6b, 0x54, 0x10, 0x22, 0x36, 0xe6} }
 
 class nsNullPrincipalURI final : public nsIURI
                                , public nsISizeOf
@@ -32,23 +34,28 @@ public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIURI
   NS_DECL_NSIIPCSERIALIZABLEURI
 
   // nsISizeOf
   virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
 
-  explicit nsNullPrincipalURI(const nsCString &aSpec);
+  // NB: This constructor exists only for deserialization.  Everyone
+  // else should call Create.
+  nsNullPrincipalURI();
 
-  // NB: This constructor exists only for deserialization.
-  nsNullPrincipalURI() { }
+  // Returns null on failure.
+  static already_AddRefed<nsNullPrincipalURI> Create();
 
 private:
+  nsNullPrincipalURI(const nsNullPrincipalURI& aOther);
+
   ~nsNullPrincipalURI() {}
 
-  void InitializeFromSpec(const nsCString &aSpec);
+  nsresult Init();
 
+  char mPathBytes[NSID_LENGTH];
   nsCString mScheme;
-  nsCString mPath;
+  nsFixedCString mPath;
 };
 
 #endif // __nsNullPrincipalURI_h__
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -988,17 +988,18 @@ nsScriptSecurityManager::CreateCodebaseP
     // At least all the callers would do the right thing in those cases, as far
     // as I can tell.  --bz
 
     nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(aURI);
     if (uriPrinc) {
         nsCOMPtr<nsIPrincipal> principal;
         uriPrinc->GetPrincipal(getter_AddRefs(principal));
         if (!principal) {
-            return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
+            principal = nsNullPrincipal::Create();
+            NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
         }
 
         principal.forget(result);
 
         return NS_OK;
     }
 
     nsRefPtr<nsPrincipal> codebase = new nsPrincipal();
@@ -1083,25 +1084,26 @@ nsScriptSecurityManager::GetCodebasePrin
 {
     NS_ENSURE_ARG(aURI);
 
     bool inheritsPrincipal;
     nsresult rv =
         NS_URIChainHasFlags(aURI,
                             nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
                             &inheritsPrincipal);
+    nsCOMPtr<nsIPrincipal> principal;
     if (NS_FAILED(rv) || inheritsPrincipal) {
-        return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, result);
+        principal = nsNullPrincipal::Create();
+        NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
+    } else {
+        rv = CreateCodebasePrincipal(aURI, aAppId, aInMozBrowser,
+                                     getter_AddRefs(principal));
+        NS_ENSURE_SUCCESS(rv, rv);
     }
-
-    nsCOMPtr<nsIPrincipal> principal;
-    rv = CreateCodebasePrincipal(aURI, aAppId, aInMozBrowser,
-                                 getter_AddRefs(principal));
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_IF_ADDREF(*result = principal);
+    principal.forget(result);
 
     return NS_OK;
 }
 
 // static
 nsIPrincipal*
 nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
 {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -454,17 +454,22 @@ nsContentUtils::Init()
 
   sSecurityManager = nsScriptSecurityManager::GetScriptSecurityManager();
   if(!sSecurityManager)
     return NS_ERROR_FAILURE;
   NS_ADDREF(sSecurityManager);
 
   sSecurityManager->GetSystemPrincipal(&sSystemPrincipal);
   MOZ_ASSERT(sSystemPrincipal);
-  NS_ADDREF(sNullSubjectPrincipal = new nsNullPrincipal());
+
+  // We use the constructor here because we want infallible initialization; we
+  // apparently don't care whether sNullSubjectPrincipal has a sane URI or not.
+  nsRefPtr<nsNullPrincipal> nullPrincipal = new nsNullPrincipal();
+  nullPrincipal->Init();
+  nullPrincipal.forget(&sNullSubjectPrincipal);
 
   nsresult rv = CallGetService(NS_IOSERVICE_CONTRACTID, &sIOService);
   if (NS_FAILED(rv)) {
     // This makes life easier, but we can live without it.
 
     sIOService = nullptr;
   }
 
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -863,26 +863,24 @@ xpc::GlobalProperties::Define(JSContext*
     return true;
 }
 
 nsresult
 xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prinOrSop,
                          SandboxOptions& options)
 {
     // Create the sandbox global object
-    nsresult rv;
     nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(prinOrSop);
     if (!principal) {
         nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(prinOrSop);
         if (sop) {
             principal = sop->GetPrincipal();
         } else {
-            nsRefPtr<nsNullPrincipal> nullPrin = new nsNullPrincipal();
-            rv = nullPrin->Init();
-            NS_ENSURE_SUCCESS(rv, rv);
+            nsRefPtr<nsNullPrincipal> nullPrin = nsNullPrincipal::Create();
+            NS_ENSURE_TRUE(nullPrin, NS_ERROR_FAILURE);
             principal = nullPrin;
         }
     }
     MOZ_ASSERT(principal);
 
     JS::CompartmentOptions compartmentOptions;
     if (options.sameZoneAs)
         compartmentOptions.setSameZoneAs(js::UncheckedUnwrap(options.sameZoneAs));
--- a/xpcom/build/ServiceList.h
+++ b/xpcom/build/ServiceList.h
@@ -26,16 +26,18 @@ MOZ_SERVICE(XPConnect, nsIXPConnect,
 MOZ_SERVICE(InDOMUtils, inIDOMUtils,
             "@mozilla.org/inspector/dom-utils;1")
 MOZ_SERVICE(PermissionManager, nsIPermissionManager,
             "@mozilla.org/permissionmanager;1");
 MOZ_SERVICE(ServiceWorkerManager, nsIServiceWorkerManager,
             "@mozilla.org/serviceworkers/manager;1");
 MOZ_SERVICE(AsyncShutdown, nsIAsyncShutdownService,
             "@mozilla.org/async-shutdown-service;1")
+MOZ_SERVICE(UUIDGenerator, nsIUUIDGenerator,
+	    "@mozilla.org/uuid-generator;1");
 
 #ifdef MOZ_USE_NAMESPACE
 namespace mozilla {
 #endif
 
 MOZ_SERVICE(HistoryService, IHistory,
             "@mozilla.org/browser/history;1")