1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39#include "qv4arraybuffer_p.h"
40#include "qv4typedarray_p.h"
41#include "qv4dataview_p.h"
42#include "qv4string_p.h"
43#include "qv4jscall_p.h"
44#include "qv4symbol_p.h"
45
46using namespace QV4;
47
48DEFINE_OBJECT_VTABLE(SharedArrayBufferCtor);
49DEFINE_OBJECT_VTABLE(ArrayBufferCtor);
50DEFINE_OBJECT_VTABLE(SharedArrayBuffer);
51DEFINE_OBJECT_VTABLE(ArrayBuffer);
52
53void Heap::SharedArrayBufferCtor::init(QV4::ExecutionContext *scope)
54{
55 Heap::FunctionObject::init(scope, QStringLiteral("SharedArrayBuffer"));
56}
57
58void Heap::ArrayBufferCtor::init(QV4::ExecutionContext *scope)
59{
60 Heap::FunctionObject::init(scope, QStringLiteral("ArrayBuffer"));
61}
62
63ReturnedValue SharedArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
64{
65 Scope scope(f);
66 if (newTarget->isUndefined())
67 return scope.engine->throwTypeError();
68
69 qint64 len = argc ? argv[0].toIndex() : 0;
70 if (scope.engine->hasException)
71 return Encode::undefined();
72 if (len < 0 || len >= INT_MAX)
73 return scope.engine->throwRangeError(QStringLiteral("SharedArrayBuffer: Invalid length."));
74
75 Scoped<SharedArrayBuffer> a(scope, scope.engine->memoryManager->allocate<SharedArrayBuffer>(args: len));
76 if (scope.engine->hasException)
77 return Encode::undefined();
78
79 return a->asReturnedValue();
80}
81
82ReturnedValue SharedArrayBufferCtor::virtualCall(const FunctionObject *f, const Value *, const Value *, int)
83{
84 return f->engine()->throwTypeError();
85}
86
87
88ReturnedValue ArrayBufferCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget)
89{
90 ExecutionEngine *v4 = f->engine();
91 Scope scope(v4);
92
93 ScopedValue l(scope, argc ? argv[0] : Value::undefinedValue());
94 double dl = l->toInteger();
95 if (v4->hasException)
96 return Encode::undefined();
97 uint len = (uint)qBound(min: 0., val: dl, max: (double)UINT_MAX);
98 if (len != dl)
99 return v4->throwRangeError(message: QLatin1String("ArrayBuffer constructor: invalid length"));
100
101 Scoped<ArrayBuffer> a(scope, v4->newArrayBuffer(length: len));
102 if (newTarget->heapObject() != f->heapObject() && newTarget->isFunctionObject()) {
103 const FunctionObject *nt = static_cast<const FunctionObject *>(newTarget);
104 ScopedObject o(scope, nt->protoProperty());
105 if (o)
106 a->setPrototypeOf(o);
107 }
108 if (scope.engine->hasException)
109 return Encode::undefined();
110
111 return a->asReturnedValue();
112}
113
114ReturnedValue ArrayBufferCtor::method_isView(const FunctionObject *, const Value *, const Value *argv, int argc)
115{
116 if (argc < 1)
117 return Encode(false);
118
119 if (argv[0].as<TypedArray>() ||
120 argv[0].as<DataView>())
121 return Encode(true);
122
123 return Encode(false);
124}
125
126
127void Heap::SharedArrayBuffer::init(size_t length)
128{
129 Object::init();
130 if (length < UINT_MAX)
131 data = QTypedArrayData<char>::allocate(capacity: length + 1);
132 if (!data) {
133 internalClass->engine->throwRangeError(QStringLiteral("ArrayBuffer: out of memory"));
134 return;
135 }
136 data->size = int(length);
137 memset(s: data->data(), c: 0, n: length + 1);
138 isShared = true;
139}
140
141void Heap::SharedArrayBuffer::init(const QByteArray& array)
142{
143 Object::init();
144 data = const_cast<QByteArray&>(array).data_ptr();
145 data->ref.ref();
146 isShared = true;
147}
148
149void Heap::SharedArrayBuffer::destroy()
150{
151 if (data && !data->ref.deref())
152 QTypedArrayData<char>::deallocate(data);
153 Object::destroy();
154}
155
156QByteArray ArrayBuffer::asByteArray() const
157{
158 QByteArrayDataPtr ba = { .ptr: d()->data };
159 ba.ptr->ref.ref();
160 return QByteArray(ba);
161}
162
163void ArrayBuffer::detach() {
164 if (!d()->data->ref.isShared())
165 return;
166
167 QTypedArrayData<char> *oldData = d()->data;
168
169 d()->data = QTypedArrayData<char>::allocate(capacity: oldData->size + 1);
170 if (!d()->data) {
171 engine()->throwRangeError(QStringLiteral("ArrayBuffer: out of memory"));
172 return;
173 }
174
175 memcpy(dest: d()->data->data(), src: oldData->data(), n: oldData->size + 1);
176
177 if (!oldData->ref.deref())
178 QTypedArrayData<char>::deallocate(data: oldData);
179}
180
181
182void SharedArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
183{
184 Scope scope(engine);
185 ScopedObject o(scope);
186 ctor->defineReadonlyConfigurableProperty(name: engine->id_length(), value: Value::fromInt32(i: 1));
187 ctor->defineReadonlyProperty(name: engine->id_prototype(), value: (o = this));
188 ctor->addSymbolSpecies();
189
190 defineDefaultProperty(name: engine->id_constructor(), value: (o = ctor));
191 defineAccessorProperty(QStringLiteral("byteLength"), getter: method_get_byteLength, setter: nullptr);
192 defineDefaultProperty(QStringLiteral("slice"), code: method_slice, argumentCount: 2);
193 ScopedString name(scope, engine->newString(QStringLiteral("SharedArrayBuffer")));
194 defineReadonlyConfigurableProperty(name: scope.engine->symbol_toStringTag(), value: name);
195}
196
197ReturnedValue SharedArrayBufferPrototype::method_get_byteLength(const FunctionObject *b, const Value *thisObject, const Value *, int)
198{
199 const SharedArrayBuffer *a = thisObject->as<SharedArrayBuffer>();
200 if (!a || a->isDetachedBuffer() || !a->isSharedArrayBuffer())
201 return b->engine()->throwTypeError();
202
203 return Encode(a->d()->data->size);
204}
205
206ReturnedValue SharedArrayBufferPrototype::method_slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
207{
208 return slice(b, thisObject, argv, argc, shared: true);
209}
210
211ReturnedValue SharedArrayBufferPrototype::slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc, bool shared)
212{
213 Scope scope(b);
214 const SharedArrayBuffer *a = thisObject->as<SharedArrayBuffer>();
215 if (!a || a->isDetachedBuffer() || (a->isSharedArrayBuffer() != shared))
216 return scope.engine->throwTypeError();
217
218 double start = argc > 0 ? argv[0].toInteger() : 0;
219 double end = (argc < 2 || argv[1].isUndefined()) ?
220 a->d()->data->size : argv[1].toInteger();
221 if (scope.hasException())
222 return QV4::Encode::undefined();
223
224 double first = (start < 0) ? qMax(a: a->d()->data->size + start, b: 0.) : qMin(a: start, b: (double)a->d()->data->size);
225 double final = (end < 0) ? qMax(a: a->d()->data->size + end, b: 0.) : qMin(a: end, b: (double)a->d()->data->size);
226
227 const FunctionObject *constructor = a->speciesConstructor(scope, defaultConstructor: shared ? scope.engine->sharedArrayBufferCtor() : scope.engine->arrayBufferCtor());
228 if (!constructor)
229 return scope.engine->throwTypeError();
230
231 double newLen = qMax(a: final - first, b: 0.);
232 ScopedValue argument(scope, QV4::Encode(newLen));
233 QV4::Scoped<SharedArrayBuffer> newBuffer(scope, constructor->callAsConstructor(argv: argument, argc: 1));
234 if (!newBuffer || newBuffer->d()->data->size < (int)newLen ||
235 newBuffer->isDetachedBuffer() || (newBuffer->isSharedArrayBuffer() != shared) ||
236 newBuffer->sameValue(other: *a) ||
237 a->isDetachedBuffer())
238 return scope.engine->throwTypeError();
239
240 memcpy(dest: newBuffer->d()->data->data(), src: a->d()->data->data() + (uint)first, n: newLen);
241 return newBuffer->asReturnedValue();
242}
243
244
245void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
246{
247 Scope scope(engine);
248 ScopedObject o(scope);
249 ctor->defineReadonlyConfigurableProperty(name: engine->id_length(), value: Value::fromInt32(i: 1));
250 ctor->defineReadonlyProperty(name: engine->id_prototype(), value: (o = this));
251 ctor->defineDefaultProperty(QStringLiteral("isView"), code: ArrayBufferCtor::method_isView, argumentCount: 1);
252 ctor->addSymbolSpecies();
253
254 defineDefaultProperty(name: engine->id_constructor(), value: (o = ctor));
255 defineAccessorProperty(QStringLiteral("byteLength"), getter: method_get_byteLength, setter: nullptr);
256 defineDefaultProperty(QStringLiteral("slice"), code: method_slice, argumentCount: 2);
257 defineDefaultProperty(QStringLiteral("toString"), code: method_toString, argumentCount: 0);
258 ScopedString name(scope, engine->newString(QStringLiteral("ArrayBuffer")));
259 defineReadonlyConfigurableProperty(name: scope.engine->symbol_toStringTag(), value: name);
260}
261
262ReturnedValue ArrayBufferPrototype::method_get_byteLength(const FunctionObject *f, const Value *thisObject, const Value *, int)
263{
264 const ArrayBuffer *a = thisObject->as<ArrayBuffer>();
265 if (!a || a->isDetachedBuffer() || a->isSharedArrayBuffer())
266 return f->engine()->throwTypeError();
267
268 return Encode(a->d()->data->size);
269}
270
271ReturnedValue ArrayBufferPrototype::method_slice(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
272{
273 return slice(b, thisObject, argv, argc, shared: false);
274}
275
276ReturnedValue ArrayBufferPrototype::method_toString(const FunctionObject *b, const Value *thisObject, const Value *, int)
277{
278 ExecutionEngine *v4 = b->engine();
279 const ArrayBuffer *a = thisObject->as<ArrayBuffer>();
280 if (!a)
281 RETURN_UNDEFINED();
282 return Encode(v4->newString(s: QString::fromUtf8(str: a->asByteArray())));
283}
284

source code of qtdeclarative/src/qml/jsruntime/qv4arraybuffer.cpp