Implement most remaining methods of Atomics

The only missing ones now are wait() and wake().

Change-Id: I2c0ee78cdd8a249e0e841861dd4b76c4665b0ae0
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
This commit is contained in:
Lars Knoll 2018-08-24 17:17:34 +02:00
parent e4e220fb56
commit 83ded6108a
4 changed files with 124 additions and 18 deletions

View File

@ -138,9 +138,31 @@ ReturnedValue Atomics::method_and(const FunctionObject *f, const Value *, const
return atomicReadModifyWrite(f, argv, argc, AtomicAnd);
}
ReturnedValue Atomics::method_compareExchange(const FunctionObject *f, const Value *, const Value *, int)
ReturnedValue Atomics::method_compareExchange(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
return f->engine()->throwTypeError();
Scope scope(f);
if (!argc)
return scope.engine->throwTypeError();
SharedArrayBuffer *buffer = validateSharedIntegerTypedArray(scope, argv[0]);
if (!buffer)
return Encode::undefined();
const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Primitive::undefinedValue());
if (index < 0)
return Encode::undefined();
Value expected = Primitive::fromReturnedValue((argc > 2 ? argv[2] : Primitive::undefinedValue()).convertedToNumber());
if (scope.hasException())
return Encode::undefined();
Value v = Primitive::fromReturnedValue((argc > 3 ? argv[3] : Primitive::undefinedValue()).convertedToNumber());
if (scope.hasException())
return Encode::undefined();
int bytesPerElement = a.d()->type->bytesPerElement;
int byteOffset = a.d()->byteOffset + index * bytesPerElement;
return a.d()->type->atomicCompareExchange(buffer->data() + byteOffset, expected, v);
}
ReturnedValue Atomics::method_exchange(const FunctionObject *f, const Value *, const Value *argv, int argc)
@ -148,14 +170,40 @@ ReturnedValue Atomics::method_exchange(const FunctionObject *f, const Value *, c
return atomicReadModifyWrite(f, argv, argc, AtomicExchange);
}
ReturnedValue Atomics::method_isLockFree(const FunctionObject *f, const Value *, const Value *, int)
ReturnedValue Atomics::method_isLockFree(const FunctionObject *, const Value *, const Value *argv, int argc)
{
return f->engine()->throwTypeError();
if (!argc)
return Encode(false);
double n = argv[0].toInteger();
if (n == 4.)
return Encode(true);
if (n == 2.)
return Encode(QAtomicOps<unsigned short>::isTestAndSetNative());
#ifdef Q_ATOMIC_INT8_IS_SUPPORTED
if (n == 1.)
return Encode(QAtomicOps<unsigned char>::isTestAndSetNative());
#endif
return Encode(false);
}
ReturnedValue Atomics::method_load(const FunctionObject *f, const Value *, const Value *, int)
ReturnedValue Atomics::method_load(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
return f->engine()->throwTypeError();
Scope scope(f);
if (!argc)
return scope.engine->throwTypeError();
SharedArrayBuffer *buffer = validateSharedIntegerTypedArray(scope, argv[0]);
if (!buffer)
return Encode::undefined();
const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Primitive::undefinedValue());
if (index < 0)
return Encode::undefined();
int bytesPerElement = a.d()->type->bytesPerElement;
int byteOffset = a.d()->byteOffset + index * bytesPerElement;
return a.d()->type->atomicLoad(buffer->data() + byteOffset);
}
ReturnedValue Atomics::method_or(const FunctionObject *f, const Value *, const Value *argv, int argc)
@ -163,9 +211,28 @@ ReturnedValue Atomics::method_or(const FunctionObject *f, const Value *, const V
return atomicReadModifyWrite(f, argv, argc, AtomicOr);
}
ReturnedValue Atomics::method_store(const FunctionObject *f, const Value *, const Value *, int)
ReturnedValue Atomics::method_store(const FunctionObject *f, const Value *, const Value *argv, int argc)
{
return f->engine()->throwTypeError();
Scope scope(f);
if (!argc)
return scope.engine->throwTypeError();
SharedArrayBuffer *buffer = validateSharedIntegerTypedArray(scope, argv[0]);
if (!buffer)
return Encode::undefined();
const TypedArray &a = static_cast<const TypedArray &>(argv[0]);
int index = validateAtomicAccess(scope, a, argc > 1 ? argv[1] : Primitive::undefinedValue());
if (index < 0)
return Encode::undefined();
Value v = Primitive::fromReturnedValue((argc > 2 ? argv[2] : Primitive::undefinedValue()).convertedToNumber());
if (scope.hasException())
return Encode::undefined();
int bytesPerElement = a.d()->type->bytesPerElement;
int byteOffset = a.d()->byteOffset + index * bytesPerElement;
return a.d()->type->atomicStore(buffer->data() + byteOffset, v);
}
ReturnedValue Atomics::method_sub(const FunctionObject *f, const Value *, const Value *argv, int argc)

View File

@ -149,7 +149,7 @@ template <typename T>
ReturnedValue atomicAdd(char *data, Value v)
{
T value = valueToType<T>(v);
typename QAtomicOps< T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
value = QAtomicOps<T>::fetchAndAddOrdered(*mem, value);
return typeToValue(value);
}
@ -158,7 +158,7 @@ template <typename T>
ReturnedValue atomicAnd(char *data, Value v)
{
T value = valueToType<T>(v);
typename QAtomicOps< T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
value = QAtomicOps<T>::fetchAndAndOrdered(*mem, value);
return typeToValue(value);
}
@ -167,7 +167,7 @@ template <typename T>
ReturnedValue atomicExchange(char *data, Value v)
{
T value = valueToType<T>(v);
typename QAtomicOps< T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
value = QAtomicOps<T>::fetchAndStoreOrdered(*mem, value);
return typeToValue(value);
}
@ -176,7 +176,7 @@ template <typename T>
ReturnedValue atomicOr(char *data, Value v)
{
T value = valueToType<T>(v);
typename QAtomicOps< T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
value = QAtomicOps<T>::fetchAndOrOrdered(*mem, value);
return typeToValue(value);
}
@ -185,7 +185,7 @@ template <typename T>
ReturnedValue atomicSub(char *data, Value v)
{
T value = valueToType<T>(v);
typename QAtomicOps< T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
value = QAtomicOps<T>::fetchAndSubOrdered(*mem, value);
return typeToValue(value);
}
@ -194,11 +194,40 @@ template <typename T>
ReturnedValue atomicXor(char *data, Value v)
{
T value = valueToType<T>(v);
typename QAtomicOps< T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
value = QAtomicOps<T>::fetchAndXorOrdered(*mem, value);
return typeToValue(value);
}
template <typename T>
ReturnedValue atomicCompareExchange(char *data, Value expected, Value v)
{
T value = valueToType<T>(v);
T exp = valueToType<T>(expected);
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
T old;
QAtomicOps<T>::testAndSetOrdered(*mem, exp, value, &old);
return typeToValue(old);
}
template <typename T>
ReturnedValue atomicLoad(char *data)
{
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
T val = QAtomicOps<T>::load(*mem);
return typeToValue(val);
}
template <typename T>
ReturnedValue atomicStore(char *data, Value v)
{
T value = valueToType<T>(v);
typename QAtomicOps<T>::Type *mem = reinterpret_cast<typename QAtomicOps<T>::Type *>(data);
QAtomicOps<T>::store(*mem, value);
return typeToValue(value);
}
template<typename T>
constexpr TypedArrayOperations TypedArrayOperations::create(const char *name)
{
@ -206,7 +235,10 @@ constexpr TypedArrayOperations TypedArrayOperations::create(const char *name)
name,
::read<T>,
::write<T>,
{ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }
{ nullptr, nullptr, nullptr, nullptr, nullptr, nullptr },
nullptr,
nullptr,
nullptr
};
}
@ -217,7 +249,10 @@ constexpr TypedArrayOperations TypedArrayOperations::createWithAtomics(const cha
name,
::read<T>,
::write<T>,
{ ::atomicAdd<T>, ::atomicAnd<T>, ::atomicExchange<T>, ::atomicOr<T>, ::atomicSub<T>, ::atomicXor<T> }
{ ::atomicAdd<T>, ::atomicAnd<T>, ::atomicExchange<T>, ::atomicOr<T>, ::atomicSub<T>, ::atomicXor<T> },
::atomicCompareExchange<T>,
::atomicLoad<T>,
::atomicStore<T>
};
}

View File

@ -87,6 +87,9 @@ struct TypedArrayOperations {
typedef ReturnedValue (*Read)(const char *data);
typedef void (*Write)(char *data, Value value);
typedef ReturnedValue (*AtomicModify)(char *data, Value value);
typedef ReturnedValue (*AtomicCompareExchange)(char *data, Value expected, Value v);
typedef ReturnedValue (*AtomicLoad)(char *data);
typedef ReturnedValue (*AtomicStore)(char *data, Value value);
template<typename T>
static constexpr TypedArrayOperations create(const char *name);
@ -98,6 +101,9 @@ struct TypedArrayOperations {
Read read;
Write write;
AtomicModify atomicModifyOps[AtomicModifyOps::NAtomicModifyOps];
AtomicCompareExchange atomicCompareExchange;
AtomicLoad atomicLoad;
AtomicStore atomicStore;
};
namespace Heap {

View File

@ -134,8 +134,6 @@ built-ins/AsyncFunction/instance-prototype-property.js fails
built-ins/AsyncGeneratorPrototype/next/name.js fails
built-ins/AsyncGeneratorPrototype/return/name.js fails
built-ins/AsyncGeneratorPrototype/throw/name.js fails
built-ins/Atomics/isLockFree/corner-cases.js fails
built-ins/Atomics/isLockFree/value.js fails
built-ins/Atomics/wait/did-timeout.js fails
built-ins/Atomics/wait/good-views.js fails
built-ins/Atomics/wait/nan-timeout.js fails