зеркало из https://github.com/mozilla/pjs.git
Bug 748983. Fix the instanceof behavior for new bindings in situations where we don't need a custom hasInstance hook. r=peterv
This commit is contained in:
Родитель
f110e1483e
Коммит
ae2f03e9ab
|
@ -25,17 +25,27 @@ DefineConstants(JSContext* cx, JSObject* obj, ConstantSpec* cs)
|
|||
|
||||
static JSObject*
|
||||
CreateInterfaceObject(JSContext* cx, JSObject* global, JSObject* receiver,
|
||||
JSClass* constructorClass, JSObject* proto,
|
||||
JSClass* constructorClass, JSNative constructorNative,
|
||||
unsigned ctorNargs, JSObject* proto,
|
||||
JSFunctionSpec* staticMethods, ConstantSpec* constants,
|
||||
const char* name)
|
||||
{
|
||||
JSObject* functionProto = JS_GetFunctionPrototype(cx, global);
|
||||
if (!functionProto) {
|
||||
return NULL;
|
||||
JSObject* constructor;
|
||||
if (constructorClass) {
|
||||
JSObject* functionProto = JS_GetFunctionPrototype(cx, global);
|
||||
if (!functionProto) {
|
||||
return NULL;
|
||||
}
|
||||
constructor = JS_NewObject(cx, constructorClass, functionProto, global);
|
||||
} else {
|
||||
MOZ_ASSERT(constructorNative);
|
||||
JSFunction* fun = JS_NewFunction(cx, constructorNative, ctorNargs,
|
||||
JSFUN_CONSTRUCTOR, global, name);
|
||||
if (!fun) {
|
||||
return NULL;
|
||||
}
|
||||
constructor = JS_GetFunctionObject(fun);
|
||||
}
|
||||
|
||||
JSObject* constructor =
|
||||
JS_NewObject(cx, constructorClass, functionProto, global);
|
||||
if (!constructor) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -92,17 +102,20 @@ CreateInterfacePrototypeObject(JSContext* cx, JSObject* global,
|
|||
JSObject*
|
||||
CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
|
||||
JSObject* protoProto, JSClass* protoClass,
|
||||
JSClass* constructorClass, JSFunctionSpec* methods,
|
||||
JSClass* constructorClass, JSNative constructor,
|
||||
unsigned ctorNargs, JSFunctionSpec* methods,
|
||||
JSPropertySpec* properties, ConstantSpec* constants,
|
||||
JSFunctionSpec* staticMethods, const char* name)
|
||||
{
|
||||
MOZ_ASSERT(protoClass || constructorClass, "Need at least one class!");
|
||||
MOZ_ASSERT(protoClass || constructorClass || constructor,
|
||||
"Need at least one class or a constructor!");
|
||||
MOZ_ASSERT(!(methods || properties) || protoClass,
|
||||
"Methods or properties but no protoClass!");
|
||||
MOZ_ASSERT(!staticMethods || constructorClass,
|
||||
"Static methods but no constructorClass!");
|
||||
MOZ_ASSERT(bool(name) == bool(constructorClass),
|
||||
MOZ_ASSERT(!staticMethods || constructorClass || constructor,
|
||||
"Static methods but no constructorClass or constructor!");
|
||||
MOZ_ASSERT(bool(name) == bool(constructorClass || constructor),
|
||||
"Must have name precisely when we have an interface object");
|
||||
MOZ_ASSERT(!constructorClass || !constructor);
|
||||
|
||||
JSObject* proto;
|
||||
if (protoClass) {
|
||||
|
@ -117,9 +130,10 @@ CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject *receiver,
|
|||
}
|
||||
|
||||
JSObject* interface;
|
||||
if (constructorClass) {
|
||||
if (constructorClass || constructor) {
|
||||
interface = CreateInterfaceObject(cx, global, receiver, constructorClass,
|
||||
proto, staticMethods, constants, name);
|
||||
constructor, ctorNargs, proto,
|
||||
staticMethods, constants, name);
|
||||
if (!interface) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -239,5 +253,17 @@ QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||
{
|
||||
return Throw<true>(cx, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
JSBool
|
||||
ThrowingConstructorWorkers(JSContext* cx, unsigned argc, JS::Value* vp)
|
||||
{
|
||||
return Throw<false>(cx, NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -231,7 +231,14 @@ struct ConstantSpec
|
|||
* This is null if we should not create an interface prototype
|
||||
* object.
|
||||
* constructorClass is the JSClass to use for the interface object.
|
||||
* This is null if we should not create an interface object.
|
||||
* This is null if we should not create an interface object or
|
||||
* if it should be a function object.
|
||||
* constructor is the JSNative to use as a constructor. If this is non-null, it
|
||||
* should be used as a JSNative to back the interface object, which
|
||||
* should be a Function. If this is null, then we should create an
|
||||
* object of constructorClass, unless that's also null, in which
|
||||
* case we should not create an interface object at all.
|
||||
* ctorNargs is the length of the constructor function; 0 if no constructor
|
||||
* methods and properties are to be defined on the interface prototype object;
|
||||
* these arguments are allowed to be null if there are no
|
||||
* methods or properties respectively.
|
||||
|
@ -251,7 +258,8 @@ struct ConstantSpec
|
|||
JSObject*
|
||||
CreateInterfaceObjects(JSContext* cx, JSObject* global, JSObject* receiver,
|
||||
JSObject* protoProto, JSClass* protoClass,
|
||||
JSClass* constructorClass, JSFunctionSpec* methods,
|
||||
JSClass* constructorClass, JSNative constructor,
|
||||
unsigned ctorNargs, JSFunctionSpec* methods,
|
||||
JSPropertySpec* properties, ConstantSpec* constants,
|
||||
JSFunctionSpec* staticMethods, const char* name);
|
||||
|
||||
|
@ -507,6 +515,10 @@ InitIds(JSContext* cx, Spec* specs, jsid* ids)
|
|||
|
||||
JSBool
|
||||
QueryInterface(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
JSBool
|
||||
ThrowingConstructor(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
JSBool
|
||||
ThrowingConstructorWorkers(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -156,8 +156,10 @@ class CGInterfaceObjectJSClass(CGThing):
|
|||
# We're purely for internal consumption
|
||||
return ""
|
||||
def define(self):
|
||||
if not self.descriptor.hasInstanceInterface:
|
||||
return ""
|
||||
ctorname = "NULL" if not self.descriptor.interface.ctor() else CONSTRUCT_HOOK_NAME
|
||||
hasinstance = "NULL" if not self.descriptor.hasInstanceInterface else HASINSTANCE_HOOK_NAME
|
||||
hasinstance = HASINSTANCE_HOOK_NAME
|
||||
return """
|
||||
static JSClass InterfaceObjectClass = {
|
||||
"Function", 0,
|
||||
|
@ -657,6 +659,12 @@ class PropertyDefiner:
|
|||
str += self.generateArray(self.chrome, self.variableName(True))
|
||||
return str
|
||||
|
||||
# The length of a method is the maximum of the lengths of the
|
||||
# argument lists of all its overloads.
|
||||
def methodLength(method):
|
||||
signatures = method.signatures()
|
||||
return max([len(arguments) for (retType, arguments) in signatures])
|
||||
|
||||
class MethodDefiner(PropertyDefiner):
|
||||
"""
|
||||
A class for defining methods on a prototype object.
|
||||
|
@ -664,12 +672,6 @@ class MethodDefiner(PropertyDefiner):
|
|||
def __init__(self, descriptor, name, static):
|
||||
PropertyDefiner.__init__(self, descriptor, name)
|
||||
|
||||
# The length of a method is the maximum of the lengths of the
|
||||
# argument lists of all its overloads.
|
||||
def methodLength(method):
|
||||
signatures = method.signatures()
|
||||
return max([len(arguments) for (retType, arguments) in signatures])
|
||||
|
||||
methods = [m for m in descriptor.interface.members if
|
||||
m.isMethod() and m.isStatic() == static]
|
||||
self.chrome = [{"name": m.identifier.name,
|
||||
|
@ -858,12 +860,25 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
" return NULL;\n"
|
||||
"}") % getParentProto
|
||||
|
||||
needInterfaceObjectClass = (needInterfaceObject and
|
||||
self.descriptor.hasInstanceInterface)
|
||||
needConstructor = (needInterfaceObject and
|
||||
not self.descriptor.hasInstanceInterface)
|
||||
if self.descriptor.interface.ctor():
|
||||
constructHook = CONSTRUCT_HOOK_NAME
|
||||
constructArgs = methodLength(self.descriptor.interface.ctor())
|
||||
else:
|
||||
constructHook = "ThrowingConstructorWorkers" if self.descriptor.workers else "ThrowingConstructor"
|
||||
constructArgs = 0
|
||||
|
||||
call = CGGeneric(("return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,\n"
|
||||
" %s, %s,\n"
|
||||
" %s, %s, %s, %d,\n"
|
||||
" %%(methods)s, %%(attrs)s, %%(consts)s, %%(staticMethods)s,\n"
|
||||
" %s);") % (
|
||||
"&PrototypeClass" if needInterfacePrototypeObject else "NULL",
|
||||
"&InterfaceObjectClass" if needInterfaceObject else "NULL",
|
||||
"&InterfaceObjectClass" if needInterfaceObjectClass else "NULL",
|
||||
constructHook if needConstructor else "NULL",
|
||||
constructArgs,
|
||||
'"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL"))
|
||||
|
||||
if self.properties.hasChromeOnly():
|
||||
|
|
|
@ -13,6 +13,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
_TEST_FILES = \
|
||||
test_lookupGetter.html \
|
||||
test_InstanceOf.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=748983
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 748983</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=748983">Mozilla Bug 748983</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 748983 **/
|
||||
ok(document instanceof EventTarget, "document is an event target")
|
||||
ok(new XMLHttpRequest() instanceof XMLHttpRequest, "instanceof should work on XHR");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче