Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qv4atomics.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant
6#include "qv4atomics_p.h"
7#include "qv4symbol_p.h"
8
9using namespace QV4;
10
12
13void Heap::Atomics::init()
14{
15 Object::init();
16 Scope scope(internalClass->engine);
17 ScopedObject m(scope, this);
18
19 m->defineDefaultProperty(QStringLiteral("add"), QV4::Atomics::method_add, 3);
20 m->defineDefaultProperty(QStringLiteral("and"), QV4::Atomics::method_and, 3);
21 m->defineDefaultProperty(QStringLiteral("compareExchange"), QV4::Atomics::method_compareExchange, 4);
22 m->defineDefaultProperty(QStringLiteral("exchange"), QV4::Atomics::method_exchange, 3);
23 m->defineDefaultProperty(QStringLiteral("isLockFree"), QV4::Atomics::method_isLockFree, 1);
24 m->defineDefaultProperty(QStringLiteral("load"), QV4::Atomics::method_load, 2);
25 m->defineDefaultProperty(QStringLiteral("or"), QV4::Atomics::method_or, 3);
26 m->defineDefaultProperty(QStringLiteral("store"), QV4::Atomics::method_store, 3);
27 m->defineDefaultProperty(QStringLiteral("sub"), QV4::Atomics::method_sub, 3);
28 m->defineDefaultProperty(QStringLiteral("wait"), QV4::Atomics::method_wait, 4);
29 m->defineDefaultProperty(QStringLiteral("wake"), QV4::Atomics::method_wake, 3);
30 m->defineDefaultProperty(QStringLiteral("xor"), QV4::Atomics::method_xor, 3);
31
32 ScopedString name(scope, scope.engine->newString(QStringLiteral("Atomics")));
33 m->defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), name);
34}
35
36static SharedArrayBuffer *validateSharedIntegerTypedArray(Scope &scope, const Value &typedArray, bool onlyInt32 = false)
37{
38 const TypedArray *a = typedArray.as<TypedArray>();
39 if (!a) {
40 scope.engine->throwTypeError();
41 return nullptr;
42 }
43
44 TypedArrayType t(a->arrayType());
45 if (!a->d()->type->atomicLoad || (onlyInt32 && t != TypedArrayType::Int32Array)) {
46 scope.engine->throwTypeError();
47 return nullptr;
48 }
49
50 Scoped<SharedArrayBuffer> buffer(scope, a->d()->buffer);
51 if (!buffer->isSharedArrayBuffer()) {
52 scope.engine->throwTypeError();
53 return nullptr;
54 }
55 Q_ASSERT(!buffer->hasDetachedArrayData());
56 return buffer;
57}
58
59static int validateAtomicAccess(Scope &scope, const TypedArray &typedArray, const Value &index)
60{
61 const TypedArray &a = static_cast<const TypedArray &>(typedArray);
62 qint64 idx = index.toIndex();
63 if (scope.hasException())
64 return -1;
65 if (idx < 0 || idx >= a.length()) {
66 scope.engine->throwRangeError(QStringLiteral("index out of range."));
67 return -1;
68 }
69 return static_cast<int>(idx);
70}
71
72ReturnedValue atomicReadModifyWrite(const FunctionObject *f, const Value *argv, int argc, AtomicModifyOps modify)
73{
74 Scope scope(f);
75 if (!argc)
76 return scope.engine->throwTypeError();
77
78 SharedArrayBuffer *buffer = validateSharedIntegerTypedArray(scope, argv[0]);
79 if (!buffer)
80 return Encode::undefined();
81 const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
82 int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Value::undefinedValue());
83 if (index < 0)
84 return Encode::undefined();
85
86 Value v = Value::fromReturnedValue((argc > 2 ? argv[2] : Value::undefinedValue()).convertedToNumber());
87 if (scope.hasException())
88 return Encode::undefined();
89
90 int bytesPerElement = a.d()->type->bytesPerElement;
91 int byteOffset = a.d()->byteOffset + index * bytesPerElement;
92
93 return a.d()->type->atomicModifyOps[modify](buffer->arrayData() + byteOffset, v);
94}
95
96ReturnedValue Atomics::method_add(const FunctionObject *f, const Value *, const Value *argv, int argc)
97{
98 return atomicReadModifyWrite(f, argv, argc, AtomicAdd);
99}
100
101ReturnedValue Atomics::method_and(const FunctionObject *f, const Value *, const Value *argv, int argc)
102{
103 return atomicReadModifyWrite(f, argv, argc, AtomicAnd);
104}
105
106ReturnedValue Atomics::method_compareExchange(const FunctionObject *f, const Value *, const Value *argv, int argc)
107{
108 Scope scope(f);
109 if (!argc)
110 return scope.engine->throwTypeError();
111
112 SharedArrayBuffer *buffer = validateSharedIntegerTypedArray(scope, argv[0]);
113 if (!buffer)
114 return Encode::undefined();
115 const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
116 int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Value::undefinedValue());
117 if (index < 0)
118 return Encode::undefined();
119
120 Value expected = Value::fromReturnedValue((argc > 2 ? argv[2] : Value::undefinedValue()).convertedToNumber());
121 if (scope.hasException())
122 return Encode::undefined();
123 Value v = Value::fromReturnedValue((argc > 3 ? argv[3] : Value::undefinedValue()).convertedToNumber());
124 if (scope.hasException())
125 return Encode::undefined();
126
127 int bytesPerElement = a.d()->type->bytesPerElement;
128 int byteOffset = a.d()->byteOffset + index * bytesPerElement;
129
130 return a.d()->type->atomicCompareExchange(buffer->arrayData() + byteOffset, expected, v);
131}
132
133ReturnedValue Atomics::method_exchange(const FunctionObject *f, const Value *, const Value *argv, int argc)
134{
135 return atomicReadModifyWrite(f, argv, argc, AtomicExchange);
136}
137
138ReturnedValue Atomics::method_isLockFree(const FunctionObject *, const Value *, const Value *argv, int argc)
139{
140 if (!argc)
141 return Encode(false);
142 double n = argv[0].toInteger();
143 if (n == 4.)
144 return Encode(true);
145 if (n == 2.)
146 return Encode(QAtomicOps<unsigned short>::isTestAndSetNative());
147#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
148 if (n == 1.)
149 return Encode(QAtomicOps<unsigned char>::isTestAndSetNative());
150#endif
151 return Encode(false);
152}
153
154ReturnedValue Atomics::method_load(const FunctionObject *f, const Value *, const Value *argv, int argc)
155{
156 Scope scope(f);
157 if (!argc)
158 return scope.engine->throwTypeError();
159
160 SharedArrayBuffer *buffer = validateSharedIntegerTypedArray(scope, argv[0]);
161 if (!buffer)
162 return Encode::undefined();
163 const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
164 int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Value::undefinedValue());
165 if (index < 0)
166 return Encode::undefined();
167
168 int bytesPerElement = a.d()->type->bytesPerElement;
169 int byteOffset = a.d()->byteOffset + index * bytesPerElement;
170
171 return a.d()->type->atomicLoad(buffer->arrayData() + byteOffset);
172}
173
174ReturnedValue Atomics::method_or(const FunctionObject *f, const Value *, const Value *argv, int argc)
175{
176 return atomicReadModifyWrite(f, argv, argc, AtomicOr);
177}
178
179ReturnedValue Atomics::method_store(const FunctionObject *f, const Value *, const Value *argv, int argc)
180{
181 Scope scope(f);
182 if (!argc)
183 return scope.engine->throwTypeError();
184
185 SharedArrayBuffer *buffer = validateSharedIntegerTypedArray(scope, argv[0]);
186 if (!buffer)
187 return Encode::undefined();
188 const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
189 int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Value::undefinedValue());
190 if (index < 0)
191 return Encode::undefined();
192
193 Value v = Value::fromReturnedValue((argc > 2 ? argv[2] : Value::undefinedValue()).convertedToNumber());
194 if (scope.hasException())
195 return Encode::undefined();
196
197 int bytesPerElement = a.d()->type->bytesPerElement;
198 int byteOffset = a.d()->byteOffset + index * bytesPerElement;
199
200 return a.d()->type->atomicStore(buffer->arrayData() + byteOffset, v);
201}
202
203ReturnedValue Atomics::method_sub(const FunctionObject *f, const Value *, const Value *argv, int argc)
204{
205 return atomicReadModifyWrite(f, argv, argc, AtomicSub);
206}
207
208ReturnedValue Atomics::method_wait(const FunctionObject *f, const Value *, const Value *, int)
209{
210 return f->engine()->throwTypeError();
211}
212
213ReturnedValue Atomics::method_wake(const FunctionObject *f, const Value *, const Value *, int)
214{
215 return f->engine()->throwTypeError();
216}
217
218ReturnedValue Atomics::method_xor(const FunctionObject *f, const Value *, const Value *argv, int argc)
219{
220 return atomicReadModifyWrite(f, argv, argc, AtomicXor);
221
222}
static int validateAtomicAccess(Scope &scope, const TypedArray &typedArray, const Value &index)
static SharedArrayBuffer * validateSharedIntegerTypedArray(Scope &scope, const Value &typedArray, bool onlyInt32=false)
ReturnedValue atomicReadModifyWrite(const FunctionObject *f, const Value *argv, int argc, AtomicModifyOps modify)
DEFINE_OBJECT_VTABLE(Atomics)