Bug 500846 - Calculate sObjectClass in non-browser embeddings. r+sr=bzbarsky
authorBlake Kaplan <mrbkap@gmail.com>
Wed, 01 Jul 2009 12:12:32 -0700
changeset 29949 9e01b09a82a4ebbc71869166ab47c3dae4c33673
parent 29948 b5bdefc2cac7e4ea1598294ce6afa2035a19dca7
child 29950 608f66b040bd23feb6d904060567b172c3903b7b
push idunknown
push userunknown
push dateunknown
bugs500846
milestone1.9.2a1pre
Bug 500846 - Calculate sObjectClass in non-browser embeddings. r+sr=bzbarsky
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/base/nsJSEnvironment.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1444,26 +1444,31 @@ jsval nsDOMClassInfo::sOnpaste_id       
 jsval nsDOMClassInfo::sJava_id            = JSVAL_VOID;
 jsval nsDOMClassInfo::sPackages_id        = JSVAL_VOID;
 
 static const JSClass *sObjectClass = nsnull;
 const JSClass *nsDOMClassInfo::sXPCNativeWrapperClass = nsnull;
 
 static PRBool sDoSecurityCheckInAddProperty = PR_TRUE;
 
-const JSClass*
-NS_DOMClassInfo_GetXPCNativeWrapperClass()
-{
-  return nsDOMClassInfo::GetXPCNativeWrapperClass();
-}
-
-void
-NS_DOMClassInfo_SetXPCNativeWrapperClass(JSClass* aClass)
-{
-  nsDOMClassInfo::SetXPCNativeWrapperClass(aClass);
+/**
+ * Set our JSClass pointer for the Object class
+ */
+static void
+FindObjectClass(JSObject* aGlobalObject)
+{
+  NS_ASSERTION(!sObjectClass,
+               "Double set of sObjectClass");
+  JSObject *obj, *proto = aGlobalObject;
+  do {
+    obj = proto;
+    proto = STOBJ_GET_PROTO(obj);
+  } while (proto);
+
+  sObjectClass = STOBJ_GET_CLASS(obj);
 }
 
 static void
 PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty)
 {
   nsCOMPtr<nsIStringBundleService>
     stringService(do_GetService(NS_STRINGBUNDLE_CONTRACTID));
   if (!stringService) {
@@ -4149,16 +4154,25 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
   static const nsIID *sSupportsIID = &NS_GET_IID(nsISupports);
 
   // This is safe because...
   if (mData->mProtoChainInterface == sSupportsIID ||
       !mData->mProtoChainInterface) {
     return NS_OK;
   }
 
+  // This is called before any other location that requires
+  // sObjectClass, so compute it here. We assume that nobody has had a
+  // chance to monkey around with proto's prototype chain before this.
+  if (!sObjectClass) {
+    FindObjectClass(proto);
+    NS_ASSERTION(sObjectClass && !strcmp(sObjectClass->name, "Object"),
+                 "Incorrect object class!");
+  }
+
   NS_ASSERTION(::JS_GetPrototype(cx, proto) &&
                JS_GET_CLASS(cx, ::JS_GetPrototype(cx, proto)) == sObjectClass,
                "Hmm, somebody did something evil?");
  
 #ifdef DEBUG
   if (mData->mHasClassInterface) {
     nsCOMPtr<nsIInterfaceInfoManager>
       iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
@@ -4394,31 +4408,16 @@ nsDOMClassInfo::ShutDown()
 }
 
 // Window helper
 
 NS_IMETHODIMP
 nsWindowSH::PreCreate(nsISupports *nativeObj, JSContext *cx,
                       JSObject *globalObj, JSObject **parentObj)
 {
-  // Since this is one of the first calls we'll get from XPConnect,
-  // grab the pointer to the Object class so we'll have it later on.
-
-  if (!sObjectClass) {
-    JSObject *obj, *proto = globalObj;
-    JSAutoRequest ar(cx);
-
-    do {
-      obj = proto;
-      proto = ::JS_GetPrototype(cx, obj);
-    } while (proto);
-
-    sObjectClass = JS_GET_CLASS(cx, obj);
-  }
-
   // Normally ::PreCreate() is used to give XPConnect the parent
   // object for the object that's being wrapped, this parent object is
   // set as the parent of the wrapper and it's also used to find the
   // right scope for the object being wrapped. Now, in the case of the
   // global object the wrapper shouldn't have a parent but we supply
   // one here anyway (the global object itself) and this will be used
   // by XPConnect only to find the right scope, once the scope is
   // found XPConnect will find the existing wrapper (which always
@@ -5740,17 +5739,17 @@ ResolvePrototype(nsIXPConnect *aXPConnec
     }
   }
 
   if (dot_prototype) {
     JSObject *xpc_proto_proto = ::JS_GetPrototype(cx, dot_prototype);
 
     if (proto &&
         (!xpc_proto_proto ||
-         JS_GET_CLASS(cx, xpc_proto_proto) == sObjectClass)) {
+         JS_GET_CLASS(cx, xpc_proto_proto) == nsDOMClassInfo::GetObjectClass())) {
       if (!::JS_SetPrototype(cx, dot_prototype, proto)) {
         return NS_ERROR_UNEXPECTED;
       }
     }
   } else {
     dot_prototype = ::JS_NewObject(cx, &sDOMConstructorProtoClass, proto,
                                    obj);
     NS_ENSURE_TRUE(dot_prototype, NS_ERROR_OUT_OF_MEMORY);
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -38,16 +38,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsDOMClassInfo_h___
 #define nsDOMClassInfo_h___
 
 #include "nsIDOMClassInfo.h"
 #include "nsIXPCScriptable.h"
 #include "jsapi.h"
+#include "jsobj.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIScriptContext.h"
 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
 #include "nsIScriptGlobalObject.h"
 
 class nsIDOMWindow;
 class nsIDOMNSHTMLOptionCollection;
 class nsIPluginInstance;
@@ -151,17 +152,17 @@ public:
   static nsresult ThrowJSException(JSContext *cx, nsresult aResult);
 
   /**
    * Get our JSClass pointer for the XPCNativeWrapper class
    */
   static const JSClass* GetXPCNativeWrapperClass() {
     return sXPCNativeWrapperClass;
   }
-  
+
   /**
    * Set our JSClass pointer for the XPCNativeWrapper class
    */
   static void SetXPCNativeWrapperClass(JSClass* aClass) {
     NS_ASSERTION(!sXPCNativeWrapperClass,
                  "Double set of sXPCNativeWrapperClass");
     sXPCNativeWrapperClass = aClass;
   }
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2450,19 +2450,16 @@ nsJSContext::ConnectToInner(nsIScriptGlo
 }
 
 void *
 nsJSContext::GetNativeContext()
 {
   return mContext;
 }
 
-const JSClass* NS_DOMClassInfo_GetXPCNativeWrapperClass();
-void NS_DOMClassInfo_SetXPCNativeWrapperClass(JSClass* aClass);
-
 nsresult
 nsJSContext::InitContext(nsIScriptGlobalObject *aGlobalObject)
 {
   // Make sure callers of this use
   // WillInitializeContext/DidInitializeContext around this call.
   NS_ENSURE_TRUE(!mIsInitialized, NS_ERROR_ALREADY_INITIALIZED);
 
   if (!mContext)
@@ -2512,17 +2509,17 @@ nsJSContext::InitContext(nsIScriptGlobal
     rv = xpc->InitClassesWithNewWrappedGlobal(mContext, aGlobalObject,
                                               NS_GET_IID(nsISupports),
                                               flags,
                                               getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Now check whether we need to grab a pointer to the
     // XPCNativeWrapper class
-    if (!NS_DOMClassInfo_GetXPCNativeWrapperClass()) {
+    if (!nsDOMClassInfo::GetXPCNativeWrapperClass()) {
       JSAutoRequest ar(mContext);
       rv = FindXPCNativeWrapperClass(holder);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   } else {
     // If there's already a global object in mContext we're called
     // after ::JS_ClearScope() was called. We'll have to tell
     // XPConnect to re-initialize the global object to do things like
@@ -2922,17 +2919,17 @@ nsJSContext::AddSupportsPrimitiveTojsval
     }
   }
   return NS_OK;
 }
 
 nsresult
 nsJSContext::FindXPCNativeWrapperClass(nsIXPConnectJSObjectHolder *aHolder)
 {
-  NS_ASSERTION(!NS_DOMClassInfo_GetXPCNativeWrapperClass(),
+  NS_ASSERTION(!nsDOMClassInfo::GetXPCNativeWrapperClass(),
                "Why was this called?");
 
   JSObject *globalObj;
   aHolder->GetJSObject(&globalObj);
   NS_ASSERTION(globalObj, "Must have global by now!");
 
   const char* arg = "arg";
   NS_NAMED_LITERAL_STRING(body, "return new XPCNativeWrapper(arg);");
@@ -2959,18 +2956,19 @@ nsJSContext::FindXPCNativeWrapperClass(n
   if (!ok) {
     // No need to notify about pending exceptions here; we don't
     // expect any other than out of memory, really.
     return NS_ERROR_FAILURE;
   }
 
   NS_ASSERTION(JSVAL_IS_OBJECT(wrapper), "This should be an object!");
 
-  NS_DOMClassInfo_SetXPCNativeWrapperClass(
+  nsDOMClassInfo::SetXPCNativeWrapperClass(
     ::JS_GET_CLASS(mContext, JSVAL_TO_OBJECT(wrapper)));
+
   return NS_OK;
 }
 
 static JSPropertySpec OptionsProperties[] = {
   {"strict",    (int8)JSOPTION_STRICT,   JSPROP_ENUMERATE | JSPROP_PERMANENT},
   {"werror",    (int8)JSOPTION_WERROR,   JSPROP_ENUMERATE | JSPROP_PERMANENT},
   {"relimit",   (int8)JSOPTION_RELIMIT,  JSPROP_ENUMERATE | JSPROP_PERMANENT},
   {0}