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>
This commit is contained in:
parent
d9e70d1a49
commit
a2c97406ca
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -802,8 +802,8 @@ void tst_QJSEngine::globalObjectProperties_enumerate()
|
|||
<< "unescape"
|
||||
<< "SyntaxError"
|
||||
<< "undefined"
|
||||
// JavaScriptCore
|
||||
<< "JSON"
|
||||
<< "ArrayBuffer"
|
||||
;
|
||||
QSet<QString> actualNames;
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue