aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-09-16 19:44:45 +0200
committerLars Knoll <lars.knoll@qt.io>2018-09-27 08:34:14 +0000
commit20a434faa81059fd2e969e7c372758d2e03da9e6 (patch)
tree07f41afc9663342a2ef06e8e0692cf3022950176 /src/qml/jsruntime
parent7c592625032a98f68fd6a09026e466c5fbc7bb09 (diff)
Speed up instanceof operations
Introduce a shortcut if the rhs is a functionobject with the regular function proto as prototype. Add an optimized instanceOf implementation when we already have some checks done, and inline some methods. Change-Id: Iab9b648ae7bbec749b319e883b6ae90a23875454 Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4engine.cpp19
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp10
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h19
-rw-r--r--src/qml/jsruntime/qv4object.cpp20
-rw-r--r--src/qml/jsruntime/qv4object_p.h14
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp12
6 files changed, 62 insertions, 32 deletions
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 522ad7669f..8f64c84eae 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -348,14 +348,23 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
auto *index = &_index;
#endif
ic = newInternalClass(QV4::FunctionPrototype::staticVTable(), objectPrototype());
+ auto addProtoHasInstance = [&] {
+ // Add an invalid prototype slot, so that all function objects have the same layout
+ // This helps speed up instanceof operations and other things where we need to query
+ // prototype property (as we always know it's location)
+ ic = ic->addMember(id_prototype()->propertyKey(), Attr_Invalid, index);
+ Q_ASSERT(index->index == Heap::FunctionObject::Index_Prototype);
+ // add an invalid @hasInstance slot, so that we can quickly track whether the
+ // hasInstance method has been reimplemented. This is required for a fast
+ // instanceof implementation
+ ic = ic->addMember(symbol_hasInstance()->propertyKey(), Attr_Invalid, index);
+ Q_ASSERT(index->index == Heap::FunctionObject::Index_HasInstance);
+ };
+ addProtoHasInstance();
jsObjects[FunctionProto] = memoryManager->allocObject<FunctionPrototype>(ic->d());
ic = newInternalClass(FunctionObject::staticVTable(), functionPrototype());
+ addProtoHasInstance();
classes[Class_FunctionObject] = ic->d();
- // Add an invalid prototype slot, so that all function objects have the same layout
- // This helps speed up instanceof operations and other things where we need to query
- // prototype property (as we always know it's location)
- ic = ic->addMember(id_prototype()->propertyKey(), Attr_Invalid, index);
- Q_ASSERT(index->index == Heap::FunctionObject::Index_Prototype);
ic = ic->addMember(id_name()->propertyKey(), Attr_ReadOnly, index);
Q_ASSERT(index->index == Heap::ArrowFunction::Index_Name);
ic = ic->addMember(id_length()->propertyKey(), Attr_ReadOnly_ButConfigurable, index);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index cc5f086276..f6b279ddaf 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -205,16 +205,6 @@ Heap::FunctionObject *FunctionObject::createBuiltinFunction(ExecutionEngine *eng
return function->d();
}
-bool FunctionObject::isBinding() const
-{
- return d()->vtable() == QQmlBindingFunction::staticVTable();
-}
-
-bool FunctionObject::isBoundFunction() const
-{
- return d()->vtable() == BoundFunction::staticVTable();
-}
-
ReturnedValue FunctionObject::getHomeObject() const
{
const MemberFunction *m = as<MemberFunction>();
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 8a2c84a8f6..b08b333411 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -77,7 +77,8 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
DECLARE_MARKOBJECTS(FunctionObject);
enum {
Index_ProtoConstructor = 0,
- Index_Prototype = 0
+ Index_Prototype = 0,
+ Index_HasInstance = 1,
};
bool isConstructor() const {
@@ -112,7 +113,7 @@ struct IndexedBuiltinFunction : FunctionObject {
struct ArrowFunction : FunctionObject {
enum {
- Index_Name = Index_Prototype + 1,
+ Index_Name = Index_HasInstance + 1,
Index_Length
};
void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr);
@@ -214,8 +215,12 @@ struct Q_QML_EXPORT FunctionObject: Object {
ReturnedValue getHomeObject() const;
- ReturnedValue protoProperty() const { return get(engine()->id_prototype()); }
-
+ ReturnedValue protoProperty() const {
+ return getValueByIndex(Heap::FunctionObject::Index_Prototype);
+ }
+ bool hasHasInstanceProperty() const {
+ return !internalClass()->propertyData.at(Heap::FunctionObject::Index_HasInstance).isEmpty();
+ }
QQmlSourceLocation sourceLocation() const;
};
@@ -316,6 +321,12 @@ struct BoundFunction: FunctionObject {
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
+inline bool FunctionObject::isBoundFunction() const
+{
+ return d()->vtable() == BoundFunction::staticVTable();
+}
+
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index ea374e43c0..a7ede4627c 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -731,21 +731,27 @@ ReturnedValue Object::virtualInstanceOf(const Object *typeObject, const Value &v
if (!function)
return engine->throwTypeError();
- Heap::FunctionObject *f = function->d();
- if (function->isBoundFunction())
- f = function->cast<BoundFunction>()->target();
+ return checkedInstanceOf(engine, function, var);
+}
+
+ReturnedValue Object::checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *f, const Value &var)
+{
+ Scope scope(engine);
+ if (f->isBoundFunction()) {
+ ScopedValue v(scope, static_cast<const BoundFunction *>(f)->target());
+ f = v->as<FunctionObject>();
+ }
// 15.3.5.3, 1: HasInstance can only be used on an object
const Object *lhs = var.as<Object>();
if (!lhs)
return Encode(false);
- Scope scope(f->internalClass->engine);
// 15.3.5.3, 2
- ScopedFunctionObject ff(scope, f);
- ScopedObject o(scope, ff->protoProperty());
+ Value p = Value::fromReturnedValue(f->protoProperty());
+ const Object *o = p.objectValue();
if (!o) // 15.3.5.3, 3
- return engine->throwTypeError();
+ return f->engine()->throwTypeError();
Heap::Object *v = lhs->d();
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 7ac9888a88..6753ebfcd4 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -191,9 +191,14 @@ struct Q_QML_EXPORT Object: Managed {
return getValueAccessor(thisObject, v, attrs);
}
ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const {
- Scope scope(this->engine());
- ScopedValue t(scope, const_cast<Object *>(this));
- return getValue(t, v, attrs);
+ return getValue(*this, v, attrs);
+ }
+ ReturnedValue getValueByIndex(uint propertyIndex) const {
+ PropertyAttributes attrs = internalClass()->propertyData.at(propertyIndex);
+ const Value *v = propertyData(propertyIndex);
+ if (!attrs.isAccessor())
+ return v->asReturnedValue();
+ return getValueAccessor(*this, *v, attrs);
}
static ReturnedValue getValueAccessor(const Value &thisObject, const Value &v, PropertyAttributes attrs);
@@ -382,6 +387,9 @@ protected:
static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
static qint64 virtualGetLength(const Managed *m);
static ReturnedValue virtualInstanceOf(const Object *typeObject, const Value &var);
+public:
+ // qv4runtime uses this directly
+ static ReturnedValue checkedInstanceOf(ExecutionEngine *engine, const FunctionObject *typeObject, const Value &var);
private:
bool internalDefineOwnProperty(ExecutionEngine *engine, uint index, const InternalClassEntry *memberEntry, const Property *p, PropertyAttributes attrs);
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 0a098ff7ef..7b1a38ff06 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -349,15 +349,21 @@ QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Val
if (!rhs)
return engine->throwTypeError();
+ const FunctionObject *f = rhs->as<FunctionObject>();
+ // shortcut hasInstance evaluation. In this case we know that we are calling the regular hasInstance()
+ // method of the FunctionPrototype
+ if (f && f->d()->prototype() == engine->functionPrototype()->d() && !f->hasHasInstanceProperty())
+ return Object::checkedInstanceOf(engine, f, 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)
+ FunctionObject *fHasInstance = hasInstance->as<FunctionObject>();
+ if (!fHasInstance)
return engine->throwTypeError();
- ScopedValue result(scope, f->call(&rval, &lval, 1));
+ ScopedValue result(scope, fHasInstance->call(&rval, &lval, 1));
return Encode(result->toBoolean());
}