From 5f83e6dfe698d65a0c145ccfd09c9f00609311ca Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Wed, 8 Feb 2017 22:57:11 +0100 Subject: Object: Allow put and putIndexed to return success or failure Some parts of the ES6 (and even ES5!) spec specifically require handling of a property write failure. This will be introduced in followup changes, as it's going to be rather more involved than this. Change-Id: Ie482493fcf4780df0e23619650a856421d20bd55 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4argumentsobject.cpp | 9 ++++--- src/qml/jsruntime/qv4argumentsobject_p.h | 2 +- src/qml/jsruntime/qv4object.cpp | 41 +++++++++++++++++--------------- src/qml/jsruntime/qv4object_p.h | 22 ++++++++--------- src/qml/jsruntime/qv4qmlcontext.cpp | 27 ++++++++++----------- src/qml/jsruntime/qv4qmlcontext_p.h | 2 +- src/qml/jsruntime/qv4qobjectwrapper.cpp | 9 ++++--- src/qml/jsruntime/qv4qobjectwrapper_p.h | 2 +- src/qml/jsruntime/qv4sequenceobject.cpp | 13 +++++----- src/qml/jsruntime/qv4typedarray.cpp | 7 +++--- src/qml/jsruntime/qv4typedarray_p.h | 2 +- 11 files changed, 70 insertions(+), 66 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 9354bcb1a3..7c1cc92a13 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -166,18 +166,17 @@ ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *ha return Encode::undefined(); } -void ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value) +bool ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value) { ArgumentsObject *args = static_cast(m); if (!args->fullyCreated() && index >= static_cast(args->context()->callData->argc)) args->fullyCreate(); - if (args->fullyCreated()) { - Object::putIndexed(m, index, value); - return; - } + if (args->fullyCreated()) + return Object::putIndexed(m, index, value); args->context()->callData->args[index] = value; + return true; } bool ArgumentsObject::deleteIndexedProperty(Managed *m, uint index) diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 0a2ea3b42a..f80ade9611 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -128,7 +128,7 @@ struct ArgumentsObject: Object { bool defineOwnProperty(ExecutionEngine *engine, uint index, const Property *desc, PropertyAttributes attrs); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static void putIndexed(Managed *m, uint index, const Value &value); + static bool putIndexed(Managed *m, uint index, const Value &value); static bool deleteIndexedProperty(Managed *m, uint index); static PropertyAttributes queryIndexed(const Managed *m, uint index); static void markObjects(Heap::Base *that, ExecutionEngine *e); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 3d87675699..0ef53d5703 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -107,11 +107,11 @@ ReturnedValue Object::getValue(const Value &thisObject, const Value &v, Property return scope.result.asReturnedValue(); } -void Object::putValue(uint memberIndex, const Value &value) +bool Object::putValue(uint memberIndex, const Value &value) { QV4::InternalClass *ic = internalClass(); if (ic->engine->hasException) - return; + return false; PropertyAttributes attrs = ic->propertyData[memberIndex]; @@ -124,7 +124,7 @@ void Object::putValue(uint memberIndex, const Value &value) callData->args[0] = value; callData->thisObject = this; setter->call(scope, callData); - return; + return !ic->engine->hasException; } goto reject; } @@ -133,11 +133,12 @@ void Object::putValue(uint memberIndex, const Value &value) goto reject; *propertyData(memberIndex) = value; - return; + return true; reject: if (engine()->current->strictMode) engine()->throwTypeError(); + return false; } void Object::defineDefaultProperty(const QString &name, const Value &value) @@ -446,14 +447,14 @@ ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty return static_cast(m)->internalGetIndexed(index, hasProperty); } -void Object::put(Managed *m, String *name, const Value &value) +bool Object::put(Managed *m, String *name, const Value &value) { - static_cast(m)->internalPut(name, value); + return static_cast(m)->internalPut(name, value); } -void Object::putIndexed(Managed *m, uint index, const Value &value) +bool Object::putIndexed(Managed *m, uint index, const Value &value) { - static_cast(m)->internalPutIndexed(index, value); + return static_cast(m)->internalPutIndexed(index, value); } PropertyAttributes Object::query(const Managed *m, String *name) @@ -711,10 +712,10 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const // Section 8.12.5 -void Object::internalPut(String *name, const Value &value) +bool Object::internalPut(String *name, const Value &value) { if (internalClass()->engine->hasException) - return; + return false; uint idx = name->asArrayIndex(); if (idx != UINT_MAX) @@ -743,7 +744,7 @@ void Object::internalPut(String *name, const Value &value) uint l = value.asArrayLength(&ok); if (!ok) { engine()->throwRangeError(value); - return; + return false; } ok = setArrayLength(l); if (!ok) @@ -751,7 +752,7 @@ void Object::internalPut(String *name, const Value &value) } else { *v = value; } - return; + return true; } else if (!prototype()) { if (!isExtensible()) goto reject; @@ -782,11 +783,11 @@ void Object::internalPut(String *name, const Value &value) callData->args[0] = value; callData->thisObject = this; setter->call(scope, callData); - return; + return !internalClass()->engine->hasException; } insertMember(name, value); - return; + return true; reject: if (engine()->current->strictMode) { @@ -794,12 +795,13 @@ void Object::internalPut(String *name, const Value &value) name->toQString() + QLatin1Char('\"'); engine()->throwTypeError(message); } + return false; } -void Object::internalPutIndexed(uint index, const Value &value) +bool Object::internalPutIndexed(uint index, const Value &value) { if (internalClass()->engine->hasException) - return; + return false; PropertyAttributes attrs; @@ -821,7 +823,7 @@ void Object::internalPutIndexed(uint index, const Value &value) goto reject; else *v = value; - return; + return true; } else if (!prototype()) { if (!isExtensible()) goto reject; @@ -852,15 +854,16 @@ void Object::internalPutIndexed(uint index, const Value &value) callData->args[0] = value; callData->thisObject = this; setter->call(scope, callData); - return; + return !internalClass()->engine->hasException; } arraySet(index, value); - return; + return true; reject: if (engine()->current->strictMode) engine()->throwTypeError(); + return false; } // Section 8.12.7 diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 33f29840df..d321df2451 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -130,8 +130,8 @@ struct ObjectVTable void (*construct)(const Managed *, Scope &scope, CallData *data); ReturnedValue (*get)(const Managed *, String *name, bool *hasProperty); ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty); - void (*put)(Managed *, String *name, const Value &value); - void (*putIndexed)(Managed *, uint index, const Value &value); + bool (*put)(Managed *, String *name, const Value &value); + bool (*putIndexed)(Managed *, uint index, const Value &value); PropertyAttributes (*query)(const Managed *, String *name); PropertyAttributes (*queryIndexed)(const Managed *, uint index); bool (*deleteProperty)(Managed *m, String *name); @@ -230,7 +230,7 @@ struct Q_QML_EXPORT Object: Managed { return getValue(t, v, attrs); } - void putValue(uint memberIndex, const Value &value); + bool putValue(uint memberIndex, const Value &value); /* The spec default: Writable: true, Enumerable: false, Configurable: true */ void defineDefaultProperty(String *name, const Value &value) { @@ -336,10 +336,10 @@ public: { return vtable()->get(this, name, hasProperty); } inline ReturnedValue getIndexed(uint idx, bool *hasProperty = 0) const { return vtable()->getIndexed(this, idx, hasProperty); } - inline void put(String *name, const Value &v) - { vtable()->put(this, name, v); } - inline void putIndexed(uint idx, const Value &v) - { vtable()->putIndexed(this, idx, v); } + inline bool put(String *name, const Value &v) + { return vtable()->put(this, name, v); } + inline bool putIndexed(uint idx, const Value &v) + { return vtable()->putIndexed(this, idx, v); } PropertyAttributes query(String *name) const { return vtable()->query(this, name); } PropertyAttributes queryIndexed(uint index) const @@ -368,8 +368,8 @@ protected: static void call(const Managed *m, Scope &scope, CallData *); static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); - static void putIndexed(Managed *m, uint index, const Value &value); + static bool put(Managed *m, String *name, const Value &value); + static bool putIndexed(Managed *m, uint index, const Value &value); static PropertyAttributes query(const Managed *m, String *name); static PropertyAttributes queryIndexed(const Managed *m, uint index); static bool deleteProperty(Managed *m, String *name); @@ -383,8 +383,8 @@ protected: private: ReturnedValue internalGet(String *name, bool *hasProperty) const; ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; - void internalPut(String *name, const Value &value); - void internalPutIndexed(uint index, const Value &value); + bool internalPut(String *name, const Value &value); + bool internalPutIndexed(uint index, const Value &value); bool internalDeleteProperty(String *name); bool internalDeleteIndexedProperty(uint index); diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 889f4ea288..cdc29c8b9c 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -225,21 +225,19 @@ ReturnedValue QmlContextWrapper::get(const Managed *m, String *name, bool *hasPr return Encode::undefined(); } -void QmlContextWrapper::put(Managed *m, String *name, const Value &value) +bool QmlContextWrapper::put(Managed *m, String *name, const Value &value) { Q_ASSERT(m->as()); QmlContextWrapper *resource = static_cast(m); ExecutionEngine *v4 = resource->engine(); QV4::Scope scope(v4); if (scope.hasException()) - return; + return false; QV4::Scoped wrapper(scope, resource); uint member = wrapper->internalClass()->find(name); - if (member < UINT_MAX) { - wrapper->putValue(member, value); - return; - } + if (member < UINT_MAX) + return wrapper->putValue(member, value); if (wrapper->d()->isNullWrapper) { if (wrapper && wrapper->d()->readOnly) { @@ -247,11 +245,10 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) QLatin1Char('"'); ScopedString e(scope, v4->newString(error)); v4->throwError(e); - return; + return false; } - Object::put(m, name, value); - return; + return Object::put(m, name, value); } // Its possible we could delay the calculation of the "actual" context (in the case @@ -260,7 +257,7 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) QQmlContextData *expressionContext = context; if (!context) - return; + return false; // See QV8ContextWrapper::Getter for resolution order @@ -270,18 +267,18 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) const QV4::IdentifierHash &properties = context->propertyNames(); // Search context properties if (properties.count() && properties.value(name) != -1) - return; + return false; // Search scope object if (scopeObject && QV4::QObjectWrapper::setQmlProperty(v4, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value)) - return; + return true; scopeObject = 0; // Search context object if (context->contextObject && QV4::QObjectWrapper::setQmlProperty(v4, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value)) - return; + return true; context = context->parent; } @@ -292,10 +289,10 @@ void QmlContextWrapper::put(Managed *m, String *name, const Value &value) QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + QLatin1Char('"'); v4->throwError(error); - return; + return false; } - Object::put(m, name, value); + return Object::put(m, name, value); } void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QmlContextWrapper *qml) diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 9aec7467da..6e5e743609 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -100,7 +100,7 @@ struct Q_QML_EXPORT QmlContextWrapper : Object void setReadOnly(bool b) { d()->readOnly = b; } static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); }; struct Q_QML_EXPORT QmlContext : public ExecutionContext diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 7260e71fab..283c3dad04 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -625,13 +625,13 @@ QV4::ReturnedValue QObjectWrapper::get(const Managed *m, String *name, bool *has return that->getQmlProperty(qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true); } -void QObjectWrapper::put(Managed *m, String *name, const Value &value) +bool QObjectWrapper::put(Managed *m, String *name, const Value &value) { QObjectWrapper *that = static_cast(m); ExecutionEngine *v4 = that->engine(); if (v4->hasException || QQmlData::wasDeleted(that->d()->object())) - return; + return false; QQmlContextData *qmlContext = v4->callingQmlContext(); if (!setQmlProperty(v4, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) { @@ -642,10 +642,13 @@ void QObjectWrapper::put(Managed *m, String *name, const Value &value) QString error = QLatin1String("Cannot assign to non-existent property \"") + name->toQString() + QLatin1Char('\"'); v4->throwError(error); + return false; } else { - QV4::Object::put(m, name, value); + return QV4::Object::put(m, name, value); } } + + return true; } PropertyAttributes QObjectWrapper::query(const Managed *m, String *name) diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index b09e06cec5..d81ef2a680 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -192,7 +192,7 @@ protected: QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const; static ReturnedValue get(const Managed *m, String *name, bool *hasProperty); - static void put(Managed *m, String *name, const Value &value); + static bool put(Managed *m, String *name, const Value &value); static PropertyAttributes query(const Managed *, String *name); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e); diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index 8ce10e326d..6d3110771e 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -274,20 +274,20 @@ public: return Encode::undefined(); } - void containerPutIndexed(uint index, const QV4::Value &value) + bool containerPutIndexed(uint index, const QV4::Value &value) { if (internalClass()->engine->hasException) - return; + return false; /* Qt containers have int (rather than uint) allowable indexes. */ if (index > INT_MAX) { generateWarning(engine(), QLatin1String("Index out of range during indexed set")); - return; + return false; } if (d()->isReference) { if (!d()->object) - return; + return false; loadReference(); } @@ -313,6 +313,7 @@ public: if (d()->isReference) storeReference(); + return true; } QV4::PropertyAttributes containerQueryIndexed(uint index) const @@ -540,8 +541,8 @@ public: static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty) { return static_cast *>(that)->containerGetIndexed(index, hasProperty); } - static void putIndexed(Managed *that, uint index, const QV4::Value &value) - { static_cast *>(that)->containerPutIndexed(index, value); } + static bool putIndexed(Managed *that, uint index, const QV4::Value &value) + { return static_cast *>(that)->containerPutIndexed(index, value); } static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index) { return static_cast *>(that)->containerQueryIndexed(index); } static bool deleteIndexedProperty(QV4::Managed *that, uint index) diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index cecd1e6958..5573a2e57f 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -398,11 +398,11 @@ ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProp return a->d()->type->read(a->d()->buffer->data->data(), byteOffset); } -void TypedArray::putIndexed(Managed *m, uint index, const Value &value) +bool TypedArray::putIndexed(Managed *m, uint index, const Value &value) { ExecutionEngine *v4 = static_cast(m)->engine(); if (v4->hasException) - return; + return false; Scope scope(v4); Scoped a(scope, static_cast(m)); @@ -413,11 +413,12 @@ void TypedArray::putIndexed(Managed *m, uint index, const Value &value) goto reject; a->d()->type->write(scope.engine, a->d()->buffer->data->data(), byteOffset, value); - return; + return true; reject: if (scope.engine->current->strictMode) scope.engine->throwTypeError(); + return false; } void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor) diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index eefed2db4b..fbf13c9815 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -133,7 +133,7 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object static void markObjects(Heap::Base *that, ExecutionEngine *e); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static void putIndexed(Managed *m, uint index, const Value &value); + static bool putIndexed(Managed *m, uint index, const Value &value); }; struct TypedArrayCtor: FunctionObject -- cgit v1.2.3