Make instanceOf compliant with the ES7 spec

Add implementation for Function.prototype[Symbol.hasInstance]
and call it when defined.

Change-Id: Iad6b0c075452b46ba710ffe7b94b74b71f715d22
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Lars Knoll 2018-04-25 22:34:55 +02:00
parent a4207b2f95
commit 440a25388b
5 changed files with 27 additions and 19 deletions

View File

@ -41,6 +41,7 @@
#include "qv4objectproto_p.h"
#include "qv4stringobject_p.h"
#include "qv4function_p.h"
#include "qv4symbol_p.h"
#include <private/qv4mm_p.h>
#include "qv4arrayobject_p.h"
@ -277,6 +278,7 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("apply"), method_apply, 2);
defineDefaultProperty(QStringLiteral("call"), method_call, 1);
defineDefaultProperty(QStringLiteral("bind"), method_bind, 1);
defineDefaultProperty(engine->symbol_hasInstance(), method_hasInstance, 1, Attr_ReadOnly);
}
ReturnedValue FunctionPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
@ -385,6 +387,17 @@ ReturnedValue FunctionPrototype::method_bind(const FunctionObject *b, const Valu
return bound->asReturnedValue();
}
ReturnedValue FunctionPrototype::method_hasInstance(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
{
if (!argc)
return false;
const Object *o = thisObject->as<Object>();
if (!o)
return f->engine()->throwTypeError();
return Object::instanceOf(o, argv[0]);
}
DEFINE_OBJECT_VTABLE(ScriptFunction);
ReturnedValue ScriptFunction::callAsConstructor(const FunctionObject *fo, const Value *argv, int argc)

View File

@ -205,6 +205,7 @@ struct FunctionPrototype: FunctionObject
static ReturnedValue method_apply(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_bind(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
};
struct IndexedBuiltinFunction : FunctionObject

View File

@ -61,6 +61,7 @@
#include <private/qqmlengine_p.h>
#include <private/qqmljavascriptexpression_p.h>
#include "qv4qobjectwrapper_p.h"
#include "qv4symbol_p.h"
#include <private/qv8engine_p.h>
#endif
@ -361,8 +362,16 @@ QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Val
if (!rhs)
return engine->throwTypeError();
// 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result.
return rhs->instanceOf(lval);
Scope scope(engine);
ScopedValue hasInstance(scope, rhs->get(engine->symbol_hasInstance()));
if (hasInstance->isUndefined())
return rhs->instanceOf(lval);
FunctionObject *f = hasInstance->as<FunctionObject>();
if (!f)
return engine->throwTypeError();
ScopedValue result(scope, f->call(&rval, &lval, 1));
return Encode(result->toBoolean());
}
QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)

View File

@ -1174,14 +1174,8 @@ QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObj
MOTH_END_INSTR(CmpIn)
MOTH_BEGIN_INSTR(CmpInstanceOf)
// 11.8.6, 5: rval must be an Object
if (Q_UNLIKELY(!Primitive::fromReturnedValue(acc).isObject())) {
acc = engine->throwTypeError();
goto catchException;
}
// 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result.
acc = Primitive::fromReturnedValue(acc).objectValue()->instanceOf(STACK_VALUE(lhs));
STORE_ACC();
acc = Runtime::method_instanceof(engine, STACK_VALUE(lhs), ACC);
CHECK_EXCEPTION;
MOTH_END_INSTR(CmpInstanceOf)

View File

@ -583,16 +583,10 @@ built-ins/Function/length/S15.3.5.1_A2_T1.js fails
built-ins/Function/length/S15.3.5.1_A2_T2.js fails
built-ins/Function/length/S15.3.5.1_A2_T3.js fails
built-ins/Function/proto-from-ctor-realm.js fails
built-ins/Function/prototype/Symbol.hasInstance/length.js fails
built-ins/Function/prototype/Symbol.hasInstance/name.js fails
built-ins/Function/prototype/Symbol.hasInstance/prop-desc.js fails
built-ins/Function/prototype/Symbol.hasInstance/this-val-bound-target.js fails
built-ins/Function/prototype/Symbol.hasInstance/this-val-not-callable.js fails
built-ins/Function/prototype/Symbol.hasInstance/this-val-poisoned-prototype.js fails
built-ins/Function/prototype/Symbol.hasInstance/value-get-prototype-of-err.js fails
built-ins/Function/prototype/Symbol.hasInstance/value-negative.js fails
built-ins/Function/prototype/Symbol.hasInstance/value-non-obj.js fails
built-ins/Function/prototype/Symbol.hasInstance/value-positive.js fails
built-ins/Function/prototype/bind/BoundFunction_restricted-properties.js fails
built-ins/Function/prototype/bind/get-fn-realm.js fails
built-ins/Function/prototype/bind/instance-construct-newtarget-boundtarget-bound.js fails
@ -4795,9 +4789,6 @@ language/expressions/generators/yield-spread-arr-single.js fails
language/expressions/generators/yield-star-before-newline.js fails
language/expressions/instanceof/prototype-getter-with-object-throws.js fails
language/expressions/instanceof/prototype-getter-with-object.js fails
language/expressions/instanceof/symbol-hasinstance-get-err.js fails
language/expressions/instanceof/symbol-hasinstance-invocation.js fails
language/expressions/instanceof/symbol-hasinstance-to-boolean.js fails
language/expressions/logical-and/tco-right.js strictFails
language/expressions/logical-or/tco-right.js strictFails
language/expressions/new.target/asi.js fails