☠☠ backed out by 15b55cb42f7a ☠ ☠ | |
author | Blake Kaplan <mrbkap@gmail.com> |
Mon, 09 Mar 2015 15:01:00 +0100 | |
changeset 232756 | 6c7ebb2f5a9221ecc6e23a5d8f5ac1f79de4ce28 |
parent 232755 | 68233f28f9598b644b67dc06a97a60ef8ee7dc56 |
child 232757 | 15b55cb42f7aaeb8d2174e7f5b10902b844629af |
push id | 28392 |
push user | kwierso@gmail.com |
push date | Tue, 10 Mar 2015 22:33:53 +0000 |
treeherder | mozilla-central@440b80b56ba6 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | billm |
bugs | 1134006 |
milestone | 39.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
|
--- a/dom/base/test/chrome/cpows_parent.xul +++ b/dom/base/test/chrome/cpows_parent.xul @@ -201,23 +201,41 @@ function recvErrorReportingTest(message) { throw "Test Error Probe"; } let savedElement = null; function recvDomTest(message) { savedElement = message.objects.element; + is(savedElement.QueryInterface(Components.interfaces.nsISupports), savedElement, + "QI to nsISupports works"); + is(savedElement.QueryInterface(Components.interfaces.nsIDOMNode), savedElement, + "QI to a random (implemented) interface works"); + + function testNoInterface(savedElement, i) { + try { + savedElement.QueryInterface(i); + ok(false, "should have thrown an exception"); + } catch (e) { + is(e.result, Components.results.NS_ERROR_NO_INTERFACE, "threw the right exception"); + } + } + + testNoInterface(savedElement, Components.interfaces.nsIDOMAttr); + testNoInterface(savedElement, Components.interfaces.nsIClassInfo); + // Test to ensure that we don't pass CPOWs to C++-implemented interfaces. // See bug 1072980. if (test_state == "remote") { - // This doesn't work because we intercept toString specially + // This doesn't work because we intercept toString and QueryInterface specially // and don't cache the function pointer. // See bug 1140636. todo_is(savedElement.toString, savedElement.toString, "toString identity works"); + todo_is(savedElement.QueryInterface, savedElement.QueryInterface, "toString identity works"); // This does work because we create a CPOW for isEqualNode that stays // alive as long as we have a reference to the first CPOW (so as long // as it's detectable). is(savedElement.isEqualNode, savedElement.isEqualNode, "webidl function identity works"); let walker = Components.classes["@mozilla.org/inspector/deep-tree-walker;1"] .createInstance(Components.interfaces.inIDeepTreeWalker);
--- a/js/ipc/JavaScriptTypes.ipdlh +++ b/js/ipc/JavaScriptTypes.ipdlh @@ -32,16 +32,17 @@ struct LocalObject uint64_t serializedId; }; struct RemoteObject { uint64_t serializedId; bool isCallable; bool isConstructor; + bool isDOMObject; nsCString objectTag; }; union ObjectVariant { LocalObject; RemoteObject; };
--- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -5,41 +5,48 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "WrapperOwner.h" #include "JavaScriptLogging.h" #include "mozilla/unused.h" #include "mozilla/dom/BindingUtils.h" #include "jsfriendapi.h" +#include "js/CharacterEncoding.h" #include "xpcprivate.h" #include "CPOWTimer.h" #include "WrapperFactory.h" #include "nsIRemoteTagService.h" using namespace js; using namespace JS; using namespace mozilla; using namespace mozilla::jsipc; struct AuxCPOWData { ObjectId id; bool isCallable; bool isConstructor; + bool isDOMObject; // The object tag is just some auxilliary information that clients can use // however they see fit. nsCString objectTag; - AuxCPOWData(ObjectId id, bool isCallable, bool isConstructor, const nsACString &objectTag) + AuxCPOWData(ObjectId id, + bool isCallable, + bool isConstructor, + bool isDOMObject, + const nsACString &objectTag) : id(id), isCallable(isCallable), isConstructor(isConstructor), + isDOMObject(isDOMObject), objectTag(objectTag) {} }; WrapperOwner::WrapperOwner(JSRuntime *rt) : JavaScriptShared(rt), inactive_(false) { @@ -148,17 +155,17 @@ bool CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle<JSPropertyDescriptor> desc) const { FORWARD(getPropertyDescriptor, (cx, proxy, id, desc)); } bool WrapperOwner::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, - MutableHandle<JSPropertyDescriptor> desc) + MutableHandle<JSPropertyDescriptor> desc) { ObjectId objId = idOf(proxy); JSIDVariant idVar; if (!toJSIDVariant(cx, id, &idVar)) return false; ReturnStatus status; @@ -178,17 +185,17 @@ bool CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, MutableHandle<JSPropertyDescriptor> desc) const { FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc)); } bool WrapperOwner::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, - MutableHandle<JSPropertyDescriptor> desc) + MutableHandle<JSPropertyDescriptor> desc) { ObjectId objId = idOf(proxy); JSIDVariant idVar; if (!toJSIDVariant(cx, id, &idVar)) return false; ReturnStatus status; @@ -209,17 +216,17 @@ CPOWProxyHandler::defineProperty(JSConte MutableHandle<JSPropertyDescriptor> desc, ObjectOpResult &result) const { FORWARD(defineProperty, (cx, proxy, id, desc, result)); } bool WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, - MutableHandle<JSPropertyDescriptor> desc, + MutableHandle<JSPropertyDescriptor> desc, ObjectOpResult &result) { ObjectId objId = idOf(proxy); JSIDVariant idVar; if (!toJSIDVariant(cx, id, &idVar)) return false; @@ -334,16 +341,29 @@ WrapperOwner::hasOwn(JSContext *cx, Hand bool CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandleValue vp) const { FORWARD(get, (cx, proxy, receiver, id, vp)); } static bool +CPOWDOMQI(JSContext *cx, unsigned argc, Value *vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + if (!args.thisv().isObject() || !IsCPOW(&args.thisv().toObject())) { + JS_ReportError(cx, "bad this object passed to special QI"); + return false; + } + + RootedObject proxy(cx, &args.thisv().toObject()); + FORWARD(DOMQI, (cx, proxy, args)); +} + +static bool CPOWToString(JSContext *cx, unsigned argc, Value *vp) { CallArgs args = CallArgsFromVp(argc, vp); RootedObject callee(cx, &args.callee()); RootedValue cpowValue(cx); if (!JS_GetProperty(cx, callee, "__cpow__", &cpowValue)) return false; @@ -388,29 +408,88 @@ WrapperOwner::toString(JSContext *cx, Ha if (!str) return false; args.rval().setString(str); return true; } bool +WrapperOwner::DOMQI(JSContext *cx, JS::HandleObject proxy, JS::CallArgs &args) +{ + // Someone's calling us, handle nsISupports specially to avoid unnecessary + // CPOW traffic. + HandleValue id = args[0]; + if (id.isObject()) { + RootedObject idobj(cx, &id.toObject()); + nsCOMPtr<nsIJSID> jsid; + + nsresult rv = UnwrapArg<nsIJSID>(idobj, getter_AddRefs(jsid)); + if (NS_SUCCEEDED(rv)) { + MOZ_ASSERT(jsid, "bad wrapJS"); + const nsID *idptr = jsid->GetID(); + if (idptr->Equals(NS_GET_IID(nsISupports))) { + args.rval().set(args.thisv()); + return true; + } + + // Webidl-implemented DOM objects never have nsIClassInfo. + if (idptr->Equals(NS_GET_IID(nsIClassInfo))) + return Throw(cx, NS_ERROR_NO_INTERFACE); + } + } + + // It wasn't nsISupports, call into the other process to do the QI for us + // (since we don't know what other interfaces our object supports). Note + // that we have to use JS_GetPropertyDescriptor here to avoid infinite + // recursion back into CPOWDOMQI via WrapperOwner::get(). + // We could stash the actual QI function on our own function object to avoid + // if we're called multiple times, but since we're transient, there's no + // point right now. + JS::Rooted<JSPropertyDescriptor> propDesc(cx); + if (!JS_GetPropertyDescriptor(cx, proxy, "QueryInterface", &propDesc)) + return false; + + if (!propDesc.value().isObject()) { + MOZ_ASSERT_UNREACHABLE("We didn't get QueryInterface off a node"); + return Throw(cx, NS_ERROR_UNEXPECTED); + } + return JS_CallFunctionValue(cx, proxy, propDesc.value(), args, args.rval()); +} + +bool WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, MutableHandleValue vp) { ObjectId objId = idOf(proxy); ObjectVariant receiverVar; if (!toObjectVariant(cx, receiver, &receiverVar)) return false; JSIDVariant idVar; if (!toJSIDVariant(cx, id, &idVar)) return false; + AuxCPOWData *data = AuxCPOWDataOf(proxy); + if (data->isDOMObject && + idVar.type() == JSIDVariant::TnsString && + idVar.get_nsString().EqualsLiteral("QueryInterface")) + { + // Handle QueryInterface on DOM Objects specially since we can assume + // certain things about their implementation. + RootedFunction qi(cx, JS_NewFunction(cx, CPOWDOMQI, 1, 0, proxy, + "QueryInterface")); + if (!qi) + return false; + + vp.set(ObjectValue(*JS_GetFunctionObject(qi))); + return true; + } + JSVariant val; ReturnStatus status; if (!SendGet(objId, receiverVar, idVar, &status, &val)) return ipcfail(cx); LOG_STACK(); if (!ok(cx, status)) @@ -962,16 +1041,17 @@ MakeRemoteObject(JSContext *cx, ObjectId if (service) { RootedValue objVal(cx, ObjectValue(*obj)); service->GetRemoteObjectTag(objVal, objectTag); } return RemoteObject(id.serialize(), JS::IsCallable(obj), JS::IsConstructor(obj), + dom::IsDOMObject(obj), objectTag); } bool WrapperOwner::toObjectVariant(JSContext *cx, JSObject *objArg, ObjectVariant *objVarp) { RootedObject obj(cx, objArg); MOZ_ASSERT(obj); @@ -1046,16 +1126,17 @@ WrapperOwner::fromRemoteObjectVariant(JS return nullptr; // Incref once we know the decref will be called. incref(); AuxCPOWData *aux = new AuxCPOWData(objId, objVar.isCallable(), objVar.isConstructor(), + objVar.isDOMObject(), objVar.objectTag()); SetProxyExtra(obj, 0, PrivateValue(this)); SetProxyExtra(obj, 1, PrivateValue(aux)); } if (!JS_WrapObject(cx, &obj)) return nullptr;
--- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -58,16 +58,17 @@ class WrapperOwner : public virtual Java const char* className(JSContext *cx, JS::HandleObject proxy); bool getPrototype(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleObject protop); bool regexp_toShared(JSContext *cx, JS::HandleObject proxy, js::RegExpGuard *g); nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp); bool toString(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args); + bool DOMQI(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args); /* * Check that |obj| is a DOM wrapper whose prototype chain contains * |prototypeID| at depth |depth|. */ bool domInstanceOf(JSContext *cx, JSObject *obj, int prototypeID, int depth, bool *bp); bool active() { return !inactive_; }