• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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>
162     void Set(ArraySizeT idx, T elem);
163 
164     template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false>
165     T Get(ArraySizeT idx) const;
166 
167     template <class T, bool IS_DYN>
168     static constexpr size_t GetElementSize();
169 
170     template <class T>
171     T GetBase();
172 
173     // Pass thread parameter to speed up interpreter
174     template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
175     void Set([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx, T elem);
176 
177     template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false>
178     T Get([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx) const;
179 
ObjectSize(uint32_t componentSize)180     size_t ObjectSize(uint32_t componentSize) const
181     {
182         return ComputeSize(componentSize, length_);
183     }
184 
GetLengthOffset()185     static constexpr uint32_t GetLengthOffset()
186     {
187         return MEMBER_OFFSET(Array, length_);
188     }
189 
GetDataOffset()190     static constexpr uint32_t GetDataOffset()
191     {
192         return MEMBER_OFFSET(Array, data_);
193     }
194 
195     template <bool IS_DYN>
GetElementOffset(ArraySizeT idx)196     ArraySizeT GetElementOffset(ArraySizeT idx) const
197     {
198         size_t elemSize;
199         // NOLINTNEXTLINE(readability-braces-around-statements)
200         if constexpr (IS_DYN) {
201             elemSize = TaggedValue::TaggedTypeSize();
202         } else {  // NOLINT(readability-misleading-indentation)
203             elemSize = ClassAddr<ark::Class>()->GetComponentSize();
204         }
205         return GetDataOffset() + idx * elemSize;
206     }
207 
208     template <class DimIterator>
209     static Array *CreateMultiDimensionalArray(ManagedThread *thread, ark::Class *klass, uint32_t nargs,
210                                               const DimIterator &iter, size_t dimIdx = 0);
211 
212 private:
SetLength(ArraySizeT length)213     void SetLength(ArraySizeT length)
214     {
215         // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints
216         // imposed on other reads or writes
217         length_.store(length, std::memory_order_relaxed);
218     }
219 
220     std::atomic<ArraySizeT> length_;
221     // Align by 64bits, because dynamic language data is always 64bits
222     __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0];  // NOLINT(modernize-avoid-c-arrays)
223 };
224 
225 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader));
226 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(ArraySizeT), sizeof(uint64_t)));
227 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0);
228 
229 #ifdef PANDA_TARGET_64
230 constexpr uint32_t ARRAY_LENGTH_OFFSET = 8U;
231 static_assert(ARRAY_LENGTH_OFFSET == ark::coretypes::Array::GetLengthOffset());
232 constexpr uint32_t ARRAY_DATA_OFFSET = 16U;
233 static_assert(ARRAY_DATA_OFFSET == ark::coretypes::Array::GetDataOffset());
234 #endif
235 }  // namespace ark::coretypes
236 
237 #endif  // PANDA_RUNTIME_CORETYPES_ARRAY_H_
238