diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-06-19 13:28:26 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-06-25 07:36:48 +0000 |
commit | 1596112e146b28541bcee412ed159cdea7e692d0 (patch) | |
tree | 29e858041496256c9c9c700fca4fb7220d78d46e /src | |
parent | 3823e9b94f849f8344b81250fac708ac2eaccd16 (diff) |
Add Proxy support for prototype handling
Cleanup get/setPrototypeOf and fix some smaller incompatibilities
in the default implementation for Object.
Add the methods to the vtable and reimplement them according to
spec for ProxyObjects.
Clean up the Object.prototype.get/setPrototypeOf/__proto__ methods
and fix a smaller bug in the Reflect API for those methods.
Change-Id: I6e438753332ec4db963d6cdcf86f340ff212777a
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
22 files changed, 205 insertions, 106 deletions
diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index fb20a1c457..60c1f89c9b 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -323,7 +323,7 @@ static ReturnedValue qmlsqldatabase_executeSql(const FunctionObject *b, const Va if (query.exec()) { QV4::Scoped<QQmlSqlDatabaseWrapper> rows(scope, QQmlSqlDatabaseWrapper::create(scope.engine)); QV4::ScopedObject p(scope, databaseData(scope.engine)->rowsProto.value()); - rows->setPrototype(p.getPointer()); + rows->setPrototypeUnchecked(p.getPointer()); rows->d()->type = Heap::QQmlSqlDatabaseWrapper::Rows; *rows->d()->database = db; *rows->d()->sqlQuery = query; @@ -397,7 +397,7 @@ static ReturnedValue qmlsqldatabase_changeVersion(const FunctionObject *b, const Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(scope.engine)); ScopedObject p(scope, databaseData(scope.engine)->queryProto.value()); - w->setPrototype(p.getPointer()); + w->setPrototypeUnchecked(p.getPointer()); w->d()->type = Heap::QQmlSqlDatabaseWrapper::Query; *w->d()->database = db; *w->d()->version = *r->d()->version; @@ -449,7 +449,7 @@ static ReturnedValue qmlsqldatabase_transaction_shared(const FunctionObject *b, Scoped<QQmlSqlDatabaseWrapper> w(scope, QQmlSqlDatabaseWrapper::create(scope.engine)); QV4::ScopedObject p(scope, databaseData(scope.engine)->queryProto.value()); - w->setPrototype(p.getPointer()); + w->setPrototypeUnchecked(p.getPointer()); w->d()->type = Heap::QQmlSqlDatabaseWrapper::Query; *w->d()->database = db; *w->d()->version = *r->d()->version; @@ -773,7 +773,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) QV4::Scoped<QQmlSqlDatabaseWrapper> db(scope, QQmlSqlDatabaseWrapper::create(scope.engine)); QV4::ScopedObject p(scope, databaseData(scope.engine)->databaseProto.value()); - db->setPrototype(p.getPointer()); + db->setPrototypeUnchecked(p.getPointer()); *db->d()->database = database; *db->d()->version = version; diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp index cf05245f5b..6d43b3880b 100644 --- a/src/particles/qquickv4particledata.cpp +++ b/src/particles/qquickv4particledata.cpp @@ -520,7 +520,7 @@ QQuickV4ParticleData::QQuickV4ParticleData(QV4::ExecutionEngine* v4, QQuickParti QV4ParticleDataDeletable *d = particleV4Data(scope.engine); QV4::ScopedObject o(scope, v4->memoryManager->allocate<QV4ParticleData>(datum, system)); QV4::ScopedObject p(scope, d->proto.value()); - o->setPrototype(p); + o->setPrototypeUnchecked(p); m_v4Value = o; } diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index aaac4e0a9a..01ec44e250 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -852,7 +852,7 @@ QJSValue QJSValue::prototype() const ScopedObject o(scope, QJSValuePrivate::getValue(this)->as<QV4::Object>()); if (!o) return QJSValue(); - ScopedObject p(scope, o->prototype()); + ScopedObject p(scope, o->getPrototypeOf()); if (!p) return QJSValue(NullValue); return QJSValue(o->internalClass()->engine, p.asReturnedValue()); @@ -884,7 +884,7 @@ void QJSValue::setPrototype(const QJSValue& prototype) if (!val) return; if (val->isNull()) { - o->setPrototype(nullptr); + o->setPrototypeOf(nullptr); return; } @@ -895,7 +895,7 @@ void QJSValue::setPrototype(const QJSValue& prototype) qWarning("QJSValue::setPrototype() failed: cannot set a prototype created in a different engine"); return; } - if (!o->setPrototype(p)) + if (!o->setPrototypeOf(p)) qWarning("QJSValue::setPrototype() failed: cyclic prototype value"); } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 7cef7c8039..5f202b8a24 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -402,7 +402,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsObjects[URIErrorProto] = memoryManager->allocObject<URIErrorPrototype>(ic->d()); jsObjects[VariantProto] = memoryManager->allocate<VariantPrototype>(); - Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d()); + Q_ASSERT(variantPrototype()->getPrototypeOf() == objectPrototype()->d()); #if QT_CONFIG(qml_sequence_object) ic = newInternalClass(SequencePrototype::staticVTable(), SequencePrototype::defaultPrototype(this)); @@ -1849,7 +1849,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) } else if (Object *o = value->objectValue()) { // Look in the prototype chain. QV4::Scope scope(this); - QV4::ScopedObject proto(scope, o->prototype()); + QV4::ScopedObject proto(scope, o->getPrototypeOf()); while (proto) { bool canCast = false; if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) { @@ -1870,7 +1870,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) *reinterpret_cast<void* *>(data) = var.data(); return true; } - proto = proto->prototype(); + proto = proto->getPrototypeOf(); } } } else if (value->isNull() && name.endsWith('*')) { diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp index a29eef513c..1c4c970c2e 100644 --- a/src/qml/jsruntime/qv4generatorobject.cpp +++ b/src/qml/jsruntime/qv4generatorobject.cpp @@ -78,9 +78,9 @@ Heap::FunctionObject *GeneratorFunction::create(ExecutionContext *context, Funct Scope scope(context); Scoped<GeneratorFunction> g(scope, context->engine()->memoryManager->allocate<GeneratorFunction>(context, function)); ScopedObject proto(scope, scope.engine->newObject()); - proto->setPrototype(scope.engine->generatorPrototype()); + proto->setPrototypeOf(scope.engine->generatorPrototype()); g->defineDefaultProperty(scope.engine->id_prototype(), proto, Attr_NotConfigurable|Attr_NotEnumerable); - g->setPrototype(ScopedObject(scope, scope.engine->generatorFunctionCtor()->get(scope.engine->id_prototype()))); + g->setPrototypeOf(ScopedObject(scope, scope.engine->generatorFunctionCtor()->get(scope.engine->id_prototype()))); return g->d(); } @@ -104,7 +104,7 @@ ReturnedValue GeneratorFunction::call(const FunctionObject *f, const Value *this Scope scope(gf); Scoped<GeneratorObject> g(scope, scope.engine->memoryManager->allocManaged<GeneratorObject>(requiredMemory, scope.engine->classes[EngineBase::Class_GeneratorObject])); - g->setPrototype(ScopedObject(scope, gf->get(scope.engine->id_prototype()))); + g->setPrototypeOf(ScopedObject(scope, gf->get(scope.engine->id_prototype()))); Heap::GeneratorObject *gp = g->d(); gp->stack.size = stackSize; @@ -160,7 +160,7 @@ void GeneratorPrototype::init(ExecutionEngine *engine, Object *ctor) ctorProto->defineDefaultProperty(engine->symbol_toStringTag(), (v = engine->newIdentifier(QStringLiteral("GeneratorFunction"))), Attr_ReadOnly_ButConfigurable); ctorProto->defineDefaultProperty(engine->id_prototype(), (v = this), Attr_ReadOnly_ButConfigurable); - setPrototype(engine->iteratorPrototype()); + setPrototypeOf(engine->iteratorPrototype()); defineDefaultProperty(QStringLiteral("constructor"), ctorProto, Attr_ReadOnly_ButConfigurable); defineDefaultProperty(QStringLiteral("next"), method_next, 1); defineDefaultProperty(QStringLiteral("return"), method_return, 1); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 02acc1a5e0..d1f71b18ae 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -93,19 +93,6 @@ void Heap::Object::setUsedAsProto() internalClass.set(internalClass->engine, internalClass->asProtoClass()); } -bool Object::setPrototype(Object *proto) -{ - Heap::Object *p = proto ? proto->d() : nullptr; - Heap::Object *pp = p; - while (pp) { - if (pp == d()) - return false; - pp = pp->prototype(); - } - setInternalClass(internalClass()->changePrototype(p)); - return true; -} - ReturnedValue Object::getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs) { if (!attrs.isAccessor()) @@ -278,6 +265,11 @@ void Object::insertMember(StringOrSymbol *s, const Property *p, PropertyAttribut } } +void Object::setPrototypeUnchecked(const Object *p) +{ + setInternalClass(internalClass()->changePrototype(p ? p->d() : nullptr)); +} + // Section 8.12.2 PropertyIndex Object::getValueOrSetter(StringOrSymbol *name, PropertyAttributes *attrs) { @@ -484,7 +476,7 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const return str.asReturnedValue(); } } - o = o->prototype(); + o = o->getPrototypeOf(); } if (exists) { @@ -543,13 +535,13 @@ bool Object::internalPut(StringOrSymbol *name, const Value &value) memberIndex.set(engine, value); } return true; - } else if (!prototype()) { + } else if (!getPrototypeOf()) { if (!isExtensible()) return false; } else { // clause 4 Scope scope(engine); - memberIndex = ScopedObject(scope, prototype())->getValueOrSetter(name, &attrs); + memberIndex = ScopedObject(scope, getPrototypeOf())->getValueOrSetter(name, &attrs); if (!memberIndex.isNull()) { if (attrs.isAccessor()) { if (!memberIndex->as<FunctionObject>()) @@ -608,13 +600,13 @@ bool Object::internalPutIndexed(uint index, const Value &value) arrayIndex.set(engine, value); return true; - } else if (!prototype()) { + } else if (!getPrototypeOf()) { if (!isExtensible()) return false; } else { // clause 4 Scope scope(engine); - arrayIndex = ScopedObject(scope, prototype())->getValueOrSetter(index, &attrs); + arrayIndex = ScopedObject(scope, getPrototypeOf())->getValueOrSetter(index, &attrs); if (!arrayIndex.isNull()) { if (attrs.isAccessor()) { if (!arrayIndex->as<FunctionObject>()) @@ -978,7 +970,7 @@ bool Object::hasProperty(const Managed *m, Identifier id) if (o->getOwnProperty(id, p) != Attr_Invalid) return true; - o = o->prototype(); + o = o->getPrototypeOf(); } return false; @@ -1033,6 +1025,34 @@ bool Object::preventExtensions(Managed *m) return true; } +Heap::Object *Object::getPrototypeOf(const Managed *m) +{ + return m->internalClass()->prototype; +} + +bool Object::setPrototypeOf(Managed *m, const Object *proto) +{ + Q_ASSERT(m->isObject()); + Object *o = static_cast<Object *>(m); + Heap::Object *current = o->internalClass()->prototype; + Heap::Object *protod = proto ? proto->d() : nullptr; + if (current == protod) + return true; + if (!o->internalClass()->extensible) + return false; + Heap::Object *p = protod; + while (p) { + if (p == o->d()) + return false; + if (reinterpret_cast<const ObjectVTable *>(p->vtable())->getPrototypeOf != + reinterpret_cast<const ObjectVTable *>(Object::staticVTable())->getPrototypeOf) + break; + p = p->prototype(); + } + o->setInternalClass(o->internalClass()->changePrototype(protod)); + return true; +} + bool Object::setArrayLength(uint newLen) { Q_ASSERT(isArrayObject()); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index b55e8f25e2..6ec7452ca6 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -179,6 +179,8 @@ struct ObjectVTable PropertyAttributes (*getOwnProperty)(Managed *m, Identifier id, Property *p); bool (*isExtensible)(const Managed *); bool (*preventExtensions)(Managed *); + Heap::Object *(*getPrototypeOf)(const Managed *); + bool (*setPrototypeOf)(Managed *, const Object *); qint64 (*getLength)(const Managed *m); void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); ReturnedValue (*instanceOf)(const Object *typeObject, const Value &var); @@ -200,6 +202,8 @@ const QV4::ObjectVTable classname::static_vtbl = \ getOwnProperty, \ isExtensible, \ preventExtensions, \ + getPrototypeOf, \ + setPrototypeOf, \ getLength, \ advanceIterator, \ instanceOf \ @@ -244,8 +248,6 @@ struct Q_QML_EXPORT Object: Managed { void setProperty(ExecutionEngine *engine, uint index, Heap::Base *b) const { d()->setProperty(engine, index, b); } const ObjectVTable *vtable() const { return reinterpret_cast<const ObjectVTable *>(d()->vtable()); } - Heap::Object *prototype() const { return d()->prototype(); } - bool setPrototype(Object *proto); PropertyAttributes getOwnProperty(Identifier id, Property *p = nullptr) { return vtable()->getOwnProperty(this, id, p); @@ -307,6 +309,9 @@ struct Q_QML_EXPORT Object: Managed { bool isExtensible() const { return vtable()->isExtensible(this); } bool preventExtensions() { return vtable()->preventExtensions(this); } + Heap::Object *getPrototypeOf() const { return vtable()->getPrototypeOf(this); } + bool setPrototypeOf(const Object *p) { return vtable()->setPrototypeOf(this, p); } + void setPrototypeUnchecked(const Object *p); // Array handling @@ -366,7 +371,7 @@ public: Scope scope(engine()); ScopedObject p(scope, this); - while ((p = p->prototype())) + while ((p = p->getPrototypeOf())) if (p->arrayData()) return true; @@ -445,6 +450,8 @@ protected: static PropertyAttributes getOwnProperty(Managed *m, Identifier id, Property *p); static bool isExtensible(const Managed *m); static bool preventExtensions(Managed *); + static Heap::Object *getPrototypeOf(const Managed *); + static bool setPrototypeOf(Managed *, const Object *); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static qint64 getLength(const Managed *m); static ReturnedValue instanceOf(const Object *typeObject, const Value &var); diff --git a/src/qml/jsruntime/qv4objectiterator.cpp b/src/qml/jsruntime/qv4objectiterator.cpp index 109e189ede..fc4a06747f 100644 --- a/src/qml/jsruntime/qv4objectiterator.cpp +++ b/src/qml/jsruntime/qv4objectiterator.cpp @@ -109,7 +109,7 @@ void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttrib shadowed = true; break; } - o = o->prototype(); + o = o->getPrototypeOf(); } if (shadowed) continue; @@ -118,7 +118,7 @@ void ObjectIterator::next(Value *name, uint *index, Property *pd, PropertyAttrib } if (flags & WithProtoChain) - current->setM(co->prototype()); + current->setM(co->getPrototypeOf()); else current->setM(nullptr); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 84238477fd..9d52ab1980 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -71,7 +71,7 @@ ReturnedValue ObjectCtor::callAsConstructor(const FunctionObject *f, const Value ScopedObject obj(scope, scope.engine->newObject()); ScopedObject proto(scope, ctor->get(scope.engine->id_prototype())); if (!!proto) - obj->setPrototype(proto); + obj->setPrototypeOf(proto); return obj.asReturnedValue(); } else { return argv[0].toObject(v4)->asReturnedValue(); @@ -136,7 +136,7 @@ ReturnedValue ObjectPrototype::method_getPrototypeOf(const FunctionObject *b, co if (scope.engine->hasException) return QV4::Encode::undefined(); - ScopedObject p(scope, o->prototype()); + ScopedObject p(scope, o->getPrototypeOf()); return (!!p ? p->asReturnedValue() : Encode::null()); } @@ -264,7 +264,7 @@ ReturnedValue ObjectPrototype::method_create(const FunctionObject *builtin, cons ScopedObject O(scope, argv[0]); ScopedObject newObject(scope, scope.engine->newObject()); - newObject->setPrototype(O); + newObject->setPrototypeOf(O); if (argc > 1 && !argv[1].isUndefined()) { @@ -516,17 +516,10 @@ ReturnedValue ObjectPrototype::method_setPrototypeOf(const FunctionObject *f, co return argv[0].asReturnedValue(); ScopedObject o(scope, argv[0]); - ScopedObject p(scope, argv[1]); - Q_ASSERT(!!o); - - if (o->prototype() != p->d()) { - bool ok = false; - if (o->isExtensible()) { - ok = o->setPrototype(p); - } - if (!ok) - return scope.engine->throwTypeError(QStringLiteral("Object.setPrototypeOf: Could not change prototype")); - } + const Object *p = argv[1].isNull() ? nullptr : static_cast<const Object *>(argv + 1); + bool ok = o->setPrototypeOf(p); + if (!ok) + return scope.engine->throwTypeError(QStringLiteral("Could not change prototype.")); return o->asReturnedValue(); } @@ -604,11 +597,11 @@ ReturnedValue ObjectPrototype::method_isPrototypeOf(const FunctionObject *b, con ScopedObject O(scope, thisObject->toObject(scope.engine)); if (scope.engine->hasException) return QV4::Encode::undefined(); - ScopedObject proto(scope, V->prototype()); + ScopedObject proto(scope, V->getPrototypeOf()); while (proto) { if (O->d() == proto->d()) return Encode(true); - proto = proto->prototype(); + proto = proto->getPrototypeOf(); } return Encode(false); } @@ -694,32 +687,21 @@ ReturnedValue ObjectPrototype::method_get_proto(const FunctionObject *b, const V if (!o) THROW_TYPE_ERROR(); - return Encode(o->prototype()); + return Encode(o->getPrototypeOf()); } ReturnedValue ObjectPrototype::method_set_proto(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { Scope scope(b); ScopedObject o(scope, thisObject); - if (!o || !argc) + if (!o || !argc || (!argv[0].isObject() && !argv[0].isNull())) THROW_TYPE_ERROR(); - if (argv[0].isNull()) { - o->setPrototype(nullptr); - RETURN_UNDEFINED(); - } - - ScopedObject p(scope, argv[0]); - bool ok = false; - if (!!p) { - if (o->prototype() == p->d()) { - ok = true; - } else if (o->isExtensible()) { - ok = o->setPrototype(p); - } - } + const Object *p = argv[0].isNull() ? nullptr : static_cast<const Object *>(argv); + bool ok = o->setPrototypeOf(p); if (!ok) - return scope.engine->throwTypeError(QStringLiteral("Cyclic __proto__ value")); + return scope.engine->throwTypeError(QStringLiteral("Could not change prototype.")); + return Encode::undefined(); RETURN_UNDEFINED(); } diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp index e499dfbcf1..80e1b70a1a 100644 --- a/src/qml/jsruntime/qv4proxy.cpp +++ b/src/qml/jsruntime/qv4proxy.cpp @@ -361,6 +361,89 @@ bool ProxyObject::preventExtensions(Managed *m) return result; } +Heap::Object *ProxyObject::getPrototypeOf(const Managed *m) +{ + Scope scope(m); + const ProxyObject *o = static_cast<const ProxyObject *>(m); + if (!o->d()->handler) { + scope.engine->throwTypeError(); + return nullptr; + } + + ScopedObject target(scope, o->d()->target); + Q_ASSERT(target); + ScopedObject handler(scope, o->d()->handler); + ScopedString name(scope, scope.engine->newString(QStringLiteral("getPrototypeOf"))); + ScopedValue trap(scope, handler->get(name)); + if (scope.hasException()) + return nullptr; + if (trap->isNullOrUndefined()) + return target->getPrototypeOf(); + if (!trap->isFunctionObject()) { + scope.engine->throwTypeError(); + return nullptr; + } + + JSCallData cdata(scope, 1, nullptr, handler); + cdata.args[0] = target; + + ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + if (!trapResult->isNull() && !trapResult->isObject()) { + scope.engine->throwTypeError(); + return nullptr; + } + Heap::Object *proto = trapResult->isNull() ? nullptr : static_cast<Heap::Object *>(trapResult->heapObject()); + if (!target->isExtensible()) { + Heap::Object *targetProto = target->getPrototypeOf(); + if (proto != targetProto) { + scope.engine->throwTypeError(); + return nullptr; + } + } + return proto; +} + +bool ProxyObject::setPrototypeOf(Managed *m, const Object *p) +{ + Scope scope(m); + const ProxyObject *o = static_cast<const ProxyObject *>(m); + if (!o->d()->handler) { + scope.engine->throwTypeError(); + return false; + } + + ScopedObject target(scope, o->d()->target); + Q_ASSERT(target); + ScopedObject handler(scope, o->d()->handler); + ScopedString name(scope, scope.engine->newString(QStringLiteral("setPrototypeOf"))); + ScopedValue trap(scope, handler->get(name)); + if (scope.hasException()) + return false; + if (trap->isNullOrUndefined()) + return target->setPrototypeOf(p); + if (!trap->isFunctionObject()) { + scope.engine->throwTypeError(); + return false; + } + + JSCallData cdata(scope, 2, nullptr, handler); + cdata.args[0] = target; + cdata.args[1] = p ? p->asReturnedValue() : Encode::null(); + + ScopedValue trapResult(scope, static_cast<const FunctionObject *>(trap.ptr)->call(cdata)); + bool result = trapResult->toBoolean(); + if (!result) + return false; + if (!target->isExtensible()) { + Heap::Object *targetProto = target->getPrototypeOf(); + if (p->d() != targetProto) { + scope.engine->throwTypeError(); + return false; + } + } + return true; +} + //ReturnedValue ProxyObject::callAsConstructor(const FunctionObject *f, const Value *argv, int argc) //{ diff --git a/src/qml/jsruntime/qv4proxy_p.h b/src/qml/jsruntime/qv4proxy_p.h index a8b5b63a6c..cbabc7e5d9 100644 --- a/src/qml/jsruntime/qv4proxy_p.h +++ b/src/qml/jsruntime/qv4proxy_p.h @@ -95,6 +95,8 @@ struct ProxyObject: Object { static PropertyAttributes getOwnProperty(Managed *m, Identifier id, Property *p); static bool isExtensible(const Managed *m); static bool preventExtensions(Managed *); + static Heap::Object *getPrototypeOf(const Managed *); + static bool setPrototypeOf(Managed *, const Object *); // those might require a second proxy object that derives from FunctionObject... // static ReturnedValue callAsConstructor(const FunctionObject *f, const Value *argv, int argc); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 2ab77502d6..94d645ac2b 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -2093,7 +2093,7 @@ ReturnedValue QMetaObjectWrapper::constructInternal(const Value *argv, int argc) } Scoped<QMetaObjectWrapper> metaObject(scope, this); object->defineDefaultProperty(v4->id_constructor(), metaObject); - object->setPrototype(const_cast<QMetaObjectWrapper*>(this)); + object->setPrototypeOf(const_cast<QMetaObjectWrapper*>(this)); return object.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp index 219e28b6e7..9b4a5a2375 100644 --- a/src/qml/jsruntime/qv4reflect.cpp +++ b/src/qml/jsruntime/qv4reflect.cpp @@ -175,12 +175,14 @@ ReturnedValue Reflect::method_getOwnPropertyDescriptor(const FunctionObject *f, return ObjectPrototype::method_getOwnPropertyDescriptor(f, thisObject, argv, argc); } -ReturnedValue Reflect::method_getPrototypeOf(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) +ReturnedValue Reflect::method_getPrototypeOf(const FunctionObject *f, const Value *, const Value *argv, int argc) { if (!argc || !argv[0].isObject()) return f->engine()->throwTypeError(); - return ObjectPrototype::method_getPrototypeOf(f, thisObject, argv, argc); + const Object *o = static_cast<const Object *>(argv); + Heap::Object *p = o->getPrototypeOf(); + return (p ? p->asReturnedValue() : Encode::null()); } ReturnedValue Reflect::method_has(const FunctionObject *f, const Value *, const Value *argv, int argc) @@ -260,10 +262,13 @@ ReturnedValue Reflect::method_set(const FunctionObject *f, const Value *, const return Encode(result); } -ReturnedValue Reflect::method_setPrototypeOf(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc) +ReturnedValue Reflect::method_setPrototypeOf(const FunctionObject *f, const Value *, const Value *argv, int argc) { - if (argc < 2 || !argv[0].isObject()) + if (argc < 2 || !argv[0].isObject() || (!argv[1].isNull() && !argv[1].isObject())) return f->engine()->throwTypeError(); - return ObjectPrototype::method_setPrototypeOf(f, thisObject, argv, argc); + Scope scope(f); + ScopedObject o(scope, static_cast<const Object *>(argv)); + const Object *proto = argv[1].isNull() ? nullptr : static_cast<const Object *>(argv + 1); + return Encode(o->setPrototypeOf(proto)); } diff --git a/src/qml/jsruntime/qv4reflect_p.h b/src/qml/jsruntime/qv4reflect_p.h index 73d257e006..d480e1d914 100644 --- a/src/qml/jsruntime/qv4reflect_p.h +++ b/src/qml/jsruntime/qv4reflect_p.h @@ -73,7 +73,7 @@ struct Reflect : Object { static ReturnedValue method_deleteProperty(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_get(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_getOwnPropertyDescriptor(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); - static ReturnedValue method_getPrototypeOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_getPrototypeOf(const FunctionObject *, const Value *, const Value *argv, int argc); static ReturnedValue method_has(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_isExtensible(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_ownKeys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 3eadfe04a6..86aa18c3a4 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -410,9 +410,9 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(3)); ctor->defineReadonlyProperty(engine->id_prototype(), *this); ctor->defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); - ctor->setPrototype(engine->intrinsicTypedArrayCtor()); + ctor->setPrototypeOf(engine->intrinsicTypedArrayCtor()); - setPrototype(engine->intrinsicTypedArrayPrototype()); + setPrototypeOf(engine->intrinsicTypedArrayPrototype()); defineDefaultProperty(engine->id_constructor(), (o = ctor)); defineReadonlyProperty(QStringLiteral("BYTES_PER_ELEMENT"), Primitive::fromInt32(operations[ctor->d()->type].bytesPerElement)); } diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 22e20de8d7..9986d3577a 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1409,7 +1409,7 @@ void QQmlComponent::incubateObject(QQmlV4Function *args) QV4::Scoped<QV4::QmlIncubatorObject> r(scope, v4->memoryManager->allocate<QV4::QmlIncubatorObject>(mode)); QV4::ScopedObject p(scope, e->incubationProto.value()); - r->setPrototype(p); + r->setPrototypeOf(p); if (!valuemap->isUndefined()) r->d()->valuemap.set(scope.engine, valuemap); diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index f17f0fb77a..cdca4f794c 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -828,7 +828,7 @@ QV4::ReturnedValue QQmlLocale::wrap(ExecutionEngine *v4, const QLocale &locale) QV4::Scoped<QQmlLocaleData> wrapper(scope, v4->memoryManager->allocate<QQmlLocaleData>()); *wrapper->d()->locale = locale; QV4::ScopedObject p(scope, d->prototype.value()); - wrapper->setPrototype(p); + wrapper->setPrototypeOf(p); return wrapper.asReturnedValue(); } diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 41531c1df3..a8faac4b0d 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -611,7 +611,7 @@ ReturnedValue Node::create(ExecutionEngine *v4, NodeImpl *data) switch (data->type) { case NodeImpl::Attr: - instance->setPrototype((p = Attr::prototype(v4))); + instance->setPrototypeUnchecked((p = Attr::prototype(v4))); break; case NodeImpl::Comment: case NodeImpl::Document: @@ -623,13 +623,13 @@ ReturnedValue Node::create(ExecutionEngine *v4, NodeImpl *data) case NodeImpl::ProcessingInstruction: return Encode::undefined(); case NodeImpl::CDATA: - instance->setPrototype((p = CDATA::prototype(v4))); + instance->setPrototypeUnchecked((p = CDATA::prototype(v4))); break; case NodeImpl::Text: - instance->setPrototype((p = Text::prototype(v4))); + instance->setPrototypeUnchecked((p = Text::prototype(v4))); break; case NodeImpl::Element: - instance->setPrototype((p = Element::prototype(v4))); + instance->setPrototypeUnchecked((p = Element::prototype(v4))); break; } @@ -643,7 +643,7 @@ ReturnedValue Element::prototype(ExecutionEngine *engine) Scope scope(engine); ScopedObject p(scope, engine->newObject()); ScopedObject pp(scope); - p->setPrototype((pp = NodePrototype::getProto(engine))); + p->setPrototypeUnchecked((pp = NodePrototype::getProto(engine))); p->defineAccessorProperty(QStringLiteral("tagName"), NodePrototype::method_get_nodeName, nullptr); d->elementPrototype.set(engine, p); engine->v8Engine->freezeObject(p); @@ -658,7 +658,7 @@ ReturnedValue Attr::prototype(ExecutionEngine *engine) Scope scope(engine); ScopedObject p(scope, engine->newObject()); ScopedObject pp(scope); - p->setPrototype((pp = NodePrototype::getProto(engine))); + p->setPrototypeUnchecked((pp = NodePrototype::getProto(engine))); p->defineAccessorProperty(QStringLiteral("name"), method_name, nullptr); p->defineAccessorProperty(QStringLiteral("value"), method_value, nullptr); p->defineAccessorProperty(QStringLiteral("ownerElement"), method_ownerElement, nullptr); @@ -715,7 +715,7 @@ ReturnedValue CharacterData::prototype(ExecutionEngine *v4) Scope scope(v4); ScopedObject p(scope, v4->newObject()); ScopedObject pp(scope); - p->setPrototype((pp = NodePrototype::getProto(v4))); + p->setPrototypeUnchecked((pp = NodePrototype::getProto(v4))); p->defineAccessorProperty(QStringLiteral("data"), NodePrototype::method_get_nodeValue, nullptr); p->defineAccessorProperty(QStringLiteral("length"), method_length, nullptr); d->characterDataPrototype.set(v4, p); @@ -751,7 +751,7 @@ ReturnedValue Text::prototype(ExecutionEngine *v4) Scope scope(v4); ScopedObject p(scope, v4->newObject()); ScopedObject pp(scope); - p->setPrototype((pp = CharacterData::prototype(v4))); + p->setPrototypeUnchecked((pp = CharacterData::prototype(v4))); p->defineAccessorProperty(QStringLiteral("isElementContentWhitespace"), method_isElementContentWhitespace, nullptr); p->defineAccessorProperty(QStringLiteral("wholeText"), method_wholeText, nullptr); d->textPrototype.set(v4, p); @@ -768,7 +768,7 @@ ReturnedValue CDATA::prototype(ExecutionEngine *v4) Scope scope(v4); ScopedObject p(scope, v4->newObject()); ScopedObject pp(scope); - p->setPrototype((pp = Text::prototype(v4))); + p->setPrototypeUnchecked((pp = Text::prototype(v4))); d->cdataPrototype.set(v4, p); v4->v8Engine->freezeObject(p); } @@ -782,7 +782,7 @@ ReturnedValue Document::prototype(ExecutionEngine *v4) Scope scope(v4); ScopedObject p(scope, v4->newObject()); ScopedObject pp(scope); - p->setPrototype((pp = NodePrototype::getProto(v4))); + p->setPrototypeUnchecked((pp = NodePrototype::getProto(v4))); p->defineAccessorProperty(QStringLiteral("xmlVersion"), method_xmlVersion, nullptr); p->defineAccessorProperty(QStringLiteral("xmlEncoding"), method_xmlEncoding, nullptr); p->defineAccessorProperty(QStringLiteral("xmlStandalone"), method_xmlStandalone, nullptr); @@ -879,7 +879,7 @@ ReturnedValue Document::load(ExecutionEngine *v4, const QByteArray &data) ScopedObject instance(scope, v4->memoryManager->allocate<Node>(document)); document->release(); // the GC should own the NodeImpl via Node now ScopedObject p(scope); - instance->setPrototype((p = Document::prototype(v4))); + instance->setPrototypeUnchecked((p = Document::prototype(v4))); return instance.asReturnedValue(); } @@ -1650,7 +1650,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager(), scope.engine); Scoped<QQmlXMLHttpRequestWrapper> w(scope, scope.engine->memoryManager->allocate<QQmlXMLHttpRequestWrapper>(r)); ScopedObject proto(scope, ctor->d()->proto); - w->setPrototype(proto); + w->setPrototypeUnchecked(proto); return w.asReturnedValue(); } diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index b5e25fb6d4..f99c4def45 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -223,13 +223,13 @@ static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) QV4::Scope scope(v4); bool instanceOfObject = false; - QV4::ScopedObject p(scope, object->prototype()); + QV4::ScopedObject p(scope, object->getPrototypeOf()); while (p) { if (p->d() == v4->objectPrototype()->d()) { instanceOfObject = true; break; } - p = p->prototype(); + p = p->getPrototypeOf(); } if (!instanceOfObject) return; diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index 33fe5f3438..98b90af5c3 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -2563,7 +2563,7 @@ QQmlV4Handle QQmlDelegateModelGroup::get(int index) QV4::Scope scope(v4); QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(cacheItem)); QV4::ScopedObject p(scope, model->m_cacheMetaType->modelItemProto.value()); - o->setPrototype(p); + o->setPrototypeOf(p); ++cacheItem->scriptRef; return QQmlV4Handle(o); @@ -3395,7 +3395,7 @@ public: QV4::ScopedObject changeProto(scope, engineData(v4)->changeProto.value()); QV4::Scoped<QQmlDelegateModelGroupChange> object(scope, QQmlDelegateModelGroupChange::create(v4)); - object->setPrototype(changeProto); + object->setPrototypeOf(changeProto); object->d()->change = change; if (hasProperty) diff --git a/src/qml/util/qqmladaptormodel.cpp b/src/qml/util/qqmladaptormodel.cpp index 3016316e57..4130eff33a 100644 --- a/src/qml/util/qqmladaptormodel.cpp +++ b/src/qml/util/qqmladaptormodel.cpp @@ -439,7 +439,7 @@ public: QV4::Scope scope(v4); QV4::ScopedObject proto(scope, type->prototype.value()); QV4::ScopedObject o(scope, proto->engine()->memoryManager->allocate<QQmlDelegateModelItemObject>(this)); - o->setPrototype(proto); + o->setPrototypeOf(proto); ++scriptRef; return o.asReturnedValue(); } @@ -620,7 +620,7 @@ public: QV4::Scope scope(v4); QV4::ScopedObject o(scope, v4->memoryManager->allocate<QQmlDelegateModelItemObject>(this)); QV4::ScopedObject p(scope, data->listItemProto.value()); - o->setPrototype(p); + o->setPrototypeOf(p); ++scriptRef; return o.asReturnedValue(); } diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 07d5f6d39b..314b7904b4 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -956,7 +956,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE QQuickContext2DEngineData *ed = engineData(scope.engine); QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, scope.engine->memoryManager->allocate<QQuickJSContext2DPixelData>()); QV4::ScopedObject p(scope, ed->pixelArrayProto.value()); - pixelData->setPrototype(p); + pixelData->setPrototypeOf(p); if (image.isNull()) { *pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32); @@ -1584,7 +1584,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(const QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>()); QV4::ScopedObject p(scope, ed->gradientProto.value()); - gradient->setPrototype(p); + gradient->setPrototypeOf(p); *gradient->d()->brush = QLinearGradient(x0, y0, x1, y1); RETURN_RESULT(*gradient); } @@ -1636,7 +1636,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(const QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>()); QV4::ScopedObject p(scope, ed->gradientProto.value()); - gradient->setPrototype(p); + gradient->setPrototypeOf(p); *gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r1, QPointF(x0, y0), r0); RETURN_RESULT(*gradient); } @@ -1680,7 +1680,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(cons QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocate<QQuickContext2DStyle>()); QV4::ScopedObject p(scope, ed->gradientProto.value()); - gradient->setPrototype(p); + gradient->setPrototypeOf(p); *gradient->d()->brush = QConicalGradient(x, y, angle); RETURN_RESULT(*gradient); } @@ -4401,7 +4401,7 @@ void QQuickContext2D::setV4Engine(QV4::ExecutionEngine *engine) QV4::Scope scope(engine); QV4::Scoped<QQuickJSContext2D> wrapper(scope, engine->memoryManager->allocate<QQuickJSContext2D>()); QV4::ScopedObject p(scope, ed->contextPrototype.value()); - wrapper->setPrototype(p); + wrapper->setPrototypeOf(p); wrapper->d()->context = this; m_v4value = wrapper; } |