aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-09-01 23:21:21 +0200
committerLars Knoll <lars.knoll@qt.io>2018-09-04 18:25:38 +0000
commitf5ad1a13e5ce9ce1389ea7731829ea455259a4db (patch)
tree3e340593b23df47c9f016d2db43d9184a1a64e59 /src
parenta6ba4f044e3611fb66a6cce87bc06933c3e27070 (diff)
Fix a couple of internals in TypedArrays
Handle property keys that are numeric strings, and implement getOwnProperty. Change-Id: I4c7ed21b6429b07f02a28bce537bcb7934a993d3 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4propertykey.cpp19
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h1
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp61
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h1
4 files changed, 68 insertions, 14 deletions
diff --git a/src/qml/jsruntime/qv4propertykey.cpp b/src/qml/jsruntime/qv4propertykey.cpp
index 12a3653034..361ade17c2 100644
--- a/src/qml/jsruntime/qv4propertykey.cpp
+++ b/src/qml/jsruntime/qv4propertykey.cpp
@@ -42,6 +42,7 @@
#include <QtCore/qstring.h>
#include <qv4string_p.h>
#include <qv4engine_p.h>
+#include <qv4scopedvalue_p.h>
QV4::Heap::StringOrSymbol *QV4::PropertyKey::toStringOrSymbol(QV4::ExecutionEngine *e)
{
@@ -60,6 +61,24 @@ bool QV4::PropertyKey::isSymbol() const {
return s && !s->internalClass->vtable->isString && s->internalClass->vtable->isStringOrSymbol;
}
+bool QV4::PropertyKey::isCanonicalNumericIndexString() const
+{
+ if (isArrayIndex())
+ return true;
+ if (isSymbol())
+ return false;
+ Heap::String *s = static_cast<Heap::String *>(asStringOrSymbol());
+ Scope scope(s->internalClass->engine);
+ ScopedString str(scope, s);
+ double d = str->toNumber();
+ if (d == 0. && std::signbit(d))
+ return true;
+ ScopedString converted(scope, Primitive::fromDouble(d).toString(scope.engine));
+ if (converted->equals(str))
+ return true;
+ return false;
+}
+
QString QV4::PropertyKey::toQString() const
{
if (isArrayIndex())
diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h
index 7134b06c6d..cb2661f244 100644
--- a/src/qml/jsruntime/qv4propertykey_p.h
+++ b/src/qml/jsruntime/qv4propertykey_p.h
@@ -126,6 +126,7 @@ public:
bool isString() const;
bool isSymbol() const;
+ bool isCanonicalNumericIndexString() const;
Q_QML_EXPORT QString toQString() const;
Heap::StringOrSymbol *toStringOrSymbol(ExecutionEngine *e);
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 1d5ab5564e..a07443077e 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -459,22 +459,26 @@ Heap::TypedArray *TypedArray::create(ExecutionEngine *e, Heap::TypedArray::Type
ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
{
- if (!id.isArrayIndex())
+ uint index = id.asArrayIndex();
+ if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
return Object::virtualGet(m, id, receiver, hasProperty);
+ // fall through, with index == UINT_MAX it'll do the right thing.
- 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;
- if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength()) {
+ if (index >= a->length()) {
if (hasProperty)
*hasProperty = false;
return Encode::undefined();
}
+
+ uint bytesPerElement = a->d()->type->bytesPerElement;
+ uint byteOffset = a->d()->byteOffset + index * bytesPerElement;
+ Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength());
+
if (hasProperty)
*hasProperty = true;
return a->d()->type->read(a->d()->buffer->data->data() + byteOffset);
@@ -482,17 +486,42 @@ ReturnedValue TypedArray::virtualGet(const Managed *m, PropertyKey id, const Val
bool TypedArray::virtualHasProperty(const Managed *m, PropertyKey id)
{
+ uint index = id.asArrayIndex();
+ if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
+ return Object::virtualHasProperty(m, id);
+ // fall through, with index == UINT_MAX it'll do the right thing.
+
+ const TypedArray *a = static_cast<const TypedArray *>(m);
+ if (a->d()->buffer->isDetachedBuffer()) {
+ a->engine()->throwTypeError();
+ return false;
+ }
+ if (index >= a->length())
+ return false;
+ return true;
+}
+
+PropertyAttributes TypedArray::virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p)
+{
+ uint index = id.asArrayIndex();
+ if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
+ return Object::virtualGetOwnProperty(m, id, p);
+ // fall through, with index == UINT_MAX it'll do the right thing.
+
bool hasProperty = false;
- virtualGet(m, id, nullptr, &hasProperty);
- return hasProperty;
+ ReturnedValue v = virtualGet(m, id, m, &hasProperty);
+ if (p)
+ p->value = v;
+ return hasProperty ? Attr_NotConfigurable : PropertyAttributes();
}
bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
{
- if (!id.isArrayIndex())
+ uint index = id.asArrayIndex();
+ if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
return Object::virtualPut(m, id, value, receiver);
+ // fall through, with index == UINT_MAX it'll do the right thing.
- uint index = id.asArrayIndex();
ExecutionEngine *v4 = static_cast<Object *>(m)->engine();
if (v4->hasException)
return false;
@@ -502,10 +531,12 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu
if (a->d()->buffer->isDetachedBuffer())
return scope.engine->throwTypeError();
+ if (index >= a->length())
+ return false;
+
uint bytesPerElement = a->d()->type->bytesPerElement;
uint byteOffset = a->d()->byteOffset + index * bytesPerElement;
- if (byteOffset + bytesPerElement > (uint)a->d()->buffer->byteLength())
- return false;
+ Q_ASSERT(byteOffset + bytesPerElement <= (uint)a->d()->buffer->byteLength());
Value v = Primitive::fromReturnedValue(value.convertedToNumber());
if (scope.hasException() || a->d()->buffer->isDetachedBuffer())
@@ -516,10 +547,12 @@ bool TypedArray::virtualPut(Managed *m, PropertyKey id, const Value &value, Valu
bool TypedArray::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs)
{
- TypedArray *a = static_cast<TypedArray *>(m);
- if (!id.isArrayIndex())
- return Object::virtualDefineOwnProperty(m, id, p, attrs);
uint index = id.asArrayIndex();
+ if (index == UINT_MAX && !id.isCanonicalNumericIndexString())
+ return Object::virtualDefineOwnProperty(m, id, p, attrs);
+ // fall through, with index == UINT_MAX it'll do the right thing.
+
+ TypedArray *a = static_cast<TypedArray *>(m);
if (index >= a->length() || attrs.isAccessor())
return false;
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index f89d966974..ad0953ed0c 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -167,6 +167,7 @@ struct Q_QML_PRIVATE_EXPORT TypedArray : Object
static ReturnedValue virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
static bool virtualHasProperty(const Managed *m, PropertyKey id);
+ static PropertyAttributes virtualGetOwnProperty(Managed *m, PropertyKey id, Property *p);
static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
static bool virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property *p, PropertyAttributes attrs);