arkcompiler_ets_runtime/ecmascript/builtins/builtins_atomics.cpp
fangting 30d0fdadbb optimize libark_jsruntiem builtins
optimize libark_jsruntiem builtins

Issue:#IAFU21
Signed-off-by: fangting <fangting12@huawei.com>
2024-08-04 16:17:12 +08:00

654 lines
30 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2022-2024 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 "libpandabase/utils/time.h"
#include "ecmascript/checkpoint/thread_state_transition.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 = false;
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, Atomics, 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).
uint32_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()) {
if (value->IsBoolean()) {
value = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt64(thread, value));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
}
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->GetCurrentEcmaContext()->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, Atomics, 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).
uint32_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)
{
BUILTINS_API_TRACE(thread, Atomics, AtomicReadModifyWrite);
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).
uint32_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());
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(typedArray));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
// 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, uint32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op)
{
BUILTINS_API_TRACE(thread, Atomics, AtomicReadModifyWriteCase);
JSHandle<JSTaggedValue> arrBufHadle(thread, arrBuf);
JSHandle<JSTaggedValue> value = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
void *pointer = BuiltinsArrayBuffer::GetDataPointFromBuffer(arrBufHadle.GetTaggedValue());
uint8_t *block = reinterpret_cast<uint8_t *>(pointer);
uint32_t size = argv->GetArgsNumber();
switch (type) {
case DataViewType::UINT8: {
uint8_t tag = JSTaggedValue::ToInt8(thread, value);
pointer = BuiltinsArrayBuffer::GetDataPointFromBuffer(arrBufHadle.GetTaggedValue());
block = reinterpret_cast<uint8_t *>(pointer);
return HandleWithUint8(thread, size, block, indexedPosition, argv, op, tag);
}
case DataViewType::INT8:{
int8_t tag = JSTaggedValue::ToInt8(thread, value);
pointer = BuiltinsArrayBuffer::GetDataPointFromBuffer(arrBufHadle.GetTaggedValue());
block = reinterpret_cast<uint8_t *>(pointer);
return HandleWithInt8(thread, size, block, indexedPosition, argv, op, tag);
}
case DataViewType::UINT16: {
uint16_t tag = JSTaggedValue::ToInt16(thread, value);
pointer = BuiltinsArrayBuffer::GetDataPointFromBuffer(arrBufHadle.GetTaggedValue());
block = reinterpret_cast<uint8_t *>(pointer);
return HandleWithUint16(thread, size, block, indexedPosition, argv, op, tag);
}
case DataViewType::INT16: {
int16_t tag = JSTaggedValue::ToInt16(thread, value);
pointer = BuiltinsArrayBuffer::GetDataPointFromBuffer(arrBufHadle.GetTaggedValue());
block = reinterpret_cast<uint8_t *>(pointer);
return HandleWithInt16(thread, size, block, indexedPosition, argv, op, tag);
}
case DataViewType::UINT32: {
uint32_t tag = JSTaggedValue::ToUint32(thread, value);
pointer = BuiltinsArrayBuffer::GetDataPointFromBuffer(arrBufHadle.GetTaggedValue());
block = reinterpret_cast<uint8_t *>(pointer);
return HandleWithUint32(thread, size, block, indexedPosition, argv, op, tag);
}
case DataViewType::INT32: {
int32_t tag = static_cast<int32_t>(JSTaggedValue::ToUint32(thread, value));
pointer = BuiltinsArrayBuffer::GetDataPointFromBuffer(arrBufHadle.GetTaggedValue());
block = reinterpret_cast<uint8_t *>(pointer);
return HandleWithInt32(thread, size, block, indexedPosition, argv, op, tag);
}
case DataViewType::BIGINT64: {
int64_t val = 0;
bool lossless = true;
BigInt::BigIntToInt64(thread, value, &val, &lossless);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return HandleWithBigInt64(thread, size, block, indexedPosition, argv, op, val, lossless);
}
case DataViewType::BIGUINT64: {
uint64_t val = 0;
bool lossless = true;
BigInt::BigIntToUint64(thread, value, &val, &lossless);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
return HandleWithBigUint64(thread, size, block, indexedPosition, argv, op, val, lossless);
}
default:
break;
}
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithUint8(JSThread *thread, uint32_t size, uint8_t *block,
uint32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op, uint8_t &tag)
{
BUILTINS_API_TRACE(thread, Atomics, HandleWithUint8);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint8_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
if (size == 3) { // the number of parameters is 3
auto result = op((block + indexedPosition), arg, ARGS_NUMBER);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint8_t newTag = JSTaggedValue::ToUint8(thread, newValue);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
arg[1] = newTag;
auto result = op((block + indexedPosition), arg, ARGS_NUMBER);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithInt8(JSThread *thread, uint32_t size, uint8_t *block,
uint32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op, int8_t &tag)
{
BUILTINS_API_TRACE(thread, Atomics, HandleWithInt8);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
int8_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int8_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int8_t newTag = JSTaggedValue::ToInt8(thread, newValue);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
arg[1] = newTag;
auto result = op(reinterpret_cast<int8_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithUint16(JSThread *thread, uint32_t size, uint8_t *block,
uint32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op, uint16_t &tag)
{
BUILTINS_API_TRACE(thread, Atomics, HandleWithUint16);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint16_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<uint16_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint16_t newTag = JSTaggedValue::ToUint16(thread, newValue);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
arg[1] = newTag;
auto result = op(reinterpret_cast<uint16_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithInt16(JSThread *thread, uint32_t size, uint8_t *block,
uint32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op, int16_t &tag)
{
BUILTINS_API_TRACE(thread, Atomics, HandleWithInt16);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
int16_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int16_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int16_t newTag = JSTaggedValue::ToInt16(thread, newValue);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
arg[1] = newTag;
auto result = op(reinterpret_cast<int16_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithUint32(JSThread *thread, uint32_t size, uint8_t *block,
uint32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op, uint32_t &tag)
{
BUILTINS_API_TRACE(thread, Atomics, HandleWithUint32);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint32_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<uint32_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return JSTaggedValue(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
uint32_t newTag = JSTaggedValue::ToUint32(thread, newValue);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
arg[1] = newTag;
auto result = op(reinterpret_cast<uint32_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithInt32(JSThread *thread, uint32_t size, uint8_t *block,
uint32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op, int32_t &tag)
{
BUILTINS_API_TRACE(thread, Atomics, HandleWithInt32);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
int32_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int32_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return BuiltinsBase::GetTaggedInt(result);
}
JSHandle<JSTaggedValue> newValue = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::FOURTH);
int32_t newTag = JSTaggedValue::ToInt32(thread, newValue);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
arg[1] = newTag;
auto result = op(reinterpret_cast<int32_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return JSTaggedValue(result);
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithBigInt64(JSThread *thread, uint32_t size, uint8_t *block,
uint32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op,
int64_t &tag, bool &lossless)
{
BUILTINS_API_TRACE(thread, Atomics, HandleWithBigInt64);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
int64_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<int64_t *>(block + indexedPosition), arg, ARGS_NUMBER);
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);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
arg[1] = newVal;
auto result = op(reinterpret_cast<int64_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return BigInt::Int64ToBigInt(thread, result).GetTaggedValue();
}
template<typename callbackfun>
JSTaggedValue BuiltinsAtomics::HandleWithBigUint64(JSThread *thread, uint32_t size, uint8_t *block,
uint32_t indexedPosition,
EcmaRuntimeCallInfo *argv, const callbackfun &op,
uint64_t &tag, bool &lossless)
{
BUILTINS_API_TRACE(thread, Atomics, HandleWithBigUint64);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
uint64_t arg[ARGS_NUMBER] = {0};
arg[0] = tag;
if (size == 3) { // the number of parameters is 3
auto result = op(reinterpret_cast<uint64_t *>(block + indexedPosition), arg, ARGS_NUMBER);
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);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(GetCallArg(argv, 0)));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
arg[1] = newVal;
auto result = op(reinterpret_cast<uint64_t *>(block + indexedPosition), arg, ARGS_NUMBER);
return BigInt::Uint64ToBigInt(thread, result).GetTaggedValue();
}
template <typename T>
WaitResult BuiltinsAtomics::DoWait(JSThread *thread, JSHandle<JSTaggedValue> &arrayBuffer,
size_t index, T execpt, double timeout)
{
BUILTINS_API_TRACE(thread, Atomics, DoWait);
MutexGuard lockGuard(g_mutex);
void *buffer = BuiltinsArrayBuffer::GetDataPointFromBuffer(arrayBuffer.GetTaggedValue());
ASSERT(buffer != nullptr);
WaiterListNode *node = thread->GetCurrentEcmaContext()->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;
ThreadNativeScope nativeScope(thread);
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)
{
void *buffer = BuiltinsArrayBuffer::GetDataPointFromBuffer(arrayBuffer.GetTaggedValue());
ASSERT(buffer != nullptr);
MutexGuard lockGuard(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