aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2014-09-10 16:39:23 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2014-10-29 09:07:12 +0100
commit868478e92afaa9d0823f3a65ff3d7b44216087ea (patch)
tree82156a50555923810ad8a8ffcf2452e405d8d396 /src/qml
parenta2c97406cad22a73a4c68303ef54128cf756f577 (diff)
Implement DataView
The second class that is required for typed array support. Change-Id: Idc2dcec7c1eee541f76dc5ab1aea6057ba03cb93 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src/qml')
-rw-r--r--src/qml/jsruntime/jsruntime.pri6
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp316
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h96
-rw-r--r--src/qml/jsruntime/qv4engine.cpp14
-rw-r--r--src/qml/jsruntime/qv4engine_p.h4
5 files changed, 433 insertions, 3 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 566d2563cc..3914537a19 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -43,7 +43,8 @@ SOURCES += \
$$PWD/qv4qmlextensions.cpp \
$$PWD/qv4vme_moth.cpp \
$$PWD/qv4profiling.cpp \
- $$PWD/qv4arraybuffer.cpp
+ $$PWD/qv4arraybuffer.cpp \
+ $$PWD/qv4dataview.cpp
HEADERS += \
$$PWD/qv4global_p.h \
@@ -91,7 +92,8 @@ HEADERS += \
$$PWD/qv4qmlextensions_p.h \
$$PWD/qv4vme_moth_p.h \
$$PWD/qv4profiling_p.h \
- $$PWD/qv4arraybuffer_p.h
+ $$PWD/qv4arraybuffer_p.h \
+ $$PWD/qv4dataview_p.h
}
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
new file mode 100644
index 0000000000..2750b2ceff
--- /dev/null
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -0,0 +1,316 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4dataview_p.h"
+#include "qv4arraybuffer_p.h"
+
+#include "qendian.h"
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(DataViewCtor);
+DEFINE_OBJECT_VTABLE(DataView);
+
+DataViewCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("DataView"))
+{
+ setVTable(staticVTable());
+}
+
+ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData)
+{
+ Scope scope(m->engine());
+ Scoped<ArrayBuffer> buffer(scope, callData->argument(0));
+ if (!buffer)
+ return scope.engine->currentContext()->throwTypeError();
+
+ double bo = callData->argc > 1 ? callData->args[1].toNumber() : 0;
+ uint byteOffset = (uint)bo;
+ uint bufferLength = buffer->d()->data->size;
+ double bl = callData->argc < 3 || callData->args[2].isUndefined() ? (bufferLength - bo) : callData->args[2].toNumber();
+ uint byteLength = (uint)bl;
+ if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength)
+ return scope.engine->currentContext()->throwRangeError(QStringLiteral("DataView: constructor arguments out of range"));
+
+ Scoped<DataView> a(scope, scope.engine->memoryManager->alloc<DataView>(scope.engine));
+ a->d()->buffer = buffer;
+ a->d()->byteLength = byteLength;
+ a->d()->byteOffset = byteOffset;
+ return a.asReturnedValue();
+
+}
+
+ReturnedValue DataViewCtor::call(Managed *that, CallData *callData)
+{
+ return construct(that, callData);
+}
+
+
+DataView::Data::Data(ExecutionEngine *e)
+ : Object::Data(e->dataViewClass),
+ buffer(0),
+ byteLength(0),
+ byteOffset(0)
+{
+}
+
+
+void DataView::markObjects(Managed *that, ExecutionEngine *e)
+{
+ DataView *v = static_cast<DataView *>(that);
+ v->d()->buffer->mark(e);
+}
+
+void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedObject o(scope);
+ ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3));
+ ctor->defineReadonlyProperty(engine->id_prototype, (o = this));
+ defineDefaultProperty(engine->id_constructor, (o = ctor));
+ defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0);
+ defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0);
+ defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0);
+
+ defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 0);
+ defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 0);
+ defineDefaultProperty(QStringLiteral("getInt16"), method_get<short>, 0);
+ defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 0);
+ defineDefaultProperty(QStringLiteral("getInt32"), method_get<int>, 0);
+ defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 0);
+ defineDefaultProperty(QStringLiteral("getFloat32"), method_getFloat<float>, 0);
+ defineDefaultProperty(QStringLiteral("getFloat64"), method_getFloat<double>, 0);
+
+ defineDefaultProperty(QStringLiteral("setInt8"), method_setChar<signed char>, 0);
+ defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 0);
+ defineDefaultProperty(QStringLiteral("setInt16"), method_set<short>, 0);
+ defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 0);
+ defineDefaultProperty(QStringLiteral("setInt32"), method_set<int>, 0);
+ defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0);
+ defineDefaultProperty(QStringLiteral("setFloat32"), method_setFloat<float>, 0);
+ defineDefaultProperty(QStringLiteral("setFloat64"), method_setFloat<double>, 0);
+}
+
+ReturnedValue DataViewPrototype::method_get_buffer(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<DataView> v(scope, ctx->d()->callData->thisObject);
+ if (!v)
+ return ctx->throwTypeError();
+
+ return Encode(v->d()->buffer->asReturnedValue());
+}
+
+ReturnedValue DataViewPrototype::method_get_byteLength(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<DataView> v(scope, ctx->d()->callData->thisObject);
+ if (!v)
+ return ctx->throwTypeError();
+
+ return Encode(v->d()->byteLength);
+}
+
+ReturnedValue DataViewPrototype::method_get_byteOffset(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<DataView> v(scope, ctx->d()->callData->thisObject);
+ if (!v)
+ return ctx->throwTypeError();
+
+ return Encode(v->d()->byteOffset);
+}
+
+template <typename T>
+ReturnedValue DataViewPrototype::method_getChar(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<DataView> v(scope, ctx->d()->callData->thisObject);
+ if (!v || ctx->d()->callData->argc < 1)
+ return ctx->throwTypeError();
+ double l = ctx->d()->callData->args[0].toNumber();
+ uint idx = (uint)l;
+ if (l != idx || idx + sizeof(T) > v->d()->byteLength)
+ return ctx->throwTypeError();
+ idx += v->d()->byteOffset;
+
+ T t = T(v->d()->buffer->d()->data->data()[idx]);
+
+ return Encode((int)t);
+}
+
+template <typename T>
+ReturnedValue DataViewPrototype::method_get(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<DataView> v(scope, ctx->d()->callData->thisObject);
+ if (!v || ctx->d()->callData->argc < 1)
+ return ctx->throwTypeError();
+ double l = ctx->d()->callData->args[0].toNumber();
+ uint idx = (uint)l;
+ if (l != idx || idx + sizeof(T) > v->d()->byteLength)
+ return ctx->throwTypeError();
+ idx += v->d()->byteOffset;
+
+ bool littleEndian = ctx->d()->callData->argc < 2 ? false : ctx->d()->callData->args[1].toBoolean();
+
+ T t = littleEndian
+ ? qFromLittleEndian<T>((uchar *)v->d()->buffer->d()->data->data() + idx)
+ : qFromBigEndian<T>((uchar *)v->d()->buffer->d()->data->data() + idx);
+
+ return Encode(t);
+}
+
+template <typename T>
+ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<DataView> v(scope, ctx->d()->callData->thisObject);
+ if (!v || ctx->d()->callData->argc < 1)
+ return ctx->throwTypeError();
+ double l = ctx->d()->callData->args[0].toNumber();
+ uint idx = (uint)l;
+ if (l != idx || idx + sizeof(T) > v->d()->byteLength)
+ return ctx->throwTypeError();
+ idx += v->d()->byteOffset;
+
+ bool littleEndian = ctx->d()->callData->argc < 2 ? false : ctx->d()->callData->args[1].toBoolean();
+
+ if (sizeof(T) == 4) {
+ // float
+ union {
+ uint i;
+ float f;
+ } u;
+ u.i = littleEndian
+ ? qFromLittleEndian<uint>((uchar *)v->d()->buffer->d()->data->data() + idx)
+ : qFromBigEndian<uint>((uchar *)v->d()->buffer->d()->data->data() + idx);
+ return Encode(u.f);
+ } else {
+ Q_ASSERT(sizeof(T) == 8);
+ union {
+ quint64 i;
+ double d;
+ } u;
+ u.i = littleEndian
+ ? qFromLittleEndian<quint64>((uchar *)v->d()->buffer->d()->data->data() + idx)
+ : qFromBigEndian<quint64>((uchar *)v->d()->buffer->d()->data->data() + idx);
+ return Encode(u.d);
+ }
+}
+
+template <typename T>
+ReturnedValue DataViewPrototype::method_setChar(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<DataView> v(scope, ctx->d()->callData->thisObject);
+ if (!v || ctx->d()->callData->argc < 1)
+ return ctx->throwTypeError();
+ double l = ctx->d()->callData->args[0].toNumber();
+ uint idx = (uint)l;
+ if (l != idx || idx + sizeof(T) > v->d()->byteLength)
+ return ctx->throwTypeError();
+ idx += v->d()->byteOffset;
+
+ int val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInt32() : 0;
+ v->d()->buffer->d()->data->data()[idx] = (char)val;
+
+ return Encode::undefined();
+}
+
+template <typename T>
+ReturnedValue DataViewPrototype::method_set(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<DataView> v(scope, ctx->d()->callData->thisObject);
+ if (!v || ctx->d()->callData->argc < 1)
+ return ctx->throwTypeError();
+ double l = ctx->d()->callData->args[0].toNumber();
+ uint idx = (uint)l;
+ if (l != idx || idx + sizeof(T) > v->d()->byteLength)
+ return ctx->throwTypeError();
+ idx += v->d()->byteOffset;
+
+ int val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInt32() : 0;
+
+ bool littleEndian = ctx->d()->callData->argc < 3 ? false : ctx->d()->callData->args[2].toBoolean();
+
+ if (littleEndian)
+ qToLittleEndian<T>(val, (uchar *)v->d()->buffer->d()->data->data() + idx);
+ else
+ qToBigEndian<T>(val, (uchar *)v->d()->buffer->d()->data->data() + idx);
+
+ return Encode::undefined();
+}
+
+template <typename T>
+ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<DataView> v(scope, ctx->d()->callData->thisObject);
+ if (!v || ctx->d()->callData->argc < 1)
+ return ctx->throwTypeError();
+ double l = ctx->d()->callData->args[0].toNumber();
+ uint idx = (uint)l;
+ if (l != idx || idx + sizeof(T) > v->d()->byteLength)
+ return ctx->throwTypeError();
+ idx += v->d()->byteOffset;
+
+ double val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toNumber() : qSNaN();
+ bool littleEndian = ctx->d()->callData->argc < 3 ? false : ctx->d()->callData->args[2].toBoolean();
+
+ if (sizeof(T) == 4) {
+ // float
+ union {
+ uint i;
+ float f;
+ } u;
+ u.f = val;
+ if (littleEndian)
+ qToLittleEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx);
+ else
+ qToBigEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx);
+ } else {
+ Q_ASSERT(sizeof(T) == 8);
+ union {
+ quint64 i;
+ double d;
+ } u;
+ u.d = val;
+ if (littleEndian)
+ qToLittleEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx);
+ else
+ qToBigEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx);
+ }
+ return Encode::undefined();
+}
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
new file mode 100644
index 0000000000..aa8a0201d9
--- /dev/null
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4DATAVIEW_H
+#define QV4DATAVIEW_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct ArrayBuffer;
+
+struct DataViewCtor: FunctionObject
+{
+ struct Data : FunctionObject::Data {
+ Data(ExecutionContext *scope);
+ };
+
+ V4_OBJECT(FunctionObject)
+
+ static ReturnedValue construct(Managed *m, CallData *callData);
+ static ReturnedValue call(Managed *that, CallData *callData);
+};
+
+struct DataView : Object
+{
+ struct Data : Object::Data {
+ Data(ExecutionEngine *e);
+ ArrayBuffer *buffer;
+ uint byteLength;
+ uint byteOffset;
+ };
+ V4_OBJECT(Object)
+
+ static void markObjects(Managed *that, ExecutionEngine *e);
+};
+
+struct DataViewPrototype: Object
+{
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_get_buffer(CallContext *ctx);
+ static ReturnedValue method_get_byteLength(CallContext *ctx);
+ static ReturnedValue method_get_byteOffset(CallContext *ctx);
+ template <typename T>
+ static ReturnedValue method_getChar(CallContext *ctx);
+ template <typename T>
+ static ReturnedValue method_get(CallContext *ctx);
+ template <typename T>
+ static ReturnedValue method_getFloat(CallContext *ctx);
+ template <typename T>
+ static ReturnedValue method_setChar(CallContext *ctx);
+ template <typename T>
+ static ReturnedValue method_set(CallContext *ctx);
+ template <typename T>
+ static ReturnedValue method_setFloat(CallContext *ctx);
+};
+
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 239bb85167..454928252f 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -62,6 +62,7 @@
#include "qv4qmlextensions_p.h"
#include "qv4memberdata_p.h"
#include "qv4arraybuffer_p.h"
+#include "qv4dataview_p.h"
#include <QtCore/QTextStream>
#include <QDateTime>
@@ -254,6 +255,8 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
id_destroy = newIdentifier(QStringLiteral("destroy"));
id_valueOf = newIdentifier(QStringLiteral("valueOf"));
id_byteLength = newIdentifier(QStringLiteral("byteLength"));
+ id_byteOffset = newIdentifier(QStringLiteral("byteOffset"));
+ id_buffer = newIdentifier(QStringLiteral("buffer"));
memberDataClass = InternalClass::create(this, MemberData::staticVTable(), 0);
@@ -369,10 +372,15 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
// typed arrays
arrayBufferCtor = memoryManager->alloc<ArrayBufferCtor>(rootContext);
- Scoped<ArrayBufferPrototype> arrayBufferPrototype(scope, memoryManager->alloc<ArrayBufferPrototype>(arrayBufferClass));
+ Scoped<ArrayBufferPrototype> arrayBufferPrototype(scope, memoryManager->alloc<ArrayBufferPrototype>(objectClass));
arrayBufferPrototype->init(this, arrayBufferCtor.asObject());
arrayBufferClass = InternalClass::create(this, ArrayBuffer::staticVTable(), arrayBufferPrototype);
+ dataViewCtor = memoryManager->alloc<DataViewCtor>(rootContext);
+ Scoped<DataViewPrototype> dataViewPrototype(scope, memoryManager->alloc<DataViewPrototype>(objectClass));
+ dataViewPrototype->init(this, dataViewCtor.asObject());
+ dataViewClass = InternalClass::create(this, DataView::staticVTable(), dataViewPrototype);
+
//
// set up the global object
//
@@ -397,6 +405,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
globalObject->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor);
globalObject->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor);
globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), arrayBufferCtor);
+ globalObject->defineDefaultProperty(QStringLiteral("DataView"), dataViewCtor);
ScopedObject o(scope);
globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(QV4::InternalClass::create(this, MathObject::staticVTable(), objectPrototype))));
globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(QV4::InternalClass::create(this, JsonObject::staticVTable(), objectPrototype))));
@@ -899,6 +908,8 @@ void ExecutionEngine::markObjects()
id_destroy->mark(this);
id_valueOf->mark(this);
id_byteLength->mark(this);
+ id_byteOffset->mark(this);
+ id_buffer->mark(this);
objectCtor.mark(this);
stringCtor.mark(this);
@@ -916,6 +927,7 @@ void ExecutionEngine::markObjects()
typeErrorCtor.mark(this);
uRIErrorCtor.mark(this);
arrayBufferCtor.mark(this);
+ dataViewCtor.mark(this);
sequencePrototype.mark(this);
exceptionValue.mark(this);
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index d2d36e9e19..ba96649ab9 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -190,6 +190,7 @@ public:
Value uRIErrorCtor;
Value sequencePrototype;
Value arrayBufferCtor;
+ Value dataViewCtor;
InternalClassPool *classPool;
InternalClass *emptyClass;
@@ -226,6 +227,7 @@ public:
InternalClass *memberDataClass;
InternalClass *arrayBufferClass;
+ InternalClass *dataViewClass;
EvalFunction *evalFunction;
FunctionObject *thrower;
@@ -266,6 +268,8 @@ public:
StringValue id_destroy;
StringValue id_valueOf;
StringValue id_byteLength;
+ StringValue id_byteOffset;
+ StringValue id_buffer;
QSet<CompiledData::CompilationUnit*> compilationUnits;