* 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)
{
JSTaggedValue buffer = TypedArrayHelper::ValidateTypedArray(thread, typedArray);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
JSHandle<JSTaggedValue> bufferHandle(thread, buffer);
DataViewType type = JSTypedArray::Cast(typedArray->GetTaggedObject())->GetContentType();
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());
}
}
return bufferHandle.GetTaggedValue();
}
uint32_t AtomicHelper::ValidateAtomicAccess(JSThread *thread, const JSHandle<JSTaggedValue> typedArray,
JSHandle<JSTaggedValue> requestIndex)
{
ASSERT(typedArray->IsECMAObject() && typedArray->IsTypedArray());
JSHandle<JSObject> typedArrayObj(typedArray);
JSHandle<JSTypedArray> srcObj(typedArray);
uint32_t length = srcObj->GetArrayLength();
JSTaggedNumber accessIndex = JSTaggedValue::ToIndex(thread, requestIndex);
RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
uint64_t index = base::NumberHelper::DoubleToUInt64(accessIndex.GetNumber());
if (index >= length) {
THROW_RANGE_ERROR_AND_RETURN(thread, "Index is overflow.", 0);
}
DataViewType elementType = JSTypedArray::Cast(*typedArrayObj)->GetContentType();
uint32_t elementSize = TypedArrayHelper::GetSizeFromType(elementType);
uint32_t offset = srcObj->GetByteOffset();
ASSERT(index * elementSize + offset <= UINT32_MAX);
uint32_t allOffset = static_cast<uint32_t>(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> bufferTag;
if (UNLIKELY(JSTypedArray::Cast(typedArray->GetTaggedObject())->ContentTypeIsBigInt())) {
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);
}
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(typedArray));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
DataViewType type = JSTypedArray::Cast(typedArray->GetTaggedObject())->GetContentType();
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);
uint32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index);
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(typedArray));
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
DataViewType elementType = JSTypedArray::Cast(typedArray->GetTaggedObject())->GetContentType();
return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer.GetTaggedValue(),
indexedPosition, elementType, true);
}
}