1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "ecmascript/base/atomic_helper.h" 17#include "ecmascript/base/typed_array_helper-inl.h" 18 19namespace panda::ecmascript::base { 20using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer; 21 22JSTaggedValue AtomicHelper::ValidateIntegerTypedArray(JSThread *thread, JSHandle<JSTaggedValue> typedArray, 23 bool waitable) 24{ 25 // 1. If waitable is not present, set waitable to false. 26 // 2. Let buffer be ? ValidateTypedArray(typedArray). 27 JSTaggedValue buffer = TypedArrayHelper::ValidateTypedArray(thread, typedArray); 28 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 29 30 JSHandle<JSTaggedValue> bufferHandle(thread, buffer); 31 32 // 3. Let typeName be typedArray.[[TypedArrayName]]. 33 // 4. Let type be the Element Type value in Table 60 for typeName. 34 JSHandle<JSTaggedValue> typeName(thread, JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName()); 35 DataViewType type = JSTypedArray::GetTypeFromName(thread, typeName); 36 37 // 5. If waitable is true, then 38 // a. If typeName is not "Int32Array" or "BigInt64Array", throw a TypeError exception. 39 // 6. Else, 40 // a. If ! IsUnclampedIntegerElementType(type) is false and ! IsBigIntElementType(type) is false, 41 // throw a TypeError exception. 42 if (waitable) { 43 if (!(type == DataViewType::INT32 || type == DataViewType::BIGINT64)) { 44 THROW_TYPE_ERROR_AND_RETURN(thread, "The typeName is not Int32Array/BigInt64Array.", 45 JSTaggedValue::Exception()); 46 } 47 } else { 48 if (!(BuiltinsArrayBuffer::IsUnclampedIntegerElementType(type) || 49 BuiltinsArrayBuffer::IsBigIntElementType(type))) { 50 THROW_TYPE_ERROR_AND_RETURN(thread, "The typedArray type is not UnclampedInteger/BigInt.", 51 JSTaggedValue::Exception()); 52 } 53 } 54 // 7. Return buffer. 55 return bufferHandle.GetTaggedValue(); 56} 57 58uint32_t AtomicHelper::ValidateAtomicAccess(JSThread *thread, const JSHandle<JSTaggedValue> typedArray, 59 JSHandle<JSTaggedValue> requestIndex) 60{ 61 // 1. Assert: typedArray is an Object that has a [[ViewedArrayBuffer]] internal slot. 62 ASSERT(typedArray->IsECMAObject() && typedArray->IsTypedArray()); 63 // 2. Let length be typedArray.[[ArrayLength]]. 64 JSHandle<JSObject> typedArrayObj(typedArray); 65 JSHandle<JSTypedArray> srcObj(typedArray); 66 int32_t length = static_cast<int32_t>(srcObj->GetArrayLength()); 67 68 // 3. Let accessIndex be ? ToIndex(requestIndex). 69 JSTaggedNumber accessIndex = JSTaggedValue::ToIndex(thread, requestIndex); 70 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0); 71 int32_t index = base::NumberHelper::DoubleInRangeInt32(accessIndex.GetNumber()); 72 73 // 4. Assert: accessIndex ≥ 0. 74 ASSERT(index >= 0); 75 76 // 5. If accessIndex ≥ length, throw a RangeError exception. 77 if (index >= length) { 78 THROW_RANGE_ERROR_AND_RETURN(thread, "Index is overflow.", 0); 79 } 80 81 // 6. Let arrayTypeName be typedArray.[[TypedArrayName]]. 82 // 7. Let elementSize be the Element Size value specified in Table 60 for arrayTypeName. 83 // 8. Let offset be typedArray.[[ByteOffset]]. 84 JSHandle<JSTaggedValue> arrayTypeName(thread, JSTypedArray::Cast(*typedArrayObj)->GetTypedArrayName()); 85 DataViewType elementType = JSTypedArray::GetTypeFromName(thread, arrayTypeName); 86 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(elementType); 87 uint32_t offset = srcObj->GetByteOffset(); 88 // 9. Return (accessIndex × elementSize) + offset. 89 ASSERT((static_cast<size_t>(index) * static_cast<size_t>(elementSize) + 90 static_cast<size_t>(offset)) <= static_cast<size_t>(UINT32_MAX)); 91 uint32_t allOffset = static_cast<uint32_t>(index) * elementSize + offset; 92 return allOffset; 93} 94 95JSTaggedValue AtomicHelper::AtomicStore(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray, 96 JSHandle<JSTaggedValue> index, JSHandle<JSTaggedValue> &value) 97{ 98 JSTaggedValue bufferValue = ValidateIntegerTypedArray(thread, typedArray); 99 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 100 JSHandle<JSTaggedValue> buffer(thread, bufferValue); 101 uint32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index); 102 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 103 JSHandle<JSTaggedValue> arrayTypeName(thread, 104 JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName()); 105 DataViewType type = JSTypedArray::GetTypeFromName(thread, arrayTypeName); 106 JSHandle<JSTaggedValue> bufferTag; 107 if (type == DataViewType::BIGUINT64 || type == DataViewType::BIGINT64) { 108 JSTaggedValue integerValue = JSTaggedValue::ToBigInt(thread, value); 109 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 110 bufferTag = JSHandle<JSTaggedValue>(thread, integerValue); 111 } else { 112 JSTaggedNumber integerValue = JSTaggedValue::ToInteger(thread, value); 113 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 114 bufferTag = JSHandle<JSTaggedValue>(thread, integerValue); 115 } 116 BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(typedArray)); 117 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 118 BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer.GetTaggedValue(), indexedPosition, type, bufferTag, true); 119 return bufferTag.GetTaggedValue(); 120} 121 122JSTaggedValue AtomicHelper::AtomicLoad(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray, 123 JSHandle<JSTaggedValue> index) 124{ 125 JSTaggedValue bufferValue = ValidateIntegerTypedArray(thread, typedArray); 126 JSHandle<JSTaggedValue> buffer(thread, bufferValue); 127 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 128 uint32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index); 129 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 130 BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(typedArray)); 131 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 132 JSHandle<JSTaggedValue> arrayTypeName(thread, 133 JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName()); 134 DataViewType elementType = JSTypedArray::GetTypeFromName(thread, arrayTypeName); 135 return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer.GetTaggedValue(), 136 indexedPosition, elementType, true); 137} 138} // panda::ecmascript::base 139 140