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

This commit is contained in:
Boris Zbarsky 2014-01-08 10:29:15 -05:00
Родитель aa6686aaf9
Коммит 0b927c76d8
4 изменённых файлов: 158 добавлений и 13 удалений

Просмотреть файл

@ -87,6 +87,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 {
@ -2185,5 +2202,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

Просмотреть файл

@ -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,
@ -202,9 +207,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);
@ -230,8 +236,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;
}
@ -240,6 +245,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)
{
@ -2350,6 +2363,15 @@ CreateGlobal(JSContext* aCx, T* aObject, nsWrapperCache* aCache,
return global;
}
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

Просмотреть файл

@ -1588,8 +1588,10 @@ class MethodDefiner(PropertyDefiner):
jitinfo = ("&%s_methodinfo" % accessor)
if m.get("allowCrossOriginThis", False):
accessor = "genericCrossOriginMethod"
else:
elif self.descriptor.needsSpecialGenericOps():
accessor = "genericMethod"
else:
accessor = "GenericBindingMethod"
else:
jitinfo = "nullptr"
@ -1646,8 +1648,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)
@ -1665,8 +1669,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)
@ -8629,7 +8635,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'])):
@ -8641,7 +8647,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.isStatic():
@ -8653,7 +8659,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:
if m.isStatic():
@ -8665,17 +8671,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))

Просмотреть файл

@ -494,6 +494,16 @@ class Descriptor(DescriptorProvider):
any((m.isAttr() or m.isMethod()) and m.isStatic() for m
in self.interface.members))
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):
"""