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
19 namespace panda::ecmascript::base {
20 using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer;
21
ValidateIntegerTypedArray(JSThread * thread,JSHandle<JSTaggedValue> typedArray,bool waitable)22 JSTaggedValue 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,
35 JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName(thread));
36 DataViewType type = JSTypedArray::GetTypeFromName(thread, typeName);
37
38 // 5. If waitable is true, then
39 // a. If typeName is not "Int32Array" or "BigInt64Array", throw a TypeError exception.
40 // 6. Else,
41 // a. If ! IsUnclampedIntegerElementType(type) is false and ! IsBigIntElementType(type) is false,
42 // throw a TypeError exception.
43 if (waitable) {
44 if (!(type == DataViewType::INT32 || type == DataViewType::BIGINT64)) {
45 THROW_TYPE_ERROR_AND_RETURN(thread, "The typeName is not Int32Array/BigInt64Array.",
46 JSTaggedValue::Exception());
47 }
48 } else {
49 if (!(BuiltinsArrayBuffer::IsUnclampedIntegerElementType(type) ||
50 BuiltinsArrayBuffer::IsBigIntElementType(type))) {
51 THROW_TYPE_ERROR_AND_RETURN(thread, "The typedArray type is not UnclampedInteger/BigInt.",
52 JSTaggedValue::Exception());
53 }
54 }
55 // 7. Return buffer.
56 return bufferHandle.GetTaggedValue();
57 }
58
ValidateAtomicAccess(JSThread * thread,const JSHandle<JSTaggedValue> typedArray,JSHandle<JSTaggedValue> requestIndex)59 uint32_t AtomicHelper::ValidateAtomicAccess(JSThread *thread, const JSHandle<JSTaggedValue> typedArray,
60 JSHandle<JSTaggedValue> requestIndex)
61 {
62 // 1. Assert: typedArray is an Object that has a [[ViewedArrayBuffer]] internal slot.
63 ASSERT(typedArray->IsECMAObject() && typedArray->IsTypedArray());
64 // 2. Let length be typedArray.[[ArrayLength]].
65 JSHandle<JSObject> typedArrayObj(typedArray);
66 JSHandle<JSTypedArray> srcObj(typedArray);
67 uint32_t length = srcObj->GetArrayLength();
68
69 // 3. Let accessIndex be ? ToIndex(requestIndex).
70 JSTaggedNumber accessIndex = JSTaggedValue::ToIndex(thread, requestIndex);
71 RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0);
72 uint64_t index = base::NumberHelper::DoubleToUInt64(accessIndex.GetNumber());
73 // 4. If accessIndex ≥ length, throw a RangeError exception.
74 if (index >= length) {
75 THROW_RANGE_ERROR_AND_RETURN(thread, "Index is overflow.", 0);
76 }
77
78 // 5. Let arrayTypeName be typedArray.[[TypedArrayName]].
79 // 6. Let elementSize be the Element Size value specified in Table 60 for arrayTypeName.
80 // 7. Let offset be typedArray.[[ByteOffset]].
81 JSHandle<JSTaggedValue> arrayTypeName(thread, JSTypedArray::Cast(*typedArrayObj)->GetTypedArrayName(thread));
82 DataViewType elementType = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
83 uint32_t elementSize = TypedArrayHelper::GetSizeFromType(elementType);
84 uint32_t offset = srcObj->GetByteOffset();
85 // 8. Return (accessIndex × elementSize) + offset.
86 ASSERT(index * elementSize + offset <= UINT32_MAX);
87 uint32_t allOffset = static_cast<uint32_t>(index * elementSize + offset);
88 return allOffset;
89 }
90
AtomicStore(JSThread * thread,const JSHandle<JSTaggedValue> & typedArray,JSHandle<JSTaggedValue> index,JSHandle<JSTaggedValue> & value)91 JSTaggedValue AtomicHelper::AtomicStore(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
92 JSHandle<JSTaggedValue> index, JSHandle<JSTaggedValue> &value)
93 {
94 JSTaggedValue bufferValue = ValidateIntegerTypedArray(thread, typedArray);
95 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
96 JSHandle<JSTaggedValue> buffer(thread, bufferValue);
97 uint32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index);
98 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
99 JSHandle<JSTaggedValue> arrayTypeName(thread,
100 JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName(thread));
101 DataViewType type = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
102 JSHandle<JSTaggedValue> bufferTag;
103 if (type == DataViewType::BIGUINT64 || type == DataViewType::BIGINT64) {
104 JSTaggedValue integerValue = JSTaggedValue::ToBigInt(thread, value);
105 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
106 bufferTag = JSHandle<JSTaggedValue>(thread, integerValue);
107 } else {
108 JSTaggedNumber integerValue = JSTaggedValue::ToInteger(thread, value);
109 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
110 bufferTag = JSHandle<JSTaggedValue>(thread, integerValue);
111 }
112 BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(typedArray));
113 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
114 BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer.GetTaggedValue(), indexedPosition, type, bufferTag, true);
115 return bufferTag.GetTaggedValue();
116 }
117
AtomicLoad(JSThread * thread,const JSHandle<JSTaggedValue> & typedArray,JSHandle<JSTaggedValue> index)118 JSTaggedValue AtomicHelper::AtomicLoad(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
119 JSHandle<JSTaggedValue> index)
120 {
121 JSTaggedValue bufferValue = ValidateIntegerTypedArray(thread, typedArray);
122 JSHandle<JSTaggedValue> buffer(thread, bufferValue);
123 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
124 uint32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index);
125 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
126 BuiltinsArrayBuffer::IsDetachedBuffer(thread, JSHandle<JSTypedArray>::Cast(typedArray));
127 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
128 JSHandle<JSTaggedValue> arrayTypeName(thread,
129 JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName(thread));
130 DataViewType elementType = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
131 return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer.GetTaggedValue(),
132 indexedPosition, elementType, true);
133 }
134 } // panda::ecmascript::base
135
136