Fixing bug 413767. Make caps use faster JS class/parent/private/proto accessors. r=mrbkap@gmail.com, sr=brendan@mozilla.org
authorjst@mozilla.org
Tue, 29 Jan 2008 12:51:01 -0800
changeset 10939 e8d00681628f10786e4a9fa9ecfb56c689a77821
parent 10938 b324a844c7a0104db21d9dd102c6faf71565b857
child 10940 99e0063fa3791608e307318c395be3bcddc93dca
push idunknown
push userunknown
push dateunknown
reviewersmrbkap, brendan
bugs413767
milestone1.9b3pre
Fixing bug 413767. Make caps use faster JS class/parent/private/proto accessors. r=mrbkap@gmail.com, sr=brendan@mozilla.org
caps/include/nsScriptSecurityManager.h
caps/src/nsScriptSecurityManager.cpp
--- a/caps/include/nsScriptSecurityManager.h
+++ b/caps/include/nsScriptSecurityManager.h
@@ -404,17 +404,17 @@ private:
     static JSBool JS_DLL_CALLBACK
     CheckObjectAccess(JSContext *cx, JSObject *obj,
                       jsval id, JSAccessMode mode,
                       jsval *vp);
 
     // Returns null if a principal cannot be found; generally callers
     // should error out at that point.
     static nsIPrincipal*
-    doGetObjectPrincipal(JSContext *cx, JSObject *obj
+    doGetObjectPrincipal(JSObject *obj
 #ifdef DEBUG
                          , PRBool aAllowShortCircuit = PR_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*
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -54,16 +54,17 @@
 #include "nsCRT.h"
 #include "nsCRTGlue.h"
 #include "nsIJSContextStack.h"
 #include "nsDOMError.h"
 #include "nsDOMCID.h"
 #include "jsdbgapi.h"
 #include "jsarena.h"
 #include "jsfun.h"
+#include "jsobj.h"
 #include "nsIXPConnect.h"
 #include "nsIXPCSecurityManager.h"
 #include "nsTextFormatter.h"
 #include "nsIStringBundle.h"
 #include "nsNetUtil.h"
 #include "nsIProperties.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
@@ -115,16 +116,34 @@ JSValIDToString(JSContext *cx, const jsv
 {
     JSAutoRequest ar(cx);
     JSString *str = JS_ValueToString(cx, idval);
     if(!str)
         return nsnull;
     return reinterpret_cast<PRUnichar*>(JS_GetStringChars(str));
 }
 
+// Inline copy of JS_GetPrivate() for better inlining and optimization
+// possibilities. Also doesn't take a cx argument as it's not
+// needed. We access the private data only on objects whose private
+// data is not expected to change during the lifetime of the object,
+// so thus we won't worry about locking and holding on to slot values
+// etc while referencing private data.
+inline void *
+caps_GetJSPrivate(JSObject *obj)
+{
+    jsval v;
+
+    JS_ASSERT(STOBJ_GET_CLASS(obj)->flags & JSCLASS_HAS_PRIVATE);
+    v = obj->fslots[JSSLOT_PRIVATE];
+    if (!JSVAL_IS_INT(v))
+        return NULL;
+    return JSVAL_TO_PRIVATE(v);
+}
+
 static nsIScriptContext *
 GetScriptContext(JSContext *cx)
 {
     return GetScriptContextFromJSContext(cx);
 }
 
 inline void SetPendingException(JSContext *cx, const char *aMsg)
 {
@@ -592,17 +611,17 @@ nsScriptSecurityManager::CheckObjectAcce
     //    trust domain's window or document object.
     // *vp can be a primitive, in that case, we use obj as the target
     // object.
     JSObject* target = JSVAL_IS_PRIMITIVE(*vp) ? obj : JSVAL_TO_OBJECT(*vp);
 
     // Do the same-origin check -- this sets a JS exception if the check fails.
     // Pass the parent object's class name, as we have no class-info for it.
     nsresult rv =
-        ssm->CheckPropertyAccess(cx, target, JS_GetClass(cx, obj)->name, id,
+        ssm->CheckPropertyAccess(cx, target, STOBJ_GET_CLASS(obj)->name, id,
                                  (mode & JSACC_WRITE) ?
                                  nsIXPCSecurityManager::ACCESS_SET_PROPERTY :
                                  nsIXPCSecurityManager::ACCESS_GET_PROPERTY);
 
     if (NS_FAILED(rv))
         return JS_FALSE; // Security check failed (XXX was an error reported?)
 
     return JS_TRUE;
@@ -794,17 +813,17 @@ nsScriptSecurityManager::CheckPropertyAc
             {
 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
                 printf("sameOrigin ");
 #endif
                 nsCOMPtr<nsIPrincipal> principalHolder;
                 nsIPrincipal *objectPrincipal;
                 if(aJSObject)
                 {
-                    objectPrincipal = doGetObjectPrincipal(cx, aJSObject);
+                    objectPrincipal = doGetObjectPrincipal(aJSObject);
                     if (!objectPrincipal)
                         rv = NS_ERROR_DOM_SECURITY_ERR;
                 }
                 else if(aTargetURI)
                 {
                     if (NS_FAILED(GetCodebasePrincipal(
                           aTargetURI, getter_AddRefs(principalHolder))))
                         return NS_ERROR_FAILURE;
@@ -841,18 +860,16 @@ nsScriptSecurityManager::CheckPropertyAc
         else
             rv = NS_OK;
     }
 
     if (NS_SUCCEEDED(rv) && classInfoData.IsContentNode())
     {
         // No access to anonymous content from the web!  (bug 164086)
         nsIContent *content = static_cast<nsIContent*>(aObj);
-        NS_ASSERTION(content, "classinfo had CONTENT_NODE set but node did not"
-                              "implement nsIContent!  Fasten your seat belt.");
         if (content->IsNativeAnonymous()) {
             rv = NS_ERROR_DOM_SECURITY_ERR;
         }
     }
 
     if (NS_SUCCEEDED(rv))
     {
 #ifdef DEBUG_CAPS_CheckPropertyAccessImpl
@@ -1644,24 +1661,24 @@ nsScriptSecurityManager::CheckFunctionAc
         GetFunctionObjectPrincipal(aCx, (JSObject *)aFunObj, nsnull, &rv);
 
     // If subject is null, get a principal from the function object's scope.
     if (NS_SUCCEEDED(rv) && !subject)
     {
 #ifdef DEBUG
         {
             JSFunction *fun =
-                (JSFunction *)JS_GetPrivate(aCx, (JSObject *)aFunObj);
+                (JSFunction *)caps_GetJSPrivate((JSObject *)aFunObj);
             JSScript *script = JS_GetFunctionScript(aCx, fun);
 
             NS_ASSERTION(!script, "Null principal for non-native function!");
         }
 #endif
 
-        subject = doGetObjectPrincipal(aCx, (JSObject*)aFunObj);
+        subject = doGetObjectPrincipal((JSObject*)aFunObj);
     }
 
     if (!subject)
         return NS_ERROR_FAILURE;
 
     if (subject == mSystemPrincipal)
         // This is the system principal: just allow access
         return NS_OK;
@@ -1676,17 +1693,17 @@ nsScriptSecurityManager::CheckFunctionAc
 
     if (!result)
       return NS_ERROR_DOM_SECURITY_ERR;
 
     /*
     ** Get origin of subject and object and compare.
     */
     JSObject* obj = (JSObject*)aTargetObj;
-    nsIPrincipal* object = doGetObjectPrincipal(aCx, obj);
+    nsIPrincipal* object = doGetObjectPrincipal(obj);
 
     if (!object)
         return NS_ERROR_FAILURE;        
 
     // Note that CheckSameOriginPrincipalInternal already does an equality
     // comparison on subject and object, so no need for us to do it.
     return CheckSameOriginPrincipalInternal(subject, object, PR_TRUE);
 }
@@ -2156,17 +2173,17 @@ nsScriptSecurityManager::GetScriptPrinci
 // static
 nsIPrincipal*
 nsScriptSecurityManager::GetFunctionObjectPrincipal(JSContext *cx,
                                                     JSObject *obj,
                                                     JSStackFrame *fp,
                                                     nsresult *rv)
 {
     NS_PRECONDITION(rv, "Null out param");
-    JSFunction *fun = (JSFunction *) JS_GetPrivate(cx, obj);
+    JSFunction *fun = (JSFunction *) caps_GetJSPrivate(obj);
     JSScript *script = JS_GetFunctionScript(cx, fun);
 
     *rv = NS_OK;
 
     if (!script)
     {
         // A native function: skip it in order to find its scripted caller.
         return nsnull;
@@ -2196,17 +2213,17 @@ nsScriptSecurityManager::GetFunctionObje
         // different scope than the one it is parented by at runtime,
         // hence the creation of a clone to carry the correct scope
         // chain linkage.
         //
         // Since principals follow scope, we must get the object
         // principal from the clone's scope chain. There are no
         // reliable principals compiled into the function itself.
 
-        nsIPrincipal *result = doGetObjectPrincipal(cx, obj);
+        nsIPrincipal *result = doGetObjectPrincipal(obj);
         if (!result)
             *rv = NS_ERROR_FAILURE;
         return result;
     }
 
     return GetScriptPrincipal(cx, script, rv);
 }
 
@@ -2225,17 +2242,17 @@ nsScriptSecurityManager::GetFramePrincip
         return GetScriptPrincipal(cx, script, rv);
     }
 
     nsIPrincipal* result = GetFunctionObjectPrincipal(cx, obj, fp, rv);
 
 #ifdef DEBUG
     if (NS_SUCCEEDED(*rv) && !result)
     {
-        JSFunction *fun = (JSFunction *)JS_GetPrivate(cx, obj);
+        JSFunction *fun = (JSFunction *)caps_GetJSPrivate(obj);
         JSScript *script = JS_GetFunctionScript(cx, fun);
 
         NS_ASSERTION(!script, "Null principal for non-native function!");
     }
 #endif
 
     return result;
 }
@@ -2300,76 +2317,76 @@ nsScriptSecurityManager::GetSubjectPrinc
     JSStackFrame *fp;
     return GetPrincipalAndFrame(cx, &fp, rv);
 }
 
 NS_IMETHODIMP
 nsScriptSecurityManager::GetObjectPrincipal(JSContext *aCx, JSObject *aObj,
                                             nsIPrincipal **result)
 {
-    *result = doGetObjectPrincipal(aCx, aObj);
+    *result = doGetObjectPrincipal(aObj);
     if (!*result)
         return NS_ERROR_FAILURE;
     NS_ADDREF(*result);
     return NS_OK;
 }
 
 // static
 nsIPrincipal*
-nsScriptSecurityManager::doGetObjectPrincipal(JSContext *aCx, JSObject *aObj
+nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj
 #ifdef DEBUG
                                               , PRBool aAllowShortCircuit
 #endif
                                               )
 {
     NS_ASSERTION(aCx && aObj, "Bad call to doGetObjectPrincipal()!");
     nsIPrincipal* result = nsnull;
 
 #ifdef DEBUG
     JSObject* origObj = aObj;
 #endif
     
-    const JSClass *jsClass = JS_GET_CLASS(aCx, aObj);
+    const JSClass *jsClass = STOBJ_GET_CLASS(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.
 
     if (jsClass == &js_FunctionClass) {
-        aObj = JS_GetParent(aCx, aObj);
+        aObj = STOBJ_GET_PARENT(aObj);
 
         if (!aObj)
             return nsnull;
 
-        jsClass = JS_GET_CLASS(aCx, aObj);
+        jsClass = STOBJ_GET_CLASS(aObj);
 
         if (jsClass == &js_CallClass) {
-            aObj = JS_GetParent(aCx, aObj);
+            aObj = STOBJ_GET_PARENT(aObj);
 
             if (!aObj)
                 return nsnull;
 
-            jsClass = JS_GET_CLASS(aCx, aObj);
+            jsClass = STOBJ_GET_CLASS(aObj);
         }
     }
 
     do {
         // Note: jsClass is set before this loop, and also at the
         // *end* of this loop.
 
         // NOTE: These class and getObjectOps hook checks better match
         // what IS_WRAPPER_CLASS() does in xpconnect!
         if (jsClass == sXPCWrappedNativeJSClass ||
             jsClass->getObjectOps == sXPCWrappedNativeGetObjOps1 ||
             jsClass->getObjectOps == sXPCWrappedNativeGetObjOps2) {
             nsIXPConnectWrappedNative *xpcWrapper =
-                (nsIXPConnectWrappedNative *)JS_GetPrivate(aCx, aObj);
+                (nsIXPConnectWrappedNative *)caps_GetJSPrivate(aObj);
 
             if (xpcWrapper) {
 #ifdef DEBUG
                 if (aAllowShortCircuit) {
 #endif
                     result = xpcWrapper->GetObjectPrincipal();
 
                     if (result) {
@@ -2388,17 +2405,17 @@ nsScriptSecurityManager::doGetObjectPrin
 
                     if (result) {
                         break;
                     }
                 }
             }
         } else if (!(~jsClass->flags & (JSCLASS_HAS_PRIVATE |
                                         JSCLASS_PRIVATE_IS_NSISUPPORTS))) {
-            nsISupports *priv = (nsISupports *)JS_GetPrivate(aCx, aObj);
+            nsISupports *priv = (nsISupports *)caps_GetJSPrivate(aObj);
 
 #ifdef DEBUG
             if (aAllowShortCircuit) {
                 nsCOMPtr<nsIXPConnectWrappedNative> xpcWrapper =
                     do_QueryInterface(priv);
 
                 NS_ASSERTION(!xpcWrapper ||
                              !strcmp(jsClass->name, "XPCNativeWrapper"),
@@ -2414,26 +2431,26 @@ nsScriptSecurityManager::doGetObjectPrin
                 result = objPrin->GetPrincipal();
 
                 if (result) {
                     break;
                 }
             }
         }
 
-        aObj = JS_GetParent(aCx, aObj);
+        aObj = STOBJ_GET_PARENT(aObj);
 
         if (!aObj)
             break;
 
-        jsClass = JS_GET_CLASS(aCx, aObj);
+        jsClass = STOBJ_GET_CLASS(aObj);
     } while (1);
 
     NS_ASSERTION(!aAllowShortCircuit ||
-                 result == doGetObjectPrincipal(aCx, origObj, PR_FALSE),
+                 result == doGetObjectPrincipal(origObj, PR_FALSE),
                  "Principal mismatch.  Not good");
     
     return result;
 }
 
 nsresult
 nsScriptSecurityManager::SavePrincipal(nsIPrincipal* aToSave)
 {