Bug 975042 - Implement resolveOwnProperty and enumerateNames trap. r=peterv

This commit is contained in:
Bobby Holley 2014-03-20 23:47:24 -03:00
parent 7d73a1180e
commit dfee9350c7

View File

@ -295,10 +295,7 @@ public:
virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
HandleObject holder, HandleId id,
MutableHandle<JSPropertyDescriptor> desc, unsigned flags)
{
MOZ_ASSUME_UNREACHABLE("Not yet implemented");
}
MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
static bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
MutableHandle<JSPropertyDescriptor> 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<JSPropertyDescriptor> 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<JSFlatString*> 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<JSFunction*> 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)
{