• 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_H_
16 #define PANDA_RUNTIME_CORETYPES_ARRAY_H_
17 
18 #include <securec.h>
19 #include <cstddef>
20 #include <cstdint>
21 
22 #include "libpandabase/macros.h"
23 #include "libpandabase/mem/mem.h"
24 #include "libpandabase/mem/space.h"
25 #include "libpandabase/utils/span.h"
26 #include "libpandafile/bytecode_instruction-inl.h"
27 #include "runtime/include/class-inl.h"
28 #include "runtime/include/language_context.h"
29 #include "runtime/include/object_header.h"
30 #include "runtime/mem/heap_manager.h"
31 #include "runtime/include/coretypes/tagged_value.h"
32 
33 namespace ark {
34 class ManagedThread;
35 class PandaVM;
36 }  // namespace ark
37 
38 namespace ark::interpreter {
39 template <BytecodeInstruction::Format FORMAT, bool IS_DYNAMIC = false>
40 class DimIterator;
41 }  // namespace ark::interpreter
42 
43 namespace ark::coretypes {
44 class DynClass;
45 using ArraySizeT = ark::ArraySizeT;
46 using ArraySsizeT = ark::ArraySsizeT;
47 
48 class Array : public ObjectHeader {
49 public:
50     static constexpr ArraySizeT MAX_ARRAY_INDEX = std::numeric_limits<ArraySizeT>::max();
51 
Cast(ObjectHeader * object)52     static Array *Cast(ObjectHeader *object)
53     {
54         // NOTE(linxiang) to do assert
55         return reinterpret_cast<Array *>(object);
56     }
57 
58     PANDA_PUBLIC_API static Array *Create(ark::Class *arrayClass, const uint8_t *data, ArraySizeT length,
59                                           ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT,
60                                           bool pinned = false);
61 
62     PANDA_PUBLIC_API static Array *Create(ark::Class *arrayClass, ArraySizeT length,
63                                           ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT,
64                                           bool pinned = false);
65 
66     PANDA_PUBLIC_API static Array *Create(DynClass *dynarrayclass, ArraySizeT length,
67                                           ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT,
68                                           bool pinned = false);
69 
70     static Array *CreateTagged(const PandaVM *vm, ark::BaseClass *arrayClass, ArraySizeT length,
71                                ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT,
72                                TaggedValue initValue = TaggedValue::Undefined());
73 
ComputeSize(size_t elemSize,ArraySizeT length)74     static size_t ComputeSize(size_t elemSize, ArraySizeT length)
75     {
76         ASSERT(elemSize != 0);
77         size_t size = sizeof(Array) + elemSize * length;
78 #ifdef PANDA_TARGET_32
79         // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
80         size_t sizeLimit = (std::numeric_limits<size_t>::max() - sizeof(Array)) / elemSize;
81         if (UNLIKELY(sizeLimit < static_cast<size_t>(length))) {
82             return 0;
83         }
84 #endif
85         return size;
86     }
87 
GetLength()88     ArraySizeT GetLength() const
89     {
90         // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints
91         // imposed on other reads or writes
92         return length_.load(std::memory_order_relaxed);
93     }
94 
GetData()95     uint32_t *GetData()
96     {
97         return data_;
98     }
99 
GetData()100     const uint32_t *GetData() const
101     {
102         return data_;
103     }
104 
105     template <class T, bool IS_VOLATILE = false>
106     T GetPrimitive(size_t offset) const;
107 
108     template <class T, bool IS_VOLATILE = false>
109     void SetPrimitive(size_t offset, T value);
110 
111     template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true, bool IS_DYN = false>
112     ObjectHeader *GetObject(int offset) const;
113 
114     template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
115     void SetObject(size_t offset, ObjectHeader *value);
116 
117     template <class T>
118     T GetPrimitive(size_t offset, std::memory_order memoryOrder) const;
119 
120     template <class T>
121     void SetPrimitive(size_t offset, T value, std::memory_order memoryOrder);
122 
123     template <bool NEED_READ_BARRIER = true, bool IS_DYN = false>
124     ObjectHeader *GetObject(size_t offset, std::memory_order memoryOrder) const;
125 
126     template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
127     void SetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
128 
129     template <typename T>
130     bool CompareAndSetPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong);
131 
132     template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
133     bool CompareAndSetObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
134                              std::memory_order memoryOrder, bool strong);
135 
136     template <typename T>
137     T CompareAndExchangePrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong);
138 
139     template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
140     ObjectHeader *CompareAndExchangeObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
141                                            std::memory_order memoryOrder, bool strong);
142 
143     template <typename T>
144     T GetAndSetPrimitive(size_t offset, T value, std::memory_order memoryOrder);
145 
146     template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
147     ObjectHeader *GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
148 
149     template <typename T>
150     T GetAndAddPrimitive(size_t offset, T value, std::memory_order memoryOrder);
151 
152     template <typename T>
153     T GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memoryOrder);
154 
155     template <typename T>
156     T GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memoryOrder);
157 
158     template <typename T>
159     T GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memoryOrder);
160 
161     template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false, bool IS_VOLATILE = false>
162     std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, void> Set(ArraySizeT idx, T elem,
163                                                                           uint32_t byteOffset = 0);
164 
165     template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false, bool IS_VOLATILE = false>
166     std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, T> Get(ArraySizeT idx, uint32_t byteOffset = 0) const;
167 
168     template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
169     std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, std::pair<bool, T>> CompareAndExchange(
170         ArraySizeT idx, T oldValue, T newValue, std::memory_order memoryOrder, bool strong, uint32_t byteOffset = 0);
171 
172     template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
173     std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, T> Exchange(ArraySizeT idx, T value,
174                                                                             std::memory_order memoryOrder,
175                                                                             uint32_t byteOffset = 0);
176 
177     template <class T>
178     std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndAdd(ArraySizeT idx, T value, std::memory_order memoryOrder,
179                                                            uint32_t byteOffset = 0);
180 
181     template <class T>
182     std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndSub(ArraySizeT idx, T value, std::memory_order memoryOrder,
183                                                            uint32_t byteOffset = 0);
184 
185     template <class T>
186     std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndBitwiseOr(ArraySizeT idx, T value, std::memory_order memoryOrder,
187                                                                  uint32_t byteOffset = 0);
188 
189     template <class T>
190     std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndBitwiseAnd(ArraySizeT idx, T value,
191                                                                   std::memory_order memoryOrder,
192                                                                   uint32_t byteOffset = 0);
193 
194     template <class T>
195     std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndBitwiseXor(ArraySizeT idx, T value,
196                                                                   std::memory_order memoryOrder,
197                                                                   uint32_t byteOffset = 0);
198 
199     template <class T, bool IS_DYN>
200     static constexpr size_t GetElementSize();
201 
202     template <class T>
203     T GetBase();
204 
205     // Pass thread parameter to speed up interpreter
206     template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
207     void Set([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx, T elem);
208 
209     template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false>
210     T Get([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx) const;
211 
212     template <class T, bool NEED_BARRIER = true, bool IS_DYN = false>
213     void Fill(T elem, ArraySizeT start, ArraySizeT end);
214 
ObjectSize(uint32_t componentSize)215     size_t ObjectSize(uint32_t componentSize) const
216     {
217         return ComputeSize(componentSize, length_);
218     }
219 
GetLengthOffset()220     static constexpr uint32_t GetLengthOffset()
221     {
222         return MEMBER_OFFSET(Array, length_);
223     }
224 
GetDataOffset()225     static constexpr uint32_t GetDataOffset()
226     {
227         return MEMBER_OFFSET(Array, data_);
228     }
229 
230     template <bool IS_DYN>
GetElementOffset(ArraySizeT idx)231     ArraySizeT GetElementOffset(ArraySizeT idx) const
232     {
233         size_t elemSize;
234         // NOLINTNEXTLINE(readability-braces-around-statements)
235         if constexpr (IS_DYN) {
236             elemSize = TaggedValue::TaggedTypeSize();
237         } else {  // NOLINT(readability-misleading-indentation)
238             elemSize = ClassAddr<ark::Class>()->GetComponentSize();
239         }
240         return GetDataOffset() + idx * elemSize;
241     }
242 
243     template <class DimIterator>
244     static Array *CreateMultiDimensionalArray(ManagedThread *thread, ark::Class *klass, uint32_t nargs,
245                                               const DimIterator &iter, size_t dimIdx = 0);
246 
247 private:
SetLength(ArraySizeT length)248     void SetLength(ArraySizeT length)
249     {
250         // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints
251         // imposed on other reads or writes
252         length_.store(length, std::memory_order_relaxed);
253     }
254 
255     template <class T>
256     void FillPrimitiveElem(T elem, ArraySizeT start, ArraySizeT end, size_t elemSize);
257 
258     std::atomic<ArraySizeT> length_;
259     // Align by 64bits, because dynamic language data is always 64bits
260     __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0];  // NOLINT(modernize-avoid-c-arrays)
261 };
262 
263 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader));
264 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(ArraySizeT), sizeof(uint64_t)));
265 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0);
266 
267 constexpr uint32_t ARRAY_LENGTH_OFFSET = sizeof(ObjectHeader);
268 static_assert(ARRAY_LENGTH_OFFSET == ark::coretypes::Array::GetLengthOffset());
269 constexpr uint32_t ARRAY_DATA_OFFSET = ARRAY_LENGTH_OFFSET + sizeof(uint64_t);
270 static_assert(ARRAY_DATA_OFFSET == ark::coretypes::Array::GetDataOffset());
271 
272 }  // namespace ark::coretypes
273 
274 #endif  // PANDA_RUNTIME_CORETYPES_ARRAY_H_
275