bug 728250 - remove JSPrincipals::codebase. r=:luke,:bz
authorIgor Bukanov <igor@mir2.org>
Fri, 09 Mar 2012 10:48:50 +0100
changeset 91509 f51a5ba84b56710a0fe6494b55dd013e6bcb5fa5
parent 91508 ebe67819f6f9d04e2ce5ae6736910d2cf5e68369
child 91510 6da02c90a5de04ba5bf355858ee0365a1ca095fd
push id783
push userlsblakk@mozilla.com
push dateTue, 24 Apr 2012 17:33:42 +0000
treeherdermozilla-beta@11faed19f136 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs728250
milestone13.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 728250 - remove JSPrincipals::codebase. r=:luke,:bz In just 2 cases where JSPrincipals::codebase is used it can be reconstructed from the values stored in the associated nsJSPrincipal. In addition the patch makes nsJSprincipals to inherit both from nsIPrincipal and JSPrincipals allowing to use static_cast to convert between nsIPrincipal and JSPrincipals pointers and to drop many cases of manual JSPrincipal reference counting.
caps/idl/nsIPrincipal.idl
caps/include/nsJSPrincipals.h
caps/include/nsNullPrincipal.h
caps/include/nsPrincipal.h
caps/include/nsScriptSecurityManager.h
caps/include/nsSystemPrincipal.h
caps/src/nsJSPrincipals.cpp
caps/src/nsNullPrincipal.cpp
caps/src/nsPrincipal.cpp
caps/src/nsScriptSecurityManager.cpp
caps/src/nsSystemPrincipal.cpp
content/base/src/nsFrameMessageManager.cpp
dom/base/nsJSEnvironment.cpp
dom/workers/Principal.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/Workers.h
ipc/testshell/XPCShellEnvironment.cpp
js/public/MemoryMetrics.h
js/src/MemoryMetrics.cpp
js/src/frontend/Parser.cpp
js/src/frontend/TokenStream.cpp
js/src/jsapi-tests/testChromeBuffer.cpp
js/src/jsapi-tests/testCloneScript.cpp
js/src/jsapi-tests/testOriginPrincipals.cpp
js/src/jsapi-tests/testXDR.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsexn.cpp
js/src/jsgc.cpp
js/src/jsobj.cpp
js/src/jsobjinlines.h
js/src/jsscript.cpp
js/src/jsxdrapi.cpp
js/src/shell/js.cpp
js/src/vm/GlobalObject.cpp
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSSubScriptLoader.cpp
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/AccessCheck.cpp
security/manager/ssl/src/nsCrypto.cpp
--- a/caps/idl/nsIPrincipal.idl
+++ b/caps/idl/nsIPrincipal.idl
@@ -47,17 +47,17 @@ struct JSPrincipals;
 %}
 
 interface nsIURI;
 interface nsIContentSecurityPolicy;
 
 [ptr] native JSContext(JSContext);
 [ptr] native JSPrincipals(JSPrincipals);
 
-[scriptable, uuid(1f83b0e0-6b63-4bdc-a50a-b9afe256bd25)]
+[scriptable, uuid(f8c4c89a-d726-421b-8415-3e34b241175b)]
 interface nsIPrincipal : nsISerializable
 {
     /**
      * Values of capabilities for each principal. Order is
      * significant: if an operation is performed on a set
      * of capabilities, the minimum is computed.
      */
     const short ENABLE_DENIED                = 1;
@@ -92,22 +92,16 @@ interface nsIPrincipal : nsISerializable
     boolean equalsIgnoringDomain(in nsIPrincipal other);
 
     /**
      * Returns a hash value for the principal.
      */
     [noscript] readonly attribute unsigned long hashValue;
 
     /**
-     * Returns the JS equivalent of the principal.
-     * @see JSPrincipals.h
-     */
-    [noscript] JSPrincipals getJSPrincipals(in JSContext cx);
-
-    /**
      * The domain security policy of the principal.
      */
     // XXXcaa should this be here?  The script security manager is the only
     // thing that should care about this.  Wouldn't storing this data in one
     // of the hashtables in nsScriptSecurityManager be better?
     // XXXbz why is this writable?  Who should have write access to this?  What
     // happens if this principal is in our hashtable and we pass it out of the
     // security manager and someone writes to this field?  Especially if they
--- a/caps/include/nsJSPrincipals.h
+++ b/caps/include/nsJSPrincipals.h
@@ -38,19 +38,52 @@
 
 #ifndef nsJSPrincipals_h__
 #define nsJSPrincipals_h__
 #include "jsapi.h"
 #include "nsIPrincipal.h"
 
 class nsCString;
 
-struct nsJSPrincipals : JSPrincipals
+struct nsJSPrincipals : nsIPrincipal, JSPrincipals
 {
-  static nsresult Startup();
-  nsJSPrincipals();
-  nsresult Init(nsIPrincipal* aPrincipal, const nsCString& aCodebase);
-  ~nsJSPrincipals(void);
+  static JSBool Subsume(JSPrincipals *jsprin, JSPrincipals *other);
+  static void Destroy(JSPrincipals *jsprin);
+  static JSBool Transcode(JSXDRState *xdr, JSPrincipals **jsprinp);
+
+  /*
+   * Get a weak reference to nsIPrincipal associated with the given JS
+   * principal.
+   */
+  static nsJSPrincipals* get(JSPrincipals *principals) {
+    nsJSPrincipals *self = static_cast<nsJSPrincipals *>(principals);
+    MOZ_ASSERT_IF(self, self->debugToken == DEBUG_TOKEN);
+    return self;
+  }
+  
+  static nsJSPrincipals* get(nsIPrincipal *principal) {
+    nsJSPrincipals *self = static_cast<nsJSPrincipals *>(principal);
+    MOZ_ASSERT_IF(self, self->debugToken == DEBUG_TOKEN);
+    return self;
+  }
 
-  nsIPrincipal *nsIPrincipalPtr; // [WEAK] it owns us.
+  nsJSPrincipals() {
+    refcount = 0;
+    setDebugToken(DEBUG_TOKEN);
+  }
+
+  virtual ~nsJSPrincipals() {
+    setDebugToken(0);
+  }
+
+  /**
+   * Return a string that can be used as JS script filename in error reports.
+   */
+  virtual void GetScriptLocation(nsACString &aStr) = 0;
+
+#ifdef DEBUG
+  virtual void dumpImpl() = 0;
+#endif
+
+  static const uint32_t DEBUG_TOKEN = 0x0bf41760;
 };
 
 #endif /* nsJSPrincipals_h__ */
--- a/caps/include/nsNullPrincipal.h
+++ b/caps/include/nsNullPrincipal.h
@@ -54,33 +54,38 @@ class nsIURI;
 #define NS_NULLPRINCIPAL_CLASSNAME "nullprincipal"
 #define NS_NULLPRINCIPAL_CID \
 { 0xdd156d62, 0xd26f, 0x4441, \
  { 0x9c, 0xdb, 0xe8, 0xf0, 0x91, 0x07, 0xc2, 0x73 } }
 #define NS_NULLPRINCIPAL_CONTRACTID "@mozilla.org/nullprincipal;1"
 
 #define NS_NULLPRINCIPAL_SCHEME "moz-nullprincipal"
 
-class nsNullPrincipal : public nsIPrincipal
+class nsNullPrincipal : public nsJSPrincipals
 {
 public:
   nsNullPrincipal();
   
-  // Our refcount is managed by mJSPrincipals.  Use this macro to avoid an
+  // 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
-  // mJSPrincipals munging code between the various principal classes without
+  // 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
 
   nsresult Init();
 
-protected:
+  virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
+
+#ifdef DEBUG
+  virtual void dumpImpl() MOZ_OVERRIDE;
+#endif 
+
+ protected:
   virtual ~nsNullPrincipal();
 
-  nsJSPrincipals mJSPrincipals;
   nsCOMPtr<nsIURI> mURI;
 };
 
 #endif // nsNullPrincipal_h__
--- a/caps/include/nsPrincipal.h
+++ b/caps/include/nsPrincipal.h
@@ -46,26 +46,26 @@
 #include "nsHashtable.h"
 #include "nsJSPrincipals.h"
 #include "nsTArray.h"
 #include "nsAutoPtr.h"
 
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 
-class nsPrincipal : public nsIPrincipal
+class nsPrincipal : public nsJSPrincipals
 {
 public:
   nsPrincipal();
 
 protected:
   virtual ~nsPrincipal();
 
 public:
-  // Our refcount is managed by mJSPrincipals.  Use this macro to avoid
+  // Our refcount is managed by nsJSPrincipals.  Use this macro to avoid
   // an extra refcount member.
   NS_DECL_ISUPPORTS_INHERITED
 public:
 
   NS_DECL_NSIPRINCIPAL
   NS_DECL_NSISERIALIZABLE
 
   // Either Init() or InitFromPersistent() must be called before
@@ -95,18 +95,23 @@ public:
   enum AnnotationValue { AnnotationEnabled=1, AnnotationDisabled };
 
   void SetURI(nsIURI *aURI);
   nsresult SetCapability(const char *capability, void **annotation, 
                          AnnotationValue value);
 
   static const char sInvalid[];
 
+  virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
+
+#ifdef DEBUG
+  virtual void dumpImpl() MOZ_OVERRIDE;
+#endif 
+
 protected:
-  nsJSPrincipals mJSPrincipals;
   nsTArray< nsAutoPtr<nsHashtable> > mAnnotations;
   nsHashtable* mCapabilities;
   nsCString mPrefName;
   static PRInt32 sCapabilitiesOrdinal;
 
   // XXXcaa This is a semi-hack.  The best solution here is to keep
   // a reference to an interface here, except there is no interface
   // that we can use yet.
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -423,16 +423,19 @@ private:
     nsScriptSecurityManager();
     virtual ~nsScriptSecurityManager();
 
     static JSBool
     CheckObjectAccess(JSContext *cx, JSObject *obj,
                       jsid id, JSAccessMode mode,
                       jsval *vp);
 
+    static JSPrincipals *
+    ObjectPrincipalFinder(JSObject *obj);
+    
     // Decides, based on CSP, whether or not eval() and stuff can be executed.
     static JSBool
     ContentSecurityPolicyPermitsJSAction(JSContext *cx);
 
     // Returns null if a principal cannot be found; generally callers
     // should error out at that point.
     static nsIPrincipal*
     doGetObjectPrincipal(JSObject *obj
--- a/caps/include/nsSystemPrincipal.h
+++ b/caps/include/nsSystemPrincipal.h
@@ -45,30 +45,33 @@
 
 #define NS_SYSTEMPRINCIPAL_CLASSNAME "systemprincipal"
 #define NS_SYSTEMPRINCIPAL_CID \
 { 0x4a6212db, 0xaccb, 0x11d3, \
 { 0xb7, 0x65, 0x0, 0x60, 0xb0, 0xb6, 0xce, 0xcb }}
 #define NS_SYSTEMPRINCIPAL_CONTRACTID "@mozilla.org/systemprincipal;1"
 
 
-class nsSystemPrincipal : public nsIPrincipal
+class nsSystemPrincipal : public nsJSPrincipals
 {
 public:
-    // Our refcount is managed by mJSPrincipals.  Use this macro to avoid
+    // Our refcount is managed by nsJSPrincipals.  Use this macro to avoid
     // an extra refcount member.
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIPRINCIPAL
     NS_DECL_NSISERIALIZABLE
 
-    nsresult Init(JSPrincipals **jsprin);
+    nsSystemPrincipal();
+
+    virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
 
-    nsSystemPrincipal();
+#ifdef DEBUG
+    virtual void dumpImpl() MOZ_OVERRIDE;
+#endif 
 
 protected:
     virtual ~nsSystemPrincipal(void);
 
-    nsJSPrincipals mJSPrincipals;
     // XXX Probably unnecessary.  See bug 143559.
     NS_DECL_OWNINGTHREAD
 };
 
 #endif // nsSystemPrincipal_h__
--- a/caps/src/nsJSPrincipals.cpp
+++ b/caps/src/nsJSPrincipals.cpp
@@ -45,56 +45,54 @@
 #include "nsCOMPtr.h"
 #include "jsapi.h"
 #include "jsxdrapi.h"
 #include "nsIJSRuntimeService.h"
 #include "nsIServiceManager.h"
 #include "nsMemory.h"
 #include "nsStringBuffer.h"
 
-static JSBool
-nsJSPrincipalsSubsume(JSPrincipals *jsprin, JSPrincipals *other)
+// for mozilla::dom::workers::kJSPrincipalsDebugToken
+#include "mozilla/dom/workers/Workers.h"
+
+/* static */ JSBool
+nsJSPrincipals::Subsume(JSPrincipals *jsprin, JSPrincipals *other)
 {
-    nsJSPrincipals *nsjsprin = static_cast<nsJSPrincipals *>(jsprin);
-    nsJSPrincipals *nsother  = static_cast<nsJSPrincipals *>(other);
-
     bool result;
-    nsresult rv = nsjsprin->nsIPrincipalPtr->Subsumes(nsother->nsIPrincipalPtr,
-                                                      &result);
+    nsresult rv = nsJSPrincipals::get(jsprin)->Subsumes(nsJSPrincipals::get(other), &result);
     return NS_SUCCEEDED(rv) && result;
 }
 
-static void
-nsDestroyJSPrincipals(JSContext *cx, struct JSPrincipals *jsprin)
+/* static */ void
+nsJSPrincipals::Destroy(JSPrincipals *jsprin)
 {
-    nsJSPrincipals *nsjsprin = static_cast<nsJSPrincipals *>(jsprin);
+    // The JS runtime can call this method during the last GC when
+    // nsScriptSecurityManager is destroyed. So we must not assume here that
+    // the security manager still exists.
+
+    nsJSPrincipals *nsjsprin = nsJSPrincipals::get(jsprin);
 
     // We need to destroy the nsIPrincipal. We'll do this by adding
     // to the refcount and calling release
 
-    // Note that we don't want to use NS_IF_RELEASE because it will try
-    // to set nsjsprin->nsIPrincipalPtr to nsnull *after* nsjsprin has
-    // already been destroyed.
 #ifdef NS_BUILD_REFCNT_LOGGING
     // The refcount logging considers AddRef-to-1 to indicate creation,
     // so trick it into thinking it's otherwise, but balance the
     // Release() we do below.
     nsjsprin->refcount++;
-    nsjsprin->nsIPrincipalPtr->AddRef();
+    nsjsprin->AddRef();
     nsjsprin->refcount--;
 #else
     nsjsprin->refcount++;
 #endif
-    nsjsprin->nsIPrincipalPtr->Release();
-    // The nsIPrincipal that we release owns the JSPrincipal struct,
-    // so we don't need to worry about "codebase"
+    nsjsprin->Release();
 }
 
-static JSBool
-nsTranscodeJSPrincipals(JSXDRState *xdr, JSPrincipals **jsprinp)
+/* static */ JSBool
+nsJSPrincipals::Transcode(JSXDRState *xdr, JSPrincipals **jsprinp)
 {
     nsresult rv;
 
     if (xdr->mode == JSXDR_ENCODE) {
         nsIObjectOutputStream *stream =
             reinterpret_cast<nsIObjectOutputStream*>(xdr->userdata);
 
         // Flush xdr'ed data to the underlying object output stream.
@@ -102,22 +100,17 @@ nsTranscodeJSPrincipals(JSXDRState *xdr,
         char *data = (char*) ::JS_XDRMemGetData(xdr, &size);
 
         rv = stream->Write32(size);
         if (NS_SUCCEEDED(rv)) {
             rv = stream->WriteBytes(data, size);
             if (NS_SUCCEEDED(rv)) {
                 ::JS_XDRMemResetData(xdr);
 
-                // Require that GetJSPrincipals has been called already by the
-                // code that compiled the script that owns the principals.
-                nsJSPrincipals *nsjsprin =
-                    static_cast<nsJSPrincipals*>(*jsprinp);
-
-                rv = stream->WriteObject(nsjsprin->nsIPrincipalPtr, true);
+                rv = stream->WriteObject(nsJSPrincipals::get(*jsprinp), true);
             }
         }
     } else {
         NS_ASSERTION(JS_XDRMemDataLeft(xdr) == 0, "XDR out of sync?!");
         nsIObjectInputStream *stream =
             reinterpret_cast<nsIObjectInputStream*>(xdr->userdata);
 
         nsCOMPtr<nsIPrincipal> prin;
@@ -136,89 +129,43 @@ nsTranscodeJSPrincipals(JSXDRState *xdr,
                     // Any decode-mode JSXDRState whose userdata points to an
                     // nsIObjectInputStream instance must use nsMemory to Alloc
                     // and Free its data buffer.  Swap the new buffer we just
                     // read for the old, exhausted data.
                     olddata = (char*) ::JS_XDRMemGetData(xdr, &oldsize);
                     nsMemory::Free(olddata);
                     ::JS_XDRMemSetData(xdr, data, size);
 
-                    prin->GetJSPrincipals(xdr->cx, jsprinp);
+                    *jsprinp = nsJSPrincipals::get(prin);
+                    JS_HoldPrincipals(*jsprinp);
                 }
             }
         }
     }
 
     if (NS_FAILED(rv)) {
         ::JS_ReportError(xdr->cx, "can't %scode principals (failure code %x)",
                          (xdr->mode == JSXDR_ENCODE) ? "en" : "de",
                          (unsigned int) rv);
         return JS_FALSE;
     }
     return JS_TRUE;
 }
 
-nsresult
-nsJSPrincipals::Startup()
-{
-    nsCOMPtr<nsIJSRuntimeService> rtsvc = nsXPConnect::GetXPConnect();
-    if (!rtsvc)
-        return NS_ERROR_FAILURE;
-
-    JSRuntime *rt;
-    rtsvc->GetRuntime(&rt);
-    NS_ASSERTION(rt != nsnull, "no JSRuntime?!");
-
-    JSSecurityCallbacks *callbacks = JS_GetRuntimeSecurityCallbacks(rt);
-    NS_ASSERTION(callbacks, "Need a callbacks struct by now!");
+#ifdef DEBUG
 
-    NS_ASSERTION(!callbacks->principalsTranscoder,
-                 "oops, JS_SetPrincipalsTranscoder wars!");
-
-    callbacks->principalsTranscoder = nsTranscodeJSPrincipals;
-    return NS_OK;
-}
-
-nsJSPrincipals::nsJSPrincipals()
+// Defined here so one can do principals->dump() in the debugger
+JS_EXPORT_API(void)
+JSPrincipals::dump()
 {
-    codebase = nsnull;
-    refcount = 0;
-    destroy = nsDestroyJSPrincipals;
-    subsume = nsJSPrincipalsSubsume;
-    nsIPrincipalPtr = nsnull;
+    if (debugToken == nsJSPrincipals::DEBUG_TOKEN) {
+        static_cast<nsJSPrincipals *>(this)->dumpImpl();
+    } else if (debugToken == mozilla::dom::workers::kJSPrincipalsDebugToken) {
+        fprintf(stderr, "Web Worker principal singleton (%p)\n", this);
+    } else {
+        fprintf(stderr,
+                "!!! JSPrincipals (%p) is not nsJSPrincipals instance - bad token: "
+                "actual=0x%x expected=0x%x\n",
+                this, unsigned(debugToken), unsigned(nsJSPrincipals::DEBUG_TOKEN));
+    }
 }
 
-nsresult
-nsJSPrincipals::Init(nsIPrincipal *aPrincipal, const nsCString& aCodebase)
-{
-    if (nsIPrincipalPtr) {
-        NS_ERROR("Init called twice!");
-        return NS_ERROR_UNEXPECTED;
-    }
-
-    nsIPrincipalPtr = aPrincipal;
-    nsStringBuffer* buf = nsStringBuffer::FromString(aCodebase);
-    char* data;
-    if (buf) {
-        buf->AddRef();
-        data = static_cast<char*>(buf->Data());
-    } else {
-        PRUint32 len = aCodebase.Length();
-        buf = nsStringBuffer::Alloc(len + 1); // addrefs
-        if (!buf) {
-            return NS_ERROR_OUT_OF_MEMORY;
-        }
-        data = static_cast<char*>(buf->Data());
-        memcpy(data, aCodebase.get(), len);
-        data[len] = '\0';
-    }
-    
-    codebase = data;
-
-    return NS_OK;
-}
-
-nsJSPrincipals::~nsJSPrincipals()
-{
-    if (codebase) {
-        nsStringBuffer::FromData(codebase)->Release();
-    }
-}
+#endif 
--- a/caps/src/nsNullPrincipal.cpp
+++ b/caps/src/nsNullPrincipal.cpp
@@ -64,27 +64,27 @@ NS_IMPL_QUERY_INTERFACE2_CI(nsNullPrinci
                             nsISerializable)
 NS_IMPL_CI_INTERFACE_GETTER2(nsNullPrincipal,
                              nsIPrincipal,
                              nsISerializable)
 
 NS_IMETHODIMP_(nsrefcnt) 
 nsNullPrincipal::AddRef()
 {
-  NS_PRECONDITION(PRInt32(mJSPrincipals.refcount) >= 0, "illegal refcnt");
-  nsrefcnt count = PR_ATOMIC_INCREMENT(&mJSPrincipals.refcount);
+  NS_PRECONDITION(PRInt32(refcount) >= 0, "illegal refcnt");
+  nsrefcnt count = PR_ATOMIC_INCREMENT(&refcount);
   NS_LOG_ADDREF(this, count, "nsNullPrincipal", sizeof(*this));
   return count;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
 nsNullPrincipal::Release()
 {
-  NS_PRECONDITION(0 != mJSPrincipals.refcount, "dup release");
-  nsrefcnt count = PR_ATOMIC_DECREMENT(&mJSPrincipals.refcount);
+  NS_PRECONDITION(0 != refcount, "dup release");
+  nsrefcnt count = PR_ATOMIC_DECREMENT(&refcount);
   NS_LOG_RELEASE(this, count, "nsNullPrincipal");
   if (count == 0) {
     delete this;
   }
 
   return count;
 }
 
@@ -128,19 +128,34 @@ nsNullPrincipal::Init()
   if (str.Length() != prefixLen + suffixLen) {
     NS_WARNING("Out of memory allocating null-principal URI");
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   mURI = new nsNullPrincipalURI(str);
   NS_ENSURE_TRUE(mURI, NS_ERROR_OUT_OF_MEMORY);
 
-  return mJSPrincipals.Init(this, str);
+  return NS_OK;
+}
+
+void
+nsNullPrincipal::GetScriptLocation(nsACString &aStr)
+{
+  mURI->GetSpec(aStr);
 }
 
+#ifdef DEBUG
+void nsNullPrincipal::dumpImpl()
+{
+  nsCAutoString str;
+  mURI->GetSpec(str);
+  fprintf(stderr, "nsNullPrincipal (%p) = %s\n", this, str.get());
+}
+#endif 
+
 /**
  * nsIPrincipal implementation
  */
 
 NS_IMETHODIMP
 nsNullPrincipal::GetPreferences(char** aPrefName, char** aID,
                                 char** aSubjectName,
                                 char** aGrantedList, char** aDeniedList,
@@ -175,27 +190,16 @@ nsNullPrincipal::EqualsIgnoringDomain(ns
 NS_IMETHODIMP
 nsNullPrincipal::GetHashValue(PRUint32 *aResult)
 {
   *aResult = (NS_PTR_TO_INT32(this) >> 2);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsNullPrincipal::GetJSPrincipals(JSContext *cx, JSPrincipals **aJsprin)
-{
-  NS_PRECONDITION(mJSPrincipals.nsIPrincipalPtr,
-                  "mJSPrincipals is uninitalized!");
-
-  JSPRINCIPALS_HOLD(cx, &mJSPrincipals);
-  *aJsprin = &mJSPrincipals;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 nsNullPrincipal::GetSecurityPolicy(void** aSecurityPolicy)
 {
   // We don't actually do security policy caching.  And it's not like anyone
   // can set a security policy for us anyway.
   *aSecurityPolicy = nsnull;
   return NS_OK;
 }
 
--- a/caps/src/nsPrincipal.cpp
+++ b/caps/src/nsPrincipal.cpp
@@ -88,28 +88,28 @@ NS_IMPL_QUERY_INTERFACE2_CI(nsPrincipal,
                             nsISerializable)
 NS_IMPL_CI_INTERFACE_GETTER2(nsPrincipal,
                              nsIPrincipal,
                              nsISerializable)
 
 NS_IMETHODIMP_(nsrefcnt)
 nsPrincipal::AddRef()
 {
-  NS_PRECONDITION(PRInt32(mJSPrincipals.refcount) >= 0, "illegal refcnt");
+  NS_PRECONDITION(PRInt32(refcount) >= 0, "illegal refcnt");
   // XXXcaa does this need to be threadsafe?  See bug 143559.
-  nsrefcnt count = PR_ATOMIC_INCREMENT(&mJSPrincipals.refcount);
+  nsrefcnt count = PR_ATOMIC_INCREMENT(&refcount);
   NS_LOG_ADDREF(this, count, "nsPrincipal", sizeof(*this));
   return count;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
 nsPrincipal::Release()
 {
-  NS_PRECONDITION(0 != mJSPrincipals.refcount, "dup release");
-  nsrefcnt count = PR_ATOMIC_DECREMENT(&mJSPrincipals.refcount);
+  NS_PRECONDITION(0 != refcount, "dup release");
+  nsrefcnt count = PR_ATOMIC_DECREMENT(&refcount);
   NS_LOG_RELEASE(this, count, "nsPrincipal");
   if (count == 0) {
     delete this;
   }
 
   return count;
 }
 
@@ -142,51 +142,46 @@ nsPrincipal::Init(const nsACString& aCer
   NS_ENSURE_STATE(!mInitialized);
   NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() || aCodebase); // better have one of these.
 
   mInitialized = true;
 
   mCodebase = NS_TryToMakeImmutable(aCodebase);
   mCodebaseImmutable = URIIsImmutable(mCodebase);
 
-  nsresult rv;
-  if (!aCertFingerprint.IsEmpty()) {
-    rv = SetCertificate(aCertFingerprint, aSubjectName, aPrettyName, aCert);
-    if (NS_SUCCEEDED(rv)) {
-      rv = mJSPrincipals.Init(this, mCert->fingerprint);
-    }
-  }
-  else {
-    nsCAutoString spec;
-    rv = mCodebase->GetSpec(spec);
-    if (NS_SUCCEEDED(rv)) {
-      rv = mJSPrincipals.Init(this, spec);
-    }
-  }
+  if (aCertFingerprint.IsEmpty())
+    return NS_OK;
 
-  NS_ASSERTION(NS_SUCCEEDED(rv), "nsPrincipal::Init() failed");
-
-  return rv;
+  return SetCertificate(aCertFingerprint, aSubjectName, aPrettyName, aCert);
 }
 
 nsPrincipal::~nsPrincipal(void)
 {
   SetSecurityPolicy(nsnull); 
   delete mCapabilities;
 }
 
-NS_IMETHODIMP
-nsPrincipal::GetJSPrincipals(JSContext *cx, JSPrincipals **jsprin)
+void
+nsPrincipal::GetScriptLocation(nsACString &aStr)
 {
-  NS_PRECONDITION(mJSPrincipals.nsIPrincipalPtr, "mJSPrincipals is uninitialized!");
+  if (mCert) {
+    aStr.Assign(mCert->fingerprint);
+  } else {
+    mCodebase->GetSpec(aStr);
+  }
+}
 
-  JSPRINCIPALS_HOLD(cx, &mJSPrincipals);
-  *jsprin = &mJSPrincipals;
-  return NS_OK;
+#ifdef DEBUG
+void nsPrincipal::dumpImpl()
+{
+  nsCAutoString str;
+  GetScriptLocation(str);
+  fprintf(stderr, "nsPrincipal (%p) = %s\n", this, str.get());
 }
+#endif 
 
 NS_IMETHODIMP
 nsPrincipal::GetOrigin(char **aOrigin)
 {
   *aOrigin = nsnull;
 
   nsCOMPtr<nsIURI> origin;
   if (mCodebase) {
@@ -878,19 +873,16 @@ nsPrincipal::InitFromPersistent(const ch
     }
 
     NS_TryToSetImmutable(mCodebase);
     mCodebaseImmutable = URIIsImmutable(mCodebase);
 
     mTrusted = aTrusted;
   }
 
-  rv = mJSPrincipals.Init(this, aToken);
-  NS_ENSURE_SUCCESS(rv, rv);
-
   //-- Save the preference name
   mPrefName = aPrefName;
 
   const char* ordinalBegin = PL_strpbrk(aPrefName, "1234567890");
   if (ordinalBegin) {
     PRIntn n = atoi(ordinalBegin);
     if (sCapabilitiesOrdinal <= n) {
       sCapabilitiesOrdinal = n + 1;
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -512,16 +512,23 @@ NS_IMPL_ISUPPORTS4(nsScriptSecurityManag
                    nsIChannelEventSink,
                    nsIObserver)
 
 ///////////////////////////////////////////////////
 // Methods implementing nsIScriptSecurityManager //
 ///////////////////////////////////////////////////
 
 ///////////////// Security Checks /////////////////
+
+/* static */ JSPrincipals *
+nsScriptSecurityManager::ObjectPrincipalFinder(JSObject *aObj)
+{
+    return nsJSPrincipals::get(doGetObjectPrincipal(aObj));
+}
+
 JSBool
 nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx)
 {
     // Get the security manager
     nsScriptSecurityManager *ssm =
         nsScriptSecurityManager::GetScriptSecurityManager();
 
     NS_ASSERTION(ssm, "Failed to get security manager service");
@@ -532,17 +539,17 @@ nsScriptSecurityManager::ContentSecurity
     nsIPrincipal* subjectPrincipal = ssm->GetSubjectPrincipal(cx, &rv);
 
     NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get nsIPrincipal from js context");
     if (NS_FAILED(rv))
         return JS_FALSE; // Not just absence of principal, but failure.
 
     if (!subjectPrincipal) {
         // See bug 553448 for discussion of this case.
-        NS_ASSERTION(!JS_GetSecurityCallbacks(cx)->findObjectPrincipals,
+        NS_ASSERTION(!JS_GetSecurityCallbacks(js::GetRuntime(cx))->findObjectPrincipals,
                      "CSP: Should have been able to find subject principal. "
                      "Reluctantly granting access.");
         return JS_TRUE;
     }
 
     nsCOMPtr<nsIContentSecurityPolicy> csp;
     rv = subjectPrincipal->GetCsp(getter_AddRefs(csp));
     NS_ASSERTION(NS_SUCCEEDED(rv), "CSP: Failed to get CSP from principal.");
@@ -2174,21 +2181,17 @@ nsScriptSecurityManager::GetScriptPrinci
         return nsnull;
     }
     JSPrincipals *jsp = JS_GetScriptPrincipals(cx, script);
     if (!jsp) {
         *rv = NS_ERROR_FAILURE;
         NS_ERROR("Script compiled without principals!");
         return nsnull;
     }
-    nsJSPrincipals *nsJSPrin = static_cast<nsJSPrincipals *>(jsp);
-    nsIPrincipal* result = nsJSPrin->nsIPrincipalPtr;
-    if (!result)
-        *rv = NS_ERROR_FAILURE;
-    return result;
+    return nsJSPrincipals::get(jsp);
 }
 
 // static
 nsIPrincipal*
 nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx,
                                                     JSObject *obj,
                                                     JSStackFrame *fp,
                                                     nsresult *rv)
@@ -3325,17 +3328,16 @@ nsScriptSecurityManager::nsScriptSecurit
       mPolicyPrefsChanged(true)
 {
     NS_ASSERTION(sizeof(PRWord) == sizeof(void*),
                  "PRWord and void* have different lengths on this platform. "
                  "This may cause a security failure with the SecurityLevel union.");
     mPrincipals.Init(31);
 }
 
-
 nsresult nsScriptSecurityManager::Init()
 {
     nsXPConnect* xpconnect = nsXPConnect::GetXPConnect();
      if (!xpconnect)
         return NS_ERROR_FAILURE;
 
     NS_ADDREF(sXPConnect = xpconnect);
     NS_ADDREF(sJSContextStack = xpconnect);
@@ -3360,45 +3362,40 @@ nsresult nsScriptSecurityManager::Init()
 
     rv = bundleService->CreateBundle("chrome://global/locale/security/caps.properties", &sStrBundle);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Create our system principal singleton
     nsRefPtr<nsSystemPrincipal> system = new nsSystemPrincipal();
     NS_ENSURE_TRUE(system, NS_ERROR_OUT_OF_MEMORY);
 
-    JSPrincipals *jsprin;
-    rv = system->Init(&jsprin);
-    NS_ENSURE_SUCCESS(rv, rv);
-
     mSystemPrincipal = system;
 
     //-- Register security check callback in the JS engine
     //   Currently this is used to control access to function.caller
     nsCOMPtr<nsIJSRuntimeService> runtimeService =
         do_QueryInterface(sXPConnect, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = runtimeService->GetRuntime(&sRuntime);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    static JSSecurityCallbacks securityCallbacks = {
+    static const JSSecurityCallbacks securityCallbacks = {
         CheckObjectAccess,
-        NULL,
-        NULL,
+        nsJSPrincipals::Subsume,
+        nsJSPrincipals::Transcode,
+        ObjectPrincipalFinder,
         ContentSecurityPolicyPermitsJSAction
     };
 
-#ifdef DEBUG
-    JSSecurityCallbacks *oldcallbacks =
-#endif
-    JS_SetRuntimeSecurityCallbacks(sRuntime, &securityCallbacks);
-    NS_ASSERTION(!oldcallbacks, "Someone else set security callbacks!");
-
-    JS_SetTrustedPrincipals(sRuntime, jsprin);
+    MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));
+    JS_SetSecurityCallbacks(sRuntime, &securityCallbacks);
+    JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy);
+
+    JS_SetTrustedPrincipals(sRuntime, system);
 
     return NS_OK;
 }
 
 static nsScriptSecurityManager *gScriptSecMan = nsnull;
 
 jsid nsScriptSecurityManager::sEnabledID   = JSID_VOID;
 
@@ -3412,17 +3409,17 @@ nsScriptSecurityManager::~nsScriptSecuri
     delete mCapabilities;
     gScriptSecMan = nsnull;
 }
 
 void
 nsScriptSecurityManager::Shutdown()
 {
     if (sRuntime) {
-        JS_SetRuntimeSecurityCallbacks(sRuntime, NULL);
+        JS_SetSecurityCallbacks(sRuntime, NULL);
         JS_SetTrustedPrincipals(sRuntime, NULL);
         sRuntime = nsnull;
     }
     sEnabledID = JSID_VOID;
 
     NS_IF_RELEASE(sIOService);
     NS_IF_RELEASE(sXPConnect);
     NS_IF_RELEASE(sJSContextStack);
@@ -3440,23 +3437,16 @@ nsScriptSecurityManager::GetScriptSecuri
         nsresult rv;
         rv = ssManager->Init();
         NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to initialize nsScriptSecurityManager");
         if (NS_FAILED(rv)) {
             delete ssManager;
             return nsnull;
         }
  
-        rv = nsJSPrincipals::Startup();
-        if (NS_FAILED(rv)) {
-            NS_WARNING("can't initialize JS engine security protocol glue!");
-            delete ssManager;
-            return nsnull;
-        }
- 
         rv = sXPConnect->SetDefaultSecurityManager(ssManager,
                                                    nsIXPCSecurityManager::HOOK_ALL);
         if (NS_FAILED(rv)) {
             NS_WARNING("Failed to install xpconnect security manager!");
             delete ssManager;
             return nsnull;
         }
 
--- a/caps/src/nsSystemPrincipal.cpp
+++ b/caps/src/nsSystemPrincipal.cpp
@@ -57,42 +57,55 @@ NS_IMPL_QUERY_INTERFACE2_CI(nsSystemPrin
                             nsISerializable)
 NS_IMPL_CI_INTERFACE_GETTER2(nsSystemPrincipal,
                              nsIPrincipal,
                              nsISerializable)
 
 NS_IMETHODIMP_(nsrefcnt) 
 nsSystemPrincipal::AddRef()
 {
-  NS_PRECONDITION(PRInt32(mJSPrincipals.refcount) >= 0, "illegal refcnt");
-  nsrefcnt count = PR_ATOMIC_INCREMENT(&mJSPrincipals.refcount);
+  NS_PRECONDITION(PRInt32(refcount) >= 0, "illegal refcnt");
+  nsrefcnt count = PR_ATOMIC_INCREMENT(&refcount);
   NS_LOG_ADDREF(this, count, "nsSystemPrincipal", sizeof(*this));
   return count;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
 nsSystemPrincipal::Release()
 {
-  NS_PRECONDITION(0 != mJSPrincipals.refcount, "dup release");
-  nsrefcnt count = PR_ATOMIC_DECREMENT(&mJSPrincipals.refcount);
+  NS_PRECONDITION(0 != refcount, "dup release");
+  nsrefcnt count = PR_ATOMIC_DECREMENT(&refcount);
   NS_LOG_RELEASE(this, count, "nsSystemPrincipal");
   if (count == 0) {
     delete this;
   }
 
   return count;
 }
 
+static const char SYSTEM_PRINCIPAL_SPEC[] = "[System Principal]";
+
+void
+nsSystemPrincipal::GetScriptLocation(nsACString &aStr)
+{
+    aStr.Assign(SYSTEM_PRINCIPAL_SPEC);
+}
+
+#ifdef DEBUG
+void nsSystemPrincipal::dumpImpl()
+{
+  fprintf(stderr, "nsSystemPrincipal (%p)\n", this);
+}
+#endif 
+
 
 ///////////////////////////////////////
 // Methods implementing nsIPrincipal //
 ///////////////////////////////////////
 
-#define SYSTEM_PRINCIPAL_SPEC "[System Principal]"
-
 NS_IMETHODIMP
 nsSystemPrincipal::GetPreferences(char** aPrefName, char** aID,
                                   char** aSubjectName,
                                   char** aGrantedList, char** aDeniedList,
                                   bool* aIsTrusted)
 {
     // The system principal should never be streamed out
     *aPrefName = nsnull;
@@ -275,26 +288,16 @@ nsSystemPrincipal::GetSecurityPolicy(voi
 }
 
 NS_IMETHODIMP
 nsSystemPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
 {
     return NS_OK;
 }
 
-NS_IMETHODIMP
-nsSystemPrincipal::GetJSPrincipals(JSContext *cx, JSPrincipals **jsprin)
-{
-    NS_PRECONDITION(mJSPrincipals.nsIPrincipalPtr, "mJSPrincipals is uninitialized!");
-
-    JSPRINCIPALS_HOLD(cx, &mJSPrincipals);
-    *jsprin = &mJSPrincipals;
-    return NS_OK;
-}
-
 
 //////////////////////////////////////////
 // Methods implementing nsISerializable //
 //////////////////////////////////////////
 
 NS_IMETHODIMP
 nsSystemPrincipal::Read(nsIObjectInputStream* aStream)
 {
@@ -312,29 +315,11 @@ nsSystemPrincipal::Write(nsIObjectOutput
 /////////////////////////////////////////////
 // Constructor, Destructor, initialization //
 /////////////////////////////////////////////
 
 nsSystemPrincipal::nsSystemPrincipal()
 {
 }
 
-nsresult
-nsSystemPrincipal::Init(JSPrincipals **jsprin)
-{
-    // Use an nsCString so we only do the allocation once here and then
-    // share with nsJSPrincipals
-    nsCString str(SYSTEM_PRINCIPAL_SPEC);
-    if (!str.EqualsLiteral(SYSTEM_PRINCIPAL_SPEC)) {
-        NS_WARNING("Out of memory initializing system principal");
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    nsresult rv = mJSPrincipals.Init(this, str);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    *jsprin = &mJSPrincipals;
-    return NS_OK;
-}
-
-nsSystemPrincipal::~nsSystemPrincipal(void)
+nsSystemPrincipal::~nsSystemPrincipal()
 {
 }
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -38,16 +38,17 @@
 
 #include "ContentChild.h"
 #include "ContentParent.h"
 #include "nsFrameMessageManager.h"
 #include "nsContentUtils.h"
 #include "nsIXPConnect.h"
 #include "jsapi.h"
 #include "nsJSUtils.h"
+#include "nsJSPrincipals.h"
 #include "nsNetUtil.h"
 #include "nsScriptLoader.h"
 #include "nsIJSContextStack.h"
 #include "nsIXULRuntime.h"
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIScriptSecurityManager.h"
@@ -806,25 +807,23 @@ nsFrameScriptExecutor::LoadFrameScriptIn
     nsContentUtils::ThreadJSContextStack()->Push(mCx);
     {
       // Need to scope JSAutoRequest to happen after Push but before Pop,
       // at least for now. See bug 584673.
       JSAutoRequest ar(mCx);
       JSObject* global = nsnull;
       mGlobal->GetJSObject(&global);
       if (global) {
-        JSPrincipals* jsprin = nsnull;
-        mPrincipal->GetJSPrincipals(mCx, &jsprin);
-
         uint32 oldopts = JS_GetOptions(mCx);
         JS_SetOptions(mCx, oldopts | JSOPTION_NO_SCRIPT_RVAL);
 
         JSScript* script =
-          JS_CompileUCScriptForPrincipals(mCx, nsnull, jsprin,
-                                         (jschar*)dataString.get(),
+          JS_CompileUCScriptForPrincipals(mCx, nsnull,
+                                          nsJSPrincipals::get(mPrincipal),
+                                          static_cast<const jschar*>(dataString.get()),
                                           dataString.Length(),
                                           url.get(), 1);
 
         JS_SetOptions(mCx, oldopts);
 
         if (script) {
           nsCAutoString scheme;
           uri->GetScheme(scheme);
@@ -834,18 +833,16 @@ nsFrameScriptExecutor::LoadFrameScriptIn
               new nsFrameJSScriptExecutorHolder(script);
             // Root the object also for caching.
             JS_AddNamedScriptRoot(mCx, &(holder->mScript),
                                   "Cached message manager script");
             sCachedScripts->Put(aURL, holder);
           }
           (void) JS_ExecuteScript(mCx, global, script, nsnull);
         }
-        //XXX Argh, JSPrincipals are manually refcounted!
-        JSPRINCIPALS_DROP(mCx, jsprin);
       }
     } 
     JSContext* unused;
     nsContentUtils::ThreadJSContextStack()->Pop(&unused);
   }
 }
 
 bool
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -513,21 +513,20 @@ NS_ScriptErrorReporter(JSContext *cx,
       nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
       PRUint64 innerWindowID = 0;
       if (win) {
         nsCOMPtr<nsPIDOMWindow> innerWin = win->GetCurrentInnerWindow();
         if (innerWin) {
           innerWindowID = innerWin->WindowID();
         }
       }
-      JSPrincipals *prin = report->originPrincipals;
-      nsIPrincipal *principal =
-        prin ? static_cast<nsJSPrincipals*>(prin)->nsIPrincipalPtr : nsnull;
       nsContentUtils::AddScriptRunner(
-        new ScriptErrorEvent(globalObject, principal, report->lineno,
+        new ScriptErrorEvent(globalObject,
+                             nsJSPrincipals::get(report->originPrincipals),
+                             report->lineno,
                              report->uctokenptr - report->uclinebuf,
                              report->flags, msg, fileName, sourceLine,
                              report->errorNumber != JSMSG_OUT_OF_MEMORY,
                              innerWindowID));
     }
   }
 
 #ifdef DEBUG
@@ -1213,52 +1212,45 @@ nsJSContext::EvaluateStringWithValue(con
     }
 
     return NS_OK;
   }
 
   // Safety first: get an object representing the script's principals, i.e.,
   // the entities who signed this script, or the fully-qualified-domain-name
   // or "codebase" from which it was loaded.
-  JSPrincipals *jsprin;
-  nsIPrincipal *principal = aPrincipal;
+  nsCOMPtr<nsIPrincipal> principal = aPrincipal;
   nsresult rv;
   if (!aPrincipal) {
     nsIScriptGlobalObject *global = GetGlobalObject();
     if (!global)
       return NS_ERROR_FAILURE;
     nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
       do_QueryInterface(global, &rv);
     if (NS_FAILED(rv))
       return NS_ERROR_FAILURE;
     principal = objPrincipal->GetPrincipal();
     if (!principal)
       return NS_ERROR_FAILURE;
   }
 
-  principal->GetJSPrincipals(mContext, &jsprin);
-
-  // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
-
   bool ok = false;
 
   rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
   if (NS_FAILED(rv)) {
-    JSPRINCIPALS_DROP(mContext, jsprin);
     return NS_ERROR_FAILURE;
   }
 
   // Push our JSContext on the current thread's context stack so JS called
   // from native code via XPConnect uses the right context.  Do this whether
   // or not the SecurityManager said "ok", in order to simplify control flow
   // below where we pop before returning.
   nsCOMPtr<nsIJSContextStack> stack =
            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
-    JSPRINCIPALS_DROP(mContext, jsprin);
     return NS_ERROR_FAILURE;
   }
 
   jsval val;
 
   rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1268,26 +1260,25 @@ nsJSContext::EvaluateStringWithValue(con
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
 
     JSAutoRequest ar(mContext);
 
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, aScopeObject)) {
-      JSPRINCIPALS_DROP(mContext, jsprin);
       stack->Pop(nsnull);
       return NS_ERROR_FAILURE;
     }
 
     ++mExecuteDepth;
 
     ok = ::JS_EvaluateUCScriptForPrincipalsVersion(mContext,
                                                    aScopeObject,
-                                                   jsprin,
+                                                   nsJSPrincipals::get(principal),
                                                    static_cast<const jschar*>(PromiseFlatString(aScript).get()),
                                                    aScript.Length(),
                                                    aURL,
                                                    aLineNo,
                                                    &val,
                                                    JSVersion(aVersion));
 
     --mExecuteDepth;
@@ -1296,19 +1287,16 @@ nsJSContext::EvaluateStringWithValue(con
       // Tell XPConnect about any pending exceptions. This is needed
       // to avoid dropping JS exceptions in case we got here through
       // nested calls through XPConnect.
 
       ReportPendingException();
     }
   }
 
-  // Whew!  Finally done with these manually ref-counted things.
-  JSPRINCIPALS_DROP(mContext, jsprin);
-
   // If all went well, convert val to a string (XXXbe unless undefined?).
   if (ok) {
     if (aIsUndefined) {
       *aIsUndefined = JSVAL_IS_VOID(val);
     }
 
     *aRetValue = val;
     // XXX - nsScriptObjectHolder should be used once this method moves to
@@ -1422,63 +1410,41 @@ nsJSContext::EvaluateString(const nsAStr
 
   if (!aScopeObject) {
     aScopeObject = JS_GetGlobalObject(mContext);
   }
 
   // Safety first: get an object representing the script's principals, i.e.,
   // the entities who signed this script, or the fully-qualified-domain-name
   // or "codebase" from which it was loaded.
-  JSPrincipals *jsprin;
-  nsIPrincipal *principal = aPrincipal;
-  if (aPrincipal) {
-    aPrincipal->GetJSPrincipals(mContext, &jsprin);
-  }
-  else {
+  nsCOMPtr<nsIPrincipal> principal = aPrincipal;
+  if (!aPrincipal) {
     nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal =
       do_QueryInterface(GetGlobalObject());
     if (!objPrincipal)
       return NS_ERROR_FAILURE;
     principal = objPrincipal->GetPrincipal();
     if (!principal)
       return NS_ERROR_FAILURE;
-    principal->GetJSPrincipals(mContext, &jsprin);
   }
 
-  JSPrincipals *originJSprin;
-  if (aOriginPrincipal) {
-    aOriginPrincipal->GetJSPrincipals(mContext, &originJSprin);
-  } else {
-    originJSprin = nsnull;
-  }
-
-  // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
-
   bool ok = false;
 
   nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
   if (NS_FAILED(rv)) {
-    JSPRINCIPALS_DROP(mContext, jsprin);
-    if (originJSprin) {
-      JSPRINCIPALS_DROP(mContext, originJSprin);
-    }
     return NS_ERROR_FAILURE;
   }
 
   // Push our JSContext on the current thread's context stack so JS called
   // from native code via XPConnect uses the right context.  Do this whether
   // or not the SecurityManager said "ok", in order to simplify control flow
   // below where we pop before returning.
   nsCOMPtr<nsIJSContextStack> stack =
            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
-    JSPRINCIPALS_DROP(mContext, jsprin);
-    if (originJSprin) {
-      JSPRINCIPALS_DROP(mContext, originJSprin);
-    }
     return NS_ERROR_FAILURE;
   }
 
   // The result of evaluation, used only if there were no errors.  This need
   // not be a GC root currently, provided we run the GC only from the
   // operation callback or from ScriptEvaluated.
   jsval val = JSVAL_VOID;
   jsval* vp = aRetValue ? &val : NULL;
@@ -1493,43 +1459,34 @@ nsJSContext::EvaluateString(const nsAStr
   // SecurityManager said "ok", but don't compile if aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && JSVersion(aVersion) != JSVERSION_UNKNOWN) {
     JSAutoRequest ar(mContext);
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, aScopeObject)) {
       stack->Pop(nsnull);
-      JSPRINCIPALS_DROP(mContext, jsprin);
-      if (originJSprin) {
-        JSPRINCIPALS_DROP(mContext, originJSprin);
-      }
       return NS_ERROR_FAILURE;
     }
 
     ok = JS_EvaluateUCScriptForPrincipalsVersionOrigin(
-      mContext, aScopeObject, jsprin, originJSprin,
+      mContext, aScopeObject,
+      nsJSPrincipals::get(principal), nsJSPrincipals::get(aOriginPrincipal),
       static_cast<const jschar*>(PromiseFlatString(aScript).get()),
       aScript.Length(), aURL, aLineNo, vp, JSVersion(aVersion));
 
     if (!ok) {
       // Tell XPConnect about any pending exceptions. This is needed
       // to avoid dropping JS exceptions in case we got here through
       // nested calls through XPConnect.
 
       ReportPendingException();
     }
   }
 
-  // Whew!  Finally done with these manually ref-counted things.
-  JSPRINCIPALS_DROP(mContext, jsprin);
-  if (originJSprin) {
-    JSPRINCIPALS_DROP(mContext, originJSprin);
-  }
-
   // If all went well, convert val to a string if one is wanted.
   if (ok) {
     JSAutoRequest ar(mContext);
     JSAutoEnterCompartment ac;
     if (!ac.enter(mContext, aScopeObject)) {
       stack->Pop(nsnull);
     }
     rv = JSValueToAString(mContext, val, aRetValue, aIsUndefined);
@@ -1568,57 +1525,48 @@ nsJSContext::CompileScript(const PRUnich
                            nsScriptObjectHolder<JSScript>& aScriptObject)
 {
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   NS_ENSURE_ARG_POINTER(aPrincipal);
 
   JSObject* scopeObject = ::JS_GetGlobalObject(mContext);
 
-  JSPrincipals *jsprin;
-  aPrincipal->GetJSPrincipals(mContext, &jsprin);
-  // From here on, we must JSPRINCIPALS_DROP(jsprin) before returning...
-
   bool ok = false;
 
   nsresult rv = sSecurityManager->CanExecuteScripts(mContext, aPrincipal, &ok);
   if (NS_FAILED(rv)) {
-    JSPRINCIPALS_DROP(mContext, jsprin);
     return NS_ERROR_FAILURE;
   }
 
   aScriptObject.drop(); // ensure old object not used on failure...
 
-  // SecurityManager said "ok", but don't compile if aVersion is unknown.
+  // Don't compile if SecurityManager said "not ok" or aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
-  if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
-    JSAutoRequest ar(mContext);
-
-    JSScript* script =
-        ::JS_CompileUCScriptForPrincipalsVersion(mContext,
-                                                 scopeObject,
-                                                 jsprin,
-                                                 static_cast<const jschar*>(aText),
-                                                 aTextLength,
-                                                 aURL,
-                                                 aLineNo,
-                                                 JSVersion(aVersion));
-    if (script) {
-      NS_ASSERTION(aScriptObject.getScriptTypeID()==JAVASCRIPT,
-                   "Expecting JS script object holder");
-      rv = aScriptObject.set(script);
-    } else {
-      rv = NS_ERROR_OUT_OF_MEMORY;
-    }
+  if (!ok || JSVersion(aVersion) == JSVERSION_UNKNOWN)
+    return NS_OK;
+    
+  JSAutoRequest ar(mContext);
+
+  JSScript* script =
+    ::JS_CompileUCScriptForPrincipalsVersion(mContext,
+                                             scopeObject,
+                                             nsJSPrincipals::get(aPrincipal),
+                                             static_cast<const jschar*>(aText),
+                                             aTextLength,
+                                             aURL,
+                                             aLineNo,
+                                             JSVersion(aVersion));
+  if (!script) {
+    return NS_ERROR_OUT_OF_MEMORY;
   }
-
-  // Whew!  Finally done.
-  JSPRINCIPALS_DROP(mContext, jsprin);
-  return rv;
+  NS_ASSERTION(aScriptObject.getScriptTypeID()==JAVASCRIPT,
+               "Expecting JS script object holder");
+  return aScriptObject.set(script);
 }
 
 nsresult
 nsJSContext::ExecuteScript(JSScript* aScriptObject,
                            JSObject* aScopeObject,
                            nsAString* aRetValue,
                            bool* aIsUndefined)
 {
@@ -1831,46 +1779,43 @@ nsJSContext::CompileFunction(JSObject* a
   NS_ENSURE_TRUE(mIsInitialized, NS_ERROR_NOT_INITIALIZED);
 
   // Don't compile if aVersion is unknown.  Since the caller is responsible for
   // parsing the version strings, we just check it isn't JSVERSION_UNKNOWN.
   if ((JSVersion)aVersion == JSVERSION_UNKNOWN) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
-  JSPrincipals *jsprin = nsnull;
-
   nsIScriptGlobalObject *global = GetGlobalObject();
+  nsCOMPtr<nsIPrincipal> principal;
   if (global) {
     // XXXbe why the two-step QI? speed up via a new GetGlobalObjectData func?
     nsCOMPtr<nsIScriptObjectPrincipal> globalData = do_QueryInterface(global);
     if (globalData) {
-      nsIPrincipal *prin = globalData->GetPrincipal();
-      if (!prin)
+      principal = globalData->GetPrincipal();
+      if (!principal)
         return NS_ERROR_FAILURE;
-      prin->GetJSPrincipals(mContext, &jsprin);
     }
   }
 
   JSObject *target = aTarget;
 
   JSAutoRequest ar(mContext);
 
   JSFunction* fun =
       ::JS_CompileUCFunctionForPrincipalsVersion(mContext,
-                                                 aShared ? nsnull : target, jsprin,
+                                                 aShared ? nsnull : target,
+                                                 nsJSPrincipals::get(principal),
                                                  PromiseFlatCString(aName).get(),
                                                  aArgCount, aArgArray,
                                                  static_cast<const jschar*>(PromiseFlatString(aBody).get()),
                                                  aBody.Length(),
                                                  aURL, aLineNo,
                                                  JSVersion(aVersion));
 
-  if (jsprin)
-    JSPRINCIPALS_DROP(mContext, jsprin);
   if (!fun)
     return NS_ERROR_FAILURE;
 
   *aFunctionObject = JS_GetFunctionObject(fun);
   return NS_OK;
 }
 
 nsresult
@@ -3763,43 +3708,16 @@ SetMemoryGCSliceTimePrefChangedCallback(
 {
   PRInt32 pref = Preferences::GetInt(aPrefName, -1);
   // handle overflow and negative pref values
   if (pref > 0 && pref < 100000)
     JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_SLICE_TIME_BUDGET, pref);
   return 0;
 }
 
-static JSPrincipals *
-ObjectPrincipalFinder(JSContext *cx, JSObject *obj)
-{
-  if (!sSecurityManager)
-    return nsnull;
-
-  nsCOMPtr<nsIPrincipal> principal;
-  nsresult rv =
-    sSecurityManager->GetObjectPrincipal(cx, obj,
-                                         getter_AddRefs(principal));
-
-  if (NS_FAILED(rv) || !principal) {
-    return nsnull;
-  }
-
-  JSPrincipals *jsPrincipals = nsnull;
-  principal->GetJSPrincipals(cx, &jsPrincipals);
-
-  // nsIPrincipal::GetJSPrincipals() returns a strong reference to the
-  // JS principals, but the caller of this function expects a weak
-  // reference. So we need to release here.
-
-  JSPRINCIPALS_DROP(cx, jsPrincipals);
-
-  return jsPrincipals;
-}
-
 JSObject*
 NS_DOMReadStructuredClone(JSContext* cx,
                           JSStructuredCloneReader* reader,
                           uint32_t tag,
                           uint32_t data,
                           void* closure)
 {
   // We don't currently support any extensions to structured cloning.
@@ -3848,21 +3766,16 @@ nsJSRuntime::Init()
   rv = sRuntimeService->GetRuntime(&sRuntime);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Let's make sure that our main thread is the same as the xpcom main thread.
   NS_ASSERTION(NS_IsMainThread(), "bad");
 
   sPrevGCSliceCallback = js::SetGCSliceCallback(sRuntime, DOMGCSliceCallback);
 
-  JSSecurityCallbacks *callbacks = JS_GetRuntimeSecurityCallbacks(sRuntime);
-  NS_ASSERTION(callbacks, "SecMan should have set security callbacks!");
-
-  callbacks->findObjectPrincipals = ObjectPrincipalFinder;
-
   // Set up the structured clone callbacks.
   static JSStructuredCloneCallbacks cloneCallbacks = {
     NS_DOMReadStructuredClone,
     NS_DOMWriteStructuredClone,
     NS_DOMStructuredCloneError
   };
   JS_SetStructuredCloneCallbacks(sRuntime, &cloneCallbacks);
 
@@ -3950,24 +3863,16 @@ nsJSRuntime::Shutdown()
   nsJSContext::KillCCTimer();
 
   NS_IF_RELEASE(gNameSpaceManager);
 
   if (!sContextCount) {
     // We're being shutdown, and there are no more contexts
     // alive, release the JS runtime service and the security manager.
 
-    if (sRuntimeService && sSecurityManager) {
-      JSSecurityCallbacks *callbacks = JS_GetRuntimeSecurityCallbacks(sRuntime);
-      if (callbacks) {
-        NS_ASSERTION(callbacks->findObjectPrincipals == ObjectPrincipalFinder,
-                     "Fighting over the findObjectPrincipals callback!");
-        callbacks->findObjectPrincipals = NULL;
-      }
-    }
     NS_IF_RELEASE(sRuntimeService);
     NS_IF_RELEASE(sSecurityManager);
   }
 
   sDidShutdown = true;
 }
 
 // Script object mananagement - note duplicate implementation
--- a/dom/workers/Principal.cpp
+++ b/dom/workers/Principal.cpp
@@ -35,40 +35,28 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "Principal.h"
 
 #include "jsapi.h"
 
+BEGIN_WORKERS_NAMESPACE
+
 namespace {
 
-void
-PrincipalDestroy(JSContext*, JSPrincipals*)
-{
-  // nothing
-}
-
-JSBool
-PrincipalSubsume(JSPrincipals*, JSPrincipals*)
-{
-  return JS_TRUE;
-}
-
-const char gPrincipalCodebase[] = "Web Worker";
-
 JSPrincipals gPrincipal = {
-  const_cast<char*>(gPrincipalCodebase),
-  1, PrincipalDestroy, PrincipalSubsume
+  1
+#ifdef DEBUG
+  , kJSPrincipalsDebugToken
+#endif
 };
 
 } // anonymous namespace
 
-BEGIN_WORKERS_NAMESPACE
-
 JSPrincipals*
 GetWorkerPrincipal()
 {
   return &gPrincipal;
 }
 
 END_WORKERS_NAMESPACE
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -152,16 +152,32 @@ SwapToISupportsArray(SmartPtr<T>& aSrc,
 
   nsISupports* rawSupports =
     static_cast<typename ISupportsBaseInfo<T>::ISupportsBase*>(raw);
   dest->swap(rawSupports);
 }
 
 NS_MEMORY_REPORTER_MALLOC_SIZEOF_FUN(JsWorkerMallocSizeOf, "js-worker")
 
+struct WorkerJSRuntimeStats : public JS::RuntimeStats
+{
+  WorkerJSRuntimeStats()
+   : JS::RuntimeStats(JsWorkerMallocSizeOf) { }
+
+  virtual void initExtraCompartmentStats(JSCompartment *c,
+                                         JS::CompartmentStats *cstats) MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(!cstats->extra);
+    
+    // ReportJSRuntimeExplicitTreeStats expects that cstats->extra is a char pointer
+    const char *name = js::IsAtomsCompartment(c) ? "Web Worker Atoms" : "Web Worker";
+    cstats->extra = const_cast<char *>(name);
+  }
+};
+  
 class WorkerMemoryReporter : public nsIMemoryMultiReporter
 {
   WorkerPrivate* mWorkerPrivate;
   nsCString mAddressString;
   nsCString mPathPrefix;
 
 public:
   NS_DECL_ISUPPORTS
@@ -235,18 +251,17 @@ public:
   }
 
   NS_IMETHOD
   CollectReports(nsIMemoryMultiReporterCallback* aCallback,
                  nsISupports* aClosure)
   {
     AssertIsOnMainThread();
 
-    JS::RuntimeStats rtStats(JsWorkerMallocSizeOf, xpc::GetCompartmentName,
-                             xpc::DestroyCompartmentName);
+    WorkerJSRuntimeStats rtStats;
     nsresult rv = CollectForRuntime(/* isQuick = */false, &rtStats);
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     // Always report, even if we're disabled, so that we at least get an entry
     // in about::memory.
     rv = ReportJSRuntimeExplicitTreeStats(rtStats, mPathPrefix, aCallback, aClosure);
--- a/dom/workers/Workers.h
+++ b/dom/workers/Workers.h
@@ -118,11 +118,14 @@ protected:
   // Must be acquired *before* the WorkerPrivate's mutex, when they're both held.
   mozilla::Mutex mMutex;
   WorkerPrivate* mPrivate;
 };
 
 WorkerCrossThreadDispatcher*
 GetWorkerCrossThreadDispatcher(JSContext* aCx, jsval aWorker);
 
+// Random unique constant to facilitate JSPrincipal debugging
+const uint32_t kJSPrincipalsDebugToken = 0x7e2df9d2;
+
 END_WORKERS_NAMESPACE
 
 #endif /* mozilla_dom_workers_workers_h__ */
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -62,16 +62,17 @@
 #include "nsIJSRuntimeService.h"
 #include "nsIPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIURI.h"
 #include "nsIXPConnect.h"
 #include "nsIXPCScriptable.h"
 
 #include "nsJSUtils.h"
+#include "nsJSPrincipals.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 
 #include "TestShellChild.h"
 #include "TestShellParent.h"
 
 #define EXITCODE_RUNTIME_ERROR 3
 #define EXITCODE_FILE_NOT_FOUND 4
@@ -1053,17 +1054,17 @@ XPCShellEnvironment::~XPCShellEnvironmen
         }
         mGlobalHolder.Release();
 
         JS_GC(mCx);
 
         mCxStack = nsnull;
 
         if (mJSPrincipals) {
-            JSPRINCIPALS_DROP(mCx, mJSPrincipals);
+            JS_DropPrincipals(JS_GetRuntime(mCx), mJSPrincipals);
         }
 
         JSRuntime* rt = gOldContextCallback ? JS_GetRuntime(mCx) : NULL;
 
         JS_EndRequest(mCx);
         JS_DestroyContext(mCx);
 
         if (gOldContextCallback) {
@@ -1135,20 +1136,18 @@ XPCShellEnvironment::Init()
     nsCOMPtr<nsIScriptSecurityManager> securityManager =
         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
     if (NS_SUCCEEDED(rv) && securityManager) {
         rv = securityManager->GetSystemPrincipal(getter_AddRefs(principal));
         if (NS_FAILED(rv)) {
             fprintf(stderr, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
         } else {
             // fetch the JS principals and stick in a global
-            rv = principal->GetJSPrincipals(cx, &mJSPrincipals);
-            if (NS_FAILED(rv)) {
-                fprintf(stderr, "+++ Failed to obtain JS principals from SystemPrincipal.\n");
-            }
+            mJSPrincipals = nsJSPrincipals::get(principal);
+            JS_HoldPrincipals(mJSPrincipals);
             secman->SetSystemPrincipal(principal);
         }
     } else {
         fprintf(stderr, "+++ Failed to get ScriptSecurityManager service, running without principals");
     }
 
     nsCOMPtr<nsIJSContextStack> cxStack =
         do_GetService("@mozilla.org/js/xpc/ContextStack;1");
--- a/js/public/MemoryMetrics.h
+++ b/js/public/MemoryMetrics.h
@@ -1,9 +1,12 @@
-/* ***** BEGIN LICENSE BLOCK *****
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99 ft=cpp:
+ *
+ * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (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.mozilla.org/MPL/
  *
  * Software distributed under the License is distributed on an "AS IS" basis,
@@ -56,41 +59,23 @@ namespace JS {
 struct TypeInferenceSizes
 {
     size_t scripts;
     size_t objects;
     size_t tables;
     size_t temporary;
 };
 
-typedef void* (* GetNameCallback)(JSRuntime *rt, JSCompartment *c);
-typedef void (* DestroyNameCallback)(void *string);
-
 struct CompartmentStats
 {
-    CompartmentStats()
-    {
+    CompartmentStats() {
         memset(this, 0, sizeof(*this));
     }
 
-    void init(void *name_, DestroyNameCallback destroyName)
-    {
-        name = name_;
-        destroyNameCb = destroyName;
-    }
-
-    ~CompartmentStats()
-    {
-        destroyNameCb(name);
-    }
-
-    // Pointer to an nsCString, which we can't use here.
-    void *name;
-    DestroyNameCallback destroyNameCb;
-
+    void   *extra;
     size_t gcHeapArenaHeaders;
     size_t gcHeapArenaPadding;
     size_t gcHeapArenaUnused;
 
     size_t gcHeapObjectsNonFunction;
     size_t gcHeapObjectsFunction;
     size_t gcHeapStrings;
     size_t gcHeapShapesTree;
@@ -114,18 +99,17 @@ struct CompartmentStats
     size_t mjitCode;
     size_t mjitData;
 #endif
     TypeInferenceSizes typeInferenceSizes;
 };
 
 struct RuntimeStats
 {
-    RuntimeStats(JSMallocSizeOfFun mallocSizeOf, GetNameCallback getNameCb,
-                 DestroyNameCallback destroyNameCb)
+    RuntimeStats(JSMallocSizeOfFun mallocSizeOf)
       : runtimeObject(0)
       , runtimeAtomsTable(0)
       , runtimeContexts(0)
       , runtimeNormal(0)
       , runtimeTemporary(0)
       , runtimeRegexpCode(0)
       , runtimeStackCommitted(0)
       , runtimeGCMarker(0)
@@ -144,18 +128,16 @@ struct RuntimeStats
 #ifdef JS_METHODJIT
       , totalMjit(0)
 #endif
       , totalTypeInference(0)
       , totalAnalysisTemp(0)
       , compartmentStatsVector()
       , currCompartmentStats(NULL)
       , mallocSizeOf(mallocSizeOf)
-      , getNameCb(getNameCb)
-      , destroyNameCb(destroyNameCb)
     {}
 
     size_t runtimeObject;
     size_t runtimeAtomsTable;
     size_t runtimeContexts;
     size_t runtimeNormal;
     size_t runtimeTemporary;
     size_t runtimeRegexpCode;
@@ -178,18 +160,18 @@ struct RuntimeStats
 #endif
     size_t totalTypeInference;
     size_t totalAnalysisTemp;
 
     js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
     CompartmentStats *currCompartmentStats;
 
     JSMallocSizeOfFun mallocSizeOf;
-    GetNameCallback getNameCb;
-    DestroyNameCallback destroyNameCb;
+
+    virtual void initExtraCompartmentStats(JSCompartment *c, CompartmentStats *cstats) = 0;
 };
 
 #ifdef JS_THREADSAFE
 
 extern JS_PUBLIC_API(bool)
 CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats);
 
 extern JS_PUBLIC_API(int64_t)
--- a/js/src/MemoryMetrics.cpp
+++ b/js/src/MemoryMetrics.cpp
@@ -58,17 +58,17 @@ static void
 StatsCompartmentCallback(JSRuntime *rt, void *data, JSCompartment *compartment)
 {
     // Append a new CompartmentStats to the vector.
     RuntimeStats *rtStats = static_cast<RuntimeStats *>(data);
 
     // CollectRuntimeStats reserves enough space.
     MOZ_ALWAYS_TRUE(rtStats->compartmentStatsVector.growBy(1));
     CompartmentStats &cStats = rtStats->compartmentStatsVector.back();
-    cStats.init(rtStats->getNameCb(rt, compartment), rtStats->destroyNameCb);
+    rtStats->initExtraCompartmentStats(compartment, &cStats);
     rtStats->currCompartmentStats = &cStats;
 
     // Get the compartment-level numbers.
 #ifdef JS_METHODJIT
     cStats.mjitCode = compartment->sizeOfMjitCode();
 #endif
     compartment->sizeOfTypeInferenceData(&cStats.typeInferenceSizes, rtStats->mallocSizeOf);
     cStats.shapesCompartmentTables = compartment->sizeOfShapeTable(rtStats->mallocSizeOf);
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -151,33 +151,33 @@ Parser::init(const jschar *base, size_t 
     }
     return true;
 }
 
 Parser::~Parser()
 {
     JSContext *cx = context;
     if (principals)
-        JSPRINCIPALS_DROP(cx, principals);
+        JS_DropPrincipals(cx->runtime, principals);
     if (originPrincipals)
-        JSPRINCIPALS_DROP(cx, originPrincipals);
+        JS_DropPrincipals(cx->runtime, originPrincipals);
     cx->tempLifoAlloc().release(tempPoolMark);
     cx->activeCompilations--;
 }
 
 void
 Parser::setPrincipals(JSPrincipals *prin, JSPrincipals *originPrin)
 {
     JS_ASSERT(!principals && !originPrincipals);
     principals = prin;
     if (principals)
-        JSPRINCIPALS_HOLD(context, principals);
+        JS_HoldPrincipals(principals);
     originPrincipals = originPrin;
     if (originPrincipals)
-        JSPRINCIPALS_HOLD(context, originPrincipals);
+        JS_HoldPrincipals(originPrincipals);
 }
 
 ObjectBox *
 Parser::newObjectBox(JSObject *obj)
 {
     /*
      * We use JSContext.tempLifoAlloc to allocate parsed objects and place them
      * on a list in this Parser to ensure GC safety. Thus the tempLifoAlloc
--- a/js/src/frontend/TokenStream.cpp
+++ b/js/src/frontend/TokenStream.cpp
@@ -153,17 +153,17 @@ js::IsIdentifier(JSLinearString *str)
 #endif
 
 /* Initialize members that aren't initialized in |init|. */
 TokenStream::TokenStream(JSContext *cx, JSPrincipals *prin, JSPrincipals *originPrin)
   : tokens(), cursor(), lookahead(), flags(), listenerTSData(), tokenbuf(cx),
     cx(cx), originPrincipals(JSScript::normalizeOriginPrincipals(prin, originPrin))
 {
     if (originPrincipals)
-        JSPRINCIPALS_HOLD(cx, originPrincipals);
+        JS_HoldPrincipals(originPrincipals);
 }
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 bool
 TokenStream::init(const jschar *base, size_t length, const char *fn, unsigned ln, JSVersion v)
@@ -243,17 +243,17 @@ TokenStream::init(const jschar *base, si
 
 TokenStream::~TokenStream()
 {
     if (flags & TSF_OWNFILENAME)
         cx->free_((void *) filename);
     if (sourceMap)
         cx->free_(sourceMap);
     if (originPrincipals)
-        JSPRINCIPALS_DROP(cx, originPrincipals);
+        JS_DropPrincipals(cx->runtime, originPrincipals);
 }
 
 /* Use the fastest available getc. */
 #if defined(HAVE_GETC_UNLOCKED)
 # define fast_getc getc_unlocked
 #elif defined(HAVE__GETC_NOLOCK)
 # define fast_getc _getc_nolock
 #else
--- a/js/src/jsapi-tests/testChromeBuffer.cpp
+++ b/js/src/jsapi-tests/testChromeBuffer.cpp
@@ -1,23 +1,14 @@
 #include "tests.h"
 
-static void
-Destroy(JSContext *cx, JSPrincipals *prin);
-
 JSPrincipals system_principals = {
-    (char *)"", 1, Destroy, NULL
+    1
 };
 
-static void
-Destroy(JSContext *cx, JSPrincipals *prin)
-{
-    JS_ASSERT(prin == &system_principals);
-}
-
 JSClass global_class = {
     "global",
     JSCLASS_IS_GLOBAL | JSCLASS_GLOBAL_FLAGS,
     JS_PropertyStub,
     JS_PropertyStub,
     JS_PropertyStub,
     JS_StrictPropertyStub,
     JS_EnumerateStub,
--- a/js/src/jsapi-tests/testCloneScript.cpp
+++ b/js/src/jsapi-tests/testCloneScript.cpp
@@ -47,72 +47,56 @@ BEGIN_TEST(test_cloneScript)
         CHECK(JS_CloneFunctionObject(cx, obj, B));
     }
 
     return true;
 }
 END_TEST(test_cloneScript)
 
 void
-DestroyPrincipals(JSContext *cx, JSPrincipals *principals)
+DestroyPrincipals(JSPrincipals *principals)
 {
     delete principals;
 }
 
 struct Principals : public JSPrincipals
 {
   public:
-    Principals(const char *name)
+    Principals()
     {
         refcount = 0;
-        codebase = const_cast<char *>(name);
-        destroy = DestroyPrincipals;
-        subsume = NULL;
     }
 };
 
 class AutoDropPrincipals
 {
-    JSContext *cx;
+    JSRuntime *rt;
     JSPrincipals *principals;
 
   public:
-    AutoDropPrincipals(JSContext *cx, JSPrincipals *principals)
-      : cx(cx), principals(principals)
+    AutoDropPrincipals(JSRuntime *rt, JSPrincipals *principals)
+      : rt(rt), principals(principals)
     {
-        JSPRINCIPALS_HOLD(cx, principals);
+        JS_HoldPrincipals(principals);
     }
 
     ~AutoDropPrincipals()
     {
-        JSPRINCIPALS_DROP(cx, principals);
+        JS_DropPrincipals(rt, principals);
     }
 };
 
-JSBool
-TranscodePrincipals(JSXDRState *xdr, JSPrincipals **principalsp)
-{
-    return JS_XDRBytes(xdr, reinterpret_cast<char *>(principalsp), sizeof(*principalsp));
-}
-
 BEGIN_TEST(test_cloneScriptWithPrincipals)
 {
-    JSSecurityCallbacks cbs = {
-        NULL,
-        TranscodePrincipals,
-        NULL,
-        NULL
-    };
+    JS_InitDestroyPrincipalsCallback(rt, DestroyPrincipals);
 
-    JS_SetRuntimeSecurityCallbacks(rt, &cbs);
-
-    JSPrincipals *principalsA = new Principals("A");
-    AutoDropPrincipals dropA(cx, principalsA);
-    JSPrincipals *principalsB = new Principals("B");
-    AutoDropPrincipals dropB(cx, principalsB);
+    JSPrincipals *principalsA = new Principals();
+    AutoDropPrincipals dropA(rt, principalsA);
+    JSPrincipals *principalsB = new Principals();
+    AutoDropPrincipals dropB(rt, principalsB);
 
     JSObject *A, *B;
 
     CHECK(A = createGlobal(principalsA));
     CHECK(B = createGlobal(principalsB));
 
     const char *argnames[] = { "arg" };
     const char *source = "return function() { return arg; }";
--- a/js/src/jsapi-tests/testOriginPrincipals.cpp
+++ b/js/src/jsapi-tests/testOriginPrincipals.cpp
@@ -1,53 +1,42 @@
 #include "tests.h"
 #include "jsdbgapi.h"
 #include "jsobjinlines.h"
 
 JSPrincipals *sCurrentGlobalPrincipals = NULL;
 
 JSPrincipals *
-ObjectPrincipalsFinder(JSContext *, JSObject *)
+ObjectPrincipalsFinder(JSObject *)
 {
     return sCurrentGlobalPrincipals;
 }
 
-JSSecurityCallbacks seccb = {
+static const JSSecurityCallbacks seccb = {
+    NULL,
     NULL,
     NULL,
     ObjectPrincipalsFinder,
     NULL
 };
 
-static void
-Destroy(JSContext *, JSPrincipals *)
-{}
-
-static JSBool
-Subsume(JSPrincipals *, JSPrincipals *)
-{
-    return true;
-}
-
 JSPrincipals *sOriginPrincipalsInErrorReporter = NULL;
 
 static void
 ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
 {
     sOriginPrincipalsInErrorReporter = report->originPrincipals;
 }
 
-char p1str[] = "principal1";
-JSPrincipals prin1 = { p1str, 0, Destroy, Subsume };
-char p2str[] = "principal2";
-JSPrincipals prin2 = { p2str, 0, Destroy, Subsume };
+JSPrincipals prin1 = { 1 };
+JSPrincipals prin2 = { 1 };
 
 BEGIN_TEST(testOriginPrincipals)
 {
-    JS_SetContextSecurityCallbacks(cx, &seccb);
+    JS_SetSecurityCallbacks(rt, &seccb);
 
     /*
      * Currently, the only way to set a non-trivial originPrincipal is to use
      * JS_EvaluateUCScriptForPrincipalsVersionOrigin. This does not expose the
      * compiled script, so we can only test nested scripts.
      */
 
     CHECK(testOuter("function f() {return 1}; f;"));
--- a/js/src/jsapi-tests/testXDR.cpp
+++ b/js/src/jsapi-tests/testXDR.cpp
@@ -67,34 +67,22 @@ FreezeThaw(JSContext *cx, JSScript *scri
 }
 
 static JSObject *
 FreezeThaw(JSContext *cx, JSObject *funobj)
 {
     return FreezeThawImpl(cx, funobj, JS_XDRFunctionObject);
 }
 
-static JSBool
-SubsumePrincipals(JSPrincipals *, JSPrincipals *)
-{
-    return true;
-}
-
 static JSPrincipals testPrincipals[] = {
-    { const_cast<char *>("foo.bar"), 1, NULL, SubsumePrincipals },
-    { const_cast<char *>("dot.com"), 1, NULL, SubsumePrincipals },
+    { 1 },
+    { 1 },
 };
 
 static JSBool
-CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp)
-{
-    return true;
-}
-
-static JSBool
 TranscodePrincipals(JSXDRState *xdr, JSPrincipals **principalsp)
 {
     uint32_t index;
     if (xdr->mode == JSXDR_ENCODE) {
         JSPrincipals *p = *principalsp;
         for (index = 0; ; ++index) {
             if (index == mozilla::ArrayLength(testPrincipals))
                 return false;
@@ -105,32 +93,33 @@ TranscodePrincipals(JSXDRState *xdr, JSP
 
     if (!JS_XDRUint32(xdr, &index))
         return false;
 
     if (xdr->mode == JSXDR_DECODE) {
         if (index >= mozilla::ArrayLength(testPrincipals))
             return false;
         *principalsp = &testPrincipals[index];
-        JSPRINCIPALS_HOLD(xdr->cx, *principalsp);
+        JS_HoldPrincipals(*principalsp);
     }
 
     return true;
 }
 
 BEGIN_TEST(testXDR_principals)
 {
-    static JSSecurityCallbacks seccb = {
-        CheckAccess,
+    static const JSSecurityCallbacks seccb = {
+        NULL,
+        NULL,
         TranscodePrincipals,
         NULL,
         NULL
     };
 
-    JS_SetRuntimeSecurityCallbacks(rt, &seccb);
+    JS_SetSecurityCallbacks(rt, &seccb);
 
     JSScript *script;
     for (int i = TEST_FIRST; i != TEST_END; ++i) {
         script = createScriptViaXDR(NULL, NULL, i);
         CHECK(script);
         CHECK(!JS_GetScriptPrincipals(cx, script));
         CHECK(!JS_GetScriptOriginPrincipals(cx, script));
     
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -691,16 +691,18 @@ JS_IsBuiltinFunctionConstructor(JSFuncti
 
 /*
  * Has a new runtime ever been created?  This flag is used to detect unsafe
  * changes to js_CStringsAreUTF8 after a runtime has been created, and to
  * control things that should happen only once across all runtimes.
  */
 static JSBool js_NewRuntimeWasCalled = JS_FALSE;
 
+static const JSSecurityCallbacks NullSecurityCallbacks = { };
+
 JSRuntime::JSRuntime()
   : atomsCompartment(NULL),
 #ifdef JS_THREADSAFE
     ownerThread_(NULL),
 #endif
     tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
     execAlloc_(NULL),
     bumpAlloc_(NULL),
@@ -773,17 +775,18 @@ JSRuntime::JSRuntime()
     profilingScripts(false),
     hadOutOfMemory(false),
     data(NULL),
 #ifdef JS_THREADSAFE
     gcLock(NULL),
     gcHelperThread(thisFromCtor()),
 #endif
     debuggerMutations(0),
-    securityCallbacks(NULL),
+    securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)),
+    destroyPrincipals(NULL),
     structuredCloneCallbacks(NULL),
     telemetryCallback(NULL),
     propertyRemovals(0),
     thousandsSeparator(0),
     decimalSeparator(0),
     numGrouping(0),
     anynameObject(NULL),
     functionNamespaceObject(NULL),
@@ -4446,73 +4449,57 @@ JS_CheckAccess(JSContext *cx, JSObject *
                jsval *vp, unsigned *attrsp)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     return CheckAccess(cx, obj, id, mode, vp, attrsp);
 }
 
-#ifdef JS_THREADSAFE
-JS_PUBLIC_API(int)
-JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
-{
-    return JS_ATOMIC_INCREMENT(&principals->refcount);
-}
-
-JS_PUBLIC_API(int)
-JS_DropPrincipals(JSContext *cx, JSPrincipals *principals)
+JS_PUBLIC_API(void)
+JS_HoldPrincipals(JSPrincipals *principals)
+{
+    JS_ATOMIC_INCREMENT(&principals->refcount);
+}
+
+JS_PUBLIC_API(void)
+JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals)
 {
     int rc = JS_ATOMIC_DECREMENT(&principals->refcount);
     if (rc == 0)
-        principals->destroy(cx, principals);
-    return rc;
-}
-#endif
-
-JS_PUBLIC_API(JSSecurityCallbacks *)
-JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks)
-{
-    JSSecurityCallbacks *oldcallbacks;
-
-    oldcallbacks = rt->securityCallbacks;
-    rt->securityCallbacks = callbacks;
-    return oldcallbacks;
-}
-
-JS_PUBLIC_API(JSSecurityCallbacks *)
-JS_GetRuntimeSecurityCallbacks(JSRuntime *rt)
-{
-  return rt->securityCallbacks;
-}
-
-JS_PUBLIC_API(JSSecurityCallbacks *)
-JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks)
-{
-    JSSecurityCallbacks *oldcallbacks;
-
-    oldcallbacks = cx->securityCallbacks;
-    cx->securityCallbacks = callbacks;
-    return oldcallbacks;
-}
-
-JS_PUBLIC_API(JSSecurityCallbacks *)
-JS_GetSecurityCallbacks(JSContext *cx)
-{
-  return cx->securityCallbacks
-         ? cx->securityCallbacks
-         : cx->runtime->securityCallbacks;
+        rt->destroyPrincipals(principals);
+}
+
+JS_PUBLIC_API(void)
+JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *scb)
+{
+    JS_ASSERT(scb != &NullSecurityCallbacks);
+    rt->securityCallbacks = scb ? scb : &NullSecurityCallbacks;
+}
+
+JS_PUBLIC_API(const JSSecurityCallbacks *)
+JS_GetSecurityCallbacks(JSRuntime *rt)
+{
+    return (rt->securityCallbacks != &NullSecurityCallbacks) ? rt->securityCallbacks : NULL;
 }
 
 JS_PUBLIC_API(void)
 JS_SetTrustedPrincipals(JSRuntime *rt, JSPrincipals *prin)
 {
     rt->setTrustedPrincipals(prin);
 }
 
+extern JS_PUBLIC_API(void)
+JS_InitDestroyPrincipalsCallback(JSRuntime *rt, JSDestroyPrincipalsOp destroyPrincipals)
+{
+    JS_ASSERT(destroyPrincipals);
+    JS_ASSERT(!rt->destroyPrincipals);
+    rt->destroyPrincipals = destroyPrincipals;
+}
+
 JS_PUBLIC_API(JSFunction *)
 JS_NewFunction(JSContext *cx, JSNative native, unsigned nargs, unsigned flags,
                JSObject *parent, const char *name)
 {
     JS_THREADSAFE_ASSERT(cx->compartment != cx->runtime->atomsCompartment);
     JSAtom *atom;
 
     AssertNoGC(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1515,16 +1515,22 @@ typedef JSBool
 
 typedef JSBool
 (* JSLocaleToUnicode)(JSContext *cx, const char *src, jsval *rval);
 
 /*
  * Security protocol types.
  */
 
+typedef void
+(* JSDestroyPrincipalsOp)(JSPrincipals *principals);
+
+typedef JSBool
+(* JSSubsumePrincipalsOp)(JSPrincipals *principals1, JSPrincipals *principals2);
+
 /*
  * XDR-encode or -decode a principals instance, based on whether xdr->mode is
  * JSXDR_ENCODE, in which case *principalsp should be encoded; or JSXDR_DECODE,
  * in which case implementations must return a held (via JSPRINCIPALS_HOLD),
  * non-null *principalsp out parameter.  Return true on success, false on any
  * error, which the implementation must have reported.
  */
 typedef JSBool
@@ -1534,17 +1540,17 @@ typedef JSBool
  * Return a weak reference to the principals associated with obj, possibly via
  * the immutable parent chain leading from obj to a top-level container (e.g.,
  * a window object in the DOM level 0).  If there are no principals associated
  * with obj, return null.  Therefore null does not mean an error was reported;
  * in no event should an error be reported or an exception be thrown by this
  * callback's implementation.
  */
 typedef JSPrincipals *
-(* JSObjectPrincipalsFinder)(JSContext *cx, JSObject *obj);
+(* JSObjectPrincipalsFinder)(JSObject *obj);
 
 /*
  * Used to check if a CSP instance wants to disable eval() and friends.
  * See js_CheckCSPPermitsJSAction() in jsobj.
  */
 typedef JSBool
 (* JSCSPEvalChecker)(JSContext *cx);
 
@@ -4083,78 +4089,82 @@ extern JS_PUBLIC_API(void)
 JS_SetReservedSlot(JSObject *obj, uint32_t index, jsval v);
 
 /************************************************************************/
 
 /*
  * Security protocol.
  */
 struct JSPrincipals {
-    char *codebase;
-
     /* Don't call "destroy"; use reference counting macros below. */
     int refcount;
 
-    void   (* destroy)(JSContext *cx, JSPrincipals *);
-    JSBool (* subsume)(JSPrincipals *, JSPrincipals *);
+#ifdef DEBUG
+    /* A helper to facilitate principals debugging. */
+    uint32_t    debugToken;
+#endif
+
+#ifdef __cplusplus
+    void setDebugToken(uint32_t token) {
+# ifdef DEBUG
+        debugToken = token;
+# endif
+    }
+
+    /*
+     * This is not defined by the JS engine but should be provided by the
+     * embedding.
+     */
+    JS_PUBLIC_API(void) dump();
+#endif
 };
 
-#ifdef JS_THREADSAFE
-#define JSPRINCIPALS_HOLD(cx, principals)   JS_HoldPrincipals(cx,principals)
-#define JSPRINCIPALS_DROP(cx, principals)   JS_DropPrincipals(cx,principals)
-
-extern JS_PUBLIC_API(int)
-JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals);
-
-extern JS_PUBLIC_API(int)
-JS_DropPrincipals(JSContext *cx, JSPrincipals *principals);
-
-#else
-#define JSPRINCIPALS_HOLD(cx, principals)   (++(principals)->refcount)
-#define JSPRINCIPALS_DROP(cx, principals)                                     \
-    ((--(principals)->refcount == 0)                                          \
-     ? ((*(principals)->destroy)((cx), (principals)), 0)                      \
-     : (principals)->refcount)
-#endif
-
+extern JS_PUBLIC_API(void)
+JS_HoldPrincipals(JSPrincipals *principals);
+
+extern JS_PUBLIC_API(void)
+JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals);
 
 struct JSSecurityCallbacks {
     JSCheckAccessOp            checkObjectAccess;
+    JSSubsumePrincipalsOp      subsumePrincipals;
     JSPrincipalsTranscoder     principalsTranscoder;
     JSObjectPrincipalsFinder   findObjectPrincipals;
     JSCSPEvalChecker           contentSecurityPolicyAllows;
 };
 
-extern JS_PUBLIC_API(JSSecurityCallbacks *)
-JS_SetRuntimeSecurityCallbacks(JSRuntime *rt, JSSecurityCallbacks *callbacks);
-
-extern JS_PUBLIC_API(JSSecurityCallbacks *)
-JS_GetRuntimeSecurityCallbacks(JSRuntime *rt);
-
-extern JS_PUBLIC_API(JSSecurityCallbacks *)
-JS_SetContextSecurityCallbacks(JSContext *cx, JSSecurityCallbacks *callbacks);
-
-extern JS_PUBLIC_API(JSSecurityCallbacks *)
-JS_GetSecurityCallbacks(JSContext *cx);
+extern JS_PUBLIC_API(void)
+JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *callbacks);
+
+extern JS_PUBLIC_API(const JSSecurityCallbacks *)
+JS_GetSecurityCallbacks(JSRuntime *rt);
 
 /*
  * Code running with "trusted" principals will be given a deeper stack
  * allocation than ordinary scripts. This allows trusted script to run after
  * untrusted script has exhausted the stack. This function sets the
  * runtime-wide trusted principal.
  *
  * This principals is not held (via JS_HoldPrincipals/JS_DropPrincipals) since
  * there is no available JSContext. Instead, the caller must ensure that the
  * given principals stays valid for as long as 'rt' may point to it. If the
  * principals would be destroyed before 'rt', JS_SetTrustedPrincipals must be
  * called again, passing NULL for 'prin'.
  */
 extern JS_PUBLIC_API(void)
 JS_SetTrustedPrincipals(JSRuntime *rt, JSPrincipals *prin);
 
+/*
+ * Initialize the callback that is called to destroy JSPrincipals instance
+ * when its reference counter drops to zero. The initialization can be done
+ * only once per JS runtime.
+ */
+extern JS_PUBLIC_API(void)
+JS_InitDestroyPrincipalsCallback(JSRuntime *rt, JSDestroyPrincipalsOp destroyPrincipals);
+
 /************************************************************************/
 
 /*
  * Functions and scripts.
  */
 extern JS_PUBLIC_API(JSFunction *)
 JS_NewFunction(JSContext *cx, JSNative call, unsigned nargs, unsigned flags,
                JSObject *parent, const char *name);
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -983,17 +983,16 @@ JSContext::JSContext(JSRuntime *rt)
     lastMessage(NULL),
     errorReporter(NULL),
     operationCallback(NULL),
     data(NULL),
     data2(NULL),
 #ifdef JS_THREADSAFE
     outstandingRequests(0),
 #endif
-    securityCallbacks(NULL),
     resolveFlags(0),
     rngSeed(0),
     iterValue(MagicValue(JS_NO_ITER_VALUE)),
 #ifdef JS_METHODJIT
     methodJitEnabled(false),
 #endif
     inferenceEnabled(false),
 #ifdef MOZ_TRACE_JSCALLS
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -504,21 +504,18 @@ struct JSRuntime : js::RuntimeFriendFiel
     /* These combine to interlock the GC and new requests. */
     PRLock              *gcLock;
 
     js::GCHelperThread  gcHelperThread;
 #endif /* JS_THREADSAFE */
 
     uint32_t            debuggerMutations;
 
-    /*
-     * Security callbacks set on the runtime are used by each context unless
-     * an override is set on the context.
-     */
-    JSSecurityCallbacks *securityCallbacks;
+    const JSSecurityCallbacks *securityCallbacks;
+    JSDestroyPrincipalsOp destroyPrincipals;
 
     /* Structured data callbacks are runtime-wide. */
     const JSStructuredCloneCallbacks *structuredCloneCallbacks;
 
     /* Call this to accumulate telemetry data. */
     JSAccumulateTelemetryDataCallback telemetryCallback;
 
     /*
@@ -1008,19 +1005,16 @@ struct JSContext : js::ContextFriendFiel
      * location as holding a relocatable pointer, but have no other effect on
      * GC behavior.
      */
     js::CheckRoot *checkGCRooters;
 #endif
 
 #endif /* JSGC_ROOT_ANALYSIS */
 
-    /* Security callbacks that override any defined on the runtime. */
-    JSSecurityCallbacks *securityCallbacks;
-
     /* Stored here to avoid passing it around as a parameter. */
     unsigned               resolveFlags;
 
     /* Random number generator state, used by jsmath.cpp. */
     int64_t             rngSeed;
 
     /* Location to stash the iteration value between JSOP_MOREITER and JSOP_ITERNEXT. */
     js::Value           iterValue;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -299,18 +299,17 @@ SetExnPrivate(JSContext *cx, JSObject *e
 
 static bool
 InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
                JSString *filename, unsigned lineno, JSErrorReport *report, int exnType)
 {
     JS_ASSERT(exnObject->isError());
     JS_ASSERT(!exnObject->getPrivate());
 
-    JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
-    JSCheckAccessOp checkAccess = callbacks ? callbacks->checkObjectAccess : NULL;
+    JSCheckAccessOp checkAccess = cx->runtime->securityCallbacks->checkObjectAccess;
 
     Vector<JSStackTraceElem> frames(cx);
     Vector<Value> values(cx);
     {
         SuppressErrorsGuard seg(cx);
         for (FrameRegsIter i(cx); !i.done(); ++i) {
             /*
              * An exception object stores stack values from 'fp' which may be
@@ -438,29 +437,29 @@ exn_trace(JSTracer *trc, JSObject *obj)
 /* NB: An error object's private must be set through this function. */
 static void
 SetExnPrivate(JSContext *cx, JSObject *exnObject, JSExnPrivate *priv)
 {
     JS_ASSERT(!exnObject->getPrivate());
     JS_ASSERT(exnObject->isError());
     if (JSErrorReport *report = priv->errorReport) {
         if (JSPrincipals *prin = report->originPrincipals)
-            JSPRINCIPALS_HOLD(cx, prin);
+            JS_HoldPrincipals(prin);
     }
     exnObject->setPrivate(priv);
 }
 
 static void
 exn_finalize(JSContext *cx, JSObject *obj)
 {
     if (JSExnPrivate *priv = GetExnPrivate(obj)) {
         if (JSErrorReport *report = priv->errorReport) {
             /* HOLD called by SetExnPrivate. */
             if (JSPrincipals *prin = report->originPrincipals)
-                JSPRINCIPALS_DROP(cx, prin);
+                JS_DropPrincipals(cx->runtime, prin);
             cx->free_(report);
         }
         cx->free_(priv);
     }
 }
 
 static JSBool
 exn_resolve(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2910,17 +2910,17 @@ SweepCompartments(JSContext *cx, JSGCInv
 
         if (!compartment->hold &&
             (compartment->arenas.arenaListsAreEmpty() || !rt->hasContexts()))
         {
             compartment->arenas.checkEmptyFreeLists();
             if (callback)
                 JS_ALWAYS_TRUE(callback(cx, compartment, JSCOMPARTMENT_DESTROY));
             if (compartment->principals)
-                JSPRINCIPALS_DROP(cx, compartment->principals);
+                JS_DropPrincipals(rt, compartment->principals);
             cx->delete_(compartment);
             continue;
         }
         *write++ = compartment;
     }
     rt->compartments.resize(write - rt->compartments.begin());
 }
 
@@ -3900,17 +3900,17 @@ NewCompartment(JSContext *cx, JSPrincipa
 
     JSCompartment *compartment = cx->new_<JSCompartment>(rt);
     if (compartment && compartment->init(cx)) {
         // Any compartment with the trusted principals -- and there can be
         // multiple -- is a system compartment.
         compartment->isSystemCompartment = principals && rt->trustedPrincipals() == principals;
         if (principals) {
             compartment->principals = principals;
-            JSPRINCIPALS_HOLD(cx, principals);
+            JS_HoldPrincipals(principals);
         }
 
         compartment->setGCLastBytes(8192, 8192, GC_NORMAL);
 
         /*
          * Before reporting the OOM condition, |lock| needs to be cleaned up,
          * hence the scoping.
          */
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -784,25 +784,25 @@ EvalCacheLookup(JSContext *cx, JSLinearS
      * to avoid caching nested evals in functions (thus potentially mismatching
      * on strict mode), and we could cache evals in global code if desired.
      */
     unsigned count = 0;
     JSScript **scriptp = bucket;
 
     JSVersion version = cx->findVersion();
     JSScript *script;
+    JSSubsumePrincipalsOp subsume = cx->runtime->securityCallbacks->subsumePrincipals;
     while ((script = *scriptp) != NULL) {
         if (script->savedCallerFun &&
             script->staticLevel == staticLevel &&
             script->getVersion() == version &&
             !script->hasSingletons &&
-            (script->principals == principals ||
-             (principals && script->principals &&
-              principals->subsume(principals, script->principals) &&
-              script->principals->subsume(script->principals, principals)))) {
+            (!subsume || script->principals == principals ||
+             (subsume(principals, script->principals) &&
+              subsume(script->principals, principals)))) {
             /*
              * Get the prior (cache-filling) eval's saved caller function.
              * See frontend::CompileScript.
              */
             JSFunction *fun = script->getCallerFunction();
 
             if (fun == caller->fun()) {
                 /*
@@ -1158,22 +1158,24 @@ PrincipalsForCompiledCode(const CallRece
 
 #if JS_HAS_OBJ_WATCHPOINT
 
 static JSBool
 obj_watch_handler(JSContext *cx, JSObject *obj, jsid id, jsval old,
                   jsval *nvp, void *closure)
 {
     JSObject *callable = (JSObject *) closure;
-    if (JSPrincipals *watcher = callable->principals(cx)) {
-        if (JSObject *scopeChain = cx->stack.currentScriptedScopeChain()) {
-            if (JSPrincipals *subject = scopeChain->principals(cx)) {
-                if (!watcher->subsume(watcher, subject)) {
-                    /* Silently don't call the watch handler. */
-                    return JS_TRUE;
+    if (JSSubsumePrincipalsOp subsume = cx->runtime->securityCallbacks->subsumePrincipals) {
+        if (JSPrincipals *watcher = callable->principals(cx)) {
+            if (JSObject *scopeChain = cx->stack.currentScriptedScopeChain()) {
+                if (JSPrincipals *subject = scopeChain->principals(cx)) {
+                    if (!subsume(watcher, subject)) {
+                        /* Silently don't call the watch handler. */
+                        return true;
+                    }
                 }
             }
         }
     }
 
     /* Avoid recursion on (obj, id) already being watched on cx. */
     AutoResolving resolving(cx, obj, id, AutoResolving::WATCH);
     if (resolving.alreadyStarted())
@@ -5876,20 +5878,17 @@ namespace js {
 
 JSBool
 CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
             Value *vp, unsigned *attrsp)
 {
     JSBool writing;
     JSObject *pobj;
     JSProperty *prop;
-    Class *clasp;
     const Shape *shape;
-    JSSecurityCallbacks *callbacks;
-    JSCheckAccessOp check;
 
     while (JS_UNLIKELY(obj->isWith()))
         obj = obj->getProto();
 
     writing = (mode & JSACC_WRITE) != 0;
     switch (mode & JSACC_TYPEMASK) {
       case JSACC_PROTO:
         pobj = obj;
@@ -5943,22 +5942,19 @@ CheckAccess(JSContext *cx, JSObject *obj
      * We don't want to require all classes to supply a checkAccess hook; we
      * need that hook only for certain classes used when precompiling scripts
      * and functions ("brutal sharing").  But for general safety of built-in
      * magic properties like __proto__, we route all access checks, even for
      * classes that stub out checkAccess, through the global checkObjectAccess
      * hook.  This covers precompilation-based sharing and (possibly
      * unintended) runtime sharing across trust boundaries.
      */
-    clasp = pobj->getClass();
-    check = clasp->checkAccess;
-    if (!check) {
-        callbacks = JS_GetSecurityCallbacks(cx);
-        check = callbacks ? callbacks->checkObjectAccess : NULL;
-    }
+    JSCheckAccessOp check = pobj->getClass()->checkAccess;
+    if (!check)
+        check = cx->runtime->securityCallbacks->checkObjectAccess;
     return !check || check(cx, pobj, id, mode, vp);
 }
 
 }
 
 JSType
 js_TypeOf(JSContext *cx, JSObject *obj)
 {
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -1113,19 +1113,18 @@ inline bool
 JSObject::isCallable()
 {
     return isFunction() || getClass()->call;
 }
 
 inline JSPrincipals *
 JSObject::principals(JSContext *cx)
 {
-    JSSecurityCallbacks *cb = JS_GetSecurityCallbacks(cx);
-    if (JSObjectPrincipalsFinder finder = cb ? cb->findObjectPrincipals : NULL)
-        return finder(cx, this);
+    if (JSObjectPrincipalsFinder find = cx->runtime->securityCallbacks->findObjectPrincipals)
+        return find(this);
     return cx->compartment ? cx->compartment->principals : NULL;
 }
 
 inline uint32_t
 JSObject::slotSpan() const
 {
     if (inDictionaryMode())
         return lastProperty()->base()->slotSpan();
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -698,21 +698,21 @@ XDRScript(JSXDRState *xdr, JSScript **sc
     if (xdr->mode == JSXDR_DECODE) {
         JS_ASSERT(!script->principals);
         JS_ASSERT(!script->originPrincipals);
 
         /* The origin principals must be normalized at this point. */ 
         JS_ASSERT_IF(script->principals, script->originPrincipals);
         if (xdr->principals) {
             script->principals = xdr->principals;
-            JSPRINCIPALS_HOLD(cx, xdr->principals);
+            JS_HoldPrincipals(xdr->principals);
         }
         if (xdr->originPrincipals) {
             script->originPrincipals = xdr->originPrincipals;
-            JSPRINCIPALS_HOLD(cx, xdr->originPrincipals);
+            JS_HoldPrincipals(xdr->originPrincipals);
         }
     }
 
     if (xdr->mode == JSXDR_DECODE) {
         script->lineno = (unsigned)lineno;
         script->nslots = uint16_t(nslots);
         script->staticLevel = uint16_t(nslots >> 16);
     }
@@ -1251,24 +1251,24 @@ JSScript::NewScriptFromEmitter(JSContext
                                  "script");
         return NULL;
     }
     script->nslots = script->nfixed + bce->maxStackDepth;
     script->staticLevel = uint16_t(bce->staticLevel);
     script->principals = bce->parser->principals;
 
     if (script->principals)
-        JSPRINCIPALS_HOLD(cx, script->principals);
+        JS_HoldPrincipals(script->principals);
 
     /* Establish invariant: principals implies originPrincipals. */
     script->originPrincipals = bce->parser->originPrincipals;
     if (!script->originPrincipals)
         script->originPrincipals = script->principals;
     if (script->originPrincipals)
-        JSPRINCIPALS_HOLD(cx, script->originPrincipals);
+        JS_HoldPrincipals(script->originPrincipals);
 
     script->sourceMap = (jschar *) bce->parser->tokenStream.releaseSourceMap();
 
     if (!FinishTakingSrcNotes(cx, bce, script->notes()))
         return NULL;
     if (bce->ntrynotes != 0)
         FinishTakingTryNotes(bce, script->trynotes());
     if (bce->objectList.length != 0)
@@ -1457,19 +1457,19 @@ void
 JSScript::finalize(JSContext *cx, bool background)
 {
     CheckScript(NULL);
 
     js_CallDestroyScriptHook(cx, this);
 
     JS_ASSERT_IF(principals, originPrincipals);
     if (principals)
-        JSPRINCIPALS_DROP(cx, principals);
+        JS_DropPrincipals(cx->runtime, principals);
     if (originPrincipals)
-        JSPRINCIPALS_DROP(cx, originPrincipals);
+        JS_DropPrincipals(cx->runtime, originPrincipals);
 
     if (types)
         types->destroy();
 
 #ifdef JS_METHODJIT
     mjit::ReleaseScriptCode(cx, this);
 #endif
 
--- a/js/src/jsxdrapi.cpp
+++ b/js/src/jsxdrapi.cpp
@@ -554,17 +554,17 @@ XDRPrincipals(JSXDRState *xdr)
         if (xdr->originPrincipals && xdr->originPrincipals != xdr->principals)
             flags |= HAS_ORIGIN;
     }
 
     if (!JS_XDRUint8(xdr, &flags))
         return false;
 
     if (flags & (HAS_PRINCIPALS | HAS_ORIGIN)) {
-        JSSecurityCallbacks *scb = JS_GetSecurityCallbacks(xdr->cx);
+        const JSSecurityCallbacks *scb = JS_GetSecurityCallbacks(xdr->cx->runtime);
         if (xdr->mode == JSXDR_DECODE) {
             if (!scb || !scb->principalsTranscoder) {
                 JS_ReportErrorNumber(xdr->cx, js_GetErrorMessage, NULL,
                                      JSMSG_CANT_DECODE_PRINCIPALS);
                 return false;
             }
         } else {
             JS_ASSERT(scb);
@@ -576,17 +576,17 @@ XDRPrincipals(JSXDRState *xdr)
                 return false;
         }
 
         if (flags & HAS_ORIGIN) {
             if (!scb->principalsTranscoder(xdr, &xdr->originPrincipals))
                 return false;
         } else if (xdr->mode == JSXDR_DECODE && xdr->principals) {
             xdr->originPrincipals = xdr->principals;
-            JSPRINCIPALS_HOLD(xdr->cx, xdr->principals);
+            JS_HoldPrincipals(xdr->principals);
         }
     }
 
     return true;
 }
 
 namespace {
 
@@ -594,19 +594,19 @@ struct AutoDropXDRPrincipals {
     JSXDRState *const xdr;
 
     AutoDropXDRPrincipals(JSXDRState *xdr)
       : xdr(xdr) { }
 
     ~AutoDropXDRPrincipals() {
         if (xdr->mode == JSXDR_DECODE) {
             if (xdr->principals)
-                JSPRINCIPALS_DROP(xdr->cx, xdr->principals);
+                JS_DropPrincipals(xdr->cx->runtime, xdr->principals);
             if (xdr->originPrincipals)
-                JSPRINCIPALS_DROP(xdr->cx, xdr->originPrincipals);
+                JS_DropPrincipals(xdr->cx->runtime, xdr->originPrincipals);
         }
         xdr->principals = NULL;
         xdr->originPrincipals = NULL;
     }
 };
 
 } /* namespace anonymous */
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4862,40 +4862,30 @@ MaybeOverrideOutFileFromEnv(const char* 
                             FILE** outFile)
 {
     const char* outPath = getenv(envVar);
     if (!outPath || !*outPath || !(*outFile = fopen(outPath, "w"))) {
         *outFile = defaultOut;
     }
 }
 
-JSBool
-ShellPrincipalsSubsume(JSPrincipals *, JSPrincipals *)
-{
-    return JS_TRUE;
-}
-
-JSPrincipals shellTrustedPrincipals = {
-    (char *)"[shell trusted principals]",
-    1,
-    NULL, /* nobody should be destroying this */
-    ShellPrincipalsSubsume
-};
+/* Set the initial counter to 1 so the principal will never be destroyed. */ 
+JSPrincipals shellTrustedPrincipals = { 1 };
 
 JSBool
-CheckObjectAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
-                  jsval *vp)
+CheckObjectAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp)
 {
     return true;
 }
 
 JSSecurityCallbacks securityCallbacks = {
     CheckObjectAccess,
     NULL,
     NULL,
+    NULL,
     NULL
 };
 
 int
 main(int argc, char **argv, char **envp)
 {
     int stackDummy;
     JSRuntime *rt;
@@ -5028,17 +5018,17 @@ main(int argc, char **argv, char **envp)
     /* Use the same parameters as the browser in xpcjsruntime.cpp. */
     rt = JS_NewRuntime(32L * 1024L * 1024L);
     if (!rt)
         return 1;
 
     JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
 
     JS_SetTrustedPrincipals(rt, &shellTrustedPrincipals);
-    JS_SetRuntimeSecurityCallbacks(rt, &securityCallbacks);
+    JS_SetSecurityCallbacks(rt, &securityCallbacks);
 
     JS_SetNativeStackQuota(rt, gMaxStackSize);
 
     if (!InitWatchdog(rt))
         return 1;
 
     cx = NewContext(rt);
     if (!cx)
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -381,25 +381,22 @@ GlobalObject::clear(JSContext *cx)
 #endif
 }
 
 bool
 GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx)
 {
     HeapSlot &v = getSlotRef(RUNTIME_CODEGEN_ENABLED);
     if (v.isUndefined()) {
-        JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx);
-
         /*
          * If there are callbacks, make sure that the CSP callback is installed
          * and that it permits runtime code generation, then cache the result.
          */
-        v.set(this, RUNTIME_CODEGEN_ENABLED,
-              BooleanValue((!callbacks || !callbacks->contentSecurityPolicyAllows) ||
-                           callbacks->contentSecurityPolicyAllows(cx)));
+        JSCSPEvalChecker allows = cx->runtime->securityCallbacks->contentSecurityPolicyAllows;
+        v.set(this, RUNTIME_CODEGEN_ENABLED, BooleanValue(!allows || allows(cx)));
     }
     return !v.isFalse();
 }
 
 JSFunction *
 GlobalObject::createConstructor(JSContext *cx, Native ctor, Class *clasp, JSAtom *name,
                                 unsigned length, gc::AllocKind kind)
 {
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -75,16 +75,17 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsIURI.h"
 #include "nsIFileURL.h"
 #include "nsIJARURI.h"
 #include "nsNetUtil.h"
 #include "nsDOMFile.h"
 #include "jsxdrapi.h"
 #include "jsprf.h"
+#include "nsJSPrincipals.h"
 // For reporting errors with the console service
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsIStorageStream.h"
 #include "nsIStringStream.h"
 #include "prmem.h"
 #if defined(XP_WIN)
 #include "nsILocalFileWin.h"
@@ -640,49 +641,32 @@ class ANSIFileAutoCloser
  public:
     explicit ANSIFileAutoCloser(FILE *file) : mFile(file) {}
     ~ANSIFileAutoCloser() { fclose(mFile); }
  private:
     FILE *mFile;
 };
 #endif
 
-class JSPrincipalsHolder
-{
- public:
-    JSPrincipalsHolder(JSContext *cx, JSPrincipals *principals)
-        : mCx(cx), mPrincipals(principals) {}
-    ~JSPrincipalsHolder() { JSPRINCIPALS_DROP(mCx, mPrincipals); }
- private:
-    JSContext *mCx;
-    JSPrincipals *mPrincipals;
-};
-
 nsresult
 mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponentFile,
                                         nsIURI *aURI,
                                         JSObject **aGlobal,
                                         char **aLocation,
                                         jsval *exception)
 {
     nsresult rv;
 
-    JSPrincipals* jsPrincipals = nsnull;
     JSCLContextHelper cx(this);
 
     JS_AbortIfWrongThread(JS_GetRuntime(cx));
 
     // preserve caller's compartment
     js::AutoPreserveCompartment pc(cx);
 
-    rv = mSystemPrincipal->GetJSPrincipals(cx, &jsPrincipals);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    JSPrincipalsHolder princHolder(mContext, jsPrincipals);
-
     nsCOMPtr<nsIXPCScriptable> backstagePass;
     rv = mRuntimeService->GetBackstagePass(getter_AddRefs(backstagePass));
     NS_ENSURE_SUCCESS(rv, rv);
 
     JSCLAutoErrorReporterSetter aers(cx, mozJSLoaderErrorReporter);
 
     nsCOMPtr<nsIXPConnect> xpc =
         do_GetService(kXPConnectServiceContractID, &rv);
@@ -832,17 +816,19 @@ mozJSComponentLoader::GlobalForLocation(
 
             char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32));
             if (!buf) {
                 NS_WARNING("Failed to map file");
                 JS_SetOptions(cx, oldopts);
                 return NS_ERROR_FAILURE;
             }
 
-            script = JS_CompileScriptForPrincipalsVersion(cx, global, jsPrincipals, buf, fileSize32, nativePath.get(), 1,
+            script = JS_CompileScriptForPrincipalsVersion(cx, global,
+                                                          nsJSPrincipals::get(mSystemPrincipal),
+                                                          buf, fileSize32, nativePath.get(), 1,
                                                           JSVERSION_LATEST);
 
             PR_MemUnmap(buf, fileSize32);
 
 #else  /* HAVE_PR_MEMMAP */
 
             /**
              * No memmap implementation, so fall back to 
@@ -875,17 +861,19 @@ mozJSComponentLoader::GlobalForLocation(
 
             size_t rlen = fread(buf, 1, len, fileHandle);
             if (rlen != (PRUint64)len) {
                 free(buf);
                 JS_SetOptions(cx, oldopts);
                 NS_WARNING("Failed to read file");
                 return NS_ERROR_FAILURE;
             }
-            script = JS_CompileScriptForPrincipalsVersion(cx, global, jsPrincipals, buf, rlen, nativePath.get(), 1,
+            script = JS_CompileScriptForPrincipalsVersion(cx, global,
+                                                          nsJSPrincipals::get(mSystemPrincipal),
+                                                          buf, rlen, nativePath.get(), 1,
                                                           JSVERSION_LATEST);
 
             free(buf);
 
 #endif /* HAVE_PR_MEMMAP */
         } else {
             nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
             NS_ENSURE_SUCCESS(rv, rv);
@@ -912,17 +900,19 @@ mozJSComponentLoader::GlobalForLocation(
 
             /* read the file in one swoop */
             rv = scriptStream->Read(buf, len, &bytesRead);
             if (bytesRead != len)
                 return NS_BASE_STREAM_OSERROR;
 
             buf[len] = '\0';
 
-            script = JS_CompileScriptForPrincipalsVersion(cx, global, jsPrincipals, buf, bytesRead, nativePath.get(), 1,
+            script = JS_CompileScriptForPrincipalsVersion(cx, global,
+                                                          nsJSPrincipals::get(mSystemPrincipal),
+                                                          buf, bytesRead, nativePath.get(), 1,
                                                           JSVERSION_LATEST);
         }
         // Propagate the exception, if one exists. Also, don't leave the stale
         // exception on this context.
         JS_SetOptions(cx, oldopts);
         if (!script && exception) {
             JS_GetPendingException(cx, exception);
             JS_ClearPendingException(cx);
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -56,16 +56,17 @@
 #include "nsNetUtil.h"
 #include "nsIProtocolHandler.h"
 #include "nsIFileURL.h"
 #include "nsScriptLoader.h"
 
 #include "jsapi.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
+#include "nsJSPrincipals.h"
 
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 
 using namespace mozilla::scache;
 
 /* load() error msgs, XXX localize? */
@@ -106,17 +107,16 @@ ReportError(JSContext *cx, const char *m
 nsresult
 mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *target_obj,
                                  const nsAString& charset, const char *uriStr,
                                  nsIIOService *serv, nsIPrincipal *principal,
                                  JSScript **scriptp)
 {
     nsCOMPtr<nsIChannel>     chan;
     nsCOMPtr<nsIInputStream> instream;
-    JSPrincipals    *jsPrincipals;
     JSErrorReporter  er;
 
     nsresult rv;
     // Instead of calling NS_OpenURI, we create the channel ourselves and call
     // SetContentType, to avoid expensive MIME type lookups (bug 632490).
     rv = NS_NewChannel(getter_AddRefs(chan), uri, serv,
                        nsnull, nsnull, nsIRequest::LOAD_NORMAL);
     if (NS_SUCCEEDED(rv)) {
@@ -135,49 +135,38 @@ mozJSSubScriptLoader::ReadScript(nsIURI 
         return ReportError(cx, LOAD_ERROR_NOCONTENT);
     }
 
     nsCString buf;
     rv = NS_ReadInputStreamToString(instream, buf, len);
     if (NS_FAILED(rv))
         return rv;
 
-    /* we can't hold onto jsPrincipals as a module var because the
-     * JSPRINCIPALS_DROP macro takes a JSContext, which we won't have in the
-     * destructor */
-    rv = principal->GetJSPrincipals(cx, &jsPrincipals);
-    if (NS_FAILED(rv) || !jsPrincipals) {
-        return ReportError(cx, LOAD_ERROR_NOPRINCIPALS);
-    }
-
     /* set our own error reporter so we can report any bad things as catchable
      * exceptions, including the source/line number */
     er = JS_SetErrorReporter(cx, mozJSLoaderErrorReporter);
 
     if (!charset.IsVoid()) {
         nsString script;
         rv = nsScriptLoader::ConvertToUTF16(nsnull, reinterpret_cast<const PRUint8*>(buf.get()), len,
                                             charset, nsnull, script);
 
         if (NS_FAILED(rv)) {
-            JSPRINCIPALS_DROP(cx, jsPrincipals);
             return ReportError(cx, LOAD_ERROR_BADCHARSET);
         }
 
         *scriptp =
-            JS_CompileUCScriptForPrincipals(cx, target_obj, jsPrincipals,
+            JS_CompileUCScriptForPrincipals(cx, target_obj, nsJSPrincipals::get(principal),
                                             reinterpret_cast<const jschar*>(script.get()),
                                             script.Length(), uriStr, 1);
     } else {
-        *scriptp = JS_CompileScriptForPrincipals(cx, target_obj, jsPrincipals, buf.get(),
-                                                 len, uriStr, 1);
+        *scriptp = JS_CompileScriptForPrincipals(cx, target_obj, nsJSPrincipals::get(principal),
+                                                 buf.get(), len, uriStr, 1);
     }
 
-    JSPRINCIPALS_DROP(cx, jsPrincipals);
-
     /* repent for our evil deeds */
     JS_SetErrorReporter(cx, er);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 mozJSSubScriptLoader::LoadSubScript(const nsAString& url,
@@ -199,17 +188,17 @@ mozJSSubScriptLoader::LoadSubScript(cons
 
     nsresult rv = NS_OK;
 
 #ifdef NS_FUNCTION_TIMER
     NS_TIME_FUNCTION_FMT("%s (line %d) (url: %s)", MOZ_FUNCTION_NAME,
                          __LINE__, NS_LossyConvertUTF16toASCII(url).get());
 #endif
 
-    /* set mJSPrincipals if it's not here already */
+    /* set the system principal if it's not here already */
     if (!mSystemPrincipal) {
         nsCOMPtr<nsIScriptSecurityManager> secman =
             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
         if (!secman)
             return NS_OK;
 
         rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal));
         if (NS_FAILED(rv) || !mSystemPrincipal)
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -76,16 +76,17 @@
 #include "nsCOMArray.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsMemory.h"
 #include "nsISupportsImpl.h"
 #include "nsIJSRuntimeService.h"
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "nsIXPCSecurityManager.h"
+#include "nsJSPrincipals.h"
 #include "xpcpublic.h"
 #ifdef XP_MACOSX
 #include "xpcshellMacUtils.h"
 #endif
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
@@ -1734,21 +1735,23 @@ GetCurrentWorkingDirectory(nsAString& wo
     cwd.SetLength(strlen(result) + 1);
     cwd.Replace(cwd.Length() - 1, 1, '/');
     workingDirectory = NS_ConvertUTF8toUTF16(cwd);
 #endif
     return true;
 }
 
 static JSPrincipals *
-FindObjectPrincipals(JSContext *cx, JSObject *obj)
+FindObjectPrincipals(JSObject *obj)
 {
     return gJSPrincipals;
 }
 
+static JSSecurityCallbacks shellSecurityCallbacks;
+
 int
 main(int argc, char **argv, char **envp)
 {
 #ifdef XP_MACOSX
     InitAutoreleasePool();
 #endif
     JSRuntime *rt;
     JSContext *cx;
@@ -1900,31 +1903,30 @@ main(int argc, char **argv, char **envp)
             nsCOMPtr<nsIScriptSecurityManager> securityManager =
                 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
             if (NS_SUCCEEDED(rv) && securityManager) {
                 rv = securityManager->GetSystemPrincipal(getter_AddRefs(systemprincipal));
                 if (NS_FAILED(rv)) {
                     fprintf(gErrFile, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
                 } else {
                     // fetch the JS principals and stick in a global
-                    rv = systemprincipal->GetJSPrincipals(cx, &gJSPrincipals);
-                    if (NS_FAILED(rv)) {
-                        fprintf(gErrFile, "+++ Failed to obtain JS principals from SystemPrincipal.\n");
-                    }
+                    gJSPrincipals = nsJSPrincipals::get(systemprincipal);
+                    JS_HoldPrincipals(gJSPrincipals);
                     secman->SetSystemPrincipal(systemprincipal);
                 }
             } else {
                 fprintf(gErrFile, "+++ Failed to get ScriptSecurityManager service, running without principals");
             }
         }
 
-        JSSecurityCallbacks *cb = JS_GetRuntimeSecurityCallbacks(rt);
-        NS_ASSERTION(cb, "We are assuming that nsScriptSecurityManager::Init() has been run");
-        NS_ASSERTION(!cb->findObjectPrincipals, "Your pigeon is in my hole!");
-        cb->findObjectPrincipals = FindObjectPrincipals;
+        const JSSecurityCallbacks *scb = JS_GetSecurityCallbacks(rt);
+        NS_ASSERTION(scb, "We are assuming that nsScriptSecurityManager::Init() has been run");
+        shellSecurityCallbacks = *scb;
+        shellSecurityCallbacks.findObjectPrincipals = FindObjectPrincipals;
+        JS_SetSecurityCallbacks(rt, &shellSecurityCallbacks);
 
 #ifdef TEST_TranslateThis
         nsCOMPtr<nsIXPCFunctionThisTranslator>
             translator(new nsXPCFunctionThisTranslator);
         xpc->SetFunctionThisTranslator(NS_GET_IID(nsITestXPCFunctionCallback), translator, nsnull);
 #endif
 
         nsCOMPtr<nsIJSContextStack> cxstack = do_GetService("@mozilla.org/js/xpc/ContextStack;1");
@@ -2004,17 +2006,17 @@ main(int argc, char **argv, char **envp)
 //#define TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN 1
 
 #ifdef TEST_CALL_ON_WRAPPED_JS_AFTER_SHUTDOWN
             // test of late call and release (see below)
             nsCOMPtr<nsIJSContextStack> bogus;
             xpc->WrapJS(cx, glob, NS_GET_IID(nsIJSContextStack),
                         (void**) getter_AddRefs(bogus));
 #endif
-            JSPRINCIPALS_DROP(cx, gJSPrincipals);
+            JS_DropPrincipals(rt, gJSPrincipals);
             JS_ClearScope(cx, glob);
             JS_GC(cx);
             JSContext *oldcx;
             cxstack->Pop(&oldcx);
             NS_ASSERTION(oldcx == cx, "JS thread context push/pop mismatch");
             cxstack = nsnull;
             JS_GC(cx);
         } //this scopes the JSAutoCrossCompartmentCall
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3432,78 +3432,74 @@ xpc_EvalInSandbox(JSContext *cx, JSObjec
         return NS_ERROR_INVALID_ARG;
     }
 
     nsIScriptObjectPrincipal *sop =
         (nsIScriptObjectPrincipal*)xpc_GetJSPrivate(sandbox);
     NS_ASSERTION(sop, "Invalid sandbox passed");
     nsCOMPtr<nsIPrincipal> prin = sop->GetPrincipal();
 
-    JSPrincipals *jsPrincipals;
-
-    if (!prin ||
-        NS_FAILED(prin->GetJSPrincipals(cx, &jsPrincipals)) ||
-        !jsPrincipals) {
+    if (!prin) {
         return NS_ERROR_FAILURE;
     }
 
+    nsCAutoString filenameBuf;
+    if (!filename) {
+        // Default to the spec of the principal.
+        nsJSPrincipals::get(prin)->GetScriptLocation(filenameBuf);
+        filename = filenameBuf.get();
+        lineNo = 1;
+    }
+
     JSObject *callingScope;
     {
         JSAutoRequest req(cx);
 
         callingScope = JS_GetGlobalForScopeChain(cx);
         if (!callingScope) {
             return NS_ERROR_FAILURE;
         }
     }
 
     nsRefPtr<ContextHolder> sandcx = new ContextHolder(cx, sandbox);
     if (!sandcx || !sandcx->GetJSContext()) {
         JS_ReportError(cx, "Can't prepare context for evalInSandbox");
-        JSPRINCIPALS_DROP(cx, jsPrincipals);
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
     if (jsVersion != JSVERSION_DEFAULT)
         JS_SetVersion(sandcx->GetJSContext(), jsVersion);
 
     XPCPerThreadData *data = XPCPerThreadData::GetData(cx);
     XPCJSContextStack *stack = nsnull;
     if (data && (stack = data->GetJSContextStack())) {
         if (!stack->Push(sandcx->GetJSContext())) {
             JS_ReportError(cx,
                            "Unable to initialize XPConnect with the sandbox context");
-            JSPRINCIPALS_DROP(cx, jsPrincipals);
             return NS_ERROR_FAILURE;
         }
     }
 
-    if (!filename) {
-        // Default the filename to the codebase.
-        filename = jsPrincipals->codebase;
-        lineNo = 1;
-    }
-
     nsresult rv = NS_OK;
 
     {
         JSAutoRequest req(sandcx->GetJSContext());
         JSAutoEnterCompartment ac;
-        jsval v;
-        JSString *str = nsnull;
 
         if (!ac.enter(sandcx->GetJSContext(), sandbox)) {
             if (stack)
                 unused << stack->Pop();
             return NS_ERROR_FAILURE;
         }
 
+        jsval v;
+        JSString *str = nsnull;
         JSBool ok =
             JS_EvaluateUCScriptForPrincipals(sandcx->GetJSContext(), sandbox,
-                                             jsPrincipals,
+                                             nsJSPrincipals::get(prin),
                                              reinterpret_cast<const jschar *>
                                                              (PromiseFlatString(source).get()),
                                              source.Length(), filename, lineNo,
                                              &v);
         if (ok && returnStringOnly && !(JSVAL_IS_VOID(v))) {
             ok = !!(str = JS_ValueToString(sandcx->GetJSContext(), v));
         }
 
@@ -3566,18 +3562,16 @@ xpc_EvalInSandbox(JSContext *cx, JSObjec
                 *rval = v;
             }
         }
     }
 
     if (stack)
         unused << stack->Pop();
 
-    JSPRINCIPALS_DROP(cx, jsPrincipals);
-
     return rv;
 }
 
 /* JSObject import (in AUTF8String registryLocation,
  *                  [optional] in JSObject targetObj);
  */
 NS_IMETHODIMP
 nsXPCComponents_Utils::Import(const nsACString& registryLocation,
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -55,16 +55,18 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 #include "nsContentUtils.h"
 #include "nsCCUncollectableMarker.h"
 #include "jsfriendapi.h"
 #include "js/MemoryMetrics.h"
 
+#include "nsJSPrincipals.h"
+
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::xpconnect::memory;
 
 /***************************************************************************/
@@ -1215,82 +1217,53 @@ XPCJSRuntime::~XPCJSRuntime()
 #ifdef DEBUG_shaver_off
         fprintf(stderr, "nJRSI: destroyed runtime %p\n", (void *)mJSRuntime);
 #endif
     }
 
     XPCPerThreadData::ShutDown();
 }
 
-static void*
-GetCompartmentNameHelper(JSCompartment *c, bool getAddress)
+static void
+GetCompartmentName(JSCompartment *c, bool getAddress, nsCString &name)
 {
-    nsCString* name = new nsCString();
     if (js::IsAtomsCompartment(c)) {
-        name->AssignLiteral("atoms");
+        name.AssignLiteral("atoms");
     } else if (JSPrincipals *principals = JS_GetCompartmentPrincipals(c)) {
-        if (principals->codebase) {
-            name->Assign(principals->codebase);
-
-            // For system compartments we append the location, if there is one.
-            // And we append the address if |getAddress| is true, so that
-            // multiple system compartments (and there can be many) can be
-            // distinguished.
-            if (js::IsSystemCompartment(c)) {
-                xpc::CompartmentPrivate *compartmentPrivate =
-                    static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(c));
-                if (compartmentPrivate &&
-                    !compartmentPrivate->location.IsEmpty()) {
-                    name->AppendLiteral(", ");
-                    name->Append(compartmentPrivate->location);
-                }
-
-                if (getAddress) {
-                    // ample; 64-bit address max is 18 chars
-                    static const int maxLength = 31;
-                    nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
-                    name->Append(address);
-                }
-            }
+        nsJSPrincipals::get(principals)->GetScriptLocation(name);
 
-            // A hack: replace forward slashes with '\\' so they aren't
-            // treated as path separators.  Users of the reporters
-            // (such as about:memory) have to undo this change.
-            name->ReplaceChar('/', '\\');
-        } else {
-            name->AssignLiteral("null-codebase");
+        // For system compartments we append the location, if there is one.
+        // And we append the address if |getAddress| is true, so that
+        // multiple system compartments (and there can be many) can be
+        // distinguished.
+        if (js::IsSystemCompartment(c)) {
+            xpc::CompartmentPrivate *compartmentPrivate =
+                static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(c));
+            if (compartmentPrivate && !compartmentPrivate->location.IsEmpty()) {
+                name.AppendLiteral(", ");
+                name.Append(compartmentPrivate->location);
+            }
+            
+            if (getAddress) {
+                // ample; 64-bit address max is 18 chars
+                const int maxLength = 31;
+                nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
+                name.Append(address);
+            }
         }
+        
+        // A hack: replace forward slashes with '\\' so they aren't
+        // treated as path separators.  Users of the reporters
+        // (such as about:memory) have to undo this change.
+        name.ReplaceChar('/', '\\');
     } else {
-        name->AssignLiteral("null-principal");
+        name.AssignLiteral("null-principal");
     }
-    return name;
 }
 
-static void*
-GetCompartmentNameAndAddress(JSRuntime *rt, JSCompartment *c)
-{
-    return GetCompartmentNameHelper(c, /* get address = */true);
-}
-
-namespace xpc {
-
-void*
-GetCompartmentName(JSRuntime *rt, JSCompartment *c)
-{
-    return GetCompartmentNameHelper(c, /* get address = */false);
-}
-
-void
-DestroyCompartmentName(void *string)
-{
-    delete static_cast<nsCString*>(string);
-}
-
-} // namespace xpc
-
 // We have per-compartment GC heap totals, so we can't put the total GC heap
 // size in the explicit allocations tree.  But it's a useful figure, so put it
 // in the "others" list.
 
 static PRInt64
 GetGCChunkTotalBytes()
 {
     JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
@@ -1399,19 +1372,22 @@ NS_MEMORY_REPORTER_IMPLEMENT(
         }                                                                     \
     } while (0)
 
 template <int N>
 inline const nsCString
 MakePath(const nsACString &pathPrefix, const JS::CompartmentStats &cStats,
          const char (&reporterName)[N])
 {
-  return pathPrefix + NS_LITERAL_CSTRING("compartment(") +
-         *static_cast<nsCString*>(cStats.name) +
-         NS_LITERAL_CSTRING(")/") + nsDependentCString(reporterName);
+    const char *name = static_cast<char *>(cStats.extra);
+    if (!name)
+        name = "error while initializing compartment name";
+    return pathPrefix + NS_LITERAL_CSTRING("compartment(") +
+           nsDependentCString(name) + NS_LITERAL_CSTRING(")/") +
+           nsDependentCString(reporterName);
 }
 
 namespace mozilla {
 namespace xpconnect {
 namespace memory {
 
 static nsresult
 ReportCompartmentStats(const JS::CompartmentStats &cStats,
@@ -1689,28 +1665,25 @@ class JSCompartmentsMultiReporter : publ
         name.AssignLiteral("compartments");
         return NS_OK;
     }
 
     typedef js::Vector<nsCString, 0, js::SystemAllocPolicy> Paths; 
 
     static void CompartmentCallback(JSRuntime *rt, void* data, JSCompartment *c)
     {
+        // silently ignore OOM errors
         Paths *paths = static_cast<Paths *>(data);
-        nsCString *name =
-            static_cast<nsCString *>(xpc::GetCompartmentName(rt, c));
         nsCString path;
-        if (js::IsSystemCompartment(c))
-            path = NS_LITERAL_CSTRING("compartments/system/") + *name;
-        else
-            path = NS_LITERAL_CSTRING("compartments/user/") + *name;
-        if (!paths->append(path))
-            return;     // silent failure, but it's very unlikely
-
-        xpc::DestroyCompartmentName(name);
+        GetCompartmentName(c, /* getAddress = */ false, path);
+        path.Insert(js::IsSystemCompartment(c)
+                    ? NS_LITERAL_CSTRING("compartments/system/")
+                    : NS_LITERAL_CSTRING("compartments/user/"),
+                    0);
+        paths->append(path);
     }
 
     NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *cb,
                               nsISupports *closure)
     {
         // First we collect the compartment paths.  Then we report them.  Doing
         // the two steps interleaved is a bad idea, because calling |cb|
         // from within CompartmentCallback() leads to all manner of assertions.
@@ -1740,16 +1713,33 @@ class JSCompartmentsMultiReporter : publ
         return NS_OK;
     }
 };
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(JSCompartmentsMultiReporter
                               , nsIMemoryMultiReporter
                               )
 
+struct XPCJSRuntimeStats : public JS::RuntimeStats {
+    XPCJSRuntimeStats()
+      : JS::RuntimeStats(JsMallocSizeOf) { }
+    
+    ~XPCJSRuntimeStats() {
+        for (size_t i = 0; i != compartmentStatsVector.length(); ++i)
+            free(compartmentStatsVector[i].extra);
+    }
+
+    virtual void initExtraCompartmentStats(JSCompartment *c,
+                                           JS::CompartmentStats *cstats) MOZ_OVERRIDE {
+        nsCAutoString name;
+        GetCompartmentName(c, /* getAddress = */ true, name);
+        cstats->extra = strdup(name.get());
+    }
+};
+    
 class JSMemoryMultiReporter : public nsIMemoryMultiReporter
 {
 public:
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD GetName(nsACString &name)
     {
         name.AssignLiteral("js");
@@ -1761,18 +1751,17 @@ public:
     {
         XPCJSRuntime *xpcrt = nsXPConnect::GetRuntimeInstance();
 
         // In the first step we get all the stats and stash them in a local
         // data structure.  In the second step we pass all the stashed stats to
         // the callback.  Separating these steps is important because the
         // callback may be a JS function, and executing JS while getting these
         // stats seems like a bad idea.
-        JS::RuntimeStats rtStats(JsMallocSizeOf, GetCompartmentNameAndAddress,
-                                 xpc::DestroyCompartmentName);
+        XPCJSRuntimeStats rtStats;
         if (!JS::CollectRuntimeStats(xpcrt->GetJSRuntime(), &rtStats))
             return NS_ERROR_FAILURE;
 
         size_t xpconnect =
             xpcrt->SizeOfIncludingThis(JsMallocSizeOf) +
             XPCWrappedNativeScope::SizeOfAllScopesIncludingThis(JsMallocSizeOf);
 
         NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -1140,22 +1140,18 @@ static bool
 CreateNewCompartment(JSContext *cx, JSClass *clasp, nsIPrincipal *principal,
                      xpc::CompartmentPrivate *priv, JSObject **global,
                      JSCompartment **compartment)
 {
     // We take ownership of |priv|. Ensure that either we free it in the case
     // of failure or give ownership to the compartment in case of success (in
     // that case it will be free'd in CompartmentCallback during GC).
     nsAutoPtr<xpc::CompartmentPrivate> priv_holder(priv);
-    JSPrincipals *principals = nsnull;
-    if (principal)
-        principal->GetJSPrincipals(cx, &principals);
-    JSObject *tempGlobal = JS_NewCompartmentAndGlobalObject(cx, clasp, principals);
-    if (principals)
-        JSPRINCIPALS_DROP(cx, principals);
+    JSObject *tempGlobal =
+        JS_NewCompartmentAndGlobalObject(cx, clasp, nsJSPrincipals::get(principal));
 
     if (!tempGlobal)
         return false;
 
     *global = tempGlobal;
     *compartment = js::GetObjectCompartment(tempGlobal);
 
     JS_SetCompartmentPrivate(*compartment, priv_holder.forget());
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -217,19 +217,16 @@ bool Base64Decode(JSContext *cx, JS::Val
 /**
  * Convert an nsString to jsval, returning true on success.
  * Note, the ownership of the string buffer may be moved from str to rval.
  * If that happens, str will point to an empty string after this call.
  */
 bool StringToJsval(JSContext *cx, nsAString &str, JS::Value *rval);
 bool NonVoidStringToJsval(JSContext *cx, nsAString &str, JS::Value *rval);
 
-void *GetCompartmentName(JSRuntime *rt, JSCompartment *c);
-void DestroyCompartmentName(void *string);
-
 #ifdef DEBUG
 void DumpJSHeap(FILE* file);
 #endif
 } // namespace xpc
 
 class nsIMemoryMultiReporterCallback;
 
 namespace mozilla {
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -56,18 +56,17 @@
 using namespace mozilla;
 using namespace js;
 
 namespace xpc {
 
 nsIPrincipal *
 GetCompartmentPrincipal(JSCompartment *compartment)
 {
-    JSPrincipals *prin = JS_GetCompartmentPrincipals(compartment);
-    return prin ? static_cast<nsJSPrincipals *>(prin)->nsIPrincipalPtr : nsnull;
+    return nsJSPrincipals::get(JS_GetCompartmentPrincipals(compartment));
 }
 
 bool
 AccessCheck::isSameOrigin(JSCompartment *a, JSCompartment *b)
 {
     nsIPrincipal *aprin = GetCompartmentPrincipal(a);
     nsIPrincipal *bprin = GetCompartmentPrincipal(b);
 
--- a/security/manager/ssl/src/nsCrypto.cpp
+++ b/security/manager/ssl/src/nsCrypto.cpp
@@ -2159,49 +2159,39 @@ nsCryptoRunnable::~nsCryptoRunnable()
 }
 
 //Implementation that runs the callback passed to 
 //crypto.generateCRMFRequest as an event.
 NS_IMETHODIMP
 nsCryptoRunnable::Run()
 {
   nsNSSShutDownPreventionLock locker;
-  JSPrincipals *principals;
   JSContext *cx = m_args->m_cx;
 
   JSAutoRequest ar(cx);
   JSAutoEnterCompartment ac;
 
   if (!ac.enter(cx, m_args->m_scope)) {
     return NS_ERROR_FAILURE;
   }
 
-  nsresult rv = m_args->m_principals->GetJSPrincipals(cx, &principals);
-  if (NS_FAILED(rv))
-    return NS_ERROR_FAILURE;
-
   // make sure the right context is on the stack. must not return w/out popping
   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
   if (!stack || NS_FAILED(stack->Push(cx))) {
-    JSPRINCIPALS_DROP(cx, principals);
     return NS_ERROR_FAILURE;
   }
 
-  jsval retval;
-  if (JS_EvaluateScriptForPrincipals(cx, m_args->m_scope, principals,
-                                     m_args->m_jsCallback, 
-                                     strlen(m_args->m_jsCallback),
-                                     nsnull, 0,
-                                     &retval) != JS_TRUE) {
-    rv = NS_ERROR_FAILURE;
-  }
-
+  JSBool ok =
+    JS_EvaluateScriptForPrincipals(cx, m_args->m_scope,
+                                   nsJSPrincipals::get(m_args->m_principals),
+                                   m_args->m_jsCallback, 
+                                   strlen(m_args->m_jsCallback),
+                                   nsnull, 0, nsnull);
   stack->Pop(nsnull);
-  JSPRINCIPALS_DROP(cx, principals);
-  return rv;
+  return ok ? NS_OK : NS_ERROR_FAILURE;
 }
 
 //Quick helper function to check if a newly issued cert
 //already exists in the user's database.
 static bool
 nsCertAlreadyExists(SECItem *derCert)
 {
   CERTCertDBHandle *handle = CERT_GetDefaultCertDB();