• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-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 #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 panda {
34 class ManagedThread;
35 class PandaVM;
36 }  // namespace panda
37 
38 namespace panda::interpreter {
39 template <BytecodeInstruction::Format FORMAT, bool IS_DYNAMIC = false>
40 class DimIterator;
41 }  // namespace panda::interpreter
42 
43 namespace panda::coretypes {
44 class DynClass;
45 using ArraySizeT = panda::ArraySizeT;
46 using ArraySsizeT = panda::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(panda::Class *arrayClass, const uint8_t *data, ArraySizeT length,
59                                           panda::SpaceType spaceType = panda::SpaceType::SPACE_TYPE_OBJECT);
60 
61     PANDA_PUBLIC_API static Array *Create(panda::Class *arrayClass, ArraySizeT length,
62                                           panda::SpaceType spaceType = panda::SpaceType::SPACE_TYPE_OBJECT);
63 
64     PANDA_PUBLIC_API static Array *Create(DynClass *dynarrayclass, ArraySizeT length,
65                                           panda::SpaceType spaceType = panda::SpaceType::SPACE_TYPE_OBJECT);
66 
67     static Array *CreateTagged(const PandaVM *vm, panda::BaseClass *arrayClass, ArraySizeT length,
68                                panda::SpaceType spaceType = panda::SpaceType::SPACE_TYPE_OBJECT,
69                                TaggedValue initValue = TaggedValue::Undefined());
70 
ComputeSize(size_t elemSize,ArraySizeT length)71     static size_t ComputeSize(size_t elemSize, ArraySizeT length)
72     {
73         ASSERT(elemSize != 0);
74         size_t size = sizeof(Array) + elemSize * length;
75 #ifdef PANDA_TARGET_32
76         // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
77         size_t sizeLimit = (std::numeric_limits<size_t>::max() - sizeof(Array)) / elemSize;
78         if (UNLIKELY(sizeLimit < static_cast<size_t>(length))) {
79             return 0;
80         }
81 #endif
82         return size;
83     }
84 
GetLength()85     ArraySizeT GetLength() const
86     {
87         // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints
88         // imposed on other reads or writes
89         return length_.load(std::memory_order_relaxed);
90     }
91 
GetData()92     uint32_t *GetData()
93     {
94         return data_;
95     }
96 
GetData()97     const uint32_t *GetData() const
98     {
99         return data_;
100     }
101 
102     template <class T, bool IS_VOLATILE = false>
103     T GetPrimitive(size_t offset) const;
104 
105     template <class T, bool IS_VOLATILE = false>
106     void SetPrimitive(size_t offset, T value);
107 
108     template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true, bool IS_DYN = false>
109     ObjectHeader *GetObject(int offset) const;
110 
111     template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
112     void SetObject(size_t offset, ObjectHeader *value);
113 
114     template <class T>
115     T GetPrimitive(size_t offset, std::memory_order memoryOrder) const;
116 
117     template <class T>
118     void SetPrimitive(size_t offset, T value, std::memory_order memoryOrder);
119 
120     template <bool NEED_READ_BARRIER = true, bool IS_DYN = false>
121     ObjectHeader *GetObject(size_t offset, std::memory_order memoryOrder) const;
122 
123     template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
124     void SetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
125 
126     template <typename T>
127     bool CompareAndSetPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong);
128 
129     template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
130     bool CompareAndSetObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
131                              std::memory_order memoryOrder, bool strong);
132 
133     template <typename T>
134     T CompareAndExchangePrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong);
135 
136     template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
137     ObjectHeader *CompareAndExchangeObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue,
138                                            std::memory_order memoryOrder, bool strong);
139 
140     template <typename T>
141     T GetAndSetPrimitive(size_t offset, T value, std::memory_order memoryOrder);
142 
143     template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
144     ObjectHeader *GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder);
145 
146     template <typename T>
147     T GetAndAddPrimitive(size_t offset, T value, std::memory_order memoryOrder);
148 
149     template <typename T>
150     T GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memoryOrder);
151 
152     template <typename T>
153     T GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memoryOrder);
154 
155     template <typename T>
156     T GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memoryOrder);
157 
158     template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
159     void Set(ArraySizeT idx, T elem);
160 
161     template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false>
162     T Get(ArraySizeT idx) const;
163 
164     template <class T, bool IS_DYN>
165     static constexpr size_t GetElementSize();
166 
167     template <class T>
168     T GetBase();
169 
170     // Pass thread parameter to speed up interpreter
171     template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false>
172     void Set([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx, T elem);
173 
174     template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false>
175     T Get([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx) const;
176 
ObjectSize(uint32_t componentSize)177     size_t ObjectSize(uint32_t componentSize) const
178     {
179         return ComputeSize(componentSize, length_);
180     }
181 
GetLengthOffset()182     static constexpr uint32_t GetLengthOffset()
183     {
184         return MEMBER_OFFSET(Array, length_);
185     }
186 
GetDataOffset()187     static constexpr uint32_t GetDataOffset()
188     {
189         return MEMBER_OFFSET(Array, data_);
190     }
191 
192     template <bool IS_DYN>
GetElementOffset(ArraySizeT idx)193     ArraySizeT GetElementOffset(ArraySizeT idx) const
194     {
195         size_t elemSize;
196         // NOLINTNEXTLINE(readability-braces-around-statements)
197         if constexpr (IS_DYN) {
198             elemSize = TaggedValue::TaggedTypeSize();
199         } else {  // NOLINT(readability-misleading-indentation)
200             elemSize = ClassAddr<panda::Class>()->GetComponentSize();
201         }
202         return GetDataOffset() + idx * elemSize;
203     }
204 
205     template <class DimIterator>
206     static Array *CreateMultiDimensionalArray(ManagedThread *thread, panda::Class *klass, uint32_t nargs,
207                                               const DimIterator &iter, size_t dimIdx = 0);
208 
209 private:
SetLength(ArraySizeT length)210     void SetLength(ArraySizeT length)
211     {
212         // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints
213         // imposed on other reads or writes
214         length_.store(length, std::memory_order_relaxed);
215     }
216 
217     std::atomic<ArraySizeT> length_;
218     // Align by 64bits, because dynamic language data is always 64bits
219     __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0];  // NOLINT(modernize-avoid-c-arrays)
220 };
221 
222 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader));
223 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(ArraySizeT), sizeof(uint64_t)));
224 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0);
225 
226 #ifdef PANDA_TARGET_64
227 constexpr uint32_t ARRAY_LENGTH_OFFSET = 8U;
228 static_assert(ARRAY_LENGTH_OFFSET == panda::coretypes::Array::GetLengthOffset());
229 constexpr uint32_t ARRAY_DATA_OFFSET = 16U;
230 static_assert(ARRAY_DATA_OFFSET == panda::coretypes::Array::GetDataOffset());
231 #endif
232 }  // namespace panda::coretypes
233 
234 #endif  // PANDA_RUNTIME_CORETYPES_ARRAY_H
235