aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4arrayobject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4arrayobject.cpp')
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp63
1 files changed, 58 insertions, 5 deletions
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index a32017210a..40a7123232 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -14,9 +14,9 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ArrayCtor);
-void Heap::ArrayCtor::init(QV4::ExecutionContext *scope)
+void Heap::ArrayCtor::init(QV4::ExecutionEngine *engine)
{
- Heap::FunctionObject::init(scope, QStringLiteral("Array"));
+ Heap::FunctionObject::init(engine, QStringLiteral("Array"));
}
ReturnedValue ArrayCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
@@ -848,15 +848,69 @@ ReturnedValue ArrayPrototype::method_slice(const FunctionObject *b, const Value
ReturnedValue ArrayPrototype::method_sort(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
+ // Based on https://tc39.es/ecma262/#sec-array.prototype.sort
+
Scope scope(b);
+
+ ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
+
+ // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception.
+ if (!comparefn->isUndefined() && !comparefn->isFunctionObject())
+ return scope.engine->throwTypeError(QStringLiteral("The provided comparison function is not callable."));
+
+ // 2. Let obj be ? ToObject(this value).
ScopedObject instance(scope, thisObject->toObject(scope.engine));
if (!instance)
RETURN_UNDEFINED();
+ // 3. Let len be ? LengthOfArrayLike(obj).
uint len = instance->getLength();
- ScopedValue comparefn(scope, argc ? argv[0] : Value::undefinedValue());
- ArrayData::sort(scope.engine, instance, comparefn, len);
+ if (instance->arrayData() && instance->arrayData()->length()) {
+ ArrayData::sort(scope.engine, instance, comparefn, len);
+ } else {
+ // Generic implementation that does not require a populated
+ // ArrayData, this is used, for example, by `Sequences` which
+ // store their data in a different way.
+
+ // 5. Let sortedList be ? SortIndexedProperties(obj, len, SortCompare, skip-holes)
+ Value* sorted = scope.alloc(scope.engine->safeForAllocLength(len));
+ CHECK_EXCEPTION();
+
+ uint written = 0;
+ for (uint index = 0; index < len; ++index) {
+ bool hasProperty = false;
+ auto element = instance->get(index, &hasProperty);
+
+ if (hasProperty) {
+ sorted[written] = element;
+ ++written;
+ }
+ }
+
+ std::stable_sort(sorted, sorted + written, ArrayElementLessThan(scope.engine, comparefn));
+
+ // [...]
+ // 8. Repeat, while j < itemCount,
+ // a. Perform ? Set(obj, ! ToString(𝔽(j)), sortedList[j], true).
+ // [...]
+ for (uint index = 0; index < written; ++index) {
+ instance->setIndexed(index, sorted[index], QV4::Object::DoThrowOnRejection);
+ CHECK_EXCEPTION();
+ }
+
+ // [...]
+ // 10. Repeat, while j < len,
+ // a. Perform ? DeletePropertyOrThrow(obj, ! ToString(𝔽(j))).
+ // [...]
+ while (written < len) {
+ if (!instance->deleteProperty(PropertyKey::fromArrayIndex(written)))
+ return scope.engine->throwTypeError();
+ ++written;
+ }
+ }
+
+ // 11. Return obj
return thisObject->asReturnedValue();
}
@@ -1490,4 +1544,3 @@ ReturnedValue ArrayPrototype::method_get_species(const FunctionObject *, const V
{
return thisObject->asReturnedValue();
}
-