diff options
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 19 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject_p.h | 19 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 20 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object_p.h | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 12 | ||||
-rw-r--r-- | src/qml/qml/v8/qqmlbuiltinfunctions_p.h | 5 |
7 files changed, 67 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()); } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h index c5e96b3cf3..d87b83ba10 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h +++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h @@ -188,6 +188,11 @@ struct QQmlBindingFunction : public QV4::FunctionObject QQmlSourceLocation currentLocation() const; // from caller stack trace }; +inline bool FunctionObject::isBinding() const +{ + return d()->vtable() == QQmlBindingFunction::staticVTable(); +} + } QT_END_NAMESPACE |