aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-08-24 12:03:12 +0200
committerLars Knoll <lars.knoll@qt.io>2018-08-25 08:30:00 +0000
commit860807b22ab4f7d1c55ce69bb7711dcc777ceefa (patch)
tree5fbec31ef6ec7bc87353dc51fae0124ef3838753 /src
parentdd9a6999b674a9197eabbea96b1e5a34c22a8aab (diff)
Implement support for SharedArrayBuffer
We'll still need to hook this up with Worker threads to become useful. Change-Id: Iedae7307edd76368aeba163731856ebe9b32c6b6 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp120
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h72
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp2
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp5
-rw-r--r--src/qml/jsruntime/qv4engine_p.h4
-rw-r--r--src/qml/jsruntime/qv4global_p.h2
7 files changed, 164 insertions, 43 deletions
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index dc8bce12a0..9b5a983fdf 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -45,14 +45,46 @@
using namespace QV4;
+DEFINE_OBJECT_VTABLE(SharedArrayBufferCtor);
DEFINE_OBJECT_VTABLE(ArrayBufferCtor);
+DEFINE_OBJECT_VTABLE(SharedArrayBuffer);
DEFINE_OBJECT_VTABLE(ArrayBuffer);
+void Heap::SharedArrayBufferCtor::init(QV4::ExecutionContext *scope)
+{
+ Heap::FunctionObject::init(scope, QStringLiteral("SharedArrayBuffer"));
+}
+
void Heap::ArrayBufferCtor::init(QV4::ExecutionContext *scope)
{
Heap::FunctionObject::init(scope, QStringLiteral("ArrayBuffer"));
}
+ReturnedValue SharedArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
+{
+ Scope scope(f);
+ if (newTarget->isUndefined())
+ return scope.engine->throwTypeError();
+
+ qint64 len = argc ? argv[0].toIndex() : 0;
+ if (scope.engine->hasException)
+ return Encode::undefined();
+ if (len < 0 || len >= INT_MAX)
+ return scope.engine->throwRangeError(QStringLiteral("SharedArrayBuffer: Invalid length."));
+
+ Scoped<SharedArrayBuffer> a(scope, scope.engine->memoryManager->allocate<SharedArrayBuffer>(len));
+ if (scope.engine->hasException)
+ return Encode::undefined();
+
+ return a->asReturnedValue();
+}
+
+ReturnedValue SharedArrayBufferCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
+{
+ return f->engine()->throwTypeError();
+}
+
+
ReturnedValue ArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *)
{
ExecutionEngine *v4 = f->engine();
@@ -73,12 +105,6 @@ ReturnedValue ArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f,
return a->asReturnedValue();
}
-
-ReturnedValue ArrayBufferCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
-{
- return f->engine()->throwTypeError();
-}
-
ReturnedValue ArrayBufferCtor::method_isView(const FunctionObject *, const Value *, const Value *argv, int argc)
{
if (argc < 1)
@@ -92,7 +118,7 @@ ReturnedValue ArrayBufferCtor::method_isView(const FunctionObject *, const Value
}
-void Heap::ArrayBuffer::init(size_t length)
+void Heap::SharedArrayBuffer::init(size_t length)
{
Object::init();
if (length < UINT_MAX)
@@ -103,16 +129,18 @@ void Heap::ArrayBuffer::init(size_t length)
}
data->size = int(length);
memset(data->data(), 0, length + 1);
+ isShared = true;
}
-void Heap::ArrayBuffer::init(const QByteArray& array)
+void Heap::SharedArrayBuffer::init(const QByteArray& array)
{
Object::init();
data = const_cast<QByteArray&>(array).data_ptr();
data->ref.ref();
+ isShared = true;
}
-void Heap::ArrayBuffer::destroy()
+void Heap::SharedArrayBuffer::destroy()
{
if (data && !data->ref.deref())
QTypedArrayData<char>::deallocate(data);
@@ -145,66 +173,100 @@ void ArrayBuffer::detach() {
}
-void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
+void SharedArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
{
Scope scope(engine);
ScopedObject o(scope);
ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
- ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1);
ctor->addSymbolSpecies();
defineDefaultProperty(engine->id_constructor(), (o = ctor));
defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr);
defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
- defineDefaultProperty(QStringLiteral("toString"), method_toString, 0);
- ScopedString name(scope, engine->newString(QStringLiteral("ArrayBuffer")));
+ ScopedString name(scope, engine->newString(QStringLiteral("SharedArrayBuffer")));
defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), name);
}
-ReturnedValue ArrayBufferPrototype::method_get_byteLength(const FunctionObject *b, const Value *thisObject, const Value *, int)
+ReturnedValue SharedArrayBufferPrototype::method_get_byteLength(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
- const ArrayBuffer *a = thisObject->as<ArrayBuffer>();
- if (!a || a->isDetachedBuffer() || a->isSharedArrayBuffer())
+ const SharedArrayBuffer *a = thisObject->as<SharedArrayBuffer>();
+ if (!a || a->isDetachedBuffer() || !a->isSharedArrayBuffer())
return b->engine()->throwTypeError();
return Encode(a->d()->data->size);
}
-ReturnedValue ArrayBufferPrototype::method_slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+ReturnedValue SharedArrayBufferPrototype::method_slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
{
- ExecutionEngine *v4 = b->engine();
- const ArrayBuffer *a = thisObject->as<ArrayBuffer>();
- if (!a || a->isDetachedBuffer() || a->isSharedArrayBuffer())
- return v4->throwTypeError();
+ return slice(b, thisObject, argv, argc, true);
+}
+
+ReturnedValue SharedArrayBufferPrototype::slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc, bool shared)
+{
+ Scope scope(b);
+ const SharedArrayBuffer *a = thisObject->as<SharedArrayBuffer>();
+ if (!a || a->isDetachedBuffer() || (a->isSharedArrayBuffer() != shared))
+ return scope.engine->throwTypeError();
double start = argc > 0 ? argv[0].toInteger() : 0;
double end = (argc < 2 || argv[1].isUndefined()) ?
a->d()->data->size : argv[1].toInteger();
- if (v4->hasException)
+ if (scope.hasException())
return QV4::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);
- Scope scope(v4);
- const FunctionObject *constructor = a->speciesConstructor(scope, scope.engine->arrayBufferCtor());
+ const FunctionObject *constructor = a->speciesConstructor(scope, shared ? scope.engine->sharedArrayBufferCtor() : scope.engine->arrayBufferCtor());
if (!constructor)
- return v4->throwTypeError();
+ return scope.engine->throwTypeError();
double newLen = qMax(final - first, 0.);
ScopedValue argument(scope, QV4::Encode(newLen));
- QV4::Scoped<ArrayBuffer> newBuffer(scope, constructor->callAsConstructor(argument, 1));
+ QV4::Scoped<SharedArrayBuffer> newBuffer(scope, constructor->callAsConstructor(argument, 1));
if (!newBuffer || newBuffer->d()->data->size < (int)newLen ||
- newBuffer->isDetachedBuffer() || newBuffer->isSharedArrayBuffer() ||
+ newBuffer->isDetachedBuffer() || (newBuffer->isSharedArrayBuffer() != shared) ||
newBuffer->sameValue(*a) ||
a->isDetachedBuffer())
- return v4->throwTypeError();
+ return scope.engine->throwTypeError();
memcpy(newBuffer->d()->data->data(), a->d()->data->data() + (uint)first, newLen);
return newBuffer->asReturnedValue();
}
+
+void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
+{
+ Scope scope(engine);
+ ScopedObject o(scope);
+ ctor->defineReadonlyConfigurableProperty(engine->id_length(), Primitive::fromInt32(1));
+ ctor->defineReadonlyProperty(engine->id_prototype(), (o = this));
+ ctor->defineDefaultProperty(QStringLiteral("isView"), ArrayBufferCtor::method_isView, 1);
+ ctor->addSymbolSpecies();
+
+ defineDefaultProperty(engine->id_constructor(), (o = ctor));
+ defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, nullptr);
+ defineDefaultProperty(QStringLiteral("slice"), method_slice, 2);
+ defineDefaultProperty(QStringLiteral("toString"), method_toString, 0);
+ ScopedString name(scope, engine->newString(QStringLiteral("ArrayBuffer")));
+ defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), name);
+}
+
+ReturnedValue ArrayBufferPrototype::method_get_byteLength(const FunctionObject *f, const Value *thisObject, const Value *, int)
+{
+ const ArrayBuffer *a = thisObject->as<ArrayBuffer>();
+ if (!a || a->isDetachedBuffer() || a->isSharedArrayBuffer())
+ return f->engine()->throwTypeError();
+
+ return Encode(a->d()->data->size);
+}
+
+ReturnedValue ArrayBufferPrototype::method_slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
+{
+ return slice(b, thisObject, argv, argc, false);
+}
+
ReturnedValue ArrayBufferPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
{
ExecutionEngine *v4 = b->engine();
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index 036d141c2f..8344fa2554 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtQml module of the Qt Toolkit.
@@ -59,59 +59,107 @@ namespace QV4 {
namespace Heap {
-struct ArrayBufferCtor : FunctionObject {
+struct SharedArrayBufferCtor : FunctionObject {
void init(QV4::ExecutionContext *scope);
};
-struct Q_QML_PRIVATE_EXPORT ArrayBuffer : Object {
+struct ArrayBufferCtor : SharedArrayBufferCtor {
+ void init(QV4::ExecutionContext *scope);
+};
+
+struct Q_QML_PRIVATE_EXPORT SharedArrayBuffer : Object {
void init(size_t length);
void init(const QByteArray& array);
void destroy();
QTypedArrayData<char> *data;
+ bool isShared;
uint byteLength() const { return data ? data->size : 0; }
+ bool isDetachedBuffer() const { return !data; }
+ bool isSharedArrayBuffer() const { return isShared; }
+};
+
+struct Q_QML_PRIVATE_EXPORT ArrayBuffer : SharedArrayBuffer {
+ void init(size_t length) {
+ SharedArrayBuffer::init(length);
+ isShared = false;
+ }
+ void init(const QByteArray& array) {
+ SharedArrayBuffer::init(array);
+ isShared = false;
+ }
void detachArrayBuffer() {
if (data && !data->ref.deref())
QTypedArrayData<char>::deallocate(data);
data = nullptr;
}
- bool isDetachedBuffer() const { return !data; }
- bool isSharedArrayBuffer() const { return false; }
};
+
}
-struct ArrayBufferCtor: FunctionObject
+struct SharedArrayBufferCtor : FunctionObject
{
- V4_OBJECT2(ArrayBufferCtor, FunctionObject)
+ V4_OBJECT2(SharedArrayBufferCtor, FunctionObject)
static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
+};
+
+struct ArrayBufferCtor : SharedArrayBufferCtor
+{
+ V4_OBJECT2(ArrayBufferCtor, SharedArrayBufferCtor)
+
+ static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
static ReturnedValue method_isView(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+};
+struct Q_QML_PRIVATE_EXPORT SharedArrayBuffer : Object
+{
+ V4_OBJECT2(SharedArrayBuffer, Object)
+ V4_NEEDS_DESTROY
+ V4_PROTOTYPE(sharedArrayBufferPrototype)
+
+ QByteArray asByteArray() const;
+ uint byteLength() const { return d()->byteLength(); }
+ char *data() { Q_ASSERT(d()->data); return d()->data->data(); }
+ const char *constData() { Q_ASSERT(d()->data); return d()->data->data(); }
+
+ bool isShared() { return d()->data->ref.isShared(); }
+ bool isDetachedBuffer() const { return !d()->data; }
+ bool isSharedArrayBuffer() const { return d()->isShared; }
};
-struct Q_QML_PRIVATE_EXPORT ArrayBuffer : Object
+struct Q_QML_PRIVATE_EXPORT ArrayBuffer : SharedArrayBuffer
{
- V4_OBJECT2(ArrayBuffer, Object)
+ V4_OBJECT2(ArrayBuffer, SharedArrayBuffer)
V4_NEEDS_DESTROY
V4_PROTOTYPE(arrayBufferPrototype)
QByteArray asByteArray() const;
uint byteLength() const { return d()->byteLength(); }
char *data() { detach(); return d()->data ? d()->data->data() : nullptr; }
+ // ### is that detach needed?
const char *constData() { detach(); return d()->data ? d()->data->data() : nullptr; }
bool isShared() { return d()->data && d()->data->ref.isShared(); }
- bool isDetachedBuffer() const { return !d()->data; }
- bool isSharedArrayBuffer() const { return false; }
void detach();
void detachArrayBuffer() { d()->detachArrayBuffer(); }
};
-struct ArrayBufferPrototype: Object
+struct SharedArrayBufferPrototype : Object
+{
+ void init(ExecutionEngine *engine, Object *ctor);
+
+ static ReturnedValue method_get_byteLength(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+ static ReturnedValue method_slice(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
+
+ static ReturnedValue slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc, bool shared);
+};
+
+struct ArrayBufferPrototype : SharedArrayBufferPrototype
{
void init(ExecutionEngine *engine, Object *ctor);
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index 3f0e2fd1a7..d52b9488ac 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -75,7 +75,7 @@ static uint toIndex(ExecutionEngine *e, const Value &v)
ReturnedValue DataViewCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
{
Scope scope(f->engine());
- Scoped<ArrayBuffer> buffer(scope, argc ? argv[0] : Primitive::undefinedValue());
+ Scoped<SharedArrayBuffer> buffer(scope, argc ? argv[0] : Primitive::undefinedValue());
if (!newTarget || !buffer)
return scope.engine->throwTypeError();
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 6a9f865c0f..199a6f9f80 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -64,7 +64,7 @@ struct DataViewCtor : FunctionObject {
};
#define DataViewMembers(class, Member) \
- Member(class, Pointer, ArrayBuffer *, buffer) \
+ Member(class, Pointer, SharedArrayBuffer *, buffer) \
Member(class, NoMark, uint, byteLength) \
Member(class, NoMark, uint, byteOffset)
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 5ccf3d4f6e..c1a4b67d60 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -494,6 +494,10 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
// typed arrays
+ jsObjects[SharedArrayBuffer_Ctor] = memoryManager->allocate<SharedArrayBufferCtor>(global);
+ jsObjects[SharedArrayBufferProto] = memoryManager->allocate<SharedArrayBufferPrototype>();
+ static_cast<SharedArrayBufferPrototype *>(sharedArrayBufferPrototype())->init(this, sharedArrayBufferCtor());
+
jsObjects[ArrayBuffer_Ctor] = memoryManager->allocate<ArrayBufferCtor>(global);
jsObjects[ArrayBufferProto] = memoryManager->allocate<ArrayBufferPrototype>();
static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor());
@@ -539,6 +543,7 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
globalObject->defineDefaultProperty(QStringLiteral("TypeError"), *typeErrorCtor());
globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor());
+ globalObject->defineDefaultProperty(QStringLiteral("SharedArrayBuffer"), *sharedArrayBufferCtor());
globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor());
globalObject->defineDefaultProperty(QStringLiteral("Set"), *setCtor());
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index e11e607bd1..0f4a4a75a2 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -162,6 +162,7 @@ public:
#if QT_CONFIG(qml_sequence_object)
SequenceProto,
#endif
+ SharedArrayBufferProto,
ArrayBufferProto,
DataViewProto,
SetProto,
@@ -193,6 +194,7 @@ public:
SyntaxError_Ctor,
TypeError_Ctor,
URIError_Ctor,
+ SharedArrayBuffer_Ctor,
ArrayBuffer_Ctor,
DataView_Ctor,
Set_Ctor,
@@ -229,6 +231,7 @@ public:
FunctionObject *syntaxErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SyntaxError_Ctor); }
FunctionObject *typeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + TypeError_Ctor); }
FunctionObject *uRIErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + URIError_Ctor); }
+ FunctionObject *sharedArrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SharedArrayBuffer_Ctor); }
FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); }
FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); }
FunctionObject *setCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Set_Ctor); }
@@ -262,6 +265,7 @@ public:
Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); }
#endif
+ Object *sharedArrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + SharedArrayBufferProto); }
Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); }
Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); }
Object *setPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetProto); }
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index e3b3423a9d..b4dac505cd 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -190,6 +190,7 @@ namespace Heap {
struct RegExp;
struct EvalFunction;
+ struct SharedArrayBuffer;
struct ArrayBuffer;
struct DataView;
struct TypedArray;
@@ -236,6 +237,7 @@ struct RegExpObject;
struct RegExp;
struct EvalFunction;
+struct SharedArrayBuffer;
struct ArrayBuffer;
struct DataView;
struct TypedArray;