Add atomics project and modify code errors

Signed-off-by: jiangkai43 <jiangkai43@huawei.com>
https://gitee.com/openharmony/ark_js_runtime/issues/I599WU
This commit is contained in:
jiangkai43 2022-05-25 22:03:38 +08:00
parent 0c5dd8f92a
commit b13fb03d17
29 changed files with 1903 additions and 45 deletions

View File

@ -301,6 +301,7 @@ config("icu_path_test_config") {
ecma_source = [
"ecmascript/base/array_helper.cpp",
"ecmascript/base/atomic_helper.cpp",
"ecmascript/base/builtins_base.cpp",
"ecmascript/base/error_helper.cpp",
"ecmascript/base/json_parser.cpp",
@ -314,6 +315,7 @@ ecma_source = [
"ecmascript/builtins/builtins_array.cpp",
"ecmascript/builtins/builtins_arraybuffer.cpp",
"ecmascript/builtins/builtins_async_function.cpp",
"ecmascript/builtins/builtins_atomics.cpp",
"ecmascript/builtins/builtins_bigint.cpp",
"ecmascript/builtins/builtins_boolean.cpp",
"ecmascript/builtins/builtins_dataview.cpp",
@ -476,6 +478,7 @@ ecma_source = [
"ecmascript/tagged_dictionary.cpp",
"ecmascript/tagged_tree.cpp",
"ecmascript/template_string.cpp",
"ecmascript/waiter_list.cpp",
"ecmascript/weak_vector.cpp",
"ecmascript/compiler/llvm/llvm_stackmap_parser.cpp",
"ecmascript/stubs/runtime_stubs.cpp",

View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/base/atomic_helper.h"
#include "ecmascript/base/typed_array_helper-inl.h"
namespace panda::ecmascript::base {
using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
JSTaggedValue AtomicHelper::ValidateIntegerTypedArray(JSThread *thread, JSHandle<JSTaggedValue> typedArray,
bool waitable)
{
// 1. If waitable is not present, set waitable to false.
// 2. Let buffer be ? ValidateTypedArray(typedArray).
JSTaggedValue buffer = TypedArrayHelper::ValidateTypedArray(thread, typedArray);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> bufferHandle(thread, buffer);
// 3. Let typeName be typedArray.[[TypedArrayName]].
// 4. Let type be the Element Type value in Table 60 for typeName.
JSHandle<JSTaggedValue> typeName(thread, JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName());
DataViewType type = JSTypedArray::GetTypeFromName(thread, typeName);
// 5. If waitable is true, then
// a. If typeName is not "Int32Array" or "BigInt64Array", throw a TypeError exception.
// 6. Else,
// a. If ! IsUnclampedIntegerElementType(type) is false and ! IsBigIntElementType(type) is false,
// throw a TypeError exception.
if (waitable) {
if (!(type == DataViewType::INT32 || type == DataViewType::BIGINT64)) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The typeName is not Int32Array/BigInt64Array.",
JSTaggedValue::Exception());
}
} else {
if (!(BuiltinsArrayBuffer::IsUnclampedIntegerElementType(type) ||
BuiltinsArrayBuffer::IsBigIntElementType(type))) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The typedArray type is not UnclampedInteger/BigInt.",
JSTaggedValue::Exception());
}
}
// 7. Return buffer.
return bufferHandle.GetTaggedValue();
}
int32_t AtomicHelper::ValidateAtomicAccess(JSThread *thread, const JSHandle<JSTaggedValue> typedArray,
JSHandle<JSTaggedValue> requestIndex)
{
// 1. Assert: typedArray is an Object that has a [[ViewedArrayBuffer]] internal slot.
ASSERT(typedArray->IsECMAObject() && typedArray->IsTypedArray());
// 2. Let length be typedArray.[[ArrayLength]].
JSHandle<JSObject> typedArrayObj(typedArray);
JSHandle<JSTypedArray> srcObj(typedArray);
int32_t length = static_cast<int32_t>(srcObj->GetArrayLength());
// 3. Let accessIndex be ? ToIndex(requestIndex).
JSTaggedNumber accessIndex = JSTaggedValue::ToIndex(thread, requestIndex);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
int32_t index = base::NumberHelper::DoubleInRangeInt32(accessIndex.GetNumber());
// 4. Assert: accessIndex ≥ 0.
ASSERT(index >= 0);
// 5. If accessIndex ≥ length, throw a RangeError exception.
if (index >= length) {
THROW_RANGE_ERROR_AND_RETURN(thread, "Index is overflow.", 0);
}
// 6. Let arrayTypeName be typedArray.[[TypedArrayName]].
// 7. Let elementSize be the Element Size value specified in Table 60 for arrayTypeName.
// 8. Let offset be typedArray.[[ByteOffset]].
JSHandle<JSTaggedValue> arrayTypeName(thread, JSTypedArray::Cast(*typedArrayObj)->GetTypedArrayName());
int32_t elementSize = TypedArrayHelper::GetSizeFromName(thread, arrayTypeName);
uint32_t offset = srcObj->GetByteOffset();
// 9. Return (accessIndex × elementSize) + offset.
int32_t allOffset = index * elementSize + offset;
return allOffset;
}
JSTaggedValue AtomicHelper::AtomicStore(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> index, JSHandle<JSTaggedValue> &value)
{
JSTaggedValue bufferValue = ValidateIntegerTypedArray(thread, typedArray);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> buffer(thread, bufferValue);
uint32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> arrayTypeName(thread,
JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName());
DataViewType type = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
JSHandle<JSTaggedValue> bufferTag;
if (type == DataViewType::BIGUINT64 || type == DataViewType::BIGINT64) {
JSTaggedValue integerValue = JSTaggedValue::ToBigInt(thread, value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bufferTag = JSHandle<JSTaggedValue>(thread, integerValue);
} else {
JSTaggedNumber integerValue = JSTaggedValue::ToInteger(thread, value);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
bufferTag = JSHandle<JSTaggedValue>(thread, integerValue);
}
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
JSTaggedValue::Exception());
}
BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer.GetTaggedValue(), indexedPosition, type, bufferTag, true);
return bufferTag.GetTaggedValue();
}
JSTaggedValue AtomicHelper::AtomicLoad(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> index)
{
JSTaggedValue bufferValue = ValidateIntegerTypedArray(thread, typedArray);
JSHandle<JSTaggedValue> buffer(thread, bufferValue);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
int32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
JSTaggedValue::Exception());
}
JSHandle<JSTaggedValue> arrayTypeName(thread,
JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName());
DataViewType elementType = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer.GetTaggedValue(),
indexedPosition, elementType, true);
}
} // panda::ecmascript::base

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_BASE_ATOMIC_HELPER_H
#define ECMASCRIPT_BASE_ATOMIC_HELPER_H
#include "ecmascript/js_dataview.h"
namespace panda::ecmascript::base {
enum class BytesSize : int32_t {ONEBYTES = 1, TWOBYTES = 2, FOURBYTES = 4, EIGHTBYTES = 8};
class AtomicHelper final {
public:
struct SubFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_sub(arg[0], std::memory_order_seq_cst);
}
};
struct AddFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_add(arg[0], std::memory_order_seq_cst);
}
};
struct AndFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_and(arg[0], std::memory_order_seq_cst);
}
};
struct OrFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_or(arg[0], std::memory_order_seq_cst);
}
};
struct XorFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->fetch_xor(arg[0], std::memory_order_seq_cst);
}
};
struct CompareExchangeFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
T a = arg[0];
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
atomicValue->compare_exchange_strong(a, arg[1], std::memory_order_seq_cst);
return a;
}
};
struct ExchangeFun {
template<typename T>
T operator()(T *ptr, const T *arg) const
{
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(ptr);
return atomicValue->exchange(arg[0], std::memory_order_seq_cst);
}
};
// 25.4.1.1 ValidateIntegerTypedArray ( typedArray [ , waitable ] )
static JSTaggedValue ValidateIntegerTypedArray(JSThread *thread, JSHandle<JSTaggedValue> typedArray,
bool waitable = false);
// 25.4.2.2 ValidateAtomicAccess ( typedArray, requestIndex )
static int32_t ValidateAtomicAccess(JSThread *thread, const JSHandle<JSTaggedValue> typedArray,
JSHandle<JSTaggedValue> requestIndex);
static JSTaggedValue AtomicStore(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> index, JSHandle<JSTaggedValue> &value);
static JSTaggedValue AtomicLoad(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> index);
};
} // namespace panda::ecmascript::base
#endif // ECMASCRIPT_BASE_ATOMIC_HELPER_H

View File

@ -92,42 +92,6 @@ uint32_t TypedArrayHelper::GetElementSize(JSType type)
}
}
DataViewType TypedArrayHelper::GetTypeFromName(JSThread *thread, const JSHandle<JSTaggedValue> &typeName)
{
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt8ArrayString())) {
return DataViewType::INT8;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ArrayString())) {
return DataViewType::UINT8;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ClampedArrayString())) {
return DataViewType::UINT8_CLAMPED;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt16ArrayString())) {
return DataViewType::INT16;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint16ArrayString())) {
return DataViewType::UINT16;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt32ArrayString())) {
return DataViewType::INT32;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint32ArrayString())) {
return DataViewType::UINT32;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat32ArrayString())) {
return DataViewType::FLOAT32;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat64ArrayString())) {
return DataViewType::FLOAT64;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledBigInt64ArrayString())) {
return DataViewType::BIGINT64;
}
return DataViewType::BIGUINT64;
}
JSHandle<JSTaggedValue> TypedArrayHelper::GetConstructor(JSThread *thread, const JSHandle<JSTaggedValue> &obj)
{
JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();

View File

@ -186,14 +186,14 @@ JSTaggedValue TypedArrayHelper::CreateFromTypedArray(EcmaRuntimeCallInfo *argv,
THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception());
}
// 8. Let elementType be the Element Type value in Table 61 for constructorName.
DataViewType elementType = TypedArrayHelper::GetTypeFromName(thread, constructorName);
DataViewType elementType = JSTypedArray::GetTypeFromName(thread, constructorName);
// 9. Let elementLength be srcArray.[[ArrayLength]].
// 10. Let srcName be the String value of srcArray.[[TypedArrayName]].
// 11. Let srcType be the Element Type value in Table 61 for srcName.
// 12. Let srcElementSize be the Element Size value specified in Table 61 for srcName.
uint32_t elementLength = srcObj->GetArrayLength();
JSHandle<JSTaggedValue> srcName(thread, srcObj->GetTypedArrayName());
DataViewType srcType = TypedArrayHelper::GetTypeFromName(thread, srcName);
DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
uint32_t srcElementSize = TypedArrayHelper::GetSizeFromName(thread, srcName);
// 13. Let srcByteOffset be srcArray.[[ByteOffset]].
// 14. Let elementSize be the Element Size value specified in Table 61 for constructorName.

View File

@ -43,7 +43,6 @@ public:
inline static DataViewType GetType(JSType type);
inline static uint32_t GetElementSize(const JSHandle<JSTypedArray> &obj);
inline static uint32_t GetElementSize(JSType type);
inline static DataViewType GetTypeFromName(JSThread *thread, const JSHandle<JSTaggedValue> &typeName);
inline static JSHandle<JSTaggedValue> GetConstructor(JSThread *thread, const JSHandle<JSTaggedValue> &obj);
inline static JSHandle<JSFunction> GetConstructorFromName(JSThread *thread,
const JSHandle<JSTaggedValue> &typeName);

View File

@ -30,6 +30,7 @@
#include "ecmascript/builtins/builtins_array.h"
#include "ecmascript/builtins/builtins_arraybuffer.h"
#include "ecmascript/builtins/builtins_async_function.h"
#include "ecmascript/builtins/builtins_atomics.h"
#include "ecmascript/builtins/builtins_bigint.h"
#include "ecmascript/builtins/builtins_boolean.h"
#include "ecmascript/builtins/builtins_collator.h"
@ -134,6 +135,7 @@ using StringIterator = builtins::BuiltinsStringIterator;
using RegExp = builtins::BuiltinsRegExp;
using Function = builtins::BuiltinsFunction;
using Math = builtins::BuiltinsMath;
using Atomics = builtins::BuiltinsAtomics;
using ArrayBuffer = builtins::BuiltinsArrayBuffer;
using Json = builtins::BuiltinsJson;
using Proxy = builtins::BuiltinsProxy;
@ -314,6 +316,7 @@ void Builtins::Initialize(const JSHandle<GlobalEnv> &env, JSThread *thread)
InitializeGlobalObject(env, globalObject);
InitializeMath(env, objFuncPrototypeVal);
InitializeAtomics(env, objFuncPrototypeVal);
InitializeJson(env, objFuncPrototypeVal);
InitializeIterator(env, objFuncDynclass);
InitializeProxy(env);
@ -1357,6 +1360,34 @@ void Builtins::InitializeWeakSet(const JSHandle<GlobalEnv> &env, const JSHandle<
env->SetBuiltinsWeakSetFunction(thread_, weakSetFunction);
}
void Builtins::InitializeAtomics(const JSHandle<GlobalEnv> &env,
const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const
{
[[maybe_unused]] EcmaHandleScope scope(thread_);
JSHandle<JSHClass> atomicsDynclass = factory_->NewEcmaDynClass(JSObject::SIZE, JSType::JS_OBJECT,
objFuncPrototypeVal);
JSHandle<JSObject> atomicsObject = factory_->NewJSObject(atomicsDynclass);
SetFunction(env, atomicsObject, "add", Atomics::Add, FunctionLength::THREE);
SetFunction(env, atomicsObject, "and", Atomics::And, FunctionLength::THREE);
SetFunction(env, atomicsObject, "sub", Atomics::Sub, FunctionLength::THREE);
SetFunction(env, atomicsObject, "or", Atomics::Or, FunctionLength::THREE);
SetFunction(env, atomicsObject, "xor", Atomics::Xor, FunctionLength::THREE);
SetFunction(env, atomicsObject, "compareExchange", Atomics::CompareExchange, FunctionLength::FOUR);
SetFunction(env, atomicsObject, "exchange", Atomics::Exchange, FunctionLength::THREE);
SetFunction(env, atomicsObject, "isLockFree", Atomics::IsLockFree, FunctionLength::ONE);
SetFunction(env, atomicsObject, "load", Atomics::Load, FunctionLength::TWO);
SetFunction(env, atomicsObject, "store", Atomics::Store, FunctionLength::THREE);
SetFunction(env, atomicsObject, "wait", Atomics::Wait, FunctionLength::FOUR);
SetFunction(env, atomicsObject, "notify", Atomics::Notify, FunctionLength::THREE);
JSHandle<JSTaggedValue> atomicsString(factory_->NewFromASCII("Atomics"));
JSHandle<JSObject> globalObject(thread_, env->GetGlobalObject());
PropertyDescriptor atomicsDesc(thread_, JSHandle<JSTaggedValue>::Cast(atomicsObject), true, false, true);
JSObject::DefineOwnProperty(thread_, globalObject, atomicsString, atomicsDesc);
// @@ToStringTag
SetStringTagSymbol(env, atomicsObject, "Atomics");
env->SetAtomicsFunction(thread_, atomicsObject);
}
void Builtins::InitializeMath(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const
{
[[maybe_unused]] EcmaHandleScope scope(thread_);

View File

@ -141,6 +141,8 @@ private:
void InitializeMath(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const;
void InitializeAtomics(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const;
void InitializeJson(const JSHandle<GlobalEnv> &env, const JSHandle<JSTaggedValue> &objFuncPrototypeVal) const;
void InitializeString(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &primRefObjDynclass) const;

View File

@ -386,6 +386,22 @@ bool BuiltinsArrayBuffer::IsBigIntElementType(DataViewType type)
return false;
}
// es12 25.1.2.6 IsUnclampedIntegerElementType ( type )
bool BuiltinsArrayBuffer::IsUnclampedIntegerElementType(DataViewType type)
{
switch (type) {
case DataViewType::INT8:
case DataViewType::INT16:
case DataViewType::INT32:
case DataViewType::UINT8:
case DataViewType::UINT16:
case DataViewType::UINT32:
return true;
default:
return false;
}
}
template<typename T>
void BuiltinsArrayBuffer::SetTypeData(uint8_t *block, T value, uint32_t index)
{

View File

@ -66,6 +66,8 @@ public:
// 24.1.1.1 AllocateArrayBuffer(constructor, byteLength)
static JSTaggedValue AllocateArrayBuffer(JSThread *thread, const JSHandle<JSTaggedValue> &newTarget,
double byteLength);
// es12 25.1.2.6 IsUnclampedIntegerElementType ( type )
static bool IsUnclampedIntegerElementType(DataViewType type);
// es12 25.1.2.7 IsBigIntElementType ( type )
static bool IsBigIntElementType(DataViewType type);

View File

@ -0,0 +1,587 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/builtins/builtins_atomics.h"
#include "ecmascript/base/atomic_helper.h"
#include "ecmascript/base/typed_array_helper-inl.h"
#include "utils/time.h"
namespace panda::ecmascript::builtins {
using NumberHelper = base::NumberHelper;
using AtomicHelper = base::AtomicHelper;
using BytesSize = base::BytesSize;
using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
WaiterList *g_waitLists = Singleton<WaiterList>::GetInstance();
Mutex *g_mutex = Singleton<Mutex>::GetInstance();
// 25.4.2 Atomics.add ( typedArray, index, value )
JSTaggedValue BuiltinsAtomics::Sub(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Sub);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::SubFun());
}
JSTaggedValue BuiltinsAtomics::Add(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Add);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::AddFun());
}
JSTaggedValue BuiltinsAtomics::And(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, And);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::AndFun());
}
JSTaggedValue BuiltinsAtomics::Or(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Or);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::OrFun());
}
JSTaggedValue BuiltinsAtomics::Xor(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Xor);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::XorFun());
}
JSTaggedValue BuiltinsAtomics::CompareExchange(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, CompareExchange);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::CompareExchangeFun());
}
JSTaggedValue BuiltinsAtomics::Exchange(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Exchange);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicReadModifyWrite(thread, typedArray, index, argv, AtomicHelper::ExchangeFun());
}
JSTaggedValue BuiltinsAtomics::Store(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Store);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> value = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
return AtomicHelper::AtomicStore(thread, typedArray, index, value);
}
JSTaggedValue BuiltinsAtomics::Load(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, Load);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> typedArray = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
return AtomicHelper::AtomicLoad(thread, typedArray, index);
}
JSTaggedValue BuiltinsAtomics::IsLockFree(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomics, IsLockFree);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> sizeTag = GetCallArg(argv, 0);
BytesSize size = BytesSize(JSTaggedValue::ToInt32(thread, sizeTag));
bool result;
switch (size) {
case BytesSize::ONEBYTES:
case BytesSize::TWOBYTES:
case BytesSize::FOURBYTES:
case BytesSize::EIGHTBYTES:
result = true;
break;
default:
result = false;
break;
}
return JSTaggedValue(result);
}
// 25.4.11 Atomics.wait ( typedArray, index, value, timeout )
JSTaggedValue BuiltinsAtomics::Wait(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomic, Wait);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> array = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> value = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
JSHandle<JSTaggedValue> timeout = GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
JSHandle<JSTaggedValue> arrayBuffer(thread, AtomicHelper::ValidateIntegerTypedArray(thread, array, true));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 2. If IsSharedArrayBuffer(buffer) is false, throw a TypeError exception.
if (!arrayBuffer->IsSharedArrayBuffer()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "buffer is not sharedArrayBuffer.",
JSTaggedValue::Exception());
}
// 3. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
int32_t indexedPosition = AtomicHelper::ValidateAtomicAccess(thread, array, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 4. If typedArray.[[TypedArrayName]] is "BigInt64Array", let v be ? ToBigInt64(value).
// 5. Otherwise, let v be ? ToInt32(value).
int64_t v = 0;
if (array->IsJSBigInt64Array()) {
v = JSHandle<BigInt>::Cast(value)->ToInt64();
} else {
v = static_cast<int64_t>(JSTaggedValue::ToInt32(thread, value));
}
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 6. Let q be ? ToNumber(timeout).
// 7. If q is NaN or +∞𝔽, let t be +∞; else if q is -∞𝔽, let t be 0; else let t be max((q), 0).
double t = 0;
if (timeout->IsUndefined()) {
t = base::POSITIVE_INFINITY;
} else {
JSTaggedNumber q = JSTaggedValue::ToNumber(thread, timeout);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
t = q.GetNumber();
if (NumberHelper::IsNaN(q) || (!NumberHelper::IsFinite(q) && t > 0)) {
t = base::POSITIVE_INFINITY;
} else if (t < 0) {
t = 0;
}
}
// 8. Let B be AgentCanSuspend().
// 9. If B is false, throw a TypeError exception.
if (!thread->GetEcmaVM()->GetAllowAtomicWait()) {
THROW_TYPE_ERROR_AND_RETURN(thread, "vm does not allow wait to block.",
JSTaggedValue::Exception());
}
WaitResult res = WaitResult::OK;
if (array->IsJSBigInt64Array()) {
// AtomicHelper::Wait<int64_t>(thread, arrayBuffer, indexedPosition, v, t);
res = DoWait<int64_t>(thread, arrayBuffer, indexedPosition, v, t);
} else {
// AtomicHelper::Wait<int32_t>(thread, arrayBuffer, indexedPosition, static_cast<int32_t>(v), t);
res = DoWait<int32_t>(thread, arrayBuffer, indexedPosition, static_cast<int32_t>(v), t);
}
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
if (res == WaitResult::OK) {
return globalConst->GetOkString();
} else if (res == WaitResult::NOT_EQ) {
return globalConst->GetNotEqualString();
}
return globalConst->GetTimeoutString();
}
// 25.4.12 Atomics.notify ( typedArray, index, count )
JSTaggedValue BuiltinsAtomics::Notify(EcmaRuntimeCallInfo *argv)
{
ASSERT(argv);
JSThread *thread = argv->GetThread();
BUILTINS_API_TRACE(thread, Atomic, Notify);
[[maybe_unused]] EcmaHandleScope handleScope(thread);
JSHandle<JSTaggedValue> array = GetCallArg(argv, 0);
JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
JSHandle<JSTaggedValue> count = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray, true).
JSHandle<JSTaggedValue> arrayBuffer(thread, AtomicHelper::ValidateIntegerTypedArray(thread, array, true));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
int32_t indexedPosition = AtomicHelper::ValidateAtomicAccess(thread, array, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. If count is undefined, let c be +∞.
// 4. Else,
// a. Let intCount be ? ToIntegerOrInfinity(count).
// b. Let c be max(intCount, 0).
double c = 0;
if (count->IsUndefined()) {
c = base::POSITIVE_INFINITY;
} else {
JSTaggedNumber countTemp = JSTaggedValue::ToNumber(thread, count);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
c = base::NumberHelper::TruncateDouble(countTemp.GetNumber());
c = c < 0 ? 0 : c;
}
// 6. If IsSharedArrayBuffer(buffer) is false, return +0𝔽.
if (!arrayBuffer->IsSharedArrayBuffer()) {
return JSTaggedValue(0);
}
return JSTaggedValue(Signal(arrayBuffer, indexedPosition, c));
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::AtomicReadModifyWrite(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> &index, EcmaRuntimeCallInfo *argv,
const callbackfun &op)
{
if (!typedArray->IsTypedArray()) {
THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception());
}
// 1. Let buffer be ? ValidateIntegerTypedArray(typedArray).
JSTaggedValue bufferValue = base::AtomicHelper::ValidateIntegerTypedArray(thread, typedArray);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> buffer(thread, bufferValue);
// 2. Let indexedPosition be ? ValidateAtomicAccess(typedArray, index).
int32_t indexedPosition = base::AtomicHelper::ValidateAtomicAccess(thread, typedArray, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 3. Let arrayTypeName be typedArray.[[TypedArrayName]].
JSHandle<JSTaggedValue> arrayTypeName(thread,
JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName());
if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
JSTaggedValue::Exception());
}
// 7. NOTE: The above check is not redundant with the check in ValidateIntegerTypedArray because the call to
// ToBigInt or ToIntegerOrInfinity on the preceding lines can have arbitrary side effects, which could cause the
// buffer to become detached.
// 8. Let elementType be the Element Type value in Table 60 for arrayTypeName.
DataViewType elementType = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
// 9. Return GetModifySetValueInBuffer(buffer, indexedPosition, elementType, v, op).
return AtomicReadModifyWriteCase(thread, buffer.GetTaggedValue(), elementType, indexedPosition, argv, op);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::AtomicReadModifyWriteCase(JSThread *thread, JSTaggedValue arrBuf,
DataViewType type, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSArrayBuffer *jsArrayBuffer = JSArrayBuffer::Cast(arrBuf.GetTaggedObject());
JSTaggedValue data = jsArrayBuffer->GetArrayBufferData();
void *pointer = JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer();
auto *block = reinterpret_cast<uint8_t *>(pointer);
uint32_t size = argv->GetArgsNumber();
switch (type) {
case DataViewType::UINT8:
return HandleWithUint8(thread, size, block, indexedPosition, argv, op);
case DataViewType::INT8:
return HandleWithInt8(thread, size, block, indexedPosition, argv, op);
case DataViewType::UINT16:
return HandleWithUint16(thread, size, block, indexedPosition, argv, op);
case DataViewType::INT16:
return HandleWithInt16(thread, size, block, indexedPosition, argv, op);
case DataViewType::UINT32:
return HandleWithUint32(thread, size, block, indexedPosition, argv, op);
case DataViewType::INT32:
return HandleWithInt32(thread, size, block, indexedPosition, argv, op);
case DataViewType::BIGINT64:
return HandleWithBigInt64(thread, size, block, indexedPosition, argv, op);
case DataViewType::BIGUINT64:
return HandleWithBigUint64(thread, size, block, indexedPosition, argv, op);
default:
break;
}
UNREACHABLE();
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithUint8(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
uint8_t tag = JSTaggedValue::ToUint8(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op((block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint8_t newTag = JSTaggedValue::ToUint8(thread, newValue);
uint8_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op((block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithInt8(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
int8_t tag = JSTaggedValue::ToInt8(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int8_t *>(block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int8_t newTag = JSTaggedValue::ToInt8(thread, newValue);
int8_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<int8_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithUint16(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
uint16_t tag = JSTaggedValue::ToUint16(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<uint16_t *>(block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint16_t newTag = JSTaggedValue::ToUint16(thread, newValue);
uint16_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<uint16_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithInt16(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
int16_t tag = JSTaggedValue::ToInt16(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int16_t *>(block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int16_t newTag = JSTaggedValue::ToInt16(thread, newValue);
int16_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<int16_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithUint32(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
uint32_t tag = JSTaggedValue::ToUint32(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<uint32_t *>(block + indexedPosition), &tag);
return JSTaggedValue(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint32_t newTag = JSTaggedValue::ToUint32(thread, newValue);
uint32_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<uint32_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithInt32(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
int32_t tag = JSTaggedValue::ToInt32(thread, value);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int32_t *>(block + indexedPosition), &tag);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int32_t newTag = JSTaggedValue::ToInt32(thread, newValue);
int32_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
arg[1] = newTag;
auto result = op(reinterpret_cast<int32_t *>(block + indexedPosition), arg);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithBigInt64(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
int64_t val = 0;
bool lossless = true;
BigInt::BigIntToInt64(thread, value, &val, &lossless);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int64_t *>(block + indexedPosition), &val);
return BigInt::Int64ToBigInt(thread, result).GetTaggedValue();
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int64_t newVal = 0;
BigInt::BigIntToInt64(thread, newValue, &newVal, &lossless);
int64_t arg[ARGS_NUMBER] = {0};
arg[0] = val;
arg[1] = newVal;
auto result = op(reinterpret_cast<int64_t *>(block + indexedPosition), arg);
return BigInt::Int64ToBigInt(thread, result).GetTaggedValue();
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithBigUint64(JSThread *thread, uint32_t size, uint8_t *block,
int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
uint64_t val = 0;
bool lossless = true;
BigInt::BigIntToUint64(thread, value, &val, &lossless);
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<uint64_t *>(block + indexedPosition), &val);
return BigInt::Uint64ToBigInt(thread, result).GetTaggedValue();
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint64_t newVal = 0;
BigInt::BigIntToUint64(thread, newValue, &newVal, &lossless);
uint64_t arg[ARGS_NUMBER] = {0};
arg[0] = val;
arg[1] = newVal;
auto result = op(reinterpret_cast<uint64_t *>(block + indexedPosition), arg);
return BigInt::Uint64ToBigInt(thread, result).GetTaggedValue();
}
template <typename T>
WaitResult BuiltinsAtomics::DoWait(JSThread *thread, JSHandle<JSTaggedValue> &arrayBuffer,
size_t index, T execpt, double timeout)
{
MutexGuard lock_guard(g_mutex);
JSHandle<JSNativePointer> np(thread, JSHandle<JSArrayBuffer>::Cast(arrayBuffer)->GetArrayBufferData());
void *buffer = np->GetExternalPointer();
ASSERT(buffer != nullptr);
WaiterListNode *node = thread->GetEcmaVM()->GetWaiterListNode();
node->date_ = buffer;
node->index_ = index;
node->waitPointer_ = reinterpret_cast<int8_t*>(buffer) + index;
node->waiting_ = true;
std::atomic<T> *atomicValue = reinterpret_cast<std::atomic<T> *>(node->waitPointer_);
T value = atomicValue->load();
if (value != execpt) {
return WaitResult::NOT_EQ;
}
g_waitLists->AddNode(node);
uint64_t currentTime = 0;
uint64_t timeoutTime = 0;
bool hasTimeout = timeout != base::POSITIVE_INFINITY;
if (hasTimeout) {
currentTime = time::GetCurrentTimeInMillis();
timeoutTime = currentTime + static_cast<uint64_t>(timeout);
}
WaitResult res = WaitResult::OK;
while (true) {
if (!node->waiting_) {
res = WaitResult::OK;
break;
}
if (hasTimeout) {
currentTime = time::GetCurrentTimeInMillis();
if (currentTime >= timeoutTime) {
res = WaitResult::TIME_OUT;
break;
}
uint64_t untilTime = timeoutTime - currentTime;
ASSERT(untilTime != 0);
node->cond_.TimedWait(g_mutex, untilTime);
} else {
node->cond_.Wait(g_mutex);
}
}
g_waitLists->DeleteNode(node);
node->waiting_ = false;
return res;
}
uint32_t BuiltinsAtomics::Signal(JSHandle<JSTaggedValue> &arrayBuffer, const size_t &index, double wakeCount)
{
JSTaggedValue data = JSHandle<JSArrayBuffer>::Cast(arrayBuffer)->GetArrayBufferData();
void *buffer = JSNativePointer::Cast(data.GetTaggedObject())->GetExternalPointer();
ASSERT(buffer != nullptr);
MutexGuard lock_guard(g_mutex);
auto &locationListMap = g_waitLists->locationListMap_;
auto iter = locationListMap.find(reinterpret_cast<int8_t *>(buffer) + index);
if (iter == locationListMap.end()) {
return 0;
}
WaiterListNode *node = iter->second.pHead;
uint32_t wokenUpCount = 0;
while (node != nullptr && wakeCount > 0.0) {
if (!node->waiting_) {
node = node->next_;
continue;
}
if (buffer == node->date_) {
ASSERT(index == node->index_);
node->waiting_ = false;
WaiterListNode *oldNode = node;
node = node->next_;
oldNode->cond_.Signal();
if (wakeCount != base::POSITIVE_INFINITY) {
wakeCount--;
}
wokenUpCount++;
continue;
}
node = node->next_;
}
return wokenUpCount;
}
} // namespace panda::ecmascript::builtins

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_BUILTINS_BUILTINS_ATOMICS_H
#define ECMASCRIPT_BUILTINS_BUILTINS_ATOMICS_H
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/js_dataview.h"
#include "ecmascript/waiter_list.h"
namespace panda::ecmascript::builtins {
enum class WaitResult: uint8_t {OK = 0, NOT_EQ, TIME_OUT};
class BuiltinsAtomics : public base::BuiltinsBase {
public:
// 25.4.2 Atomics.add ( typedArray, index, value )
static JSTaggedValue Add(EcmaRuntimeCallInfo *argv);
// 25.4.3 Atomics.and ( typedArray, index, value )
static JSTaggedValue And(EcmaRuntimeCallInfo *argv);
// 25.4.4 Atomics.compareExchange ( typedArray, index, expectedValue, replacementValue)
static JSTaggedValue CompareExchange(EcmaRuntimeCallInfo *argv);
// 25.4.5 Atomics.exchange ( typedArray, index, value )
static JSTaggedValue Exchange(EcmaRuntimeCallInfo *argv);
// 25.4.6 Atomics.isLockFree ( size )
static JSTaggedValue IsLockFree(EcmaRuntimeCallInfo *argv);
// 25.4.7 Atomics.load ( typedArray, index )
static JSTaggedValue Load(EcmaRuntimeCallInfo *argv);
// 25.4.8 Atomics.or ( typedArray, index, value )
static JSTaggedValue Or(EcmaRuntimeCallInfo *argv);
// 25.4.9 Atomics.store ( typedArray, index, value )
static JSTaggedValue Store(EcmaRuntimeCallInfo *argv);
// 25.4.10 Atomics.sub ( typedArray, index, value )
static JSTaggedValue Sub(EcmaRuntimeCallInfo *argv);
// 25.4.11 Atomics.wait ( typedArray, index, value, timeout)
static JSTaggedValue Wait(EcmaRuntimeCallInfo *argv);
// 25.4.12 Atomics.notify ( typedArray, index, count)
static JSTaggedValue Notify(EcmaRuntimeCallInfo *argv);
// 25.4.13 Atomics.xor ( typedArray, index, value )
static JSTaggedValue Xor(EcmaRuntimeCallInfo *argv);
private:
static uint32_t Signal(JSHandle<JSTaggedValue> &arrayBuffer, const size_t &index, double wakeCount);
template <typename T>
static WaitResult DoWait(JSThread *thread, JSHandle<JSTaggedValue> &arrayBuffer,
size_t index, T execpt, double timeout);
template<typename callbackfun>
static JSTaggedValue AtomicReadModifyWrite(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<JSTaggedValue> &index, EcmaRuntimeCallInfo *argv,
const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue AtomicReadModifyWriteCase(JSThread *thread, JSTaggedValue buffer, DataViewType type,
int32_t indexedPosition, EcmaRuntimeCallInfo *argv,
const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithUint8(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithInt8(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithUint16(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithInt16(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithUint32(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithInt32(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithBigInt64(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
template<typename callbackfun>
static JSTaggedValue HandleWithBigUint64(JSThread *thread, uint32_t size, uint8_t *block, int32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op);
static constexpr int ARGS_NUMBER = 2;
};
} // namespace panda::ecmascript::builtins
#endif // ECMASCRIPT_BUILTINS_BUILTINS_MATH_H

View File

@ -992,7 +992,7 @@ JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv)
uint32_t targetLength = targetObj->GetArrayLength();
JSHandle<JSTaggedValue> targetName(thread, targetObj->GetTypedArrayName());
uint32_t targetElementSize = TypedArrayHelper::GetSizeFromName(thread, targetName);
DataViewType targetType = TypedArrayHelper::GetTypeFromName(thread, targetName);
DataViewType targetType = JSTypedArray::GetTypeFromName(thread, targetName);
uint32_t targetByteOffset = targetObj->GetByteOffset();
JSHandle<JSTaggedValue> argArray = GetCallArg(argv, 0);
@ -1084,7 +1084,7 @@ JSTaggedValue BuiltinsTypedArray::Set(EcmaRuntimeCallInfo *argv)
// 21. Let srcLength be the value of typedArrays [[ArrayLength]] internal slot.
// 22. Let srcByteOffset be the value of typedArrays [[ByteOffset]] internal slot.
JSHandle<JSTaggedValue> srcName(thread, typedArray->GetTypedArrayName());
DataViewType srcType = TypedArrayHelper::GetTypeFromName(thread, srcName);
DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
uint32_t srcElementSize = TypedArrayHelper::GetSizeFromName(thread, srcName);
uint32_t srcLength = typedArray->GetArrayLength();
uint32_t srcByteOffset = typedArray->GetByteOffset();
@ -1214,11 +1214,11 @@ JSTaggedValue BuiltinsTypedArray::Slice(EcmaRuntimeCallInfo *argv)
// 17. Let srcName be the String value of Os [[TypedArrayName]] internal slot.
// 18. Let srcType be the String value of the Element Type value in Table 49 for srcName.
JSHandle<JSTaggedValue> srcName(thread, thisObj->GetTypedArrayName());
DataViewType srcType = TypedArrayHelper::GetTypeFromName(thread, srcName);
DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName);
// 19. Let targetName be the String value of As [[TypedArrayName]] internal slot.
// 20. Let targetType be the String value of the Element Type value in Table 49 for targetName.
JSHandle<JSTaggedValue> targetName(thread, JSTypedArray::Cast(*newArrObj)->GetTypedArrayName());
DataViewType targetType = TypedArrayHelper::GetTypeFromName(thread, targetName);
DataViewType targetType = JSTypedArray::GetTypeFromName(thread, targetName);
// 21. If SameValue(srcType, targetType) is false, then
// a. Let n be 0.
// b. Repeat, while k < final

View File

@ -52,6 +52,7 @@ host_unittest_action("BuiltinsNaturalTest") {
# test file
"builtins_array_test.cpp",
"builtins_arraybuffer_test.cpp",
"builtins_atomics_test.cpp",
"builtins_boolean_test.cpp",
"builtins_dataview_test.cpp",
"builtins_date_test.cpp",

View File

@ -0,0 +1,626 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/builtins/builtins_array.h"
#include "ecmascript/builtins/builtins_atomics.h"
#include "ecmascript/builtins/builtins_typedarray.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/js_typed_array.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
using namespace panda::ecmascript::builtins;
namespace panda::test {
using TypedArray = ecmascript::builtins::BuiltinsTypedArray;
class BuiltinsAtomicsTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
EcmaVM *instance {nullptr};
EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
};
JSTypedArray *CreateTypedArray(JSThread *thread, const JSHandle<TaggedArray> &array)
{
auto ecmaVM = thread->GetEcmaVM();
JSHandle<GlobalEnv> env = ecmaVM->GetGlobalEnv();
JSHandle<JSTaggedValue> jsarray(JSArray::CreateArrayFromList(thread, array));
JSHandle<JSFunction> int8_array(env->GetInt8ArrayFunction());
JSHandle<JSObject> globalObject(thread, env->GetGlobalObject());
// 6 : test case
auto ecmaRuntimeCallInfo1 = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue(*int8_array), 6);
ecmaRuntimeCallInfo1->SetFunction(JSTaggedValue(*int8_array));
ecmaRuntimeCallInfo1->SetThis(JSTaggedValue(*globalObject));
ecmaRuntimeCallInfo1->SetCallArg(0, jsarray.GetTaggedValue());
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo1.get());
JSTaggedValue result = TypedArray::Int8ArrayConstructor(ecmaRuntimeCallInfo1.get());
EXPECT_TRUE(result.IsECMAObject());
JSTypedArray *int8arr = JSTypedArray::Cast(reinterpret_cast<TaggedObject *>(result.GetRawData()));
return int8arr;
}
HWTEST_F_L0(BuiltinsAtomicsTest, Add_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(7));
array->Set(thread, 1, JSTaggedValue(8));
array->Set(thread, 2, JSTaggedValue(9));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(5)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Add(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Add_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(10));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Add(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 0);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Add_3)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Add(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 0);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
JSTaggedValue results = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(results.GetInt(), 2);
}
HWTEST_F_L0(BuiltinsAtomicsTest, And_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(10));
array->Set(thread, 0, JSTaggedValue(7));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Add(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
}
HWTEST_F_L0(BuiltinsAtomicsTest, And_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(10));
array->Set(thread, 0, JSTaggedValue(7));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::And(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 2);
}
HWTEST_F_L0(BuiltinsAtomicsTest, CompareExchange_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 12);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(5)));
ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::CompareExchange(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
}
HWTEST_F_L0(BuiltinsAtomicsTest, CompareExchange_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 12);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(5)));
ecmaRuntimeCallInfo->SetCallArg(3, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::CompareExchange(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 2);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Exchange_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(3));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(6)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Exchange(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 3);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Exchange_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(3));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(6)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Exchange(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 3);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 6);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Or_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Or(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Or_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 12);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Or(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Sub_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(0));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Sub(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Sub_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(0));
array->Set(thread, 1, JSTaggedValue(5));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Sub(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 3);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Xor_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(7));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Xor(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Xor_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(7));
array->Set(thread, 2, JSTaggedValue(0));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Xor(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 7);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(1)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 5);
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_1)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(1)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_2)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_3)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(4)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_4)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(-3)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_FALSE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, IsLockFree_5)
{
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int32_t>(8)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::IsLockFree(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_TRUE(result.ToBoolean());
}
HWTEST_F_L0(BuiltinsAtomicsTest, Store_1)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(6));
array->Set(thread, 2, JSTaggedValue(7));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Store(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetDouble(), 2);
}
HWTEST_F_L0(BuiltinsAtomicsTest, Store_2)
{
ASSERT_NE(thread, nullptr);
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
[[maybe_unused]] JSHandle<TaggedArray> array(factory->NewTaggedArray(3));
array->Set(thread, 0, JSTaggedValue(5));
array->Set(thread, 1, JSTaggedValue(6));
array->Set(thread, 2, JSTaggedValue(7));
JSHandle<JSTaggedValue> obj = JSHandle<JSTaggedValue>(thread, CreateTypedArray(thread, array));
auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 10);
ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfo->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfo->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
ecmaRuntimeCallInfo->SetCallArg(2, JSTaggedValue(static_cast<int32_t>(2)));
[[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get());
JSTaggedValue result = BuiltinsAtomics::Store(ecmaRuntimeCallInfo.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetDouble(), 2);
auto ecmaRuntimeCallInfos = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 8);
ecmaRuntimeCallInfos->SetFunction(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetThis(JSTaggedValue::Undefined());
ecmaRuntimeCallInfos->SetCallArg(0, obj.GetTaggedValue());
ecmaRuntimeCallInfos->SetCallArg(1, JSTaggedValue(static_cast<int32_t>(0)));
prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfos.get());
result = BuiltinsAtomics::Load(ecmaRuntimeCallInfos.get());
TestHelper::TearDownFrame(thread, prev);
ASSERT_EQ(result.GetInt(), 2);
}
}

View File

@ -1711,6 +1711,8 @@ void GlobalEnv::Dump(std::ostream &os) const
GetBuiltinsWeakMapFunction().GetTaggedValue().Dump(os);
os << " - MathFunction: ";
GetMathFunction().GetTaggedValue().Dump(os);
os << " - AtomicsFunction: ";
GetAtomicsFunction().GetTaggedValue().Dump(os);
os << " - JsonFunction: ";
GetJsonFunction().GetTaggedValue().Dump(os);
os << " - StringFunction: ";
@ -3589,6 +3591,7 @@ void GlobalEnv::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &
vec.push_back(std::make_pair(CString("BuiltinsWeakSetFunction"), GetBuiltinsWeakSetFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("BuiltinsWeakMapFunction"), GetBuiltinsWeakMapFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("MathFunction"), GetMathFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("AtomicsFunction"), GetAtomicsFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("JsonFunction"), GetJsonFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("StringFunction"), GetStringFunction().GetTaggedValue()));
vec.push_back(std::make_pair(CString("ProxyFunction"), GetProxyFunction().GetTaggedValue()));

View File

@ -24,6 +24,7 @@
#include "ecmascript/mem/chunk_containers.h"
#include "ecmascript/taskpool/taskpool.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/waiter_list.h"
namespace panda {
class JSNApi;
@ -273,6 +274,21 @@ public:
hostPromiseRejectionTracker_ = cb;
}
void SetAllowAtomicWait(bool wait)
{
AllowAtomicWait_ = wait;
}
bool GetAllowAtomicWait() const
{
return AllowAtomicWait_;
}
WaiterListNode *GetWaiterListNode()
{
return &waiterListNode_;
}
void PromiseRejectionTracker(const JSHandle<JSPromise> &promise,
const JSHandle<JSTaggedValue> &reason, PromiseRejectionEvent operation)
{
@ -374,6 +390,9 @@ private:
void* data_ {nullptr};
bool isProcessingPendingJob_ = false;
// atomics
bool AllowAtomicWait_ {true};
WaiterListNode waiterListNode_;
friend class Snapshot;
friend class SnapshotProcessor;

View File

@ -81,6 +81,7 @@ class JSThread;
V(JSTaggedValue, BuiltinsWeakSetFunction, BUILTINS_WEAK_SET_FUNCTION_INDEX) \
V(JSTaggedValue, MapPrototype, MAP_PROTOTYPE_INDEX) \
V(JSTaggedValue, MathFunction, MATH_FUNCTION_INDEX) \
V(JSTaggedValue, AtomicsFunction, ATOMICS_FUNCTION_INDEX) \
V(JSTaggedValue, JsonFunction, JSON_FUNCTION_INDEX) \
V(JSTaggedValue, StringFunction, STRING_FUNCTION_INDEX) \
V(JSTaggedValue, ProxyFunction, PROXY_FUNCTION_INDEX) \

View File

@ -474,6 +474,9 @@ void GlobalEnvConstants::InitGlobalConstant(JSThread *thread)
SetConstant(ConstantIndex::ELEMENT_INDEX, factory->NewFromASCII("element"));
SetConstant(ConstantIndex::FLAGS_INDEX, factory->NewFromASCII("flags"));
SetConstant(ConstantIndex::G_INDEX, factory->NewFromASCII("g"));
SetConstant(ConstantIndex::NOT_EQUAL_INDEX, factory->NewFromASCII("not-equal"));
SetConstant(ConstantIndex::OK_INDEX, factory->NewFromASCII("ok"));
SetConstant(ConstantIndex::TIMEOUT_INDEX, factory->NewFromASCII("timed-out"));
auto accessor = factory->NewInternalAccessor(reinterpret_cast<void *>(JSFunction::PrototypeSetter),
reinterpret_cast<void *>(JSFunction::PrototypeGetter));

View File

@ -342,7 +342,10 @@ class JSThread;
V(JSTaggedValue, DisjunctionString, DISJUNCTION_INDEX, disjunction) \
V(JSTaggedValue, ElementString, ELEMENT_INDEX, element) \
V(JSTaggedValue, FlagsString, FLAGS_INDEX, flags) \
V(JSTaggedValue, GString, G_INDEX, g)
V(JSTaggedValue, GString, G_INDEX, g) \
V(JSTaggedValue, NotEqualString, NOT_EQUAL_INDEX, notEqual) \
V(JSTaggedValue, OkString, OK_INDEX, ok) \
V(JSTaggedValue, TimeoutString, TIMEOUT_INDEX, timedout)
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define GLOBAL_ENV_CONSTANT_ACCESSOR(V) \

View File

@ -954,7 +954,7 @@ std::string BigIntHelper::MultiplyImpl(std::string &a, std::string &b)
str[i + j + 1] = static_cast<int8_t>(temp2 % 10 + 48); // 2 and 10 and 48 is number
addflag = temp2 / 10;
}
str[i] += static_cast<int8_t>(mulflag + addflag);
str[i] += static_cast<uint32_t>(mulflag + addflag);
}
if (str[0] == '0') {
str = str.substr(1, str.size());
@ -1429,4 +1429,19 @@ ComparisonResult BigInt::CompareWithNumber(JSHandle<BigInt> bigint, JSHandle<JST
}
return ComparisonResult::EQUAL;
}
int64_t BigInt::ToInt64()
{
int len = GetLength();
ASSERT(len < 2); // The maximum length of the BigInt data is less 2
uint64_t value = 0;
uint32_t *addr = reinterpret_cast<uint32_t *>(&value);
for (int index = len - 1; index >= 0; --index) {
*(addr + index) = GetDigit(index);
}
if (GetSign()) {
value = ~(value - 1);
}
return static_cast<int64_t>(value);
}
} // namespace

View File

@ -89,6 +89,8 @@ public:
static JSTaggedValue AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint);
static JSTaggedNumber BigIntToNumber(JSHandle<BigInt> bigint);
static ComparisonResult CompareWithNumber(JSHandle<BigInt> bigint, JSHandle<JSTaggedValue> number);
int64_t ToInt64();
inline bool IsZero()
{
return GetLength() == 1 && !GetDigit(0);

View File

@ -406,6 +406,42 @@ bool JSTypedArray::IsValidIntegerIndex(const JSHandle<JSTaggedValue> &typedArray
return true;
}
DataViewType JSTypedArray::GetTypeFromName(JSThread *thread, const JSHandle<JSTaggedValue> &typeName)
{
const GlobalEnvConstants *globalConst = thread->GlobalConstants();
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt8ArrayString())) {
return DataViewType::INT8;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ArrayString())) {
return DataViewType::UINT8;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint8ClampedArrayString())) {
return DataViewType::UINT8_CLAMPED;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt16ArrayString())) {
return DataViewType::INT16;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint16ArrayString())) {
return DataViewType::UINT16;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledInt32ArrayString())) {
return DataViewType::INT32;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledUint32ArrayString())) {
return DataViewType::UINT32;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat32ArrayString())) {
return DataViewType::FLOAT32;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledFloat64ArrayString())) {
return DataViewType::FLOAT64;
}
if (JSTaggedValue::SameValue(typeName, globalConst->GetHandledBigInt64ArrayString())) {
return DataViewType::BIGINT64;
}
return DataViewType::BIGUINT64;
}
// static
bool JSTypedArray::FastCopyElementToArray(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
JSHandle<TaggedArray> &array)

View File

@ -17,6 +17,7 @@
#define ECMASCRIPT_JS_TYPED_ARRAY_H
#include "ecmascript/tagged_array.h"
#include "ecmascript/js_dataview.h"
#include "js_object.h"
namespace panda::ecmascript {
@ -94,6 +95,7 @@ public:
// only use in TypeArray fast set property
static JSTaggedNumber NonEcmaObjectToNumber(JSThread *thread, const JSTaggedValue tagged);
static constexpr size_t VIEWED_ARRAY_BUFFER_OFFSET = JSObject::SIZE;
static DataViewType GetTypeFromName(JSThread *thread, const JSHandle<JSTaggedValue> &typeName);
ACCESSORS(ViewedArrayBuffer, VIEWED_ARRAY_BUFFER_OFFSET, TYPED_ARRAY_NAME_OFFSET)
ACCESSORS(TypedArrayName, TYPED_ARRAY_NAME_OFFSET, BYTE_LENGTH_OFFSET)
ACCESSORS_PRIMITIVE_FIELD(ByteLength, uint32_t, BYTE_LENGTH_OFFSET, BYTE_OFFSET_OFFSET)

View File

@ -104,6 +104,7 @@ void ConcurrentMarker::Reset(bool revertCSet)
auto callback = [](Region *region) {
region->ClearMarkGCBitset();
region->ClearCrossRegionRSet();
region->ResetAliveObject();
};
if (heap_->IsFullMark()) {
heap_->EnumerateRegions(callback);

View File

@ -371,6 +371,18 @@ namespace panda::ecmascript {
V(Math, Tan) \
V(Math, Tanh) \
V(Math, Trunc) \
V(Atomics, Add) \
V(Atomics, And) \
V(Atomics, Or) \
V(Atomics, Xor) \
V(Atomics, Sub) \
V(Atomics, Exchange) \
V(Atomics, CompareEchange) \
V(Atomics, Store) \
V(Atomics, Load) \
V(Atomics, IsLockFree) \
V(Atomics, Wait) \
V(Atomics, Notify) \
V(Number, Constructor) \
V(Number, IsFinite) \
V(Number, IsInteger) \

View File

@ -19,6 +19,7 @@
#include "ecmascript/builtins/builtins_array.h"
#include "ecmascript/builtins/builtins_arraybuffer.h"
#include "ecmascript/builtins/builtins_async_function.h"
#include "ecmascript/builtins/builtins_atomics.h"
#include "ecmascript/builtins/builtins_bigint.h"
#include "ecmascript/builtins/builtins_boolean.h"
#include "ecmascript/builtins/builtins_collator.h"
@ -116,6 +117,7 @@ using StringIterator = builtins::BuiltinsStringIterator;
using RegExp = builtins::BuiltinsRegExp;
using Function = builtins::BuiltinsFunction;
using Math = builtins::BuiltinsMath;
using Atomics = builtins::BuiltinsAtomics;
using ArrayBuffer = builtins::BuiltinsArrayBuffer;
using Json = builtins::BuiltinsJson;
using Proxy = builtins::BuiltinsProxy;
@ -504,6 +506,17 @@ static uintptr_t g_nativeTable[] = {
reinterpret_cast<uintptr_t>(Math::Tan),
reinterpret_cast<uintptr_t>(Math::Tanh),
reinterpret_cast<uintptr_t>(Math::Trunc),
reinterpret_cast<uintptr_t>(Atomics::Wait),
reinterpret_cast<uintptr_t>(Atomics::Exchange),
reinterpret_cast<uintptr_t>(Atomics::CompareExchange),
reinterpret_cast<uintptr_t>(Atomics::Store),
reinterpret_cast<uintptr_t>(Atomics::Load),
reinterpret_cast<uintptr_t>(Atomics::Notify),
reinterpret_cast<uintptr_t>(Atomics::Xor),
reinterpret_cast<uintptr_t>(Atomics::Or),
reinterpret_cast<uintptr_t>(Atomics::Sub),
reinterpret_cast<uintptr_t>(Atomics::And),
reinterpret_cast<uintptr_t>(Atomics::Add),
reinterpret_cast<uintptr_t>(Json::Parse),
reinterpret_cast<uintptr_t>(Json::Stringify),
reinterpret_cast<uintptr_t>(BuiltinsIterator::Next),

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/waiter_list.h"
#include "ecmascript/base/number_helper.h"
#include "os/time.h"
namespace panda::ecmascript {
// --------------------------WaiterList------------------------------
void WaiterList::AddNode(WaiterListNode *node)
{
ASSERT(node->prev_ == nullptr);
ASSERT(node->next_ == nullptr);
auto iter = locationListMap_.find(node->waitPointer_);
if (iter != locationListMap_.end()) {
iter->second.pTail->next_ = node;
node->prev_ = iter->second.pTail;
iter->second.pTail = node;
} else {
locationListMap_.insert(std::make_pair(node->waitPointer_, HeadAndTail {node, node}));
}
}
void WaiterList::DeleteNode(WaiterListNode *node)
{
auto iter = locationListMap_.find(node->waitPointer_);
ASSERT(iter != locationListMap_.end());
WaiterListNode *temp = iter->second.pHead;
bool flag = false;
while (temp != nullptr) {
if (temp == node) {
flag = true;
break;
}
temp = temp->next_;
}
ASSERT(flag);
if (node == iter->second.pHead && node == iter->second.pTail) {
locationListMap_.erase(iter);
return;
}
if (node == iter->second.pHead) {
iter->second.pHead = node->next_;
} else {
ASSERT(node->prev_);
node->prev_->next_ = node->next_;
}
if (node == iter->second.pTail) {
iter->second.pTail = node->prev_;
} else {
ASSERT(node->next_);
node->next_->prev_ = node->prev_;
}
node->prev_ = node->next_ = nullptr;
}
} // namespace

108
ecmascript/waiter_list.h Normal file
View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_WAITER_LIST_H
#define ECMASCRIPT_WAITER_LIST_H
#include "ecmascript/ecma_macros.h"
#include "ecmascript/mem/c_containers.h"
#include "os/mutex.h"
namespace panda::ecmascript {
using Mutex = os::memory::Mutex;
using LockHolder = os::memory::LockHolder<Mutex>;
class WaiterListNode {
public:
WaiterListNode() = default;
~WaiterListNode() = default;
public:
NO_COPY_SEMANTIC(WaiterListNode);
NO_MOVE_SEMANTIC(WaiterListNode);
WaiterListNode *prev_ {nullptr};
WaiterListNode *next_ {nullptr};
// Used to call wait or Signal() to unlock wait and wake up
os::memory::ConditionVariable cond_;
// Managed Arraybuffer or SharedArrayBuffer memory data
void *date_ {nullptr};
// the offset of the element in the typedArray
size_t index_ {0};
// the memory address data corresponding to the offset
int8_t *waitPointer_ {nullptr};
// used to determine whether to wait, start wait when waiting_ is true
bool waiting_ {false};
private:
friend class WaiterList;
};
// WaiterList to manage WaiterListNode
class WaiterList {
public:
WaiterList() = default;
void AddNode(WaiterListNode *node);
void DeleteNode(WaiterListNode *node);
struct HeadAndTail {
WaiterListNode *pHead {nullptr};
WaiterListNode *pTail {nullptr};
};
// locationListMap_ is used AddNode or DeleteNode
// When calling addnode If there is no corresponding memory data, add the node corresponding to the key
CMap<int8_t *, HeadAndTail> locationListMap_;
};
// The Singleton pattern is used to creat a global metux and WaiterList
template <class T>
class Singleton {
public:
~Singleton() {}
NO_COPY_SEMANTIC(Singleton);
NO_MOVE_SEMANTIC(Singleton);
static T *GetInstance()
{
static T instance;
return &instance;
}
private:
Singleton() = default;
};
class SCOPED_CAPABILITY MutexGuard
{
public:
explicit MutexGuard(Mutex *mutex) : mutex_(mutex), lockHolder_(*mutex) {}
void Unlock() RELEASE()
{
mutex_->Unlock();
}
void Lock() ACQUIRE()
{
mutex_->Lock();
}
public:
Mutex *mutex_;
LockHolder lockHolder_;
};
} // namespace
#endif // ECMASCRIPT_WAITER_LIST_H