aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2014-09-10 14:50:28 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2014-10-29 09:06:56 +0100
commita2c97406cad22a73a4c68303ef54128cf756f577 (patch)
tree274a68bea63c6934be4e2b82147adec74759da41 /src/qml
parentd9e70d1a49af347f79db7e64bdd8e2e8083a77b5 (diff)
Implement ArrayBuffer
This is the first class required to support typed arrays in our JS engine. Change-Id: I0fe1e1ca430769c171912dda207cfae772e9b9db 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/qv4arraybuffer.cpp164
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h93
-rw-r--r--src/qml/jsruntime/qv4engine.cpp13
-rw-r--r--src/qml/jsruntime/qv4engine_p.h4
5 files changed, 278 insertions, 2 deletions
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index c27aaa90d8..566d2563cc 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -42,7 +42,8 @@ SOURCES += \
$$PWD/qv4qobjectwrapper.cpp \
$$PWD/qv4qmlextensions.cpp \
$$PWD/qv4vme_moth.cpp \
- $$PWD/qv4profiling.cpp
+ $$PWD/qv4profiling.cpp \
+ $$PWD/qv4arraybuffer.cpp
HEADERS += \
$$PWD/qv4global_p.h \
@@ -89,7 +90,8 @@ HEADERS += \
$$PWD/qv4qobjectwrapper_p.h \
$$PWD/qv4qmlextensions_p.h \
$$PWD/qv4vme_moth_p.h \
- $$PWD/qv4profiling_p.h
+ $$PWD/qv4profiling_p.h \
+ $$PWD/qv4arraybuffer_p.h
}
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
new file mode 100644
index 0000000000..9d24044d7c
--- /dev/null
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** 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 "qv4arraybuffer_p.h"
+#include "qv4typedarray_p.h"
+#include "qv4dataview_p.h"
+
+using namespace QV4;
+
+DEFINE_OBJECT_VTABLE(ArrayBufferCtor);
+DEFINE_OBJECT_VTABLE(ArrayBuffer);
+
+ArrayBufferCtor::Data::Data(ExecutionContext *scope)
+ : FunctionObject::Data(scope, QStringLiteral("ArrayBuffer"))
+{
+ setVTable(staticVTable());
+}
+
+ReturnedValue ArrayBufferCtor::construct(Managed *m, CallData *callData)
+{
+ ExecutionEngine *v4 = m->engine();
+
+ Scope scope(v4);
+ ScopedValue l(scope, callData->argument(0));
+ double dl = l->toInteger();
+ if (v4->hasException)
+ return Encode::undefined();
+ uint len = (uint)qBound(0., dl, (double)UINT_MAX);
+ if (len != dl)
+ return v4->currentContext()->throwRangeError(QLatin1String("ArrayBuffer constructor: invalid length"));
+
+ Scoped<ArrayBuffer> a(scope, v4->memoryManager->alloc<ArrayBuffer>(v4, len));
+ return a.asReturnedValue();
+}
+
+
+ReturnedValue ArrayBufferCtor::call(Managed *that, CallData *callData)
+{
+ return construct(that, callData);
+}
+
+ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx)
+{
+ QV4::Scope scope(ctx);
+ QV4::Scoped<TypedArray> a(scope, ctx->argument(0));
+ if (!!a)
+ return Encode(true);
+ QV4::Scoped<DataView> v(scope, ctx->argument(0));
+ if (!!v)
+ return Encode(true);
+ return Encode(true);
+}
+
+
+ArrayBuffer::Data::Data(ExecutionEngine *e, int length)
+ : Object::Data(e->arrayBufferClass)
+{
+ data = QTypedArrayData<char>::allocate(length + 1);
+ if (!data) {
+ data = 0;
+ e->currentContext()->throwRangeError(QStringLiteral("ArrayBuffer: out of memory"));
+ return;
+ }
+ data->size = length;
+ memset(data->data(), 0, length + 1);
+}
+
+QByteArray ArrayBuffer::asByteArray() const
+{
+ QByteArrayDataPtr ba = { d()->data };
+ ba.ptr->ref.ref();
+ return QByteArray(ba);
+}
+
+void ArrayBuffer::destroy(Managed *m)
+{
+ ArrayBuffer *b = static_cast<ArrayBuffer *>(m);
+ if (!b->d()->data->ref.deref())
+ QTypedArrayData<char>::deallocate(b->d()->data);
+}
+
+
+void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedObject o(scope);
+ ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(1));
+ ctor->defineReadonlyProperty(engine->id_prototype, (o = this));
+ ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1);
+ defineDefaultProperty(engine->id_constructor, (o = ctor));
+ defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0);
+ defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
+}
+
+ReturnedValue ArrayBufferPrototype::method_get_byteLength(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<ArrayBuffer> v(scope, ctx->d()->callData->thisObject);
+ if (!v)
+ return ctx->throwTypeError();
+
+ return Encode(v->d()->data->size);
+}
+
+ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx)
+{
+ Scope scope(ctx);
+ Scoped<ArrayBuffer> a(scope, ctx->d()->callData->thisObject);
+ if (!a)
+ return ctx->throwTypeError();
+
+ double start = ctx->d()->callData->argc > 0 ? ctx->d()->callData->args[0].toInteger() : 0;
+ double end = (ctx->d()->callData->argc < 2 || ctx->d()->callData->args[1].isUndefined()) ?
+ a->d()->data->size : ctx->d()->callData->args[1].toInteger();
+ if (scope.engine->hasException)
+ return Encode::undefined();
+
+ double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size);
+ double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size);
+
+ Scoped<FunctionObject> constructor(scope, a->get(scope.engine->id_constructor));
+ if (!constructor)
+ return ctx->throwTypeError();
+
+ ScopedCallData callData(scope, 1);
+ double newLen = qMax(final - first, 0.);
+ callData->args[0] = QV4::Encode(newLen);
+ QV4::Scoped<ArrayBuffer> newBuffer(scope, constructor->construct(callData));
+ if (!newBuffer || newBuffer->d()->data->size < (int)newLen)
+ return scope.engine->currentContext()->throwTypeError();
+
+ memcpy(newBuffer->d()->data->data(), a->d()->data->data() + (uint)first, newLen);
+
+ return newBuffer.asReturnedValue();
+}
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
new file mode 100644
index 0000000000..57ee34e570
--- /dev/null
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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 QV4ARRAYBUFFER_H
+#define QV4ARRAYBUFFER_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct ArrayBufferCtor: 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);
+
+ static ReturnedValue method_isView(CallContext *ctx);
+
+};
+
+struct ArrayBuffer : Object
+{
+ struct Data : Object::Data {
+ Data(ExecutionEngine *e, int length);
+ QTypedArrayData<char> *data;
+ };
+ V4_OBJECT(Object)
+
+ QByteArray asByteArray() const;
+ uint byteLength() const { return d()->data->size; }
+ char *data() {
+ // ### detach if refcount > 1
+ return d()->data->data();
+ }
+ const char *constData() {
+ // ### detach if refcount > 1
+ return d()->data->data();
+ }
+
+ static void destroy(Managed *m);
+};
+
+struct ArrayBufferPrototype: Object
+{
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_get_byteLength(CallContext *ctx);
+ static ReturnedValue method_slice(CallContext *ctx);
+};
+
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index ea075f9cbd..239bb85167 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -61,6 +61,7 @@
#include "qv4qobjectwrapper_p.h"
#include "qv4qmlextensions_p.h"
#include "qv4memberdata_p.h"
+#include "qv4arraybuffer_p.h"
#include <QtCore/QTextStream>
#include <QDateTime>
@@ -252,6 +253,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
id_toString = newIdentifier(QStringLiteral("toString"));
id_destroy = newIdentifier(QStringLiteral("destroy"));
id_valueOf = newIdentifier(QStringLiteral("valueOf"));
+ id_byteLength = newIdentifier(QStringLiteral("byteLength"));
memberDataClass = InternalClass::create(this, MemberData::staticVTable(), 0);
@@ -363,6 +365,14 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
static_cast<VariantPrototype *>(variantPrototype.getPointer())->init();
static_cast<SequencePrototype *>(sequencePrototype.managed())->init();
+
+ // typed arrays
+
+ arrayBufferCtor = memoryManager->alloc<ArrayBufferCtor>(rootContext);
+ Scoped<ArrayBufferPrototype> arrayBufferPrototype(scope, memoryManager->alloc<ArrayBufferPrototype>(arrayBufferClass));
+ arrayBufferPrototype->init(this, arrayBufferCtor.asObject());
+ arrayBufferClass = InternalClass::create(this, ArrayBuffer::staticVTable(), arrayBufferPrototype);
+
//
// set up the global object
//
@@ -386,6 +396,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), syntaxErrorCtor);
globalObject->defineDefaultProperty(QStringLiteral("TypeError"), typeErrorCtor);
globalObject->defineDefaultProperty(QStringLiteral("URIError"), uRIErrorCtor);
+ globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), arrayBufferCtor);
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))));
@@ -887,6 +898,7 @@ void ExecutionEngine::markObjects()
id_toString->mark(this);
id_destroy->mark(this);
id_valueOf->mark(this);
+ id_byteLength->mark(this);
objectCtor.mark(this);
stringCtor.mark(this);
@@ -903,6 +915,7 @@ void ExecutionEngine::markObjects()
syntaxErrorCtor.mark(this);
typeErrorCtor.mark(this);
uRIErrorCtor.mark(this);
+ arrayBufferCtor.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 a4a40c2f41..d2d36e9e19 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -189,6 +189,7 @@ public:
Value typeErrorCtor;
Value uRIErrorCtor;
Value sequencePrototype;
+ Value arrayBufferCtor;
InternalClassPool *classPool;
InternalClass *emptyClass;
@@ -224,6 +225,8 @@ public:
InternalClass *variantClass;
InternalClass *memberDataClass;
+ InternalClass *arrayBufferClass;
+
EvalFunction *evalFunction;
FunctionObject *thrower;
@@ -262,6 +265,7 @@ public:
StringValue id_toString;
StringValue id_destroy;
StringValue id_valueOf;
+ StringValue id_byteLength;
QSet<CompiledData::CompilationUnit*> compilationUnits;