diff options
-rw-r--r-- | src/qml/jsruntime/qv4typedarray.cpp | 106 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4typedarray_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 10 | ||||
-rw-r--r-- | tests/auto/qml/ecmascripttests/TestExpectations | 2 |
4 files changed, 75 insertions, 45 deletions
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp index c52526d686..54c3b9cfc1 100644 --- a/src/qml/jsruntime/qv4typedarray.cpp +++ b/src/qml/jsruntime/qv4typedarray.cpp @@ -57,16 +57,31 @@ DEFINE_OBJECT_VTABLE(TypedArray); Q_STATIC_ASSERT((int)ExecutionEngine::NTypedArrayTypes == (int)Heap::TypedArray::NTypes); +static inline int toInt32(Value v) +{ + Q_ASSERT(v.isNumber()); + if (v.isInteger()) + return v.integerValue(); + return Double::toInt32(v.doubleValue()); +} + +static inline double toDouble(Value v) +{ + Q_ASSERT(v.isNumber()); + if (v.isInteger()) + return v.integerValue(); + return v.doubleValue(); +} + ReturnedValue Int8ArrayRead(const char *data, int index) { return Encode((int)(signed char)data[index]); } -void Int8ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value) +void Int8ArrayWrite(char *data, int index, const Value &value) { - signed char v = (signed char)value.toUInt32(); - if (e->hasException) - return; + int n = toInt32(value); + signed char v = static_cast<signed char>(n); data[index] = v; } @@ -75,23 +90,22 @@ ReturnedValue UInt8ArrayRead(const char *data, int index) return Encode((int)(unsigned char)data[index]); } -void UInt8ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value) +void UInt8ArrayWrite(char *data, int index, const Value &value) { - unsigned char v = (unsigned char)value.toUInt32(); - if (e->hasException) - return; + int n = toInt32(value); + unsigned char v = static_cast<unsigned char>(uint(n)); data[index] = v; } -void UInt8ClampedArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value) +void UInt8ClampedArrayWrite(char *data, int index, const Value &value) { + Q_ASSERT(value.isNumber()); if (value.isInteger()) { data[index] = (char)(unsigned char)qBound(0, value.integerValue(), 255); return; } - double d = value.toNumber(); - if (e->hasException) - return; + Q_ASSERT(value.isDouble()); + double d = value.doubleValue(); // ### is there a way to optimise this? if (d <= 0 || std::isnan(d)) { data[index] = 0; @@ -123,11 +137,10 @@ ReturnedValue Int16ArrayRead(const char *data, int index) return Encode((int)*(const short *)(data + index)); } -void Int16ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value) +void Int16ArrayWrite(char *data, int index, const Value &value) { - short v = (short)value.toInt32(); - if (e->hasException) - return; + int n = toInt32(value); + short v = static_cast<short>(n); *(short *)(data + index) = v; } @@ -136,11 +149,10 @@ ReturnedValue UInt16ArrayRead(const char *data, int index) return Encode((int)*(const unsigned short *)(data + index)); } -void UInt16ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value) +void UInt16ArrayWrite(char *data, int index, const Value &value) { - unsigned short v = (unsigned short)value.toInt32(); - if (e->hasException) - return; + int n = toInt32(value); + unsigned short v = static_cast<unsigned short>(n); *(unsigned short *)(data + index) = v; } @@ -149,11 +161,9 @@ ReturnedValue Int32ArrayRead(const char *data, int index) return Encode(*(const int *)(data + index)); } -void Int32ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value) +void Int32ArrayWrite(char *data, int index, const Value &value) { - int v = (int)value.toInt32(); - if (e->hasException) - return; + int v = toInt32(value); *(int *)(data + index) = v; } @@ -162,11 +172,10 @@ ReturnedValue UInt32ArrayRead(const char *data, int index) return Encode(*(const unsigned int *)(data + index)); } -void UInt32ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value) +void UInt32ArrayWrite(char *data, int index, const Value &value) { - unsigned int v = (unsigned int)value.toUInt32(); - if (e->hasException) - return; + int n = toInt32(value); + unsigned v = static_cast<unsigned>(n); *(unsigned int *)(data + index) = v; } @@ -175,11 +184,9 @@ ReturnedValue Float32ArrayRead(const char *data, int index) return Encode(*(const float *)(data + index)); } -void Float32ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value) +void Float32ArrayWrite(char *data, int index, const Value &value) { - float v = value.toNumber(); - if (e->hasException) - return; + float v = toDouble(value); *(float *)(data + index) = v; } @@ -188,11 +195,9 @@ ReturnedValue Float64ArrayRead(const char *data, int index) return Encode(*(const double *)(data + index)); } -void Float64ArrayWrite(ExecutionEngine *e, char *data, int index, const Value &value) +void Float64ArrayWrite(char *data, int index, const Value &value) { - double v = value.toNumber(); - if (e->hasException) - return; + double v = toDouble(value); *(double *)(data + index) = v; } @@ -277,7 +282,7 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f, for (uint i = 0; i < l; ++i) { Primitive val; val.setRawValue(read(src, i*srcElementSize)); - write(scope.engine, dest, i*destElementSize, val); + write(dest, i*destElementSize, val); } } @@ -346,7 +351,10 @@ ReturnedValue TypedArrayCtor::virtualCallAsConstructor(const FunctionObject *f, ScopedValue val(scope); while (idx < l) { val = o->get(idx); - array->d()->type->write(scope.engine, b, 0, val); + val = val->convertedToNumber(); + if (scope.engine->hasException) + return Encode::undefined(); + array->d()->type->write(b, 0, val); if (scope.engine->hasException) return Encode::undefined(); ++idx; @@ -384,6 +392,8 @@ ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Val uint index = id.asArrayIndex(); Scope scope(static_cast<const Object *>(m)->engine()); Scoped<TypedArray> a(scope, static_cast<const TypedArray *>(m)); + if (a->d()->buffer->isDetachedBuffer()) + return scope.engine->throwTypeError(); uint bytesPerElement = a->d()->type->bytesPerElement; uint byteOffset = a->d()->byteOffset + index * bytesPerElement; @@ -409,13 +419,18 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu Scope scope(v4); Scoped<TypedArray> a(scope, static_cast<TypedArray *>(m)); + if (a->d()->buffer->isDetachedBuffer()) + return scope.engine->throwTypeError(); uint bytesPerElement = a->d()->type->bytesPerElement; uint byteOffset = a->d()->byteOffset + index * bytesPerElement; if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength()) return false; - a->d()->type->write(scope.engine, a->d()->buffer->data->data(), byteOffset, value); + Value v = Primitive::fromReturnedValue(value.convertedToNumber()); + if (scope.hasException() || a->d()->buffer->isDetachedBuffer()) + return scope.engine->throwTypeError(); + a->d()->type->write(a->d()->buffer->data->data(), byteOffset, v); return true; } @@ -612,13 +627,15 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_fill(const FunctionObject *b, double val = argc ? argv[0].toNumber() : std::numeric_limits<double>::quiet_NaN(); Value value = Primitive::fromDouble(val); + if (scope.hasException() || v->d()->buffer->isDetachedBuffer()) + return scope.engine->throwTypeError(); char *data = v->d()->buffer->data->data(); uint bytesPerElement = v->d()->type->bytesPerElement; uint byteOffset = v->d()->byteOffset; while (k < fin) { - v->d()->type->write(scope.engine, data, byteOffset + k * bytesPerElement, value); + v->d()->type->write(data, byteOffset + k * bytesPerElement, value); k++; } @@ -1237,7 +1254,12 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b, ScopedValue val(scope); while (idx < l) { val = o->get(idx); - a->d()->type->write(scope.engine, b, 0, val); + if (scope.hasException()) + return Encode::undefined(); + val = val->convertedToNumber(); + if (scope.hasException() || buffer->isDetachedBuffer()) + return scope.engine->throwTypeError(); + a->d()->type->write(b, 0, val); if (scope.engine->hasException) RETURN_UNDEFINED(); ++idx; @@ -1278,7 +1300,7 @@ ReturnedValue IntrinsicTypedArrayPrototype::method_set(const FunctionObject *b, for (uint i = 0; i < l; ++i) { Primitive val; val.setRawValue(read(src, i*srcElementSize)); - write(scope.engine, dest, i*elementSize, val); + write(dest, i*elementSize, val); } if (srcCopy) diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h index 31698fa6d0..775ba61ddc 100644 --- a/src/qml/jsruntime/qv4typedarray_p.h +++ b/src/qml/jsruntime/qv4typedarray_p.h @@ -61,7 +61,7 @@ namespace QV4 { struct ArrayBuffer; typedef ReturnedValue (*TypedArrayRead)(const char *data, int index); -typedef void (*TypedArrayWrite)(ExecutionEngine *engine, char *data, int index, const Value &value); +typedef void (*TypedArrayWrite)(char *data, int index, const Value &value); struct TypedArrayOperations { int bytesPerElement; diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 6a6df3eb6d..e4be6b99dd 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -408,6 +408,7 @@ public: } static bool toBooleanImpl(Value val); double toInteger() const; + inline ReturnedValue convertedToNumber() const; inline double toNumber() const; static double toNumberImpl(Value v); double toNumberImpl() const { return toNumberImpl(*this); } @@ -554,6 +555,15 @@ inline double Value::toNumber() const return toNumberImpl(); } +inline ReturnedValue Value::convertedToNumber() const +{ + if (isInteger() || isDouble()) + return asReturnedValue(); + Value v; + v.setDouble(toNumberImpl()); + return v.asReturnedValue(); +} + inline ReturnedValue Heap::Base::asReturnedValue() const { diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index de21ad7fad..3d79b87652 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -683,7 +683,6 @@ built-ins/TypedArray/from/name.js fails built-ins/TypedArray/from/prop-desc.js fails built-ins/TypedArray/prototype/constructor.js fails built-ins/TypedArray/prototype/fill/fill-values-conversion-operations-consistent-nan.js fails -built-ins/TypedArray/prototype/set/array-arg-targetbuffer-detached-on-get-src-value-throws.js fails built-ins/TypedArray/prototype/slice/bit-precision.js fails built-ins/TypedArray/prototype/sort/arraylength-internal.js fails built-ins/TypedArray/prototype/sort/comparefn-call-throws.js fails @@ -790,7 +789,6 @@ built-ins/TypedArrays/internals/Set/detached-buffer.js fails built-ins/TypedArrays/internals/Set/key-is-minus-zero.js fails built-ins/TypedArrays/internals/Set/key-is-not-integer.js fails built-ins/TypedArrays/internals/Set/key-is-out-of-bounds.js fails -built-ins/TypedArrays/internals/Set/tonumber-value-detached-buffer.js fails built-ins/TypedArrays/internals/Set/tonumber-value-throws.js strictFails built-ins/WeakMap/constructor.js fails built-ins/WeakMap/empty-iterable.js fails |