From 34094f6918993dd5d10b2eb38203a54f5168d114 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 14 Aug 2018 19:54:31 +0200 Subject: Fix toLocaleString implementations in (Typed)Array.prototype Change-Id: Idcabd68b1651ad3cae315a16cb0e1361cba21253 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4arrayobject.cpp | 33 ++++++++++++++++++++-- src/qml/jsruntime/qv4dateobject.cpp | 2 +- src/qml/jsruntime/qv4engine.cpp | 1 + src/qml/jsruntime/qv4engine_p.h | 2 ++ src/qml/jsruntime/qv4numberobject.cpp | 2 +- src/qml/jsruntime/qv4objectproto.cpp | 2 +- src/qml/jsruntime/qv4typedarray.cpp | 37 ++++++++++++++++++++----- src/qml/qml/qqmllocale.cpp | 4 +-- tests/auto/qml/ecmascripttests/TestExpectations | 13 --------- 9 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 544be06664..9be744038c 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -104,7 +104,7 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor) ScopedString name(scope); defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(engine->id_toString(), method_toString, 0); - defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); + defineDefaultProperty(engine->id_toLocaleString(), method_toLocaleString, 0); defineDefaultProperty(QStringLiteral("concat"), method_concat, 1); name = engine->newIdentifier(QStringLiteral("copyWithin")); unscopables->put(name, Primitive::fromBoolean(true)); @@ -369,9 +369,36 @@ ReturnedValue ArrayPrototype::method_toString(const FunctionObject *builtin, con return ObjectPrototype::method_toString(builtin, that, argv, argc); } -ReturnedValue ArrayPrototype::method_toLocaleString(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc) +ReturnedValue ArrayPrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *, int) { - return method_toString(builtin, thisObject, argv, argc); + Scope scope(b); + ScopedObject instance(scope, thisObject); + if (!instance) + return scope.engine->throwTypeError(); + + uint len = instance->getLength(); + const QString separator = QStringLiteral(","); + + QString R; + + ScopedValue v(scope); + ScopedString s(scope); + + for (uint k = 0; k < len; ++k) { + if (k) + R += separator; + + v = instance->get(k); + if (v->isNullOrUndefined()) + continue; + v = Runtime::method_callElement(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0); + s = v->toString(scope.engine); + if (scope.hasException()) + return Encode::undefined(); + + R += s->toQString(); + } + return scope.engine->newString(R)->asReturnedValue(); } ReturnedValue ArrayPrototype::method_concat(const FunctionObject *b, const Value *that, const Value *argv, int argc) diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 3efd626685..7335dd1ba0 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -806,7 +806,7 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor) defineDefaultProperty(engine->id_toString(), method_toString, 0); defineDefaultProperty(QStringLiteral("toDateString"), method_toDateString, 0); defineDefaultProperty(QStringLiteral("toTimeString"), method_toTimeString, 0); - defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); + defineDefaultProperty(engine->id_toLocaleString(), method_toLocaleString, 0); defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString, 0); defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString, 0); defineDefaultProperty(engine->id_valueOf(), method_valueOf, 0); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index ea17f3423c..57e93895fc 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -275,6 +275,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) jsStrings[String_index] = newIdentifier(QStringLiteral("index")); jsStrings[String_input] = newIdentifier(QStringLiteral("input")); jsStrings[String_toString] = newIdentifier(QStringLiteral("toString")); + jsStrings[String_toLocaleString] = newIdentifier(QStringLiteral("toLocaleString")); jsStrings[String_destroy] = newIdentifier(QStringLiteral("destroy")); jsStrings[String_valueOf] = newIdentifier(QStringLiteral("valueOf")); jsStrings[String_byteLength] = newIdentifier(QStringLiteral("byteLength")); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 7608c04800..e11e607bd1 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -315,6 +315,7 @@ public: String_index, String_input, String_toString, + String_toLocaleString, String_destroy, String_valueOf, String_byteLength, @@ -385,6 +386,7 @@ public: String *id_index() const { return reinterpret_cast(jsStrings + String_index); } String *id_input() const { return reinterpret_cast(jsStrings + String_input); } String *id_toString() const { return reinterpret_cast(jsStrings + String_toString); } + String *id_toLocaleString() const { return reinterpret_cast(jsStrings + String_toLocaleString); } String *id_destroy() const { return reinterpret_cast(jsStrings + String_destroy); } String *id_valueOf() const { return reinterpret_cast(jsStrings + String_valueOf); } String *id_byteLength() const { return reinterpret_cast(jsStrings + String_byteLength); } diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index d103f65d47..d552948e95 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -117,7 +117,7 @@ QT_WARNING_POP defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(engine->id_toString(), method_toString, 1); - defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); + defineDefaultProperty(engine->id_toLocaleString(), method_toLocaleString); defineDefaultProperty(engine->id_valueOf(), method_valueOf); defineDefaultProperty(QStringLiteral("toFixed"), method_toFixed, 1); defineDefaultProperty(QStringLiteral("toExponential"), method_toExponential, 1); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index ed810cb456..c968bff0fe 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -119,7 +119,7 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor) defineDefaultProperty(QStringLiteral("constructor"), (o = ctor)); defineDefaultProperty(v4->id_toString(), method_toString, 0); - defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); + defineDefaultProperty(v4->id_toLocaleString(), method_toLocaleString, 0); defineDefaultProperty(v4->id_valueOf(), method_valueOf, 0); defineDefaultProperty(QStringLiteral("hasOwnProperty"), method_hasOwnProperty, 1); defineDefaultProperty(QStringLiteral("isPrototypeOf"), method_isPrototypeOf, 1); diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index 4b2fde92a2..dc8d1fa0bb 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -1230,13 +1230,36 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_subarray(const FunctionObject return constructor->callAsConstructor(arguments, 3); } -ReturnedValue IntrinsicTypedArrayPrototype::method_toLocaleString(const FunctionObject *builtin, const Value *thisObject, const Value *argv, int argc) +ReturnedValue IntrinsicTypedArrayPrototype::method_toLocaleString(const FunctionObject *b, const Value *thisObject, const Value *, int) { - // ### FIXME - Scope scope(builtin); - ScopedString key(scope, scope.engine->newIdentifier(QStringLiteral("toLocaleString"))); - ScopedFunctionObject f(scope, scope.engine->arrayPrototype()->get(key->toPropertyKey())); - return f->call(thisObject, argv, argc); + Scope scope(b); + Scoped instance(scope, thisObject); + if (!instance || instance->d()->buffer->isDetachedBuffer()) + return scope.engine->throwTypeError(); + + uint len = instance->length(); + const QString separator = QStringLiteral(","); + + QString R; + + ScopedValue v(scope); + ScopedString s(scope); + + for (uint k = 0; k < len; ++k) { + if (instance->d()->buffer->isDetachedBuffer()) + return scope.engine->throwTypeError(); + if (k) + R += separator; + + v = instance->get(k); + v = Runtime::method_callElement(scope.engine, v, *scope.engine->id_toLocaleString(), nullptr, 0); + s = v->toString(scope.engine); + if (scope.hasException()) + return Encode::undefined(); + + R += s->toQString(); + } + return scope.engine->newString(R)->asReturnedValue(); } ReturnedValue IntrinsicTypedArrayPrototype::method_get_toStringTag(const FunctionObject *, const Value *thisObject, const Value *, int) @@ -1328,7 +1351,7 @@ void IntrinsicTypedArrayPrototype::init(ExecutionEngine *engine, IntrinsicTypedA defineDefaultProperty(QStringLiteral("some"), method_some, 1); defineDefaultProperty(QStringLiteral("set"), method_set, 1); defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 0); - defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString, 0); + defineDefaultProperty(engine->id_toLocaleString(), method_toLocaleString, 0); ScopedObject f(scope, engine->arrayPrototype()->get(engine->id_toString())); defineDefaultProperty(engine->id_toString(), f); diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 42c72e0447..f9f13e7b7c 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -77,7 +77,7 @@ static bool isLocaleObject(const QV4::Value &val) void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine) { - engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); + engine->datePrototype()->defineDefaultProperty(engine->id_toLocaleString(), method_toLocaleString); engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString); engine->datePrototype()->defineDefaultProperty(QStringLiteral("toLocaleDateString"), method_toLocaleDateString); engine->dateCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); @@ -360,7 +360,7 @@ ReturnedValue QQmlDateExtension::method_timeZoneUpdated(const QV4::FunctionObjec void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine) { - engine->numberPrototype()->defineDefaultProperty(QStringLiteral("toLocaleString"), method_toLocaleString); + engine->numberPrototype()->defineDefaultProperty(engine->id_toLocaleString(), method_toLocaleString); engine->numberPrototype()->defineDefaultProperty(QStringLiteral("toLocaleCurrencyString"), method_toLocaleCurrencyString); engine->numberCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString); } diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index 9f482b715c..2021d65d04 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -108,8 +108,6 @@ built-ins/Array/prototype/splice/create-species.js fails built-ins/Array/prototype/splice/length-and-deleteCount-exceeding-integer-limit.js fails built-ins/Array/prototype/splice/length-exceeding-integer-limit-shrink-array.js fails built-ins/Array/prototype/splice/length-near-integer-limit-grow-array.js fails -built-ins/Array/prototype/toLocaleString/S15.4.4.3_A1_T1.js fails -built-ins/Array/prototype/toLocaleString/S15.4.4.3_A3_T1.js fails built-ins/Array/prototype/toLocaleString/primitive_this_value.js strictFails built-ins/Array/prototype/toLocaleString/primitive_this_value_getter.js strictFails built-ins/Array/prototype/unshift/clamps-to-integer-limit.js fails @@ -793,17 +791,6 @@ built-ins/TypedArray/prototype/subarray/speciesctor-get-species-custom-ctor-retu built-ins/TypedArray/prototype/subarray/speciesctor-get-species-custom-ctor.js fails built-ins/TypedArray/prototype/subarray/speciesctor-get-species-use-default-ctor.js fails built-ins/TypedArray/prototype/subarray/speciesctor-get-species.js fails -built-ins/TypedArray/prototype/toLocaleString/calls-tolocalestring-from-each-value.js fails -built-ins/TypedArray/prototype/toLocaleString/calls-tostring-from-each-value.js fails -built-ins/TypedArray/prototype/toLocaleString/calls-valueof-from-each-value.js fails -built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-firstelement-tolocalestring.js fails -built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-firstelement-tostring.js fails -built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-firstelement-valueof.js fails -built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-nextelement-tolocalestring.js fails -built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-nextelement-tostring.js fails -built-ins/TypedArray/prototype/toLocaleString/return-abrupt-from-nextelement-valueof.js fails -built-ins/TypedArray/prototype/toLocaleString/this-is-not-object.js fails -built-ins/TypedArray/prototype/toLocaleString/this-is-not-typedarray-instance.js fails built-ins/TypedArrays/ctors/buffer-arg/custom-proto-access-throws.js fails built-ins/TypedArrays/ctors/buffer-arg/defined-negative-length.js fails built-ins/TypedArrays/ctors/buffer-arg/proto-from-ctor-realm.js fails -- cgit v1.2.3