Merge m-c to inbound
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 10 Jun 2012 21:34:50 -0400
changeset 96355 75b67011b798fb0ab754da5ced223dd0d0eb996a
parent 96353 b7fd38dad196e552a71a12f681b668449ddef107 (current diff)
parent 96334 af2a59c2334728db194971a51392b5eb27a70b9d (diff)
child 96356 2d4c140e2f47326f5014f6eab482a1914382cab5
push id22904
push useremorley@mozilla.com
push dateTue, 12 Jun 2012 09:45:09 +0000
treeherdermozilla-central@733994f12c53 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone16.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
Merge m-c to inbound
accessible/src/atk/HTMLTableAccessibleWrap.h
accessible/src/atk/XULListboxAccessibleWrap.h
accessible/src/atk/XULMenuAccessibleWrap.h
accessible/src/atk/XULTreeGridAccessibleWrap.h
accessible/src/generic/Accessible.h
accessible/src/generic/RootAccessible.h
accessible/src/html/HTMLTableAccessible.cpp
accessible/src/html/HTMLTableAccessible.h
accessible/src/mac/HTMLTableAccessibleWrap.h
accessible/src/mac/XULListboxAccessibleWrap.h
accessible/src/mac/XULMenuAccessibleWrap.h
accessible/src/mac/XULTreeGridAccessibleWrap.h
accessible/src/msaa/HTMLTableAccessibleWrap.cpp
accessible/src/msaa/HTMLTableAccessibleWrap.h
accessible/src/msaa/XULListboxAccessibleWrap.cpp
accessible/src/msaa/XULListboxAccessibleWrap.h
accessible/src/msaa/XULMenuAccessibleWrap.cpp
accessible/src/msaa/XULMenuAccessibleWrap.h
accessible/src/msaa/XULTreeGridAccessibleWrap.cpp
accessible/src/msaa/XULTreeGridAccessibleWrap.h
accessible/src/other/HTMLTableAccessibleWrap.h
accessible/src/other/XULMenuAccessibleWrap.h
accessible/src/other/XULTreeGridAccessibleWrap.h
accessible/src/xul/XULAlertAccessible.cpp
accessible/src/xul/XULAlertAccessible.h
accessible/src/xul/XULColorPickerAccessible.cpp
accessible/src/xul/XULColorPickerAccessible.h
accessible/src/xul/XULComboboxAccessible.cpp
accessible/src/xul/XULComboboxAccessible.h
accessible/src/xul/XULElementAccessibles.cpp
accessible/src/xul/XULElementAccessibles.h
accessible/src/xul/XULMenuAccessible.cpp
accessible/src/xul/XULMenuAccessible.h
accessible/src/xul/XULSliderAccessible.cpp
accessible/src/xul/XULSliderAccessible.h
accessible/src/xul/XULTabAccessible.cpp
accessible/src/xul/XULTabAccessible.h
accessible/src/xul/XULTreeAccessible.cpp
accessible/src/xul/XULTreeAccessible.h
accessible/src/xul/XULTreeGridAccessible.cpp
accessible/src/xul/XULTreeGridAccessible.h
caps/src/nsPrincipal.cpp
content/html/content/test/forms/test_meter_element.html
content/html/content/test/forms/test_meter_pseudo-classes.html
dom/base/nsDOMWindowUtils.cpp
dom/browser-element/BrowserElementChild.js
dom/browser-element/BrowserElementParent.js
dom/browser-element/BrowserElementParent.manifest
dom/browser-element/BrowserElementPromptService.jsm
dom/browser-element/mochitest/Makefile.in
dom/browser-element/mochitest/browserElementTestHelpers.js
dom/browser-element/mochitest/browserElement_Alert.js
dom/browser-element/mochitest/browserElement_Close.js
dom/browser-element/mochitest/browserElement_DataURI.js
dom/browser-element/mochitest/browserElement_GetScreenshot.js
dom/browser-element/mochitest/browserElement_Iconchange.js
dom/browser-element/mochitest/browserElement_KeyEvents.js
dom/browser-element/mochitest/browserElement_LoadEvents.js
dom/browser-element/mochitest/browserElement_PromptCheck.js
dom/browser-element/mochitest/browserElement_PromptConfirm.js
dom/browser-element/mochitest/browserElement_SetVisible.js
dom/browser-element/mochitest/browserElement_Titlechange.js
dom/browser-element/mochitest/browserElement_TopBarrier.js
dom/browser-element/mochitest/file_empty.html
dom/browser-element/mochitest/file_focus.html
dom/browser-element/mochitest/test_browserElement_NoAttr.html
dom/browser-element/mochitest/test_browserElement_NoPref.html
dom/browser-element/mochitest/test_browserElement_NoWhitelist.html
dom/browser-element/mochitest/test_browserElement_inproc_Alert.html
dom/browser-element/mochitest/test_browserElement_inproc_Close.html
dom/browser-element/mochitest/test_browserElement_inproc_DataURI.html
dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshot.html
dom/browser-element/mochitest/test_browserElement_inproc_Iconchange.html
dom/browser-element/mochitest/test_browserElement_inproc_KeyEvents.html
dom/browser-element/mochitest/test_browserElement_inproc_LoadEvents.html
dom/browser-element/mochitest/test_browserElement_inproc_PromptCheck.html
dom/browser-element/mochitest/test_browserElement_inproc_PromptConfirm.html
dom/browser-element/mochitest/test_browserElement_inproc_SetVisible.html
dom/browser-element/mochitest/test_browserElement_inproc_Titlechange.html
dom/browser-element/mochitest/test_browserElement_inproc_TopBarrier.html
dom/browser-element/mochitest/test_browserElement_oop_Alert.html
dom/browser-element/mochitest/test_browserElement_oop_Close.html
dom/browser-element/mochitest/test_browserElement_oop_DataURI.html
dom/browser-element/mochitest/test_browserElement_oop_GetScreenshot.html
dom/browser-element/mochitest/test_browserElement_oop_Iconchange.html
dom/browser-element/mochitest/test_browserElement_oop_KeyEvents.html
dom/browser-element/mochitest/test_browserElement_oop_LoadEvents.html
dom/browser-element/mochitest/test_browserElement_oop_PromptCheck.html
dom/browser-element/mochitest/test_browserElement_oop_PromptConfirm.html
dom/browser-element/mochitest/test_browserElement_oop_SetVisible.html
dom/browser-element/mochitest/test_browserElement_oop_Titlechange.html
dom/browser-element/mochitest/test_browserElement_oop_TopBarrier.html
dom/network/interfaces/nsIDOMUSSDReceivedEvent.idl
js/src/jit-test/tests/e4x/bug557168-1.js
js/src/jit-test/tests/e4x/bug557168-2.js
js/src/jit-test/tests/e4x/bug557168-3.js
js/src/jit-test/tests/e4x/bug557168.js
js/src/jit-test/tests/e4x/bug569843.js
js/src/jit-test/tests/e4x/bug574280.js
js/src/jit-test/tests/e4x/bug596502-version.js
js/src/jit-test/tests/e4x/bug605200.js
js/src/jit-test/tests/e4x/bug613151.js
js/src/jit-test/tests/e4x/bug632206.js
js/src/jit-test/tests/e4x/bug651966.js
js/src/jit-test/tests/e4x/bug665812.js
js/src/jit-test/tests/e4x/bug672153.js
js/src/jit-test/tests/e4x/bug700799.js
js/src/jit-test/tests/e4x/bug716713.js
js/src/jit-test/tests/e4x/bug731724.js
js/src/jit-test/tests/e4x/bug731745.js
js/src/jit-test/tests/e4x/bug737251.js
js/src/jit-test/tests/e4x/bug753885-1.js
js/src/jit-test/tests/e4x/bug753885-2.js
js/src/jit-test/tests/e4x/e4x-descendants-with-arguments.js
js/src/jit-test/tests/e4x/testXMLPropertyNames.js
js/src/vm/Debugger.cpp
layout/base/nsCSSRendering.cpp
layout/base/nsPresShell.cpp
layout/generic/Selection.h
layout/generic/nsFontInflationData.cpp
layout/generic/nsFontInflationData.h
layout/generic/nsHTMLReflowState.cpp
mobile/android/base/TabsPanel.java
mobile/android/base/resources/drawable-hdpi/tabs_carat.png
mobile/android/base/resources/drawable-land-hdpi-v14/tabs_carat.png
mobile/android/base/resources/drawable-land-mdpi-v14/tabs_carat.png
mobile/android/base/resources/drawable-land-xhdpi-v14/tabs_carat.png
mobile/android/base/resources/drawable-sw600dp-hdpi/tabs_carat.png
mobile/android/base/resources/drawable-sw600dp-mdpi/tabs_carat.png
mobile/android/base/resources/drawable-sw600dp-xhdpi/tabs_carat.png
mobile/android/base/resources/drawable-xhdpi-v11/tabs_carat.png
mobile/android/base/resources/drawable-xlarge-hdpi/tabs_carat.png
mobile/android/base/resources/drawable-xlarge-mdpi/tabs_carat.png
mobile/android/base/resources/drawable-xlarge-xhdpi/tabs_carat.png
mobile/android/base/resources/drawable/tabs_carat.png
mobile/android/base/resources/drawable/tabs_tray_active_selector.xml
mobile/android/base/resources/drawable/tabs_tray_default_selector.xml
mobile/android/base/resources/layout-sw600dp/gecko_app.xml
mobile/android/base/resources/layout-sw600dp/tabs_panel.xml
mobile/android/base/resources/layout-sw600dp/tabs_row.xml
mobile/android/base/resources/layout-xlarge/gecko_app.xml
mobile/android/base/resources/layout-xlarge/tabs_panel.xml
mobile/android/base/resources/layout-xlarge/tabs_row.xml
mobile/android/base/resources/layout/tabs_panel.xml
toolkit/components/osfile/Makefile.in
toolkit/components/osfile/osfile.jsm
toolkit/components/osfile/tests/mochi/Makefile.in
toolkit/components/osfile/tests/mochi/test_osfile_back.xul
--- a/caps/idl/nsIScriptSecurityManager.idl
+++ b/caps/idl/nsIScriptSecurityManager.idl
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 #include "nsIPrincipal.idl"
 #include "nsIXPCSecurityManager.idl"
 interface nsIURI;
 interface nsIChannel;
 
-[scriptable, uuid(cdb27711-492b-4973-938b-de81ac124658)]
+[scriptable, uuid(3708aa92-e2d9-4fd1-9e46-edfa3eb5ebf5)]
 interface nsIScriptSecurityManager : nsIXPCSecurityManager
 {
     ///////////////// Security Checks //////////////////
     /**
      * Checks whether the running script is allowed to access aProperty.
      */
     [noscript] void checkPropertyAccess(in JSContextPtr aJSContext,
                                         in JSObjectPtr aJSObject,
@@ -255,14 +255,37 @@ interface nsIScriptSecurityManager : nsI
      * Same as getSubjectPrincipal(), only faster. cx must *never* be
      * passed null, and it must be the context on the top of the
      * context stack. Does *not* reference count the returned
      * principal.
      */
     [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipal(in JSContextPtr cx);
     [noscript,notxpcom] nsIPrincipal getCxSubjectPrincipalAndFrame(in JSContextPtr cx,
                                                                    out JSStackFramePtr fp);
+
+    /**
+     * If no scripted code is running "above" (or called from) fp, then
+     * instead of looking at cx->globalObject, we will return |principal|.
+     * This function only affects |cx|. If someone pushes another context onto
+     * the context stack, then it supersedes this call.
+     * NOTE: If |fp| is non-null popContextPrincipal must be called before fp
+     * has finished executing.
+     *
+     * @param cx The context to clamp.
+     * @param fp The frame pointer to clamp at. May be 'null'.
+     * @param principal The principal to clamp to.
+     */
+    [noscript] void pushContextPrincipal(in JSContextPtr cx,
+                                         in JSStackFramePtr fp,
+                                         in nsIPrincipal principal);
+
+    /**
+     * Removes a clamp set by pushContextPrincipal from cx. This must be
+     * called in a stack-like fashion (e.g., given two contexts |a| and |b|,
+     * it is not legal to do: push(a) push(b) pop(a)).
+     */
+    [noscript] void popContextPrincipal(in JSContextPtr cx);
 };
 
 %{C++
 #define NS_SCRIPTSECURITYMANAGER_CONTRACTID "@mozilla.org/scriptsecuritymanager;1"
 #define NS_SCRIPTSECURITYMANAGER_CLASSNAME "scriptsecuritymanager"
 %}
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -398,21 +398,22 @@ private:
     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);
+    static nsIPrincipal*
+    doGetObjectPrincipal(JSObject *obj
 #ifdef DEBUG
-    static nsIPrincipal*
-    old_doGetObjectPrincipal(JSObject *obj, bool aAllowShortCircuit = true);
+                         , bool aAllowShortCircuit = true
 #endif
+                         );
 
     // Returns null if a principal cannot be found.  Note that rv can be NS_OK
     // when this happens -- this means that there was no JS running.
     nsIPrincipal*
     doGetSubjectPrincipal(nsresult* rv);
     
     nsresult
     CheckPropertyAccessImpl(PRUint32 aAction,
@@ -548,28 +549,40 @@ private:
     nsresult
     InitPrincipals(PRUint32 prefCount, const char** prefNames);
 
 #ifdef DEBUG_CAPS_HACKER
     void
     PrintPolicyDB();
 #endif
 
+    struct ContextPrincipal {
+        ContextPrincipal(ContextPrincipal *next, JSContext *cx,
+                         JSStackFrame *fp, nsIPrincipal *principal)
+            : mNext(next), mCx(cx), mFp(fp), mPrincipal(principal) {}
+
+        ContextPrincipal *mNext;
+        JSContext *mCx;
+        JSStackFrame *mFp;
+        nsCOMPtr<nsIPrincipal> mPrincipal;
+    };
+
     // JS strings we need to clean up on shutdown
     static jsid sEnabledID;
 
     inline void
     ScriptSecurityPrefChanged();
 
     nsObjectHashtable* mOriginToPolicyMap;
     DomainPolicy* mDefaultPolicy;
     nsObjectHashtable* mCapabilities;
 
     nsCOMPtr<nsIPrincipal> mSystemPrincipal;
     nsCOMPtr<nsIPrincipal> mSystemCertificate;
+    ContextPrincipal *mContextPrincipals;
     nsInterfaceHashtable<PrincipalKey, nsIPrincipal> mPrincipals;
     bool mPrefInitialized;
     bool mIsJavaScriptEnabled;
     bool mIsWritingPrefs;
     bool mPolicyPrefsChanged;
 
     static bool sStrictFileOriginPolicy;
 
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -157,16 +157,54 @@ GetPrincipalDomainOrigin(nsIPrincipal* a
 }
 
 static nsIScriptContext *
 GetScriptContext(JSContext *cx)
 {
     return GetScriptContextFromJSContext(cx);
 }
 
+// Callbacks for the JS engine to use to push/pop context principals.
+static JSBool
+PushPrincipalCallback(JSContext *cx, JSPrincipals *principals)
+{
+    // We should already be in the compartment of the given principal.
+    MOZ_ASSERT(principals ==
+               JS_GetCompartmentPrincipals((js::GetContextCompartment(cx))));
+
+    // Get the security manager.
+    nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+    if (!ssm) {
+        return true;
+    }
+
+    // Push the principal.
+    JSStackFrame *fp = NULL;
+    nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp),
+                                            nsJSPrincipals::get(principals));
+    if (NS_FAILED(rv)) {
+        JS_ReportOutOfMemory(cx);
+        return false;
+    }
+
+    return true;
+}
+
+static JSBool
+PopPrincipalCallback(JSContext *cx)
+{
+    nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+    if (ssm) {
+        ssm->PopContextPrincipal(cx);
+    }
+
+    return true;
+}
+
+
 inline void SetPendingException(JSContext *cx, const char *aMsg)
 {
     JSAutoRequest ar(cx);
     JS_ReportError(cx, "%s", aMsg);
 }
 
 inline void SetPendingException(JSContext *cx, const PRUnichar *aMsg)
 {
@@ -361,16 +399,44 @@ nsScriptSecurityManager::GetCxSubjectPri
     nsresult rv = NS_ERROR_FAILURE;
     nsIPrincipal *principal = GetPrincipalAndFrame(cx, fp, &rv);
     if (NS_FAILED(rv))
         return nsnull;
 
     return principal;
 }
 
+NS_IMETHODIMP
+nsScriptSecurityManager::PushContextPrincipal(JSContext *cx,
+                                              JSStackFrame *fp,
+                                              nsIPrincipal *principal)
+{
+    NS_ASSERTION(principal, "Must pass a non-null principal");
+
+    ContextPrincipal *cp = new ContextPrincipal(mContextPrincipals, cx, fp,
+                                                principal);
+    if (!cp)
+        return NS_ERROR_OUT_OF_MEMORY;
+
+    mContextPrincipals = cp;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsScriptSecurityManager::PopContextPrincipal(JSContext *cx)
+{
+    NS_ASSERTION(mContextPrincipals->mCx == cx, "Mismatched push/pop");
+
+    ContextPrincipal *next = mContextPrincipals->mNext;
+    delete mContextPrincipals;
+    mContextPrincipals = next;
+
+    return NS_OK;
+}
+
 ////////////////////
 // Policy Storage //
 ////////////////////
 
 // Table of security levels
 static bool
 DeleteCapability(nsHashKey *aKey, void *aData, void* closure)
 {
@@ -2232,29 +2298,62 @@ nsScriptSecurityManager::GetPrincipalAnd
 {
     NS_PRECONDITION(rv, "Null out param");
     //-- If there's no principal on the stack, look at the global object
     //   and return the innermost frame for annotations.
     *rv = NS_OK;
 
     if (cx)
     {
+        JSStackFrame *target = nsnull;
+        nsIPrincipal *targetPrincipal = nsnull;
+        for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext)
+        {
+            if (cp->mCx == cx)
+            {
+                target = cp->mFp;
+                targetPrincipal = cp->mPrincipal;
+                break;
+            }
+        }
+
         // Get principals from innermost JavaScript frame.
         JSStackFrame *fp = nsnull; // tell JS_FrameIterator to start at innermost
         for (fp = JS_FrameIterator(cx, &fp); fp; fp = JS_FrameIterator(cx, &fp))
         {
+            if (fp == target)
+                break;
             nsIPrincipal* result = GetFramePrincipal(cx, fp, rv);
             if (result)
             {
                 NS_ASSERTION(NS_SUCCEEDED(*rv), "Weird return");
                 *frameResult = fp;
                 return result;
             }
         }
 
+        // If targetPrincipal is non-null, then it means that someone wants to
+        // clamp the principals on this context to this principal. Note that
+        // fp might not equal target here (fp might be null) because someone
+        // could have set aside the frame chain in the meantime.
+        if (targetPrincipal)
+        {
+            if (fp && fp == target)
+            {
+                *frameResult = fp;
+            }
+            else
+            {
+                JSStackFrame *inner = nsnull;
+                *frameResult = JS_FrameIterator(cx, &inner);
+            }
+
+            return targetPrincipal;
+        }
+
         nsIScriptContextPrincipal* scp =
             GetScriptContextPrincipalFromJSContext(cx);
         if (scp)
         {
             nsIScriptObjectPrincipal* globalData = scp->GetObjectPrincipal();
             if (!globalData)
             {
                 *rv = NS_ERROR_FAILURE;
@@ -2275,67 +2374,47 @@ nsScriptSecurityManager::GetPrincipalAnd
 
     return nsnull;
 }
 
 nsIPrincipal*
 nsScriptSecurityManager::GetSubjectPrincipal(JSContext *cx,
                                              nsresult* rv)
 {
-    *rv = NS_OK;
-    JSCompartment *compartment = js::GetContextCompartment(cx);
-
-    // The context should always be in a compartment, either one it has entered
-    // or the one associated with its global.
-    MOZ_ASSERT(!!compartment);
-
-    JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
-    return nsJSPrincipals::get(principals);
+    NS_PRECONDITION(rv, "Null out param");
+    JSStackFrame *fp;
+    return GetPrincipalAndFrame(cx, &fp, rv);
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
                                             nsIPrincipal **result)
 {
     *result = doGetObjectPrincipal(aObj);
     if (!*result)
         return NS_ERROR_FAILURE;
     NS_ADDREF(*result);
     return NS_OK;
 }
 
 // static
 nsIPrincipal*
-nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
-{
-    JSCompartment *compartment = js::GetObjectCompartment(aObj);
-    JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
-    nsIPrincipal *principal = nsJSPrincipals::get(principals);
-
-    // We leave the old code in for a little while to make sure that pulling
-    // object principals directly off the compartment always gives an equivalent
-    // result (from a security perspective).
+nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
 #ifdef DEBUG
-    nsIPrincipal *old = old_doGetObjectPrincipal(aObj);
-    MOZ_ASSERT(NS_SUCCEEDED(CheckSameOriginPrincipal(principal, old)));
+                                              , bool aAllowShortCircuit
 #endif
-
-    return principal;
-}
-
-#ifdef DEBUG
-// static
-nsIPrincipal*
-nsScriptSecurityManager::old_doGetObjectPrincipal(JSObject *aObj,
-                                                  bool aAllowShortCircuit)
+                                              )
 {
     NS_ASSERTION(aObj, "Bad call to doGetObjectPrincipal()!");
     nsIPrincipal* result = nsnull;
 
+#ifdef DEBUG
     JSObject* origObj = aObj;
+#endif
+    
     js::Class *jsClass = js::GetObjectClass(aObj);
 
     // A common case seen in this code is that we enter this function
     // with aObj being a Function object, whose parent is a Call
     // object. Neither of those have object principals, so we can skip
     // those objects here before we enter the below loop. That way we
     // avoid wasting time checking properties of their classes etc in
     // the loop.
@@ -2359,41 +2438,48 @@ nsScriptSecurityManager::old_doGetObject
     }
 
     do {
         // Note: jsClass is set before this loop, and also at the
         // *end* of this loop.
         
         if (IS_WRAPPER_CLASS(jsClass)) {
             result = sXPConnect->GetPrincipal(aObj,
-                                              aAllowShortCircuit);
+#ifdef DEBUG
+                                              aAllowShortCircuit
+#else
+                                              true
+#endif
+                                              );
             if (result) {
                 break;
             }
         } else {
             nsISupports *priv;
             if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
                                      JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
                 priv = (nsISupports *) js::GetObjectPrivate(aObj);
             } else if (IsDOMClass(jsClass) &&
                        DOMJSClass::FromJSClass(jsClass)->mDOMObjectIsISupports) {
                 priv = UnwrapDOMObject<nsISupports>(aObj);
             } else {
                 priv = nsnull;
             }
 
+#ifdef DEBUG
             if (aAllowShortCircuit) {
                 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
                     do_QueryInterface(priv);
 
                 NS_ASSERTION(!xpcWrapper ||
                              !strcmp(jsClass->name, "XPCNativeWrapper"),
                              "Uh, an nsIXPConnectWrappedNative with the "
                              "wrong JSClass or getObjectOps hooks!");
             }
+#endif
 
             nsCOMPtr<nsIScriptObjectPrincipal> objPrin =
                 do_QueryInterface(priv);
 
             if (objPrin) {
                 result = objPrin->GetPrincipal();
 
                 if (result) {
@@ -2405,45 +2491,62 @@ nsScriptSecurityManager::old_doGetObject
         aObj = js::GetObjectParentMaybeScope(aObj);
 
         if (!aObj)
             break;
 
         jsClass = js::GetObjectClass(aObj);
     } while (1);
 
+#ifdef DEBUG
     if (aAllowShortCircuit) {
-        nsIPrincipal *principal = old_doGetObjectPrincipal(origObj, false);
+        nsIPrincipal *principal = doGetObjectPrincipal(origObj, false);
 
         // Because of inner window reuse, we can have objects with one principal
         // living in a scope with a different (but same-origin) principal. So
         // just check same-origin here.
         NS_ASSERTION(NS_SUCCEEDED(CheckSameOriginPrincipal(result, principal)),
                      "Principal mismatch.  Not good");
     }
+#endif
 
     return result;
 }
-#endif /* DEBUG */
 
 ///////////////// Capabilities API /////////////////////
 NS_IMETHODIMP
 nsScriptSecurityManager::IsCapabilityEnabled(const char *capability,
                                              bool *result)
 {
     nsresult rv;
     JSStackFrame *fp = nsnull;
     JSContext *cx = GetCurrentJSContext();
     fp = cx ? JS_FrameIterator(cx, &fp) : nsnull;
 
+    JSStackFrame *target = nsnull;
+    nsIPrincipal *targetPrincipal = nsnull;
+    for (ContextPrincipal *cp = mContextPrincipals; cp; cp = cp->mNext)
+    {
+        if (cp->mCx == cx)
+        {
+            target = cp->mFp;
+            targetPrincipal = cp->mPrincipal;
+            break;
+        }
+    }
+
     if (!fp)
     {
-        // No script code on stack. We don't have enough information and have
-        // to allow execution.
-        *result = true;
+        // No script code on stack. If we had a principal pushed for this
+        // context and fp is null, then we use that principal. Otherwise, we
+        // don't have enough information and have to allow execution.
+
+        *result = (targetPrincipal && !target)
+                  ? (targetPrincipal == mSystemPrincipal)
+                  : true;
 
         return NS_OK;
     }
 
     *result = false;
     nsIPrincipal* previousPrincipal = nsnull;
     do
     {
@@ -2477,17 +2580,17 @@ nsScriptSecurityManager::IsCapabilityEna
         if (NS_FAILED(rv)) return rv;
         if (*result)
             return NS_OK;
 
         // Capabilities do not extend to calls into C/C++ and then back into
         // the JS engine via JS_EvaluateScript or similar APIs.
         if (JS_IsGlobalFrame(cx, fp))
             break;
-    } while ((fp = JS_FrameIterator(cx, &fp)) != nsnull);
+    } while (fp != target && (fp = JS_FrameIterator(cx, &fp)) != nsnull);
 
     if (!previousPrincipal)
     {
         // No principals on the stack, all native code.  Allow
         // execution if the subject principal is the system principal.
 
         return SubjectPrincipalIsSystem(result);
     }
@@ -2961,16 +3064,17 @@ nsScriptSecurityManager::Observe(nsISupp
 
 /////////////////////////////////////////////
 // Constructor, Destructor, Initialization //
 /////////////////////////////////////////////
 nsScriptSecurityManager::nsScriptSecurityManager(void)
     : mOriginToPolicyMap(nsnull),
       mDefaultPolicy(nsnull),
       mCapabilities(nsnull),
+      mContextPrincipals(nsnull),
       mPrefInitialized(false),
       mIsJavaScriptEnabled(false),
       mIsWritingPrefs(false),
       mPolicyPrefsChanged(true)
 {
     MOZ_STATIC_ASSERT(sizeof(intptr_t) == sizeof(void*),
                       "intptr_t and void* have different lengths on this platform. "
                       "This may cause a security failure with the SecurityLevel union.");
@@ -3021,17 +3125,19 @@ nsresult nsScriptSecurityManager::Init()
 
     rv = runtimeService->GetRuntime(&sRuntime);
     NS_ENSURE_SUCCESS(rv, rv);
 
     static const JSSecurityCallbacks securityCallbacks = {
         CheckObjectAccess,
         nsJSPrincipals::Subsume,
         ObjectPrincipalFinder,
-        ContentSecurityPolicyPermitsJSAction
+        ContentSecurityPolicyPermitsJSAction,
+        PushPrincipalCallback,
+        PopPrincipalCallback
     };
 
     MOZ_ASSERT(!JS_GetSecurityCallbacks(sRuntime));
     JS_SetSecurityCallbacks(sRuntime, &securityCallbacks);
     JS_InitDestroyPrincipalsCallback(sRuntime, nsJSPrincipals::Destroy);
 
     JS_SetTrustedPrincipals(sRuntime, system);
 
@@ -3040,16 +3146,17 @@ nsresult nsScriptSecurityManager::Init()
 
 static nsScriptSecurityManager *gScriptSecMan = nsnull;
 
 jsid nsScriptSecurityManager::sEnabledID   = JSID_VOID;
 
 nsScriptSecurityManager::~nsScriptSecurityManager(void)
 {
     Preferences::RemoveObservers(this, kObservedPrefs);
+    NS_ASSERTION(!mContextPrincipals, "Leaking mContextPrincipals");
     delete mOriginToPolicyMap;
     if(mDefaultPolicy)
         mDefaultPolicy->Drop();
     delete mCapabilities;
     gScriptSecMan = nsnull;
 }
 
 void
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1193,55 +1193,56 @@ nsJSContext::EvaluateStringWithValue(con
     }
 
     return NS_OK;
   }
 
   xpc_UnmarkGrayObject(aScopeObject);
   nsAutoMicroTask mt;
 
-  // Ignore the principal that was passed in, and just assert that it matches
-  // the one we pull off the global.
-  nsCOMPtr<nsIPrincipal> principal;
-  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = do_QueryInterface(GetGlobalObject());
-  if (!objPrincipal)
-    return NS_ERROR_FAILURE;
-  principal = objPrincipal->GetPrincipal();
-  if (!principal)
-    return NS_ERROR_FAILURE;
-#ifdef DEBUG
-  bool equal = false;
-  principal->Equals(aPrincipal, &equal);
-  MOZ_ASSERT(equal);
-  nsIPrincipal *scopeObjectPrincipal =
-    nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject)));
-  equal = false;
-  principal->Equals(scopeObjectPrincipal, &equal);
-  MOZ_ASSERT(equal);
-#endif
+  // 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.
+  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;
+  }
 
   bool ok = false;
 
-  nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
+  rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
   if (NS_FAILED(rv)) {
     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))) {
     return NS_ERROR_FAILURE;
   }
 
   jsval val;
 
+  rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsJSContext::TerminationFuncHolder holder(this);
 
   // 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) {
 
     XPCAutoRequest ar(mContext);
@@ -1287,16 +1288,18 @@ nsJSContext::EvaluateStringWithValue(con
     // tricky...
   }
   else {
     if (aIsUndefined) {
       *aIsUndefined = true;
     }
   }
 
+  sSecurityManager->PopContextPrincipal(mContext);
+
   // Pop here, after JS_ValueToString and any other possible evaluation.
   if (NS_FAILED(stack->Pop(nsnull)))
     rv = NS_ERROR_FAILURE;
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(true);
 
   return rv;
@@ -1392,35 +1395,29 @@ nsJSContext::EvaluateString(const nsAStr
   nsAutoMicroTask mt;
 
   if (!aScopeObject) {
     aScopeObject = JS_GetGlobalObject(mContext);
   }
 
   xpc_UnmarkGrayObject(aScopeObject);
 
-  // Ignore the principal that was passed in, and just assert that it matches
-  // the one we pull off the global.
-  nsCOMPtr<nsIPrincipal> principal;
-  nsCOMPtr<nsIScriptObjectPrincipal> objPrincipal = do_QueryInterface(GetGlobalObject());
-  if (!objPrincipal)
-    return NS_ERROR_FAILURE;
-  principal = objPrincipal->GetPrincipal();
-  if (!principal)
-    return NS_ERROR_FAILURE;
-#ifdef DEBUG
-  bool equal = false;
-  principal->Equals(aPrincipal, &equal);
-  MOZ_ASSERT(equal);
-  nsIPrincipal *scopeObjectPrincipal =
-    nsJSPrincipals::get(JS_GetCompartmentPrincipals(js::GetObjectCompartment(aScopeObject)));
-  equal = false;
-  principal->Equals(scopeObjectPrincipal, &equal);
-  MOZ_ASSERT(equal);
-#endif
+  // 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.
+  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;
+  }
 
   bool ok = false;
 
   nsresult rv = sSecurityManager->CanExecuteScripts(mContext, principal, &ok);
   if (NS_FAILED(rv)) {
     return NS_ERROR_FAILURE;
   }
 
@@ -1435,16 +1432,19 @@ nsJSContext::EvaluateString(const nsAStr
   }
 
   // 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;
 
+  rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsJSContext::TerminationFuncHolder holder(this);
 
   ++mExecuteDepth;
 
   // 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) {
@@ -1486,16 +1486,18 @@ nsJSContext::EvaluateString(const nsAStr
 
     if (aRetValue) {
       aRetValue->Truncate();
     }
   }
 
   --mExecuteDepth;
 
+  sSecurityManager->PopContextPrincipal(mContext);
+
   // Pop here, after JS_ValueToString and any other possible evaluation.
   if (NS_FAILED(stack->Pop(nsnull)))
     rv = NS_ERROR_FAILURE;
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(true);
 
   return rv;
@@ -1583,16 +1585,25 @@ nsJSContext::ExecuteScript(JSScript* aSc
   // called from JS calls back into JS via XPConnect.
   nsresult rv;
   nsCOMPtr<nsIJSContextStack> stack =
            do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
   if (NS_FAILED(rv) || NS_FAILED(stack->Push(mContext))) {
     return NS_ERROR_FAILURE;
   }
 
+  nsCOMPtr<nsIPrincipal> principal;
+  rv = sSecurityManager->GetObjectPrincipal(mContext,
+                                            JS_GetGlobalFromScript(aScriptObject),
+                                            getter_AddRefs(principal));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = sSecurityManager->PushContextPrincipal(mContext, nsnull, principal);
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsJSContext::TerminationFuncHolder holder(this);
   XPCAutoRequest ar(mContext);
   ++mExecuteDepth;
 
   // 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;
@@ -1609,16 +1620,18 @@ nsJSContext::ExecuteScript(JSScript* aSc
 
     if (aRetValue) {
       aRetValue->Truncate();
     }
   }
 
   --mExecuteDepth;
 
+  sSecurityManager->PopContextPrincipal(mContext);
+
   // Pop here, after JS_ValueToString and any other possible evaluation.
   if (NS_FAILED(stack->Pop(nsnull)))
     rv = NS_ERROR_FAILURE;
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(true);
 
   return rv;
@@ -1849,22 +1862,34 @@ nsJSContext::CallEventHandler(nsISupport
   nsJSContext::TerminationFuncHolder holder(this);
 
   if (NS_SUCCEEDED(rv)) {
     // Convert args to jsvals.
     PRUint32 argc = 0;
     jsval *argv = nsnull;
 
     JSObject *funobj = aHandler;
+    nsCOMPtr<nsIPrincipal> principal;
+    rv = sSecurityManager->GetObjectPrincipal(mContext, funobj,
+                                              getter_AddRefs(principal));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    JSStackFrame *currentfp = nsnull;
+    rv = sSecurityManager->PushContextPrincipal(mContext,
+                                                JS_FrameIterator(mContext, &currentfp),
+                                                principal);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     jsval funval = OBJECT_TO_JSVAL(funobj);
     JSAutoEnterCompartment ac;
     js::ForceFrame ff(mContext, funobj);
     if (!ac.enter(mContext, funobj) || !ff.enter() ||
         !JS_WrapObject(mContext, &target)) {
       ReportPendingException();
+      sSecurityManager->PopContextPrincipal(mContext);
       return NS_ERROR_FAILURE;
     }
 
     Maybe<nsRootedJSValueArray> tempStorage;
 
     // Use |target| as the scope for wrapping the arguments, since aScope is
     // the safe scope in many cases, which isn't very useful.  Wrapping aTarget
     // was OK because those typically have PreCreate methods that give them the
@@ -1897,16 +1922,18 @@ nsJSContext::CallEventHandler(nsISupport
       rv = nsContentUtils::XPConnect()->JSToVariant(mContext, rval, arv);
     }
 
     // Tell XPConnect about any pending exceptions. This is needed
     // to avoid dropping JS exceptions in case we got here through
     // nested calls through XPConnect.
     if (NS_FAILED(rv))
       ReportPendingException();
+
+    sSecurityManager->PopContextPrincipal(mContext);
   }
 
   pusher.Pop();
 
   // ScriptEvaluated needs to come after we pop the stack
   ScriptEvaluated(true);
 
   return rv;
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -91,26 +91,26 @@ bindinggen_dependencies := \
 	$(INSTALL) $(IFLAGS1) $(webidl_base)/$* .
 
 $(test_webidl_files): %: $(srcdir)/test/%
 	$(INSTALL) $(IFLAGS1) $(srcdir)/test/$* .
 
 $(binding_header_files): %Binding.h: $(bindinggen_dependencies) \
                                      %.webidl \
                                      $(NULL)
-	PYTHONDONTWRITEBYTECODE=1 $(PYTHON_PATH) \
+	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
 	  $(PLY_INCLUDE) -I$(srcdir)/parser \
 	  $(srcdir)/BindingGen.py $(ACCESSOR_OPT) header \
 	  $(srcdir)/Bindings.conf $*Binding \
 	  $*.webidl
 
 $(binding_cpp_files): %Binding.cpp: $(bindinggen_dependencies) \
                                     %.webidl \
                                     $(NULL)
-	PYTHONDONTWRITEBYTECODE=1 $(PYTHON_PATH) \
+	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
 	  $(PLY_INCLUDE) -I$(srcdir)/parser \
 	  $(srcdir)/BindingGen.py $(ACCESSOR_OPT) cpp \
 	  $(srcdir)/Bindings.conf $*Binding \
 	  $*.webidl
 
 $(globalgen_targets): ParserResults.pkl
 
 CACHE_DIR = _cache
@@ -125,17 +125,17 @@ globalgen_dependencies := \
   $(NULL)
 
 $(CACHE_DIR)/.done:
 	$(MKDIR) -p $(CACHE_DIR)
 	@$(TOUCH) $@
 
 ParserResults.pkl: $(globalgen_dependencies) \
                    $(all_webidl_files)
-	PYTHONDONTWRITEBYTECODE=1 $(PYTHON_PATH) \
+	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
     $(PLY_INCLUDE) -I$(srcdir)/parser \
     $(srcdir)/GlobalGen.py $(ACCESSOR_OPT) $(srcdir)/Bindings.conf . \
     --cachedir=$(CACHE_DIR) \
     $(all_webidl_files)
 
 GARBAGE += \
   $(binding_header_files) \
   $(binding_cpp_files) \
--- a/dom/src/json/nsJSON.cpp
+++ b/dom/src/json/nsJSON.cpp
@@ -172,25 +172,42 @@ NS_IMETHODIMP
 nsJSON::EncodeFromJSVal(JS::Value *value, JSContext *cx, nsAString &result)
 {
   result.Truncate();
 
   // Begin a new request
   JSAutoRequest ar(cx);
 
   JSAutoEnterCompartment ac;
+  nsIScriptSecurityManager *ssm = nsnull;
   if (value->isObject()) {
     JSObject *obj = &value->toObject();
     if (!ac.enter(cx, obj)) {
       return NS_ERROR_FAILURE;
     }
+
+    nsCOMPtr<nsIPrincipal> principal;
+    ssm = nsContentUtils::GetSecurityManager();
+    nsresult rv = ssm->GetObjectPrincipal(cx, obj, getter_AddRefs(principal));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    JSStackFrame *fp = nsnull;
+    rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal);
+    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsJSONWriter writer;
-  if (!JS_Stringify(cx, value, NULL, JSVAL_NULL, WriteCallback, &writer)) {
+  JSBool ok = JS_Stringify(cx, value, NULL, JSVAL_NULL,
+                           WriteCallback, &writer);
+
+  if (ssm) {
+    ssm->PopContextPrincipal(cx);
+  }
+
+  if (!ok) {
     return NS_ERROR_XPC_BAD_CONVERT_JS;
   }
 
   NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED);
   writer.FlushBuffer();
   result.Assign(writer.mOutputString);
   return NS_OK;
 }
--- a/dom/tests/mochitest/whatwg/postMessage_chrome_helper.html
+++ b/dom/tests/mochitest/whatwg/postMessage_chrome_helper.html
@@ -32,17 +32,19 @@
           msg += " wrong-message(" + evt.data + ")";
 
         respond(msg);
       }
     }
     
     function respond(msg)
     {
-      SpecialPowers.wrap(window).parent.postMessage(msg, "*");
+      // ...so get privileges and test that this works with privileges
+      netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
+      window.parent.postMessage(msg, "*");
     }
     
     window.addEventListener("message", receiveMessage, false);
   </script>
 </head>
 <body>
 <h1 id="domain">example.org</h1>
 </body>
--- a/dom/tests/mochitest/whatwg/test_postMessage_chrome.html
+++ b/dom/tests/mochitest/whatwg/test_postMessage_chrome.html
@@ -88,16 +88,20 @@ function chromePathIsSet(evt)
 
 /*************
  * RECEIVERS *
  *************/
 
 function receiveContent(evt)
 {
   is(evt.isTrusted, true, "should have sent a trusted event");
+  is(evt.origin, "http://example.org", "content response event has wrong URI");
+  is(evt.source, window.frames.contentDomain,
+     "wrong source for same-domain message!");
+
   finish();
 }
 
 
 /**************
  * TEST SETUP *
  **************/
 
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -875,16 +875,30 @@ FullTrustSecMan::GetCxSubjectPrincipal(J
 NS_IMETHODIMP_(nsIPrincipal *)
 FullTrustSecMan::GetCxSubjectPrincipalAndFrame(JSContext *cx,
                                                JSStackFrame **fp)
 {
     *fp = nsnull;
     return mSystemPrincipal;
 }
 
+NS_IMETHODIMP
+FullTrustSecMan::PushContextPrincipal(JSContext *cx,
+                                      JSStackFrame *fp,
+                                      nsIPrincipal *principal)
+{
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+FullTrustSecMan::PopContextPrincipal(JSContext *cx)
+{
+    return NS_OK;
+}
+
 NS_IMETHODIMP_(nsrefcnt)
 XPCShellDirProvider::AddRef()
 {
     return 2;
 }
 
 NS_IMETHODIMP_(nsrefcnt)
 XPCShellDirProvider::Release()
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1667,16 +1667,26 @@ typedef JSPrincipals *
 /*
  * Used to check if a CSP instance wants to disable eval() and friends.
  * See js_CheckCSPPermitsJSAction() in jsobj.
  */
 typedef JSBool
 (* JSCSPEvalChecker)(JSContext *cx);
 
 /*
+ * Security callbacks for pushing and popping context principals. These are only
+ * temporarily necessary and will hopefully be gone again in a matter of weeks.
+ */
+typedef JSBool
+(* JSPushContextPrincipalOp)(JSContext *cx, JSPrincipals *principals);
+
+typedef JSBool
+(* JSPopContextPrincipalOp)(JSContext *cx);
+
+/*
  * Callback used to ask the embedding for the cross compartment wrapper handler
  * that implements the desired prolicy for this kind of object in the
  * destination compartment.
  */
 typedef JSObject *
 (* JSWrapObjectCallback)(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
                          unsigned flags);
 
@@ -4334,16 +4344,18 @@ JS_HoldPrincipals(JSPrincipals *principa
 extern JS_PUBLIC_API(void)
 JS_DropPrincipals(JSRuntime *rt, JSPrincipals *principals);
 
 struct JSSecurityCallbacks {
     JSCheckAccessOp            checkObjectAccess;
     JSSubsumePrincipalsOp      subsumePrincipals;
     JSObjectPrincipalsFinder   findObjectPrincipals;
     JSCSPEvalChecker           contentSecurityPolicyAllows;
+    JSPushContextPrincipalOp   pushContextPrincipal;
+    JSPopContextPrincipalOp    popContextPrincipal;
 };
 
 extern JS_PUBLIC_API(void)
 JS_SetSecurityCallbacks(JSRuntime *rt, const JSSecurityCallbacks *callbacks);
 
 extern JS_PUBLIC_API(const JSSecurityCallbacks *)
 JS_GetSecurityCallbacks(JSRuntime *rt);
 
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -467,16 +467,47 @@ JSStructuredCloneWriter::startObject(JSO
     if (!objs.append(ObjectValue(*obj)) || !counts.append(count))
         return false;
     checkStack();
 
     /* Write the header for obj. */
     return out.writePair(obj->isArray() ? SCTAG_ARRAY_OBJECT : SCTAG_OBJECT_OBJECT, 0);
 }
 
+class AutoEnterCompartmentAndPushPrincipal : public JSAutoEnterCompartment
+{
+  public:
+    bool enter(JSContext *cx, JSObject *target) {
+        // First, enter the compartment.
+        if (!JSAutoEnterCompartment::enter(cx, target))
+            return false;
+
+        // We only need to push a principal if we changed compartments.
+        if (state != STATE_OTHER_COMPARTMENT)
+            return true;
+
+        // Push.
+        const JSSecurityCallbacks *cb = cx->runtime->securityCallbacks;
+        if (cb->pushContextPrincipal)
+          return cb->pushContextPrincipal(cx, target->principals(cx));
+        return true;
+    };
+
+    ~AutoEnterCompartmentAndPushPrincipal() {
+        // Pop the principal if necessary.
+        if (state == STATE_OTHER_COMPARTMENT) {
+            AutoCompartment *ac = getAutoCompartment();
+            const JSSecurityCallbacks *cb = ac->context->runtime->securityCallbacks;
+            if (cb->popContextPrincipal)
+              cb->popContextPrincipal(ac->context);
+        }
+    };
+};
+
+
 bool
 JSStructuredCloneWriter::startWrite(const Value &v)
 {
     assertSameCompartment(context(), v);
 
     if (v.isString()) {
         return writeString(SCTAG_STRING, v.toString());
     } else if (v.isNumber()) {
@@ -493,17 +524,17 @@ JSStructuredCloneWriter::startWrite(cons
         // The object might be a security wrapper. See if we can clone what's
         // behind it. If we can, unwrap the object.
         obj = UnwrapObjectChecked(context(), obj);
         if (!obj)
             return false;
 
         // If we unwrapped above, we'll need to enter the underlying compartment.
         // Let the AutoEnterCompartment do the right thing for us.
-        JSAutoEnterCompartment ac;
+        AutoEnterCompartmentAndPushPrincipal ac;
         if (!ac.enter(context(), obj))
             return false;
 
         if (obj->isRegExp()) {
             RegExpObject &reobj = obj->asRegExp();
             return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) &&
                    writeString(SCTAG_STRING, reobj.getSource());
         } else if (obj->isDate()) {
@@ -538,17 +569,17 @@ JSStructuredCloneWriter::write(const Val
 {
     if (!startWrite(v))
         return false;
 
     while (!counts.empty()) {
         RootedObject obj(context(), &objs.back().toObject());
 
         // The objects in |obj| can live in other compartments.
-        JSAutoEnterCompartment ac;
+        AutoEnterCompartmentAndPushPrincipal ac;
         if (!ac.enter(context(), obj))
             return false;
 
         if (counts.back()) {
             counts.back()--;
             RootedId id(context(), ids.back());
             ids.popBack();
             checkStack();
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -1390,16 +1390,30 @@ FullTrustSecMan::CanExecuteScripts(JSCon
 /* [noscript] nsIPrincipal getSubjectPrincipal (); */
 NS_IMETHODIMP
 FullTrustSecMan::GetSubjectPrincipal(nsIPrincipal **_retval)
 {
     NS_IF_ADDREF(*_retval = mSystemPrincipal);
     return *_retval ? NS_OK : NS_ERROR_FAILURE;
 }
 
+/* [noscript] void pushContextPrincipal (in JSContextPtr cx, in JSStackFramePtr fp, in nsIPrincipal principal); */
+NS_IMETHODIMP
+FullTrustSecMan::PushContextPrincipal(JSContext * cx, JSStackFrame * fp, nsIPrincipal *principal)
+{
+    return NS_OK;
+}
+
+/* [noscript] void popContextPrincipal (in JSContextPtr cx); */
+NS_IMETHODIMP
+FullTrustSecMan::PopContextPrincipal(JSContext * cx)
+{
+    return NS_OK;
+}
+
 /* [noscript] nsIPrincipal getSystemPrincipal (); */
 NS_IMETHODIMP
 FullTrustSecMan::GetSystemPrincipal(nsIPrincipal **_retval)
 {
     NS_IF_ADDREF(*_retval = mSystemPrincipal);
     return *_retval ? NS_OK : NS_ERROR_FAILURE;
 }
 
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -1111,16 +1111,27 @@ nsXPCWrappedJSClass::CheckForException(X
         // see if JS code signaled failure result without throwing exception
         if (NS_FAILED(pending_result)) {
             return pending_result;
         }
     }
     return NS_ERROR_FAILURE;
 }
 
+class ContextPrincipalGuard
+{
+    nsIScriptSecurityManager *ssm;
+    XPCCallContext &ccx;
+  public:
+    ContextPrincipalGuard(XPCCallContext &ccx)
+      : ssm(nsnull), ccx(ccx) {}
+    void principalPushed(nsIScriptSecurityManager *ssm) { this->ssm = ssm; }
+    ~ContextPrincipalGuard() { if (ssm) ssm->PopContextPrincipal(ccx); }
+};
+
 NS_IMETHODIMP
 nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16_t methodIndex,
                                 const XPTMethodDescriptor* info,
                                 nsXPTCMiniVariant* nativeParams)
 {
     jsval* sp = nsnull;
     jsval* argv = nsnull;
     uint8_t i;
@@ -1154,29 +1165,52 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
     JSAutoEnterCompartment ac;
     if (!ac.enter(cx, obj))
         return NS_ERROR_FAILURE;
 
     ccx.SetScopeForNewJSObjects(obj);
 
     JS::AutoValueVector args(cx);
     AutoScriptEvaluate scriptEval(cx);
+    ContextPrincipalGuard principalGuard(ccx);
 
     // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
     uint8_t paramCount = info->num_args;
     uint8_t argc = paramCount -
         (paramCount && XPT_PD_IS_RETVAL(info->params[paramCount-1].flags) ? 1 : 0);
 
     if (!scriptEval.StartEvaluating(obj, xpcWrappedJSErrorReporter))
         goto pre_call_clean_up;
 
     xpcc->SetPendingResult(pending_result);
     xpcc->SetException(nsnull);
     ccx.GetThreadData()->SetException(nsnull);
 
+    if (XPCPerThreadData::IsMainThread(ccx)) {
+        // TODO Remove me in favor of security wrappers.
+        nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+        if (ssm) {
+            nsIPrincipal *objPrincipal =
+                xpc::AccessCheck::getPrincipal(js::GetObjectCompartment(obj));
+            if (objPrincipal) {
+                JSStackFrame* fp = nsnull;
+                nsresult rv =
+                    ssm->PushContextPrincipal(ccx, JS_FrameIterator(ccx, &fp),
+                                              objPrincipal);
+                if (NS_FAILED(rv)) {
+                    JS_ReportOutOfMemory(ccx);
+                    retval = NS_ERROR_OUT_OF_MEMORY;
+                    goto pre_call_clean_up;
+                }
+
+                principalGuard.principalPushed(ssm);
+            }
+        }
+    }
+
     // We use js_Invoke so that the gcthings we use as args will be rooted by
     // the engine as we do conversions and prepare to do the function call.
 
     // setup stack
 
     // if this isn't a function call then we don't need to push extra stuff
     if (!(XPT_MD_IS_SETTER(info->flags) || XPT_MD_IS_GETTER(info->flags))) {
         // We get fval before allocating the stack to avoid gc badness that can
--- a/js/xpconnect/wrappers/CrossOriginWrapper.cpp
+++ b/js/xpconnect/wrappers/CrossOriginWrapper.cpp
@@ -10,17 +10,25 @@
 #include "XPCWrapper.h"
 
 #include "CrossOriginWrapper.h"
 #include "AccessCheck.h"
 #include "WrapperFactory.h"
 
 namespace xpc {
 
-CrossOriginWrapper::CrossOriginWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags)
+NoWaiverWrapper::NoWaiverWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags)
+{
+}
+
+NoWaiverWrapper::~NoWaiverWrapper()
+{
+}
+
+CrossOriginWrapper::CrossOriginWrapper(unsigned flags) : NoWaiverWrapper(flags)
 {
 }
 
 CrossOriginWrapper::~CrossOriginWrapper()
 {
 }
 
 bool
@@ -57,9 +65,41 @@ CrossOriginWrapper::call(JSContext *cx, 
 bool
 CrossOriginWrapper::construct(JSContext *cx, JSObject *wrapper,
                               unsigned argc, js::Value *argv, js::Value *rval)
 {
     return CrossCompartmentWrapper::construct(cx, wrapper, argc, argv, rval) &&
            WrapperFactory::WaiveXrayAndWrap(cx, rval);
 }
 
+bool
+NoWaiverWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp)
+{
+    *bp = true; // always allowed
+    nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+    if (!ssm) {
+        return true;
+    }
+
+    // Note: By the time enter is called here, CrossCompartmentWrapper has
+    // already pushed the fake stack frame onto cx. Because of this, the frame
+    // that we're clamping is the one that we want (the one in our compartment).
+    JSStackFrame *fp = NULL;
+    nsIPrincipal *principal = GetCompartmentPrincipal(js::GetObjectCompartment(wrappedObject(wrapper)));
+    nsresult rv = ssm->PushContextPrincipal(cx, JS_FrameIterator(cx, &fp), principal);
+    if (NS_FAILED(rv)) {
+        NS_WARNING("Not allowing call because we're out of memory");
+        JS_ReportOutOfMemory(cx);
+        return false;
+    }
+    return true;
 }
+
+void
+NoWaiverWrapper::leave(JSContext *cx, JSObject *wrapper)
+{
+    nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
+    if (ssm) {
+        ssm->PopContextPrincipal(cx);
+    }
+}
+
+}
--- a/js/xpconnect/wrappers/CrossOriginWrapper.h
+++ b/js/xpconnect/wrappers/CrossOriginWrapper.h
@@ -10,17 +10,28 @@
 
 #include "mozilla/Attributes.h"
 
 #include "jsapi.h"
 #include "jswrapper.h"
 
 namespace xpc {
 
-class CrossOriginWrapper : public js::CrossCompartmentWrapper {
+class NoWaiverWrapper : public js::CrossCompartmentWrapper {
+  public:
+    NoWaiverWrapper(unsigned flags);
+    virtual ~NoWaiverWrapper();
+
+    virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, Action act, bool *bp) MOZ_OVERRIDE;
+    virtual void leave(JSContext *cx, JSObject *wrapper) MOZ_OVERRIDE;
+
+    static NoWaiverWrapper singleton;
+};
+
+class CrossOriginWrapper : public NoWaiverWrapper {
   public:
     CrossOriginWrapper(unsigned flags);
     virtual ~CrossOriginWrapper();
 
     virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                        bool set, js::PropertyDescriptor *desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                           bool set, js::PropertyDescriptor *desc) MOZ_OVERRIDE;
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -26,16 +26,23 @@ namespace xpc {
 // .wrappedJSObject, we want it to cross the membrane into the
 // chrome compartment without automatically being wrapped into an
 // X-ray wrapper. We achieve this by wrapping it into a special
 // transparent wrapper in the origin (non-chrome) compartment. When
 // an object with that special wrapper applied crosses into chrome,
 // we know to not apply an X-ray wrapper.
 Wrapper WaiveXrayWrapperWrapper(WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG);
 
+// Objects that haven't been explicitly waived, but have been exposed
+// to chrome don't want a CrossOriginWrapper, since that deeply-waives
+// but need the transparent behavior of a CrossOriginWrapper. The
+// NoWaiverWrapper is like a CrossOriginWrapper that can also hand out
+// XrayWrappers as return values.
+NoWaiverWrapper NoWaiverWrapper::singleton(0);
+
 // When objects for which we waived the X-ray wrapper cross into
 // chrome, we wrap them into a special cross-compartment wrapper
 // that transitively extends the waiver to all properties we get
 // off it.
 CrossOriginWrapper CrossOriginWrapper::singleton(0);
 
 static JSObject *
 GetCurrentOuter(JSContext *cx, JSObject *obj)
@@ -329,17 +336,17 @@ WrapperFactory::Rewrap(JSContext *cx, JS
                     wrapper = &XrayDOM::singleton;
                 } else if (type == XrayForDOMProxyObject) {
                     wrapper = &XrayProxy::singleton;
                 } else if (type == XrayForWrappedNative) {
                     typedef XrayWrapper<CrossCompartmentWrapper> Xray;
                     usingXray = true;
                     wrapper = &Xray::singleton;
                 } else {
-                    wrapper = &CrossCompartmentWrapper::singleton;
+                    wrapper = &NoWaiverWrapper::singleton;
                 }
             }
         }
     } else if (AccessCheck::isChrome(origin)) {
         JSFunction *fun = JS_GetObjectFunction(obj);
         if (fun) {
             if (JS_IsBuiltinEvalFunction(fun) || JS_IsBuiltinFunctionConstructor(fun)) {
                 JS_ReportError(cx, "Not allowed to access chrome eval or Function from content");