From a1ea2b8ec057bca58fdb5e9498e2f302ef0e61b4 Mon Sep 17 00:00:00 2001 From: Robin Burchell Date: Thu, 24 May 2018 21:19:22 +0200 Subject: qv4arrayobject: Implement Array.prototype.fill according to ES7 Task-number: QTBUG-56824 Change-Id: Ib12b9fe5ebdd5375f17cf4927eb9b4e292731932 Reviewed-by: Lars Knoll --- src/qml/jsruntime/qv4arrayobject.cpp | 37 ++++++++++++++++++++++++++++++++++++ src/qml/jsruntime/qv4arrayobject_p.h | 1 + src/qml/jsruntime/qv4object_p.h | 17 +++++++++++++++++ 3 files changed, 55 insertions(+) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index c04edbe872..f8398d206d 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -116,6 +116,7 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(QStringLiteral("keys"), method_keys, 0); defineDefaultProperty(QStringLiteral("lastIndexOf"), method_lastIndexOf, 1); defineDefaultProperty(QStringLiteral("every"), method_every, 1); + defineDefaultProperty(QStringLiteral("fill"), method_fill, 1); defineDefaultProperty(QStringLiteral("some"), method_some, 1); defineDefaultProperty(QStringLiteral("forEach"), method_forEach, 1); defineDefaultProperty(QStringLiteral("map"), method_map, 1); @@ -854,6 +855,42 @@ ReturnedValue ArrayPrototype::method_every(const FunctionObject *b, const Value return Encode(ok); } +ReturnedValue ArrayPrototype::method_fill(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) +{ + Scope scope(b); + ScopedObject instance(scope, thisObject->toObject(scope.engine)); + if (!instance) + RETURN_UNDEFINED(); + + uint len = instance->getLength(); + int relativeStart = argc > 1 ? argv[1].toInteger() : 0; + int relativeEnd = len; + if (argc > 2 && !argv[2].isUndefined()) { + relativeEnd = argv[2].toInteger(); + } + uint k = 0; + uint fin = 0; + + if (relativeStart < 0) { + k = std::max(len+relativeStart, uint(0)); + } else { + k = std::min(uint(relativeStart), len); + } + + if (relativeEnd < 0) { + fin = std::max(len + relativeEnd, uint(0)); + } else { + fin = std::min(uint(relativeEnd), len); + } + + while (k < fin) { + instance->setIndexed(k, argv[0], QV4::Object::DoThrowOnRejection); + k++; + } + + return instance.asReturnedValue(); +} + ReturnedValue ArrayPrototype::method_some(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { Scope scope(b); diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index 31067b0c39..a8feb65e80 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -98,6 +98,7 @@ struct ArrayPrototype: ArrayObject static ReturnedValue method_keys(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_lastIndexOf(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_every(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); + static ReturnedValue method_fill(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_some(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_forEach(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); static ReturnedValue method_map(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 7cc99376be..5ad67635db 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -385,6 +385,23 @@ public: DoNotThrow }; + // This is the same as set(), but it doesn't require creating a string key, + // 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); + // 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(); + if (!e->hasException) { // allow a custom set impl to throw itself + QString message = QLatin1String("Cannot assign to read-only property \"") + + QString::number(idx) + QLatin1Char('\"'); + e->throwTypeError(message); + } + } + return ret; + } + // ES6: 7.3.3 Set (O, P, V, Throw) inline bool set(StringOrSymbol *name, const Value &v, ThrowOnFailure shouldThrow) { -- cgit v1.2.3