Bug 956806 part 2. Share generic getters/setters/methods across all bindings. r=peterv

This commit is contained in:
Boris Zbarsky 2014-02-07 15:56:14 -05:00
parent 2292f3d2fe
commit 9ba0ae8d76
4 changed files with 158 additions and 13 deletions

View File

@ -89,6 +89,23 @@ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
return false;
}
bool
ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
const ErrNum aErrorNumber,
prototypes::ID aProtoId)
{
return ThrowInvalidThis(aCx, aArgs, aErrorNumber,
NamesOfInterfacesWithProtos[aProtoId]);
}
bool
ThrowNoSetterArg(JSContext* aCx, prototypes::ID aProtoId)
{
nsPrintfCString errorMessage("%s attribute setter",
NamesOfInterfacesWithProtos[aProtoId]);
return ThrowErrorMessage(aCx, MSG_MISSING_ARGUMENTS, errorMessage.get());
}
} // namespace dom
struct ErrorResult::Message {
@ -2202,5 +2219,94 @@ EnumerateGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj)
return JS_EnumerateStandardClasses(aCx, aObj);
}
bool
GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
if (!args.thisv().isObject()) {
return ThrowInvalidThis(cx, args,
MSG_GETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE,
protoID);
}
JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
void* self;
{
nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
if (NS_FAILED(rv)) {
return ThrowInvalidThis(cx, args,
GetInvalidThisErrorForGetter(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO),
protoID);
}
}
MOZ_ASSERT(info->type() == JSJitInfo::Getter);
JSJitGetterOp getter = info->getter;
return getter(cx, obj, self, JSJitGetterCallArgs(args));
}
bool
GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
if (!args.thisv().isObject()) {
return ThrowInvalidThis(cx, args,
MSG_SETTER_THIS_DOES_NOT_IMPLEMENT_INTERFACE,
protoID);
}
JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
void* self;
{
nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
if (NS_FAILED(rv)) {
return ThrowInvalidThis(cx, args,
GetInvalidThisErrorForSetter(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO),
protoID);
}
}
if (args.length() == 0) {
return ThrowNoSetterArg(cx, protoID);
}
MOZ_ASSERT(info->type() == JSJitInfo::Setter);
JSJitSetterOp setter = info->setter;
if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) {
return false;
}
args.rval().set(JSVAL_VOID);
return true;
}
bool
GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp)
{
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev());
prototypes::ID protoID = static_cast<prototypes::ID>(info->protoID);
if (!args.thisv().isObject()) {
return ThrowInvalidThis(cx, args,
MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE,
protoID);
}
JS::Rooted<JSObject*> obj(cx, &args.thisv().toObject());
void* self;
{
nsresult rv = UnwrapObject<void>(obj, self, protoID, info->depth);
if (NS_FAILED(rv)) {
return ThrowInvalidThis(cx, args,
GetInvalidThisErrorForMethod(rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO),
protoID);
}
}
MOZ_ASSERT(info->type() == JSJitInfo::Method);
JSJitMethodOp method = info->method;
return method(cx, obj, self, JSJitMethodCallArgs(args));
}
} // namespace dom
} // namespace mozilla

View File

@ -93,6 +93,11 @@ ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
const ErrNum aErrorNumber,
const char* aInterfaceName);
bool
ThrowInvalidThis(JSContext* aCx, const JS::CallArgs& aArgs,
const ErrNum aErrorNumber,
prototypes::ID aProtoId);
inline bool
ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
const char* ifaceName,
@ -206,9 +211,10 @@ IsDOMObject(JSObject* obj)
// (for example, overload resolution uses unwrapping to tell what sort
// of thing it's looking at).
// U must be something that a T* can be assigned to (e.g. T* or an nsRefPtr<T>).
template <prototypes::ID PrototypeID, class T, typename U>
template <class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, U& value)
UnwrapObject(JSObject* obj, U& value, prototypes::ID protoID,
uint32_t protoDepth)
{
/* First check to see whether we have a DOM object */
const DOMClass* domClass = GetDOMClass(obj);
@ -234,8 +240,7 @@ UnwrapObject(JSObject* obj, U& value)
/* This object is a DOM object. Double-check that it is safely
castable to T by checking whether it claims to inherit from the
class identified by protoID. */
if (domClass->mInterfaceChain[PrototypeTraits<PrototypeID>::Depth] ==
PrototypeID) {
if (domClass->mInterfaceChain[protoDepth] == protoID) {
value = UnwrapDOMObject<T>(obj);
return NS_OK;
}
@ -244,6 +249,14 @@ UnwrapObject(JSObject* obj, U& value)
return NS_ERROR_XPC_BAD_CONVERT_JS;
}
template <prototypes::ID PrototypeID, class T, typename U>
MOZ_ALWAYS_INLINE nsresult
UnwrapObject(JSObject* obj, U& value)
{
return UnwrapObject<T>(obj, value, PrototypeID,
PrototypeTraits<PrototypeID>::Depth);
}
inline bool
IsNotDateOrRegExp(JSContext* cx, JS::Handle<JSObject*> obj)
{
@ -2455,6 +2468,15 @@ class InternedStringId
}
};
bool
GenericBindingGetter(JSContext* cx, unsigned argc, JS::Value* vp);
bool
GenericBindingSetter(JSContext* cx, unsigned argc, JS::Value* vp);
bool
GenericBindingMethod(JSContext* cx, unsigned argc, JS::Value* vp);
} // namespace dom
} // namespace mozilla

View File

@ -1633,8 +1633,10 @@ class MethodDefiner(PropertyDefiner):
jitinfo = ("reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor)
if m.get("allowCrossOriginThis", False):
accessor = "genericCrossOriginMethod"
else:
elif self.descriptor.needsSpecialGenericOps():
accessor = "genericMethod"
else:
accessor = "GenericBindingMethod"
else:
jitinfo = "nullptr"
@ -1691,8 +1693,10 @@ class AttrDefiner(PropertyDefiner):
accessor = "genericLenientGetter"
elif attr.getExtendedAttribute("CrossOriginReadable"):
accessor = "genericCrossOriginGetter"
else:
elif self.descriptor.needsSpecialGenericOps():
accessor = "genericGetter"
else:
accessor = "GenericBindingGetter"
jitinfo = "&%s_getterinfo" % attr.identifier.name
return "{ { JS_CAST_NATIVE_TO(%s, JSPropertyOp), %s } }" % \
(accessor, jitinfo)
@ -1710,8 +1714,10 @@ class AttrDefiner(PropertyDefiner):
accessor = "genericLenientSetter"
elif attr.getExtendedAttribute("CrossOriginWritable"):
accessor = "genericCrossOriginSetter"
else:
elif self.descriptor.needsSpecialGenericOps():
accessor = "genericSetter"
else:
accessor = "GenericBindingSetter"
jitinfo = "&%s_setterinfo" % attr.identifier.name
return "{ { JS_CAST_NATIVE_TO(%s, JSStrictPropertyOp), %s } }" % \
(accessor, jitinfo)
@ -8739,7 +8745,7 @@ class CGDescriptor(CGThing):
continue
if (m.isMethod() and m == descriptor.operations['Jsonifier']):
hasJsonifier = True
hasMethod = True
hasMethod = descriptor.needsSpecialGenericOps()
jsonifierMethod = m
elif (m.isMethod() and
(not m.isIdentifierLess() or m == descriptor.operations['Stringifier'])):
@ -8751,7 +8757,7 @@ class CGDescriptor(CGThing):
cgThings.append(CGMemberJITInfo(descriptor, m))
if m.getExtendedAttribute("CrossOriginCallable"):
crossOriginMethods.add(m.identifier.name)
else:
elif descriptor.needsSpecialGenericOps():
hasMethod = True
elif m.isAttr():
if m.stringifier:
@ -8767,7 +8773,7 @@ class CGDescriptor(CGThing):
hasLenientGetter = True
elif m.getExtendedAttribute("CrossOriginReadable"):
crossOriginGetters.add(m.identifier.name)
else:
elif descriptor.needsSpecialGenericOps():
hasGetter = True
if not m.readonly:
for extAttr in ["PutForwards", "Replaceable"]:
@ -8785,17 +8791,18 @@ class CGDescriptor(CGThing):
hasLenientSetter = True
elif m.getExtendedAttribute("CrossOriginWritable"):
crossOriginSetters.add(m.identifier.name)
else:
elif descriptor.needsSpecialGenericOps():
hasSetter = True
elif m.getExtendedAttribute("PutForwards"):
cgThings.append(CGSpecializedForwardingSetter(descriptor, m))
if m.getExtendedAttribute("CrossOriginWritable"):
crossOriginSetters.add(m.identifier.name)
else:
elif descriptor.needsSpecialGenericOps():
hasSetter = True
elif m.getExtendedAttribute("Replaceable"):
cgThings.append(CGSpecializedReplaceableSetter(descriptor, m))
hasSetter = True
if descriptor.needsSpecialGenericOps():
hasSetter = True
if (not m.isStatic() and
descriptor.interface.hasInterfacePrototypeObject()):
cgThings.append(CGMemberJITInfo(descriptor, m))

View File

@ -507,6 +507,16 @@ class Descriptor(DescriptorProvider):
"HTMLEmbedElement",
"HTMLAppletElement"])
def needsSpecialGenericOps(self):
"""
Returns true if this descriptor requires generic ops other than
GenericBindingMethod/GenericBindingGetter/GenericBindingSetter.
In practice we need to do this if our this value might be an XPConnect
object or if we need to coerce null/undefined to the global.
"""
return self.hasXPConnectImpls or self.interface.isOnGlobalProtoChain()
# Some utility methods
def getTypesFromDescriptor(descriptor):
"""