• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 #ifndef PANDA_RUNTIME_CORETYPES_ARRAY_INL_H_
16 #define PANDA_RUNTIME_CORETYPES_ARRAY_INL_H_
17 
18 #include <type_traits>
19 
20 #include "runtime/include/coretypes/array.h"
21 #include "runtime/include/exceptions.h"
22 #include "runtime/include/object_accessor-inl.h"
23 #include "runtime/handle_scope.h"
24 #include "runtime/mem/vm_handle.h"
25 
26 namespace ark::coretypes {
27 
28 // IS_VOLATILE = false
29 template <class T, bool IS_VOLATILE>
GetPrimitive(size_t offset)30 inline T Array::GetPrimitive(size_t offset) const
31 {
32     return ObjectAccessor::GetPrimitive<T, IS_VOLATILE>(this, GetDataOffset() + offset);
33 }
34 
35 // IS_VOLATILE = false
36 template <class T, bool IS_VOLATILE>
SetPrimitive(size_t offset,T value)37 inline void Array::SetPrimitive(size_t offset, T value)
38 {
39     ObjectAccessor::SetPrimitive<T, IS_VOLATILE>(this, GetDataOffset() + offset, value);
40 }
41 
42 //  IS_VOLATILE = false , NEED_READ_BARRIER = true , bool IS_DYN = false
43 template <bool IS_VOLATILE, bool NEED_READ_BARRIER, bool IS_DYN>
GetObject(int offset)44 inline ObjectHeader *Array::GetObject(int offset) const
45 {
46     return ObjectAccessor::GetObject<IS_VOLATILE, NEED_READ_BARRIER, IS_DYN>(this, GetDataOffset() + offset);
47 }
48 
49 //  IS_VOLATILE = false , NEED_READ_BARRIER = true , bool IS_DYN = false
50 template <bool IS_VOLATILE, bool NEED_WRITE_BARRIER, bool IS_DYN>
SetObject(size_t offset,ObjectHeader * value)51 inline void Array::SetObject(size_t offset, ObjectHeader *value)
52 {
53     ObjectAccessor::SetObject<IS_VOLATILE, NEED_WRITE_BARRIER, IS_DYN>(this, GetDataOffset() + offset, value);
54 }
55 
56 template <class T>
GetPrimitive(size_t offset,std::memory_order memoryOrder)57 inline T Array::GetPrimitive(size_t offset, std::memory_order memoryOrder) const
58 {
59     return ObjectAccessor::GetFieldPrimitive<T>(this, GetDataOffset() + offset, memoryOrder);
60 }
61 
62 template <class T>
SetPrimitive(size_t offset,T value,std::memory_order memoryOrder)63 inline void Array::SetPrimitive(size_t offset, T value, std::memory_order memoryOrder)
64 {
65     ObjectAccessor::SetFieldPrimitive(this, GetDataOffset() + offset, value, memoryOrder);
66 }
67 
68 // NEED_READ_BARRIER = true , IS_DYN = false
69 template <bool NEED_READ_BARRIER, bool IS_DYN>
GetObject(size_t offset,std::memory_order memoryOrder)70 inline ObjectHeader *Array::GetObject(size_t offset, std::memory_order memoryOrder) const
71 {
72     return ObjectAccessor::GetFieldObject<NEED_READ_BARRIER, IS_DYN>(this, GetDataOffset() + offset, memoryOrder);
73 }
74 
75 // NEED_WRITE_BARRIER = true , IS_DYN = false
76 template <bool NEED_WRITE_BARRIER, bool IS_DYN>
SetObject(size_t offset,ObjectHeader * value,std::memory_order memoryOrder)77 inline void Array::SetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder)
78 {
79     ObjectAccessor::SetFieldObject<NEED_WRITE_BARRIER, IS_DYN>(this, GetDataOffset() + offset, value, memoryOrder);
80 }
81 
82 template <typename T>
CompareAndSetPrimitive(size_t offset,T oldValue,T newValue,std::memory_order memoryOrder,bool strong)83 inline bool Array::CompareAndSetPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder,
84                                           bool strong)
85 {
86     return ObjectAccessor::CompareAndSetFieldPrimitive(this, GetDataOffset() + offset, oldValue, newValue, memoryOrder,
87                                                        strong)
88         .first;
89 }
90 
91 // NEED_WRITE_BARRIER = true , IS_DYN = false
92 template <bool NEED_WRITE_BARRIER, bool IS_DYN>
CompareAndSetObject(size_t offset,ObjectHeader * oldValue,ObjectHeader * newValue,std::memory_order memoryOrder,bool strong)93 inline bool Array::CompareAndSetObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
94                                        std::memory_order memoryOrder, bool strong)
95 {
96     auto fieldOffset = GetDataOffset() + offset;
97     return ObjectAccessor::CompareAndSetFieldObject<NEED_WRITE_BARRIER, IS_DYN>(this, fieldOffset, oldValue, newValue,
98                                                                                 memoryOrder, strong)
99         .first;
100 }
101 
102 template <typename T>
CompareAndExchangePrimitive(size_t offset,T oldValue,T newValue,std::memory_order memoryOrder,bool strong)103 inline T Array::CompareAndExchangePrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder,
104                                             bool strong)
105 {
106     return ObjectAccessor::CompareAndSetFieldPrimitive(this, GetDataOffset() + offset, oldValue, newValue, memoryOrder,
107                                                        strong)
108         .second;
109 }
110 
111 // NEED_READ_BARRIER = true , IS_DYN = false
112 template <bool NEED_WRITE_BARRIER, bool IS_DYN>
CompareAndExchangeObject(size_t offset,ObjectHeader * oldValue,ObjectHeader * newValue,std::memory_order memoryOrder,bool strong)113 inline ObjectHeader *Array::CompareAndExchangeObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
114                                                      std::memory_order memoryOrder, bool strong)
115 {
116     auto fieldOffset = GetDataOffset() + offset;
117     return ObjectAccessor::CompareAndSetFieldObject<NEED_WRITE_BARRIER, IS_DYN>(this, fieldOffset, oldValue, newValue,
118                                                                                 memoryOrder, strong)
119         .second;
120 }
121 
122 template <typename T>
GetAndSetPrimitive(size_t offset,T value,std::memory_order memoryOrder)123 inline T Array::GetAndSetPrimitive(size_t offset, T value, std::memory_order memoryOrder)
124 {
125     return ObjectAccessor::GetAndSetFieldPrimitive(this, GetDataOffset() + offset, value, memoryOrder);
126 }
127 
128 // NEED_READ_BARRIER = true , IS_DYN = false
129 template <bool NEED_WRITE_BARRIER, bool IS_DYN>
GetAndSetObject(size_t offset,ObjectHeader * value,std::memory_order memoryOrder)130 inline ObjectHeader *Array::GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder)
131 {
132     return ObjectAccessor::GetAndSetFieldObject<NEED_WRITE_BARRIER, IS_DYN>(this, GetDataOffset() + offset, value,
133                                                                             memoryOrder);
134 }
135 
136 template <typename T>
GetAndAddPrimitive(size_t offset,T value,std::memory_order memoryOrder)137 inline T Array::GetAndAddPrimitive(size_t offset, T value, std::memory_order memoryOrder)
138 {
139     return ObjectAccessor::GetAndAddFieldPrimitive<T>(this, GetDataOffset() + offset, value, memoryOrder);
140 }
141 
142 template <typename T>
GetAndBitwiseOrPrimitive(size_t offset,T value,std::memory_order memoryOrder)143 inline T Array::GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memoryOrder)
144 {
145     return ObjectAccessor::GetAndBitwiseOrFieldPrimitive(this, GetDataOffset() + offset, value, memoryOrder);
146 }
147 
148 template <typename T>
GetAndBitwiseAndPrimitive(size_t offset,T value,std::memory_order memoryOrder)149 inline T Array::GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memoryOrder)
150 {
151     return ObjectAccessor::GetAndBitwiseAndFieldPrimitive(this, GetDataOffset() + offset, value, memoryOrder);
152 }
153 
154 template <typename T>
GetAndBitwiseXorPrimitive(size_t offset,T value,std::memory_order memoryOrder)155 inline T Array::GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memoryOrder)
156 {
157     return ObjectAccessor::GetAndBitwiseXorFieldPrimitive(this, GetDataOffset() + offset, value, memoryOrder);
158 }
159 
160 template <class T, bool NEED_WRITE_BARRIER, bool IS_DYN, bool IS_VOLATILE>
Set(ArraySizeT idx,T elem,uint32_t byteOffset)161 inline std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, void> Array::Set(ArraySizeT idx, T elem,
162                                                                                     uint32_t byteOffset)
163 {
164     size_t elemSize = (is_object_v<T> && !IS_DYN) ? sizeof(ObjectPointerType) : sizeof(T);
165     size_t offset = elemSize * idx + byteOffset;
166     // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
167     // NOLINTNEXTLINE(readability-braces-around-statements)
168     if constexpr (is_object_v<T>) {
169         ObjectAccessor::SetObject<IS_VOLATILE, NEED_WRITE_BARRIER, IS_DYN>(this, GetDataOffset() + offset, elem);
170         // NOLINTNEXTLINE(readability-misleading-indentation)
171     } else {
172         ObjectAccessor::SetPrimitive<T, IS_VOLATILE>(this, GetDataOffset() + offset, elem);
173     }
174 }
175 
176 // NEED_READ_BARRIER = true , IS_DYN = false
177 template <class T, bool NEED_READ_BARRIER, bool IS_DYN, bool IS_VOLATILE>
Get(ArraySizeT idx,uint32_t byteOffset)178 inline std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, T> Array::Get(ArraySizeT idx,
179                                                                                  uint32_t byteOffset) const
180 {
181     size_t offset = GetElementSize<T, IS_DYN>() * idx + byteOffset;
182     if constexpr (is_object_v<T>) {
183         return static_cast<T>(
184             ObjectAccessor::GetObject<IS_VOLATILE, NEED_READ_BARRIER, IS_DYN>(this, GetDataOffset() + offset));
185     }
186     return ObjectAccessor::GetPrimitive<T, IS_VOLATILE>(this, GetDataOffset() + offset);
187 }
188 
189 template <class T, bool NEED_WRITE_BARRIER, bool IS_DYN>
CompareAndExchange(ArraySizeT idx,T oldValue,T newValue,std::memory_order memoryOrder,bool strong,uint32_t byteOffset)190 inline std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, std::pair<bool, T>> Array::CompareAndExchange(
191     ArraySizeT idx, T oldValue, T newValue, std::memory_order memoryOrder, bool strong, uint32_t byteOffset)
192 {
193     size_t offset = GetElementSize<T, IS_DYN>() * idx + byteOffset;
194     if constexpr (is_object_v<T>) {
195         auto [success, obj] = ObjectAccessor::CompareAndSetFieldObject<NEED_WRITE_BARRIER, IS_DYN>(
196             this, GetDataOffset() + offset, oldValue, newValue, memoryOrder, strong);
197         return {success, reinterpret_cast<T>(obj)};
198     }
199     return ObjectAccessor::CompareAndSetFieldPrimitive<T>(this, GetDataOffset() + offset, oldValue, newValue,
200                                                           memoryOrder, strong);
201 }
202 
203 template <class T, bool NEED_WRITE_BARRIER, bool IS_DYN>
Exchange(ArraySizeT idx,T value,std::memory_order memoryOrder,uint32_t byteOffset)204 inline std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, T> Array::Exchange(ArraySizeT idx, T value,
205                                                                                       std::memory_order memoryOrder,
206                                                                                       uint32_t byteOffset)
207 {
208     size_t offset = GetElementSize<T, IS_DYN>() * idx + byteOffset;
209     if constexpr (is_object_v<T>) {
210         return ObjectAccessor::GetAndSetFieldObject(this, GetDataOffset() + offset, value, memoryOrder);
211     }
212     return ObjectAccessor::GetAndSetFieldPrimitive(this, GetDataOffset() + offset, value, memoryOrder);
213 }
214 
215 template <class T>
GetAndAdd(ArraySizeT idx,T value,std::memory_order memoryOrder,uint32_t byteOffset)216 inline std::enable_if_t<std::is_arithmetic_v<T>, T> Array::GetAndAdd(ArraySizeT idx, T value,
217                                                                      std::memory_order memoryOrder, uint32_t byteOffset)
218 {
219     size_t offset = GetElementSize<T, false>() * idx + byteOffset;
220     return ObjectAccessor::GetAndAddFieldPrimitive<T, true>(this, GetDataOffset() + offset, value, memoryOrder);
221 }
222 
223 template <class T>
GetAndSub(ArraySizeT idx,T value,std::memory_order memoryOrder,uint32_t byteOffset)224 inline std::enable_if_t<std::is_arithmetic_v<T>, T> Array::GetAndSub(ArraySizeT idx, T value,
225                                                                      std::memory_order memoryOrder, uint32_t byteOffset)
226 {
227     size_t offset = GetElementSize<T, false>() * idx + byteOffset;
228     return ObjectAccessor::GetAndSubFieldPrimitive<T, true>(this, GetDataOffset() + offset, value, memoryOrder);
229 }
230 
231 template <class T>
GetAndBitwiseOr(ArraySizeT idx,T value,std::memory_order memoryOrder,uint32_t byteOffset)232 inline std::enable_if_t<std::is_arithmetic_v<T>, T> Array::GetAndBitwiseOr(ArraySizeT idx, T value,
233                                                                            std::memory_order memoryOrder,
234                                                                            uint32_t byteOffset)
235 {
236     size_t offset = GetElementSize<T, false>() * idx + byteOffset;
237     return ObjectAccessor::GetAndBitwiseOrFieldPrimitive(this, GetDataOffset() + offset, value, memoryOrder);
238 }
239 
240 template <class T>
GetAndBitwiseAnd(ArraySizeT idx,T value,std::memory_order memoryOrder,uint32_t byteOffset)241 inline std::enable_if_t<std::is_arithmetic_v<T>, T> Array::GetAndBitwiseAnd(ArraySizeT idx, T value,
242                                                                             std::memory_order memoryOrder,
243                                                                             uint32_t byteOffset)
244 {
245     size_t offset = GetElementSize<T, false>() * idx + byteOffset;
246     return ObjectAccessor::GetAndBitwiseAndFieldPrimitive(this, GetDataOffset() + offset, value, memoryOrder);
247 }
248 
249 template <class T>
GetAndBitwiseXor(ArraySizeT idx,T value,std::memory_order memoryOrder,uint32_t byteOffset)250 inline std::enable_if_t<std::is_arithmetic_v<T>, T> Array::GetAndBitwiseXor(ArraySizeT idx, T value,
251                                                                             std::memory_order memoryOrder,
252                                                                             uint32_t byteOffset)
253 {
254     size_t offset = GetElementSize<T, false>() * idx + byteOffset;
255     return ObjectAccessor::GetAndBitwiseXorFieldPrimitive(this, GetDataOffset() + offset, value, memoryOrder);
256 }
257 
258 template <class T, bool IS_DYN>
GetElementSize()259 inline constexpr size_t Array::GetElementSize()
260 {
261     constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
262     static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
263     return (IS_REF && !IS_DYN) ? sizeof(ObjectPointerType) : sizeof(T);
264 }
265 
266 template <class T>
GetBase()267 T Array::GetBase()
268 {
269     return reinterpret_cast<T>(ToUintPtr(this) + GetDataOffset());
270 }
271 
272 // NEED_WRITE_BARRIER = true , IS_DYN = false
273 template <class T, bool NEED_WRITE_BARRIER, bool IS_DYN>
Set(const ManagedThread * thread,ArraySizeT idx,T elem)274 inline void Array::Set([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx, T elem)
275 {
276     constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
277 
278     static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
279 
280     size_t elemSize = (IS_REF && !IS_DYN) ? sizeof(ObjectPointerType) : sizeof(T);
281     size_t offset = elemSize * idx;
282 
283     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
284     if constexpr (IS_REF) {
285         ObjectAccessor::SetObject<false, NEED_WRITE_BARRIER, IS_DYN>(thread, this, GetDataOffset() + offset, elem);
286     } else {  // NOLINTNEXTLINE(readability-misleading-indentation)
287         ObjectAccessor::SetPrimitive(this, GetDataOffset() + offset, elem);
288     }
289 }
290 
291 // NEED_READ_BARRIER = true , IS_DYN = false
292 template <class T, bool NEED_READ_BARRIER, bool IS_DYN>
Get(const ManagedThread * thread,ArraySizeT idx)293 inline T Array::Get([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx) const
294 {
295     constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
296 
297     static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
298 
299     size_t elemSize = (IS_REF && !IS_DYN) ? sizeof(ObjectPointerType) : sizeof(T);
300     size_t offset = elemSize * idx;
301 
302     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
303     if constexpr (IS_REF) {
304         return ObjectAccessor::GetObject<false, NEED_READ_BARRIER, IS_DYN>(thread, this, GetDataOffset() + offset);
305     }
306     return ObjectAccessor::GetPrimitive<T>(this, GetDataOffset() + offset);
307 }
308 
309 template <class T, bool NEED_BARRIER, bool IS_DYN>
Fill(T elem,ArraySizeT start,ArraySizeT end)310 inline void Array::Fill(T elem, ArraySizeT start, ArraySizeT end)
311 {
312     static_assert(std::is_arithmetic_v<T> || is_object_v<T>,
313                   "T should be arithmetic type or pointer to managed object type");
314     size_t elemSize = (is_object_v<T> && !IS_DYN) ? sizeof(ObjectPointerType) : sizeof(T);
315     if constexpr (is_object_v<T>) {
316         size_t startOff = GetDataOffset() + elemSize * start;
317         size_t count = end > start ? end - start : 0;
318         ObjectAccessor::FillObjects<false, NEED_BARRIER, IS_DYN>(this, startOff, count, elemSize, elem);
319     } else {
320         FillPrimitiveElem<T>(elem, start, end, elemSize);
321     }
322 }
323 
324 template <class T>
FillPrimitiveElem(T elem,ArraySizeT start,ArraySizeT end,size_t elemSize)325 inline void Array::FillPrimitiveElem(T elem, ArraySizeT start, ArraySizeT end, size_t elemSize)
326 {
327     for (ArraySizeT i = start; i < end; i++) {
328         size_t offset = GetDataOffset() + elemSize * i;
329         ObjectAccessor::SetPrimitive(this, offset, elem);
330     }
331 }
332 
333 /* static */
334 template <class DimIterator>
CreateMultiDimensionalArray(ManagedThread * thread,ark::Class * klass,uint32_t nargs,const DimIterator & iter,size_t dimIdx)335 Array *Array::CreateMultiDimensionalArray(ManagedThread *thread, ark::Class *klass, uint32_t nargs,
336                                           const DimIterator &iter, size_t dimIdx)
337 {
338     auto arrSize = iter.Get(dimIdx);
339     if (arrSize < 0) {
340         ark::ThrowNegativeArraySizeException(arrSize);
341         return nullptr;
342     }
343     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
344     // Will be added later special rule for CheckObjHeaderTypeRef and VMHandler.
345     // SUPPRESS_CSA_NEXTLINE(alpha.core.CheckObjHeaderTypeRef)
346     VMHandle<Array> handle(thread, Array::Create(klass, arrSize));
347 
348     // avoid recursive OOM.
349     if (handle.GetPtr() == nullptr) {
350         return nullptr;
351     }
352     auto *component = klass->GetComponentType();
353 
354     if (component->IsArrayClass() && dimIdx + 1 < nargs) {
355         for (int32_t idx = 0; idx < arrSize; idx++) {
356             auto *array = CreateMultiDimensionalArray(thread, component, nargs, iter, dimIdx + 1);
357 
358             if (array == nullptr) {
359                 return nullptr;
360             }
361 
362             handle.GetPtr()->template Set<Array *>(idx, array);
363         }
364     }
365 
366     return handle.GetPtr();
367 }
368 }  // namespace ark::coretypes
369 
370 #endif  // PANDA_RUNTIME_CORETYPES_ARRAY_INL_H_
371