Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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#include "qv4arraybuffer_p.h"
4#include "qv4typedarray_p.h"
5#include "qv4atomics_p.h"
6#include "qv4symbol_p.h"
7
8using namespace QV4;
9
11
13{
14 Object::init();
16 ScopedObject m(scope, this);
17
18 m->defineDefaultProperty(QStringLiteral("add"), QV4::Atomics::method_add, 3);
19 m->defineDefaultProperty(QStringLiteral("and"), QV4::Atomics::method_and, 3);
20 m->defineDefaultProperty(QStringLiteral("compareExchange"), QV4::Atomics::method_compareExchange, 4);
21 m->defineDefaultProperty(QStringLiteral("exchange"), QV4::Atomics::method_exchange, 3);
22 m->defineDefaultProperty(QStringLiteral("isLockFree"), QV4::Atomics::method_isLockFree, 1);
23 m->defineDefaultProperty(QStringLiteral("load"), QV4::Atomics::method_load, 2);
24 m->defineDefaultProperty(QStringLiteral("or"), QV4::Atomics::method_or, 3);
25 m->defineDefaultProperty(QStringLiteral("store"), QV4::Atomics::method_store, 3);
26 m->defineDefaultProperty(QStringLiteral("sub"), QV4::Atomics::method_sub, 3);
27 m->defineDefaultProperty(QStringLiteral("wait"), QV4::Atomics::method_wait, 4);
28 m->defineDefaultProperty(QStringLiteral("wake"), QV4::Atomics::method_wake, 3);
29 m->defineDefaultProperty(QStringLiteral("xor"), QV4::Atomics::method_xor, 3);
30
31 ScopedString name(scope, scope.engine->newString(QStringLiteral("Atomics")));
32 m->defineReadonlyConfigurableProperty(scope.engine->symbol_toStringTag(), name);
33}
34
35static SharedArrayBuffer *validateSharedIntegerTypedArray(Scope &scope, const Value &typedArray, bool onlyInt32 = false)
36{
37 const TypedArray *a = typedArray.as<TypedArray>();
38 if (!a) {
39 scope.engine->throwTypeError();
40 return nullptr;
41 }
42
43 TypedArrayType t(a->arrayType());
44 if (!a->d()->type->atomicLoad || (onlyInt32 && t != TypedArrayType::Int32Array)) {
45 scope.engine->throwTypeError();
46 return nullptr;
47 }
48
49 Scoped<SharedArrayBuffer> buffer(scope, a->d()->buffer);
50 if (!buffer->isSharedArrayBuffer()) {
51 scope.engine->throwTypeError();
52 return nullptr;
53 }
54 Q_ASSERT(!buffer->hasDetachedArrayData());
55 return buffer;
56}
57
58static int validateAtomicAccess(Scope &scope, const TypedArray &typedArray, const Value &index)
59{
60 const TypedArray &a = static_cast<const TypedArray &>(typedArray);
61 qint64 idx = index.toIndex();
62 if (scope.hasException())
63 return -1;
64 if (idx < 0 || idx >= a.length()) {
65 scope.engine->throwRangeError(QStringLiteral("index out of range."));
66 return -1;
67 }
68 return static_cast<int>(idx);
69}
70
72{
73 Scope scope(f);
74 if (!argc)
75 return scope.engine->throwTypeError();
76
78 if (!buffer)
79 return Encode::undefined();
80 const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
81 int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Value::undefinedValue());
82 if (index < 0)
83 return Encode::undefined();
84
85 Value v = Value::fromReturnedValue((argc > 2 ? argv[2] : Value::undefinedValue()).convertedToNumber());
86 if (scope.hasException())
87 return Encode::undefined();
88
89 int bytesPerElement = a.d()->type->bytesPerElement;
90 int byteOffset = a.d()->byteOffset + index * bytesPerElement;
91
92 return a.d()->type->atomicModifyOps[modify](buffer->arrayData() + byteOffset, v);
93}
94
95ReturnedValue Atomics::method_add(const FunctionObject *f, const Value *, const Value *argv, int argc)
96{
97 return atomicReadModifyWrite(f, argv, argc, AtomicAdd);
98}
99
100ReturnedValue Atomics::method_and(const FunctionObject *f, const Value *, const Value *argv, int argc)
101{
102 return atomicReadModifyWrite(f, argv, argc, AtomicAnd);
103}
104
106{
107 Scope scope(f);
108 if (!argc)
109 return scope.engine->throwTypeError();
110
112 if (!buffer)
113 return Encode::undefined();
114 const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
115 int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Value::undefinedValue());
116 if (index < 0)
117 return Encode::undefined();
118
120 if (scope.hasException())
121 return Encode::undefined();
123 if (scope.hasException())
124 return Encode::undefined();
125
126 int bytesPerElement = a.d()->type->bytesPerElement;
127 int byteOffset = a.d()->byteOffset + index * bytesPerElement;
128
129 return a.d()->type->atomicCompareExchange(buffer->arrayData() + byteOffset, expected, v);
130}
131
132ReturnedValue Atomics::method_exchange(const FunctionObject *f, const Value *, const Value *argv, int argc)
133{
134 return atomicReadModifyWrite(f, argv, argc, AtomicExchange);
135}
136
137ReturnedValue Atomics::method_isLockFree(const FunctionObject *, const Value *, const Value *argv, int argc)
138{
139 if (!argc)
140 return Encode(false);
141 double n = argv[0].toInteger();
142 if (n == 4.)
143 return Encode(true);
144 if (n == 2.)
146#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
147 if (n == 1.)
149#endif
150 return Encode(false);
151}
152
153ReturnedValue Atomics::method_load(const FunctionObject *f, const Value *, const Value *argv, int argc)
154{
155 Scope scope(f);
156 if (!argc)
157 return scope.engine->throwTypeError();
158
160 if (!buffer)
161 return Encode::undefined();
162 const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
163 int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Value::undefinedValue());
164 if (index < 0)
165 return Encode::undefined();
166
167 int bytesPerElement = a.d()->type->bytesPerElement;
168 int byteOffset = a.d()->byteOffset + index * bytesPerElement;
169
170 return a.d()->type->atomicLoad(buffer->arrayData() + byteOffset);
171}
172
173ReturnedValue Atomics::method_or(const FunctionObject *f, const Value *, const Value *argv, int argc)
174{
175 return atomicReadModifyWrite(f, argv, argc, AtomicOr);
176}
177
178ReturnedValue Atomics::method_store(const FunctionObject *f, const Value *, const Value *argv, int argc)
179{
180 Scope scope(f);
181 if (!argc)
182 return scope.engine->throwTypeError();
183
185 if (!buffer)
186 return Encode::undefined();
187 const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
188 int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Value::undefinedValue());
189 if (index < 0)
190 return Encode::undefined();
191
193 if (scope.hasException())
194 return Encode::undefined();
195
196 int bytesPerElement = a.d()->type->bytesPerElement;
197 int byteOffset = a.d()->byteOffset + index * bytesPerElement;
198
199 return a.d()->type->atomicStore(buffer->arrayData() + byteOffset, v);
200}
201
202ReturnedValue Atomics::method_sub(const FunctionObject *f, const Value *, const Value *argv, int argc)
203{
204 return atomicReadModifyWrite(f, argv, argc, AtomicSub);
205}
206
208{
209 return f->engine()->throwTypeError();
210}
211
213{
214 return f->engine()->throwTypeError();
215}
216
217ReturnedValue Atomics::method_xor(const FunctionObject *f, const Value *, const Value *argv, int argc)
218{
219 return atomicReadModifyWrite(f, argv, argc, AtomicXor);
220
221}
QJSValue expected
Definition qjsengine.cpp:12
@ AtomicExchange
quint64 ReturnedValue
Scoped< String > ScopedString
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLfloat GLfloat f
GLenum GLuint buffer
GLuint name
GLfloat n
GLdouble GLdouble t
Definition qopenglext.h:243
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QStringLiteral(str)
long long qint64
Definition qtypes.h:60
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 DEFINE_OBJECT_VTABLE(classname)
static ReturnedValue method_wait(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_or(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_sub(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_wake(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_exchange(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_store(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_isLockFree(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_compareExchange(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_add(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_load(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_and(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static ReturnedValue method_xor(const FunctionObject *, const Value *thisObject, const Value *argv, int argc)
static constexpr ReturnedValue undefined()
ReturnedValue throwRangeError(const Value &value)
Symbol * symbol_toStringTag() const
Heap::String * newString(char16_t c)
ReturnedValue throwTypeError()
Heap::InternalClass * internalClass() const
bool hasException() const
ExecutionEngine * engine
qint64 toIndex() const
Definition qv4value_p.h:381
static constexpr Value undefinedValue()
Definition qv4value_p.h:191
static constexpr Value fromReturnedValue(ReturnedValue val)
Definition qv4value_p.h:165
const T * as() const
Definition qv4value_p.h:132
ReturnedValue convertedToNumber() const
Definition qv4value_p.h:332
double toInteger() const
Definition qv4value_p.h:394