diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index cbc4e77f4e3..cb16a72b592 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1679,6 +1679,25 @@ jsid nsDOMClassInfo::sMultiEntry_id = JSID_VOID; jsid nsDOMClassInfo::sOnload_id = JSID_VOID; jsid nsDOMClassInfo::sOnerror_id = JSID_VOID; +static const JSClass *sObjectClass = nsnull; + +/** + * 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 = js::GetObjectProto(obj); + } while (proto); + + sObjectClass = js::GetObjectJSClass(obj); +} + static void PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty) { @@ -4702,52 +4721,6 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, nsScriptNameSpaceManager *nameSpaceManager, JSObject *dot_prototype, bool install, bool *did_resolve); -static nsresult -LookupPrototypeProto(JSContext *cx, JSObject *winobj, - const nsDOMClassInfoData *ci_data, - const nsGlobalNameStruct *name_struct, - JSObject **aProtoProto); - - -static nsGlobalWindow* -FindUsableInnerWindow(nsIXPConnect *xpc, JSContext *cx, JSObject *global) -{ - // Only do this if the global object is a window. - // XXX Is there a better way to check this? - nsISupports *globalNative = xpc->GetNativeOfWrapper(cx, global); - nsCOMPtr piwin = do_QueryInterface(globalNative); - if (!piwin) { - return nsnull; - } - - nsGlobalWindow *win = nsGlobalWindow::FromSupports(globalNative); - if (win->IsClosedOrClosing()) { - return nsnull; - } - - // If the window is in a different compartment than the global object, then - // it's likely that global is a sandbox object whose prototype is a window. - // Don't do anything in this case. - if (win->FastGetGlobalJSObject() && - js::GetObjectCompartment(global) != js::GetObjectCompartment(win->FastGetGlobalJSObject())) { - return nsnull; - } - - if (win->IsOuterWindow()) { - // XXXjst: Do security checks here when we remove the security - // checks on the inner window. - - win = win->GetCurrentInnerWindowInternal(); - - JSObject* global; - if (!win || !(global = win->GetGlobalJSObject()) || - win->IsClosedOrClosing()) { - return nsnull; - } - } - - return win; -} NS_IMETHODIMP nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * proto) @@ -4766,6 +4739,19 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * proto) JS_ClearPendingException(cx); } + // 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 && mData->mProtoChainInterface && mData->mProtoChainInterface != &NS_GET_IID(nsISupports)) { @@ -4793,12 +4779,38 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * proto) // document.body's prototype will find the right function. JSObject *global = ::JS_GetGlobalForObject(cx, proto); - nsGlobalWindow *win = FindUsableInnerWindow(XPConnect(), cx, global); - if (!win) { + // Only do this if the global object is a window. + // XXX Is there a better way to check this? + nsISupports *globalNative = XPConnect()->GetNativeOfWrapper(cx, global); + nsCOMPtr piwin = do_QueryInterface(globalNative); + if (!piwin) { return NS_OK; } - global = win->FastGetGlobalJSObject(); + nsGlobalWindow *win = nsGlobalWindow::FromSupports(globalNative); + if (win->IsClosedOrClosing()) { + return NS_OK; + } + + // If the window is in a different compartment than the global object, then + // it's likely that global is a sandbox object whose prototype is a window. + // Don't do anything in this case. + if (win->FastGetGlobalJSObject() && + js::GetObjectCompartment(global) != js::GetObjectCompartment(win->FastGetGlobalJSObject())) { + return NS_OK; + } + + if (win->IsOuterWindow()) { + // XXXjst: Do security checks here when we remove the security + // checks on the inner window. + + win = win->GetCurrentInnerWindowInternal(); + + if (!win || !(global = win->GetGlobalJSObject()) || + win->IsClosedOrClosing()) { + return NS_OK; + } + } // Don't overwrite a property set by content. JSBool found; @@ -4817,23 +4829,6 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * proto) &unused); } -NS_IMETHODIMP -nsDOMClassInfo::PreCreatePrototype(JSContext * cx, JSObject * global, - JSObject **protoProto) -{ - *protoProto = nsnull; - - nsGlobalWindow *win = FindUsableInnerWindow(XPConnect(), cx, global); - if (!win) { - return NS_OK; - } - - JSObject *winObj = win->FastGetGlobalJSObject(); - - return LookupPrototypeProto(cx, winObj, mData, nsnull, protoProto); -} - - // static nsIClassInfo * NS_GetDOMClassInfoInstance(nsDOMClassInfoID aID) @@ -5186,7 +5181,7 @@ nsWindowSH::InstallGlobalScopePolluter(JSContext *cx, JSObject *obj, // scope polluter (right before Object.prototype). while ((proto = ::JS_GetPrototype(cx, o))) { - if (js::GetObjectClass(proto) == &js::ObjectClass) { + if (JS_GET_CLASS(cx, proto) == sObjectClass) { // Set the global scope polluters prototype to Object.prototype ::JS_SplicePrototype(cx, gsp, proto); @@ -6008,105 +6003,6 @@ GetXPCProto(nsIXPConnect *aXPConnect, JSContext *cx, nsGlobalWindow *aWin, return aXPConnect->HoldObject(cx, proto_obj, aProto); } -static nsresult -LookupPrototypeProto(JSContext *cx, JSObject *winobj, - const nsDOMClassInfoData *ci_data, - const nsGlobalNameStruct *name_struct, - JSObject **aProtoProto) -{ - NS_ASSERTION(ci_data || - (name_struct && - name_struct->mType == nsGlobalNameStruct::eTypeClassProto), - "Wrong type or missing ci_data!"); - - const nsIID *primary_iid = &NS_GET_IID(nsISupports); - - if (!ci_data) { - primary_iid = &name_struct->mIID; - } else if (ci_data->mProtoChainInterface) { - primary_iid = ci_data->mProtoChainInterface; - } - - if (primary_iid->Equals(NS_GET_IID(nsISupports))) { - *aProtoProto = nsnull; - return NS_OK; - } - - nsCOMPtr - iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); - NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE); - - nsCOMPtr if_info; - iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info)); - NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED); - - const nsIID *iid = nsnull; - - nsCOMPtr parent; - if (ci_data && !ci_data->mHasClassInterface) { - if_info->GetIIDShared(&iid); - } else { - if_info->GetParent(getter_AddRefs(parent)); - NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED); - - parent->GetIIDShared(&iid); - } - - if (!iid || iid->Equals(NS_GET_IID(nsISupports))) { - *aProtoProto = nsnull; - return NS_OK; - } - - const char *class_parent_name = nsnull; - if (ci_data && !ci_data->mHasClassInterface) { - // If the class doesn't have a class interface the primary - // interface is the interface that should be - // constructor.prototype.__proto__. - - if_info->GetNameShared(&class_parent_name); - } else { - // If the class does have a class interface (or there's no - // real class for this name) then the parent of the - // primary interface is what we want on - // constructor.prototype.__proto__. - - NS_ASSERTION(parent, "Whoa, this is bad, null parent here!"); - - parent->GetNameShared(&class_parent_name); - } - - JSObject *protoProto = nsnull; - - // Get class_parent_name here - if (class_parent_name) { - jsval val; - - JSAutoEnterCompartment ac; - if (!ac.enter(cx, winobj)) { - return NS_ERROR_UNEXPECTED; - } - - if (!::JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) { - return NS_ERROR_UNEXPECTED; - } - - JSObject *tmp = JSVAL_IS_OBJECT(val) ? JSVAL_TO_OBJECT(val) : nsnull; - - if (tmp) { - if (!::JS_LookupProperty(cx, tmp, "prototype", &val)) { - return NS_ERROR_UNEXPECTED; - } - - if (JSVAL_IS_OBJECT(val)) { - protoProto = JSVAL_TO_OBJECT(val); - } - } - } - - *aProtoProto = protoProto; - return NS_OK; -} - // Either ci_data must be non-null or name_struct must be non-null and of type // eTypeClassProto. static nsresult @@ -6152,6 +6048,10 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, primary_iid = ci_data->mProtoChainInterface; } + nsCOMPtr if_info; + nsCOMPtr parent; + const char *class_parent_name = nsnull; + if (!primary_iid->Equals(NS_GET_IID(nsISupports))) { JSAutoEnterCompartment ac; @@ -6175,14 +6075,76 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, !indexedDB::IDBKeyRange::DefineConstructors(cx, class_obj)) { return NS_ERROR_FAILURE; } + + nsCOMPtr + iim(do_GetService(NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID)); + NS_ENSURE_TRUE(iim, NS_ERROR_NOT_AVAILABLE); + + iim->GetInfoForIID(primary_iid, getter_AddRefs(if_info)); + NS_ENSURE_TRUE(if_info, NS_ERROR_UNEXPECTED); + + const nsIID *iid = nsnull; + + if (ci_data && !ci_data->mHasClassInterface) { + if_info->GetIIDShared(&iid); + } else { + if_info->GetParent(getter_AddRefs(parent)); + NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED); + + parent->GetIIDShared(&iid); + } + + if (iid) { + if (!iid->Equals(NS_GET_IID(nsISupports))) { + if (ci_data && !ci_data->mHasClassInterface) { + // If the class doesn't have a class interface the primary + // interface is the interface that should be + // constructor.prototype.__proto__. + + if_info->GetNameShared(&class_parent_name); + } else { + // If the class does have a class interface (or there's no + // real class for this name) then the parent of the + // primary interface is what we want on + // constructor.prototype.__proto__. + + NS_ASSERTION(parent, "Whoa, this is bad, null parent here!"); + + parent->GetNameShared(&class_parent_name); + } + } + } } { JSObject *winobj = aWin->FastGetGlobalJSObject(); - JSObject *proto; - rv = LookupPrototypeProto(cx, winobj, ci_data, name_struct, &proto); - NS_ENSURE_SUCCESS(rv, rv); + JSObject *proto = nsnull; + + if (class_parent_name) { + jsval val; + + JSAutoEnterCompartment ac; + if (!ac.enter(cx, winobj)) { + return NS_ERROR_UNEXPECTED; + } + + if (!::JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) { + return NS_ERROR_UNEXPECTED; + } + + JSObject *tmp = JSVAL_IS_OBJECT(val) ? JSVAL_TO_OBJECT(val) : nsnull; + + if (tmp) { + if (!::JS_LookupProperty(cx, tmp, "prototype", &val)) { + return NS_ERROR_UNEXPECTED; + } + + if (JSVAL_IS_OBJECT(val)) { + proto = JSVAL_TO_OBJECT(val); + } + } + } if (dot_prototype) { JSAutoEnterCompartment ac; @@ -6194,7 +6156,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, if (proto && (!xpc_proto_proto || - js::GetObjectClass(xpc_proto_proto) == &js::ObjectClass)) { + JS_GET_CLASS(cx, xpc_proto_proto) == sObjectClass)) { if (!JS_WrapObject(cx, &proto) || !JS_SetPrototype(cx, dot_prototype, proto)) { return NS_ERROR_UNEXPECTED; @@ -9581,7 +9543,7 @@ nsHTMLPluginObjElementSH::SetupProtoChain(nsIXPConnectWrappedNative *wrapper, return NS_ERROR_UNEXPECTED; } - if (pi_proto && js::GetObjectClass(pi_proto) != &js::ObjectClass) { + if (pi_proto && JS_GET_CLASS(cx, pi_proto) != sObjectClass) { // The plugin wrapper has a proto that's not Object.prototype, set // 'pi.__proto__.__proto__' to the original 'this.__proto__' if (pi_proto != my_proto && !::JS_SetPrototype(cx, pi_proto, my_proto)) { diff --git a/js/xpconnect/idl/nsIXPCScriptable.idl b/js/xpconnect/idl/nsIXPCScriptable.idl index 024ec292739..6d623705c01 100644 --- a/js/xpconnect/idl/nsIXPCScriptable.idl +++ b/js/xpconnect/idl/nsIXPCScriptable.idl @@ -73,7 +73,7 @@ * to *_retval unless they want to return PR_FALSE. */ -[uuid(9cadb17b-9990-461a-8e01-cf50aeffc2c5)] +[uuid(a40ce52e-2d8c-400f-9af2-f8784a656070)] interface nsIXPCScriptable : nsISupports { /* bitflags used for 'flags' (only 32 bits available!) */ @@ -191,14 +191,6 @@ interface nsIXPCScriptable : nsISupports in JSContextPtr cx, in JSObjectPtr obj); void postCreatePrototype(in JSContextPtr cx, in JSObjectPtr proto); - - /** - * Notify that we're about to create the prototype object for this class, - * and ask what prototype we should use for that. - */ - void preCreatePrototype(in JSContextPtr cx, - in JSObjectPtr globalObj, - out JSObjectPtr protoProtoObj); }; %{ C++ diff --git a/js/xpconnect/public/xpc_map_end.h b/js/xpconnect/public/xpc_map_end.h index 59bc9ca007c..f4f1649b497 100644 --- a/js/xpconnect/public/xpc_map_end.h +++ b/js/xpconnect/public/xpc_map_end.h @@ -228,11 +228,6 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::PostCreatePrototype(JSContext *cx, JSObject *pr {return NS_OK;} #endif -#ifndef XPC_MAP_WANT_PRE_CREATE_PROTOTYPE -NS_IMETHODIMP XPC_MAP_CLASSNAME::PreCreatePrototype(JSContext *cx, JSObject *global, JSObject **protoProto) - {*protoProto = nsnull; return NS_OK;} -#endif - /**************************************************************/ #undef XPC_MAP_CLASSNAME @@ -318,10 +313,6 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::PreCreatePrototype(JSContext *cx, JSObject *glo #undef XPC_MAP_WANT_POST_CREATE_PROTOTYPE #endif -#ifdef XPC_MAP_WANT_PRE_CREATE_PROTOTYPE -#undef XPC_MAP_WANT_PRE_CREATE_PROTOTYPE -#endif - #ifdef XPC_MAP_FLAGS #undef XPC_MAP_FLAGS #endif diff --git a/js/xpconnect/src/XPCWrappedNativeProto.cpp b/js/xpconnect/src/XPCWrappedNativeProto.cpp index 23b0140ff55..8fe3ff66335 100644 --- a/js/xpconnect/src/XPCWrappedNativeProto.cpp +++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp @@ -123,22 +123,10 @@ XPCWrappedNativeProto::Init(XPCCallContext& ccx, JSObject *parent = mScope->GetGlobalJSObject(); - JSObject *protoProto = nsnull; - if (callback) { - nsresult rv = callback->PreCreatePrototype(ccx, parent, &protoProto); - if (NS_FAILED(rv)) { - mJSProtoObject = nsnull; - XPCThrower::Throw(rv, ccx); - return false; - } - } - if (!protoProto) { - protoProto = mScope->GetPrototypeJSObject(); - } - mJSProtoObject = xpc_NewSystemInheritingJSObject(ccx, js::Jsvalify(jsclazz), - protoProto, true, parent); + mScope->GetPrototypeJSObject(), + true, parent); JSBool ok = mJSProtoObject && JS_SetPrivate(ccx, mJSProtoObject, this);