From 37409460f384826a49188ac79d93578d4d17c804 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Sun, 23 Mar 2014 11:02:13 -0300 Subject: [PATCH] Bug 975042 - Implement resolveOwnProperty and enumerateNames trap. r=peterv --- js/xpconnect/wrappers/XrayWrapper.cpp | 141 ++++++++++++++++++++++++-- 1 file changed, 133 insertions(+), 8 deletions(-) diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 70e2f4d28ad..08540bde81f 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -295,10 +295,7 @@ public: virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper, HandleObject holder, HandleId id, - MutableHandle desc, unsigned flags) - { - MOZ_ASSUME_UNREACHABLE("Not yet implemented"); - } + MutableHandle desc, unsigned flags); static bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandle desc, @@ -310,10 +307,7 @@ public: } virtual bool enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags, - AutoIdVector &props) - { - MOZ_ASSUME_UNREACHABLE("Not yet implemented"); - } + AutoIdVector &props); static bool call(JSContext *cx, HandleObject wrapper, const JS::CallArgs &args, js::Wrapper& baseInstance) @@ -389,6 +383,137 @@ const JSClass JSXrayTraits::HolderClass = { JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub }; +bool +JSXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, + HandleObject wrapper, HandleObject holder, + HandleId id, + MutableHandle desc, + unsigned flags) +{ + // Call the common code. + bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder, + id, desc, flags); + if (!ok || desc.object()) + return ok; + + // Non-prototypes don't have anything on them yet. + if (!isPrototype(holder)) + return true; + + // The non-HasPrototypes semantics implemented by traditional Xrays are kind + // of broken with respect to |own|-ness and the holder. The common code + // muddles through by only checking the holder for non-|own| lookups, but + // that doesn't work for us. So we do an explicit holder check here, and hope + // that this mess gets fixed up soon. + if (!JS_GetPropertyDescriptorById(cx, holder, id, 0, desc)) + return false; + if (desc.object()) { + desc.object().set(wrapper); + return true; + } + + // Grab the JSClass. We require all Xrayable classes to have a ClassSpec. + RootedObject target(cx, getTargetObject(wrapper)); + const js::Class *clasp = js::GetObjectClass(target); + JSProtoKey protoKey = JSCLASS_CACHED_PROTO_KEY(clasp); + MOZ_ASSERT(protoKey == getProtoKey(holder)); + MOZ_ASSERT(clasp->spec.defined()); + + // Handle the 'constructor' property. + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)) { + RootedObject constructor(cx); + { + JSAutoCompartment ac(cx, target); + if (!JS_GetClassObject(cx, protoKey, &constructor)) + return false; + } + if (!JS_WrapObject(cx, &constructor)) + return false; + desc.object().set(wrapper); + desc.setAttributes(0); + desc.setGetter(nullptr); + desc.setSetter(nullptr); + desc.value().setObject(*constructor); + return true; + } + + // Find the properties available, if any. + const JSFunctionSpec *fs = clasp->spec.prototypeFunctions; + if (!fs) + return true; + + // Compute the property name we're looking for. We'll handle indexed + // properties when we start supporting arrays. + if (!JSID_IS_STRING(id)) + return true; + Rooted str(cx, JSID_TO_FLAT_STRING(id)); + + // Scan through the properties. If we don't find anything, we're done. + for (; fs->name; ++fs) { + // We don't support self-hosted functions yet. See bug 972987. + if (fs->selfHostedName) + continue; + if (JS_FlatStringEqualsAscii(str, fs->name)) + break; + } + if (!fs->name) + return true; + + // Generate an Xrayed version of the method. + Rooted fun(cx, JS_NewFunctionById(cx, fs->call.op, fs->nargs, + 0, wrapper, id)); + if (!fun) + return false; + + // The generic Xray machinery only defines non-own properties on the holder. + // This is broken, and will be fixed at some point, but for now we need to + // cache the value explicitly. See the corresponding call to + // JS_GetPropertyById at the top of this function. + return JS_DefinePropertyById(cx, holder, id, + ObjectValue(*JS_GetFunctionObject(fun)), + nullptr, nullptr, 0) && + JS_GetPropertyDescriptorById(cx, holder, id, 0, desc); +} + +bool +JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags, + AutoIdVector &props) +{ + RootedObject holder(cx, ensureHolder(cx, wrapper)); + if (!holder) + return false; + + // Non-prototypes don't have anything on them yet. + if (!isPrototype(holder)) + return true; + + // Grab the JSClass. We require all Xrayable classes to have a ClassSpec. + RootedObject target(cx, getTargetObject(wrapper)); + const js::Class *clasp = js::GetObjectClass(target); + MOZ_ASSERT(JSCLASS_CACHED_PROTO_KEY(clasp) == getProtoKey(holder)); + MOZ_ASSERT(clasp->spec.defined()); + + // Find the properties available, if any. + const JSFunctionSpec *fs = clasp->spec.prototypeFunctions; + if (!fs) + return true; + + // Intern all the strings, and pass theme to the caller. + for (; fs->name; ++fs) { + // We don't support self-hosted functions yet. See bug 972987. + if (fs->selfHostedName) + continue; + RootedString str(cx, JS_InternString(cx, fs->name)); + if (!str) + return false; + if (!props.append(INTERNED_STRING_TO_JSID(cx, str))) + return false; + } + + // Add the 'constructor' property. + return props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)); +} + JSObject* JSXrayTraits::createHolder(JSContext *cx, JSObject *wrapper) {