• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, 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 
ValidateAtomicAccess(JSThread * thread,const JSHandle<JSTaggedValue> typedArray,JSHandle<JSTaggedValue> requestIndex)58 uint32_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 
AtomicStore(JSThread * thread,const JSHandle<JSTaggedValue> & typedArray,JSHandle<JSTaggedValue> index,JSHandle<JSTaggedValue> & value)95 JSTaggedValue 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     if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
117         THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
118                                     JSTaggedValue::Exception());
119     }
120     BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer.GetTaggedValue(), indexedPosition, type, bufferTag, true);
121     return bufferTag.GetTaggedValue();
122 }
123 
AtomicLoad(JSThread * thread,const JSHandle<JSTaggedValue> & typedArray,JSHandle<JSTaggedValue> index)124 JSTaggedValue AtomicHelper::AtomicLoad(JSThread *thread, const JSHandle<JSTaggedValue> &typedArray,
125                                        JSHandle<JSTaggedValue> index)
126 {
127     JSTaggedValue bufferValue = ValidateIntegerTypedArray(thread, typedArray);
128     JSHandle<JSTaggedValue> buffer(thread, bufferValue);
129     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
130     uint32_t indexedPosition = ValidateAtomicAccess(thread, typedArray, index);
131     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
132     if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) {
133         THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.",
134                                     JSTaggedValue::Exception());
135     }
136     JSHandle<JSTaggedValue> arrayTypeName(thread,
137                                           JSTypedArray::Cast(typedArray->GetTaggedObject())->GetTypedArrayName());
138     DataViewType elementType = JSTypedArray::GetTypeFromName(thread, arrayTypeName);
139     return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer.GetTaggedValue(),
140                                                    indexedPosition, elementType, true);
141 }
142 }  // panda::ecmascript::base
143 
144