From 98263a01373f5b225d64da216537165ae27d7ff1 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 22 Jun 2018 15:34:57 +0200 Subject: Unify put and putIndexed Pass an Identifier through those virtual methods to unify the string and integer based versions. Also add the receiver that's required in ES7 Change-Id: I4e7f01b4c97cc80bcb3c485f6343f28213dc9e6b Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4argumentsobject.cpp | 21 ++-- src/qml/jsruntime/qv4argumentsobject_p.h | 2 +- src/qml/jsruntime/qv4arrayobject.cpp | 20 ++-- src/qml/jsruntime/qv4jsonobject.cpp | 2 +- src/qml/jsruntime/qv4object.cpp | 197 +++++++++++-------------------- src/qml/jsruntime/qv4object_p.h | 29 +++-- src/qml/jsruntime/qv4proxy.cpp | 17 +-- src/qml/jsruntime/qv4proxy_p.h | 3 +- src/qml/jsruntime/qv4qmlcontext.cpp | 17 ++- src/qml/jsruntime/qv4qmlcontext_p.h | 2 +- src/qml/jsruntime/qv4qobjectwrapper.cpp | 20 ++-- src/qml/jsruntime/qv4qobjectwrapper_p.h | 2 +- src/qml/jsruntime/qv4reflect.cpp | 11 +- src/qml/jsruntime/qv4runtime.cpp | 2 +- src/qml/jsruntime/qv4sequenceobject.cpp | 8 +- src/qml/jsruntime/qv4serialize.cpp | 2 +- src/qml/jsruntime/qv4symbol_p.h | 4 +- src/qml/jsruntime/qv4typedarray.cpp | 6 +- src/qml/jsruntime/qv4typedarray_p.h | 2 +- 19 files changed, 148 insertions(+), 219 deletions(-) (limited to 'src/qml/jsruntime') diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index ba9bf9652d..c2a50a49ec 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -185,17 +185,20 @@ ReturnedValue ArgumentsObject::getIndexed(const Managed *m, uint index, bool *ha return Encode::undefined(); } -bool ArgumentsObject::putIndexed(Managed *m, uint index, const Value &value) +bool ArgumentsObject::put(Managed *m, Identifier id, const Value &value, Value *receiver) { ArgumentsObject *args = static_cast(m); - if (!args->fullyCreated() && index >= static_cast(args->context()->argc())) - args->fullyCreate(); - - if (args->fullyCreated()) - return Object::putIndexed(m, index, value); - - args->context()->setArg(index, value); - return true; + if (id.isArrayIndex()) { + uint index = id.asArrayIndex(); + if (!args->fullyCreated() && index >= static_cast(args->context()->argc())) + args->fullyCreate(); + + if (!args->fullyCreated()) { + args->context()->setArg(index, value); + return true; + } + } + return Object::put(m, id, value, receiver); } bool ArgumentsObject::deleteProperty(Managed *m, Identifier id) diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index 46110e465f..69d136674b 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -148,7 +148,7 @@ struct ArgumentsObject: Object { static bool defineOwnProperty(Managed *m, Identifier id, const Property *desc, PropertyAttributes attrs); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static bool putIndexed(Managed *m, uint index, const Value &value); + static bool put(Managed *m, Identifier id, const Value &value, Value *receiver); static bool deleteProperty(Managed *m, Identifier id); static PropertyAttributes getOwnProperty(Managed *m, Identifier id, Property *p); static qint64 getLength(const Managed *m); diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 481dfd22c6..9efb315b50 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -385,7 +385,7 @@ ReturnedValue ArrayPrototype::method_concat(const FunctionObject *b, const Value for (int i = 0, len = eltAsObj->getLength(); i < len; ++i) { entry = eltAsObj->getIndexed(i); // spec says not to throw if this fails - result->putIndexed(startIndex + i, entry); + result->put(startIndex + i, entry); } } else { result->arraySet(result->getLength(), argv[i]); @@ -675,7 +675,7 @@ ReturnedValue ArrayPrototype::method_push(const FunctionObject *b, const Value * len = instance->arrayData()->length(); } else { for (int i = 0, ei = argc; i < ei; ++i) { - if (!instance->putIndexed(len + i, argv[i])) + if (!instance->put(len + i, argv[i])) return scope.engine->throwTypeError(); } len += argc; @@ -713,12 +713,12 @@ ReturnedValue ArrayPrototype::method_reverse(const FunctionObject *b, const Valu CHECK_EXCEPTION(); bool ok; if (hiExists) - ok = instance->putIndexed(lo, hval); + ok = instance->put(lo, hval); else ok = instance->deleteProperty(Identifier::fromArrayIndex(lo)); if (ok) { if (loExists) - ok = instance->putIndexed(hi, lval); + ok = instance->put(hi, lval); else ok = instance->deleteProperty(Identifier::fromArrayIndex(hi)); } @@ -761,7 +761,7 @@ ReturnedValue ArrayPrototype::method_shift(const FunctionObject *b, const Value CHECK_EXCEPTION(); bool ok; if (exists) - ok = instance->putIndexed(k - 1, v); + ok = instance->put(k - 1, v); else ok = instance->deleteProperty(Identifier::fromArrayIndex(k - 1)); if (!ok) @@ -889,7 +889,7 @@ ReturnedValue ArrayPrototype::method_splice(const FunctionObject *b, const Value CHECK_EXCEPTION(); bool ok; if (exists) - ok = instance->putIndexed(k + itemCount, v); + ok = instance->put(k + itemCount, v); else ok = instance->deleteProperty(Identifier::fromArrayIndex(k + itemCount)); if (!ok) @@ -907,7 +907,7 @@ ReturnedValue ArrayPrototype::method_splice(const FunctionObject *b, const Value CHECK_EXCEPTION(); bool ok; if (exists) - ok = instance->putIndexed(k + itemCount - 1, v); + ok = instance->put(k + itemCount - 1, v); else ok = instance->deleteProperty(Identifier::fromArrayIndex(k + itemCount - 1)); if (!ok) @@ -917,7 +917,7 @@ ReturnedValue ArrayPrototype::method_splice(const FunctionObject *b, const Value } for (uint i = 0; i < itemCount; ++i) - instance->putIndexed(start + i, argv[i + 2]); + instance->put(start + i, argv[i + 2]); if (!instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount)))) return scope.engine->throwTypeError(); @@ -947,14 +947,14 @@ ReturnedValue ArrayPrototype::method_unshift(const FunctionObject *b, const Valu v = instance->getIndexed(k - 1, &exists); bool ok; if (exists) - ok = instance->putIndexed(k + argc - 1, v); + ok = instance->put(k + argc - 1, v); else ok = instance->deleteProperty(Identifier::fromArrayIndex(k + argc - 1)); if (!ok) return scope.engine->throwTypeError(); } for (int i = 0, ei = argc; i < ei; ++i) { - bool ok = instance->putIndexed(i, argv[i]); + bool ok = instance->put(i, argv[i]); if (!ok) return scope.engine->throwTypeError(); } diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 75a9bf4111..ed7d8611ee 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -264,7 +264,7 @@ bool JsonParser::parseMember(Object *o) ScopedString s(scope, engine->newIdentifier(key)); uint idx = s->asArrayIndex(); if (idx < UINT_MAX) { - o->putIndexed(idx, val); + o->put(idx, val); } else { o->insertMember(s, val); } diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 1597c35319..7c375db1e1 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -268,50 +268,43 @@ void Object::setPrototypeUnchecked(const Object *p) } // Section 8.12.2 -PropertyIndex Object::getValueOrSetter(StringOrSymbol *name, PropertyAttributes *attrs) +PropertyIndex Object::getValueOrSetter(Identifier id, PropertyAttributes *attrs) { - Q_ASSERT(name->asArrayIndex() == UINT_MAX); - - name->makeIdentifier(); - Identifier id = name->identifier(); - - Heap::Object *o = d(); - while (o) { - uint idx = o->internalClass->find(id); - if (idx < UINT_MAX) { - *attrs = o->internalClass->propertyData[idx]; - return o->writablePropertyData(attrs->isAccessor() ? idx + SetterOffset : idx ); - } - - o = o->prototype(); - } - *attrs = Attr_Invalid; - return { nullptr, nullptr }; -} - -PropertyIndex Object::getValueOrSetter(uint index, PropertyAttributes *attrs) -{ - Heap::Object *o = d(); - while (o) { - if (o->arrayData) { - uint idx = o->arrayData->mappedIndex(index); - if (idx != UINT_MAX) { - *attrs = o->arrayData->attributes(index); - return { o->arrayData , o->arrayData->values.values + (attrs->isAccessor() ? idx + SetterOffset : idx) }; + if (id.isArrayIndex()) { + uint index = id.asArrayIndex(); + Heap::Object *o = d(); + while (o) { + if (o->arrayData) { + uint idx = o->arrayData->mappedIndex(index); + if (idx != UINT_MAX) { + *attrs = o->arrayData->attributes(index); + return { o->arrayData , o->arrayData->values.values + (attrs->isAccessor() ? idx + SetterOffset : idx) }; + } + } + if (o->vtable()->type == Type_StringObject) { + if (index < static_cast(o)->length()) { + // this is an evil hack, but it works, as the method is only ever called from put, + // where we don't use the returned pointer there for non writable attributes + *attrs = (Attr_NotWritable|Attr_NotConfigurable); + return { reinterpret_cast(0x1), nullptr }; + } } + o = o->prototype(); } - if (o->vtable()->type == Type_StringObject) { - if (index < static_cast(o)->length()) { - // this is an evil hack, but it works, as the method is only ever called from putIndexed, - // where we don't use the returned pointer there for non writable attributes - *attrs = (Attr_NotWritable|Attr_NotConfigurable); - return { reinterpret_cast(0x1), 0 }; + } else { + Heap::Object *o = d(); + while (o) { + uint idx = o->internalClass->find(id); + if (idx < UINT_MAX) { + *attrs = o->internalClass->propertyData[idx]; + return o->writablePropertyData(attrs->isAccessor() ? idx + SetterOffset : idx ); } + + o = o->prototype(); } - o = o->prototype(); } *attrs = Attr_Invalid; - return { nullptr, 0 }; + return { nullptr, nullptr }; } ReturnedValue Object::callAsConstructor(const FunctionObject *f, const Value *, int) @@ -334,14 +327,9 @@ ReturnedValue Object::getIndexed(const Managed *m, uint index, bool *hasProperty return static_cast(m)->internalGetIndexed(index, hasProperty); } -bool Object::put(Managed *m, StringOrSymbol *name, const Value &value) -{ - return static_cast(m)->internalPut(name, value); -} - -bool Object::putIndexed(Managed *m, uint index, const Value &value) +bool Object::put(Managed *m, Identifier id, const Value &value, Value *receiver) { - return static_cast(m)->internalPutIndexed(index, value); + return static_cast(m)->internalPut(id, value, receiver); } bool Object::deleteProperty(Managed *m, Identifier id) @@ -484,31 +472,39 @@ ReturnedValue Object::internalGetIndexed(uint index, bool *hasProperty) const // Section 8.12.5 -bool Object::internalPut(StringOrSymbol *name, const Value &value) +bool Object::internalPut(Identifier id, const Value &value, Value *receiver) { ExecutionEngine *engine = this->engine(); if (engine->hasException) return false; - uint idx = name->asArrayIndex(); - if (idx != UINT_MAX) - return putIndexed(idx, value); - - name->makeIdentifier(); - Identifier id = name->identifier(); + uint index = id.asArrayIndex(); + Scope scope(engine); - PropertyIndex memberIndex{nullptr, nullptr}; - uint member = internalClass()->find(id); PropertyAttributes attrs; - if (member < UINT_MAX) { - attrs = internalClass()->propertyData[member]; - memberIndex = d()->writablePropertyData(attrs.isAccessor() ? member + SetterOffset : member); + PropertyIndex propertyIndex{nullptr, nullptr}; + + if (index != UINT_MAX) { + if (arrayData()) + propertyIndex = arrayData()->getValueOrSetter(index, &attrs); + + if (propertyIndex.isNull() && isStringObject()) { + if (index < static_cast(this)->length()) + // not writable + return false; + } + } else { + uint member = internalClass()->find(id); + if (member < UINT_MAX) { + attrs = internalClass()->propertyData[member]; + propertyIndex = d()->writablePropertyData(attrs.isAccessor() ? member + SetterOffset : member); + } } // clause 1 - if (!memberIndex.isNull()) { + if (!propertyIndex.isNull()) { if (attrs.isAccessor()) { - if (memberIndex->as()) + if (propertyIndex->as()) goto cont; return false; } else if (!attrs.isWritable()) @@ -524,7 +520,7 @@ bool Object::internalPut(StringOrSymbol *name, const Value &value) if (!ok) return false; } else { - memberIndex.set(engine, value); + propertyIndex.set(engine, value); } return true; } else if (!getPrototypeOf()) { @@ -532,11 +528,10 @@ bool Object::internalPut(StringOrSymbol *name, const Value &value) return false; } else { // clause 4 - Scope scope(engine); - memberIndex = ScopedObject(scope, getPrototypeOf())->getValueOrSetter(name, &attrs); - if (!memberIndex.isNull()) { + propertyIndex = ScopedObject(scope, getPrototypeOf())->getValueOrSetter(id, &attrs); + if (!propertyIndex.isNull()) { if (attrs.isAccessor()) { - if (!memberIndex->as()) + if (!propertyIndex->as()) return false; } else if (!isExtensible() || !attrs.isWritable()) { return false; @@ -549,84 +544,24 @@ bool Object::internalPut(StringOrSymbol *name, const Value &value) cont: // Clause 5 - if (!memberIndex.isNull() && attrs.isAccessor()) { - Q_ASSERT(memberIndex->as()); + if (!propertyIndex.isNull() && attrs.isAccessor()) { + Q_ASSERT(propertyIndex->as()); Scope scope(engine); - ScopedFunctionObject setter(scope, *memberIndex); + ScopedFunctionObject setter(scope, *propertyIndex); JSCallData jsCallData(scope, 1); jsCallData->args[0] = value; - *jsCallData->thisObject = this; + *jsCallData->thisObject = *receiver; setter->call(jsCallData); return !engine->hasException; } - insertMember(name, value); - return true; -} - -bool Object::internalPutIndexed(uint index, const Value &value) -{ - ExecutionEngine *engine = this->engine(); - if (engine->hasException) - return false; - - PropertyAttributes attrs; - - PropertyIndex arrayIndex = arrayData() ? arrayData()->getValueOrSetter(index, &attrs) : PropertyIndex{ nullptr, 0 }; - - if (arrayIndex.isNull() && isStringObject()) { - if (index < static_cast(this)->length()) - // not writable - return false; - } - - // clause 1 - if (!arrayIndex.isNull()) { - if (attrs.isAccessor()) { - if (arrayIndex->as()) - goto cont; - return false; - } else if (!attrs.isWritable()) - return false; - - arrayIndex.set(engine, value); - return true; - } else if (!getPrototypeOf()) { - if (!isExtensible()) - return false; + if (index != UINT_MAX) { + arraySet(index, value); } else { - // clause 4 - Scope scope(engine); - arrayIndex = ScopedObject(scope, getPrototypeOf())->getValueOrSetter(index, &attrs); - if (!arrayIndex.isNull()) { - if (attrs.isAccessor()) { - if (!arrayIndex->as()) - return false; - } else if (!isExtensible() || !attrs.isWritable()) { - return false; - } - } else if (!isExtensible()) { - return false; - } + Scoped name(scope, id.asHeapObject()); + insertMember(name, value); } - - cont: - - // Clause 5 - if (!arrayIndex.isNull() && attrs.isAccessor()) { - Q_ASSERT(arrayIndex->as()); - - Scope scope(engine); - ScopedFunctionObject setter(scope, *arrayIndex); - JSCallData jsCallData(scope, 1); - jsCallData->args[0] = value; - *jsCallData->thisObject = this; - setter->call(jsCallData); - return !engine->hasException; - } - - arraySet(index, value); return true; } diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index e57708d8e4..88d07ef3f1 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -171,8 +171,7 @@ struct ObjectVTable ReturnedValue (*callAsConstructor)(const FunctionObject *, const Value *argv, int argc); ReturnedValue (*get)(const Managed *, StringOrSymbol *name, bool *hasProperty); ReturnedValue (*getIndexed)(const Managed *, uint index, bool *hasProperty); - bool (*put)(Managed *, StringOrSymbol *name, const Value &value); - bool (*putIndexed)(Managed *, uint index, const Value &value); + bool (*put)(Managed *, Identifier id, const Value &value, Value *receiver); bool (*deleteProperty)(Managed *m, Identifier id); bool (*hasProperty)(const Managed *m, Identifier id); PropertyAttributes (*getOwnProperty)(Managed *m, Identifier id, Property *p); @@ -195,7 +194,6 @@ const QV4::ObjectVTable classname::static_vtbl = \ get, \ getIndexed, \ put, \ - putIndexed, \ deleteProperty, \ hasProperty, \ getOwnProperty, \ @@ -253,8 +251,7 @@ struct Q_QML_EXPORT Object: Managed { return vtable()->getOwnProperty(this, id, p); } - PropertyIndex getValueOrSetter(StringOrSymbol *name, PropertyAttributes *attrs); - PropertyIndex getValueOrSetter(uint index, PropertyAttributes *attrs); + PropertyIndex getValueOrSetter(Identifier id, PropertyAttributes *attrs); bool hasProperty(Identifier id) const { return vtable()->hasProperty(this, id); @@ -382,10 +379,14 @@ public: { return vtable()->getIndexed(this, idx, hasProperty); } // use the set variants instead, to customize throw behavior - inline bool put(StringOrSymbol *name, const Value &v) - { return vtable()->put(this, name, v); } - inline bool putIndexed(uint idx, const Value &v) - { return vtable()->putIndexed(this, idx, v); } + inline bool put(StringOrSymbol *name, const Value &v, Value *receiver = nullptr) + { if (!receiver) receiver = this; return vtable()->put(this, name->toPropertyKey(), v, receiver); } + inline bool put(uint idx, const Value &v, Value *receiver = nullptr) + { if (!receiver) receiver = this; return vtable()->put(this, Identifier::fromArrayIndex(idx), v, receiver); } + QT_DEPRECATED inline bool putIndexed(uint idx, const Value &v) + { return put(idx, v); } + inline bool put(Identifier id, const Value &v, Value *receiver = nullptr) + { if (!receiver) receiver = this; return vtable()->put(this, id, v, receiver); } enum ThrowOnFailure { DoThrowOnRejection, @@ -396,7 +397,7 @@ public: // which is much more efficient for the array case. inline bool setIndexed(uint idx, const Value &v, ThrowOnFailure shouldThrow) { - bool ret = vtable()->putIndexed(this, idx, v); + bool ret = vtable()->put(this, Identifier::fromArrayIndex(idx), v, this); // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception. if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) { ExecutionEngine *e = engine(); @@ -412,7 +413,7 @@ public: // ES6: 7.3.3 Set (O, P, V, Throw) inline bool set(StringOrSymbol *name, const Value &v, ThrowOnFailure shouldThrow) { - bool ret = vtable()->put(this, name, v); + bool ret = vtable()->put(this, name->toPropertyKey(), v, this); // ES6: 7.3.3, 6: If success is false and Throw is true, throw a TypeError exception. if (!ret && shouldThrow == ThrowOnFailure::DoThrowOnRejection) { ExecutionEngine *e = engine(); @@ -438,8 +439,7 @@ protected: static ReturnedValue call(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static bool put(Managed *m, StringOrSymbol *name, const Value &value); - static bool putIndexed(Managed *m, uint index, const Value &value); + static bool put(Managed *m, Identifier id, const Value &value, Value *receiver); static bool deleteProperty(Managed *m, Identifier id); static bool hasProperty(const Managed *m, Identifier id); static PropertyAttributes getOwnProperty(Managed *m, Identifier id, Property *p); @@ -456,8 +456,7 @@ private: bool internalDefineOwnProperty(ExecutionEngine *engine, uint index, StringOrSymbol *member, const Property *p, PropertyAttributes attrs); ReturnedValue internalGet(StringOrSymbol *name, bool *hasProperty) const; ReturnedValue internalGetIndexed(uint index, bool *hasProperty) const; - bool internalPut(StringOrSymbol *name, const Value &value); - bool internalPutIndexed(uint index, const Value &value); + bool internalPut(Identifier id, const Value &value, Value *receiver); bool internalDeleteProperty(Identifier id); friend struct ObjectIterator; diff --git a/src/qml/jsruntime/qv4proxy.cpp b/src/qml/jsruntime/qv4proxy.cpp index 5b5149a2f4..11914e4feb 100644 --- a/src/qml/jsruntime/qv4proxy.cpp +++ b/src/qml/jsruntime/qv4proxy.cpp @@ -103,7 +103,7 @@ ReturnedValue ProxyObject::getIndexed(const Managed *m, uint index, bool *hasPro return get(m, name, hasProperty); } -bool ProxyObject::put(Managed *m, StringOrSymbol *name, const Value &value) +bool ProxyObject::put(Managed *m, Identifier id, const Value &value, Value *receiver) { Scope scope(m); const ProxyObject *o = static_cast(m); @@ -117,21 +117,21 @@ bool ProxyObject::put(Managed *m, StringOrSymbol *name, const Value &value) if (scope.hasException()) return Encode::undefined(); if (trap->isNullOrUndefined()) - return target->put(name, value); + return target->put(id, value, receiver); if (!trap->isFunctionObject()) return scope.engine->throwTypeError(); JSCallData cdata(scope, 4, nullptr, handler); cdata.args[0] = target; - cdata.args[1] = name; + cdata.args[1] = id.toStringOrSymbol(scope.engine); cdata.args[2] = value; - cdata.args[3] = o->d(); // ### fix receiver handling + cdata.args[3] = *receiver; ScopedValue trapResult(scope, static_cast(trap.ptr)->call(cdata)); if (!trapResult->toBoolean()) return false; ScopedProperty targetDesc(scope); - PropertyAttributes attributes = target->getOwnProperty(name->toPropertyKey(), targetDesc); + PropertyAttributes attributes = target->getOwnProperty(id, targetDesc); if (attributes != Attr_Invalid && !attributes.isConfigurable()) { if (attributes.isData() && !attributes.isWritable()) { if (!value.sameValue(targetDesc->value)) @@ -143,13 +143,6 @@ bool ProxyObject::put(Managed *m, StringOrSymbol *name, const Value &value) return true; } -bool ProxyObject::putIndexed(Managed *m, uint index, const Value &value) -{ - Scope scope(m); - ScopedString name(scope, Primitive::fromUInt32(index).toString(scope.engine)); - return put(m, name, value); -} - bool ProxyObject::deleteProperty(Managed *m, Identifier id) { Scope scope(m); diff --git a/src/qml/jsruntime/qv4proxy_p.h b/src/qml/jsruntime/qv4proxy_p.h index 306f3f00cb..f605621210 100644 --- a/src/qml/jsruntime/qv4proxy_p.h +++ b/src/qml/jsruntime/qv4proxy_p.h @@ -87,8 +87,7 @@ struct ProxyObject: Object { static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty); static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static bool put(Managed *m, StringOrSymbol *name, const Value &value); - static bool putIndexed(Managed *m, uint index, const Value &value); + static bool put(Managed *m, Identifier id, const Value &value, Value *receiver); static bool deleteProperty(Managed *m, Identifier id); static bool hasProperty(const Managed *m, Identifier id); static PropertyAttributes getOwnProperty(Managed *m, Identifier id, Property *p); diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 4226bf7972..a3e761050c 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -229,13 +229,12 @@ ReturnedValue QQmlContextWrapper::get(const Managed *m, StringOrSymbol *n, bool return Encode::undefined(); } -bool QQmlContextWrapper::put(Managed *m, StringOrSymbol *n, const Value &value) +bool QQmlContextWrapper::put(Managed *m, Identifier id, const Value &value, Value *receiver) { Q_ASSERT(m->as()); - if (n->isSymbol()) - return Object::put(m, n, value); - String *name = static_cast(n); + if (id.isSymbol() || id.isArrayIndex()) + return Object::put(m, id, value, receiver); QQmlContextWrapper *resource = static_cast(m); ExecutionEngine *v4 = resource->engine(); @@ -244,21 +243,20 @@ bool QQmlContextWrapper::put(Managed *m, StringOrSymbol *n, const Value &value) return false; QV4::Scoped wrapper(scope, resource); - name->makeIdentifier(); - uint member = wrapper->internalClass()->find(name->identifier()); + uint member = wrapper->internalClass()->find(id); if (member < UINT_MAX) return wrapper->putValue(member, value); if (wrapper->d()->isNullWrapper) { if (wrapper && wrapper->d()->readOnly) { - QString error = QLatin1String("Invalid write to global property \"") + name->toQString() + + QString error = QLatin1String("Invalid write to global property \"") + id.toQString() + QLatin1Char('"'); ScopedString e(scope, v4->newString(error)); v4->throwError(e); return false; } - return Object::put(m, name, value); + return Object::put(m, id, value, receiver); } // It's possible we could delay the calculation of the "actual" context (in the case @@ -272,6 +270,7 @@ bool QQmlContextWrapper::put(Managed *m, StringOrSymbol *n, const Value &value) // See QV8ContextWrapper::Getter for resolution order QObject *scopeObject = wrapper->getScopeObject(); + ScopedString name(scope, id.asHeapObject()); while (context) { const QV4::IdentifierHash &properties = context->propertyNames(); @@ -302,7 +301,7 @@ bool QQmlContextWrapper::put(Managed *m, StringOrSymbol *n, const Value &value) return false; } - return Object::put(m, name, value); + return Object::put(m, id, value, receiver); } void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml) diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 86c5b62da2..2dc0e57008 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -99,7 +99,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object void setReadOnly(bool b) { d()->readOnly = b; } static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty); - static bool put(Managed *m, StringOrSymbol *name, const Value &value); + static bool put(Managed *m, Identifier id, const Value &value, Value *receiver); }; struct Q_QML_EXPORT QmlContext : public ExecutionContext diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 94d645ac2b..8476d01f67 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -703,30 +703,30 @@ QV4::ReturnedValue QObjectWrapper::get(const Managed *m, StringOrSymbol *name, b return that->getQmlProperty(qmlContext, n, IgnoreRevision, hasProperty, /*includeImports*/ true); } -bool QObjectWrapper::put(Managed *m, StringOrSymbol *n, const Value &value) +bool QObjectWrapper::put(Managed *m, Identifier id, const Value &value, Value *receiver) { - if (n->isSymbol()) - return Object::put(m, n, value); - String *name = static_cast(n); + if (!id.isString()) + return Object::put(m, id, value, receiver); + Scope scope(m); QObjectWrapper *that = static_cast(m); - ExecutionEngine *v4 = that->engine(); + ScopedString name(scope, id.asHeapObject()); - if (v4->hasException || QQmlData::wasDeleted(that->d()->object())) + if (scope.engine->hasException || QQmlData::wasDeleted(that->d()->object())) return false; - QQmlContextData *qmlContext = v4->callingQmlContext(); - if (!setQmlProperty(v4, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) { + QQmlContextData *qmlContext = scope.engine->callingQmlContext(); + if (!setQmlProperty(scope.engine, qmlContext, that->d()->object(), name, QV4::QObjectWrapper::IgnoreRevision, value)) { QQmlData *ddata = QQmlData::get(that->d()->object()); // Types created by QML are not extensible at run-time, but for other QObjects we can store them // as regular JavaScript properties, like on JavaScript objects. if (ddata && ddata->context) { QString error = QLatin1String("Cannot assign to non-existent property \"") + name->toQString() + QLatin1Char('\"'); - v4->throwError(error); + scope.engine->throwError(error); return false; } else { - return QV4::Object::put(m, name, value); + return QV4::Object::put(m, id, value, receiver); } } diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 12272c2925..5d1f79fd39 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -194,7 +194,7 @@ protected: QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const; static ReturnedValue get(const Managed *m, StringOrSymbol *name, bool *hasProperty); - static bool put(Managed *m, StringOrSymbol *name, const Value &value); + static bool put(Managed *m, Identifier id, const Value &value, Value *receiver); static PropertyAttributes getOwnProperty(Managed *m, Identifier id, Property *p); static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes); diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp index 2594f53b14..48920fd63c 100644 --- a/src/qml/jsruntime/qv4reflect.cpp +++ b/src/qml/jsruntime/qv4reflect.cpp @@ -248,17 +248,12 @@ ReturnedValue Reflect::method_set(const FunctionObject *f, const Value *, const Value undef = Primitive::undefinedValue(); const Value *index = argc > 1 ? &argv[1] : &undef; const Value &val = argc > 2 ? argv[2] : undef; + ScopedValue receiver(scope, argc >3 ? argv[3] : argv[0]); - uint n = index->asArrayIndex(); - if (n < UINT_MAX) { - bool result = o->putIndexed(n, val); - return Encode(result); - } - - ScopedStringOrSymbol name(scope, index->toPropertyKey(scope.engine)); + Scoped propertyKey(scope, index->toPropertyKey(scope.engine)); if (scope.engine->hasException) return false; - bool result = o->put(name, val); + bool result = o->put(propertyKey->toPropertyKey(), val, receiver); return Encode(result); } diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 7f2738321c..948a002e46 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -689,7 +689,7 @@ static Q_NEVER_INLINE bool setElementFallback(ExecutionEngine *engine, const Val return true; } } - return o->putIndexed(idx, value); + return o->put(idx, value); } ScopedStringOrSymbol name(scope, index.toPropertyKey(engine)); diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index f6f8e51e19..74964916ee 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -565,8 +565,12 @@ public: static QV4::ReturnedValue getIndexed(const QV4::Managed *that, uint index, bool *hasProperty) { return static_cast *>(that)->containerGetIndexed(index, hasProperty); } - static bool putIndexed(Managed *that, uint index, const QV4::Value &value) - { return static_cast *>(that)->containerPutIndexed(index, value); } + static bool put(Managed *that, Identifier id, const QV4::Value &value, Value *receiver) + { + if (id.isArrayIndex()) + return static_cast *>(that)->containerPutIndexed(id.asArrayIndex(), value); + return Object::put(that, id, value, receiver); + } static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index) { return static_cast *>(that)->containerQueryIndexed(index); } static bool deleteProperty(QV4::Managed *that, Identifier id) diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp index 31b51cbfe3..0fb6044e7d 100644 --- a/src/qml/jsruntime/qv4serialize.cpp +++ b/src/qml/jsruntime/qv4serialize.cpp @@ -332,7 +332,7 @@ ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine) ScopedValue v(scope); for (quint32 ii = 0; ii < size; ++ii) { v = deserialize(data, engine); - a->putIndexed(ii, v); + a->put(ii, v); } return a.asReturnedValue(); } diff --git a/src/qml/jsruntime/qv4symbol_p.h b/src/qml/jsruntime/qv4symbol_p.h index 3cf6bc5dde..ed04b436ef 100644 --- a/src/qml/jsruntime/qv4symbol_p.h +++ b/src/qml/jsruntime/qv4symbol_p.h @@ -117,9 +117,7 @@ struct SymbolObject : Object V4_INTERNALCLASS(SymbolObject) V4_PROTOTYPE(symbolPrototype) - static bool put(Managed *, StringOrSymbol *, const Value &) { return false; } - static bool putIndexed(Managed *, uint, const Value &) { return false; } - + static bool put(Managed *, Identifier, const Value &, Value *) { return false; } }; } diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 86aa18c3a4..bb679f7ea0 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -384,8 +384,12 @@ ReturnedValue TypedArray::getIndexed(const Managed *m, uint index, bool *hasProp return a->d()->type->read(a->d()->buffer->data->data(), byteOffset); } -bool TypedArray::putIndexed(Managed *m, uint index, const Value &value) +bool TypedArray::put(Managed *m, Identifier id, const Value &value, Value *receiver) { + if (!id.isArrayIndex()) + return Object::put(m, id, value, receiver); + + uint index = id.asArrayIndex(); ExecutionEngine *v4 = static_cast(m)->engine(); if (v4->hasException) return false; diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index 43ff1ec5b7..cbc449471b 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -140,7 +140,7 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object } static ReturnedValue getIndexed(const Managed *m, uint index, bool *hasProperty); - static bool putIndexed(Managed *m, uint index, const Value &value); + static bool put(Managed *m, Identifier id, const Value &value, Value *receiver); }; struct IntrinsicTypedArrayCtor: FunctionObject -- cgit v1.2.3