зеркало из https://github.com/mozilla/gecko-dev.git
Bug 956806 part 2. Share generic getters/setters/methods across all bindings. r=peterv
This commit is contained in:
Родитель
aa6686aaf9
Коммит
0b927c76d8
|
@ -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):
|
||||
"""
|
||||
|
|
Загрузка…
Ссылка в новой задаче