• 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 array_size_t = panda::array_size_t;
46 using array_ssize_t = panda::array_ssize_t;
47 
48 class Array : public ObjectHeader {
49 public:
50     static constexpr array_size_t MAX_ARRAY_INDEX = std::numeric_limits<array_size_t>::max();
51 
Cast(ObjectHeader * object)52     static Array *Cast(ObjectHeader *object)
53     {
54         // TODO(linxiang) to do assert
55         return reinterpret_cast<Array *>(object);
56     }
57 
58     static Array *Create(panda::Class *array_class, const uint8_t *data, array_size_t length,
59                          panda::SpaceType space_type = panda::SpaceType::SPACE_TYPE_OBJECT);
60 
61     static Array *Create(panda::Class *array_class, array_size_t length,
62                          panda::SpaceType space_type = panda::SpaceType::SPACE_TYPE_OBJECT);
63 
64     static Array *Create(DynClass *dynarrayclass, array_size_t length,
65                          panda::SpaceType space_type = panda::SpaceType::SPACE_TYPE_OBJECT);
66 
67     static Array *CreateTagged(const PandaVM *vm, panda::BaseClass *array_class, array_size_t length,
68                                panda::SpaceType space_type = panda::SpaceType::SPACE_TYPE_OBJECT,
69                                TaggedValue init_value = TaggedValue::Undefined());
70 
ComputeSize(size_t elem_size,array_size_t length)71     static size_t ComputeSize(size_t elem_size, array_size_t length)
72     {
73         ASSERT(elem_size != 0);
74         size_t size = sizeof(Array) + elem_size * length;
75 #ifdef PANDA_TARGET_32
76         size_t size_limit = (std::numeric_limits<size_t>::max() - sizeof(Array)) / elem_size;
77         if (UNLIKELY(size_limit < static_cast<size_t>(length))) {
78             return 0;
79         }
80 #endif
81         return size;
82     }
83 
GetLength()84     array_size_t GetLength() const
85     {
86         // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints
87         // imposed on other reads or writes
88         return length_.load(std::memory_order_relaxed);
89     }
90 
GetData()91     uint32_t *GetData()
92     {
93         return data_;
94     }
95 
GetData()96     const uint32_t *GetData() const
97     {
98         return data_;
99     }
100 
101     template <class T, bool is_volatile = false>
102     T GetPrimitive(size_t offset) const;
103 
104     template <class T, bool is_volatile = false>
105     void SetPrimitive(size_t offset, T value);
106 
107     template <bool is_volatile = false, bool need_read_barrier = true, bool is_dyn = false>
108     ObjectHeader *GetObject(int offset) const;
109 
110     template <bool is_volatile = false, bool need_write_barrier = true, bool is_dyn = false>
111     void SetObject(size_t offset, ObjectHeader *value);
112 
113     template <class T>
114     T GetPrimitive(size_t offset, std::memory_order memory_order) const;
115 
116     template <class T>
117     void SetPrimitive(size_t offset, T value, std::memory_order memory_order);
118 
119     template <bool need_read_barrier = true, bool is_dyn = false>
120     ObjectHeader *GetObject(size_t offset, std::memory_order memory_order) const;
121 
122     template <bool need_write_barrier = true, bool is_dyn = false>
123     void SetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order);
124 
125     template <typename T>
126     bool CompareAndSetPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, bool strong);
127 
128     template <bool need_write_barrier = true, bool is_dyn = false>
129     bool CompareAndSetObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
130                              std::memory_order memory_order, bool strong);
131 
132     template <typename T>
133     T CompareAndExchangePrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, bool strong);
134 
135     template <bool need_write_barrier = true, bool is_dyn = false>
136     ObjectHeader *CompareAndExchangeObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
137                                            std::memory_order memory_order, bool strong);
138 
139     template <typename T>
140     T GetAndSetPrimitive(size_t offset, T value, std::memory_order memory_order);
141 
142     template <bool need_write_barrier = true, bool is_dyn = false>
143     ObjectHeader *GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order);
144 
145     template <typename T>
146     T GetAndAddPrimitive(size_t offset, T value, std::memory_order memory_order);
147 
148     template <typename T>
149     T GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memory_order);
150 
151     template <typename T>
152     T GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memory_order);
153 
154     template <typename T>
155     T GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memory_order);
156 
157     template <class T, bool need_write_barrier = true, bool is_dyn = false>
158     void Set(array_size_t idx, T elem);
159 
160     template <class T, bool need_read_barrier = true, bool is_dyn = false>
161     T Get(array_size_t idx) const;
162 
163     // Pass thread parameter to speed up interpreter
164     template <class T, bool need_write_barrier = true, bool is_dyn = false>
165     void Set([[maybe_unused]] const ManagedThread *thread, array_size_t idx, T elem);
166 
167     template <class T, bool need_read_barrier = true, bool is_dyn = false>
168     T Get([[maybe_unused]] const ManagedThread *thread, array_size_t idx) const;
169 
ObjectSize(uint32_t component_size)170     size_t ObjectSize(uint32_t component_size) const
171     {
172         return ComputeSize(component_size, length_);
173     }
174 
GetLengthOffset()175     static constexpr uint32_t GetLengthOffset()
176     {
177         return MEMBER_OFFSET(Array, length_);
178     }
179 
GetDataOffset()180     static constexpr uint32_t GetDataOffset()
181     {
182         return MEMBER_OFFSET(Array, data_);
183     }
184 
185     template <bool is_dyn>
GetElementOffset(array_size_t idx)186     uint32_t GetElementOffset(array_size_t idx) const
187     {
188         size_t elem_size;
189         // NOLINTNEXTLINE(readability-braces-around-statements)
190         if constexpr (is_dyn) {
191             elem_size = TaggedValue::TaggedTypeSize();
192         } else {  // NOLINT(readability-misleading-indentation)
193             elem_size = ClassAddr<panda::Class>()->GetComponentSize();
194         }
195         return GetDataOffset() + idx * elem_size;
196     }
197 
198     template <class DimIterator>
199     static Array *CreateMultiDimensionalArray(ManagedThread *thread, panda::Class *klass, uint32_t nargs,
200                                               const DimIterator &iter, size_t dim_idx = 0);
201 
202 private:
SetLength(array_size_t length)203     void SetLength(array_size_t length)
204     {
205         // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints
206         // imposed on other reads or writes
207         length_.store(length, std::memory_order_relaxed);
208     }
209 
210     std::atomic<array_size_t> length_;
211     // Align by 64bits, because dynamic language data is always 64bits
212     __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0];  // NOLINT(modernize-avoid-c-arrays)
213 };
214 
215 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader));
216 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(array_size_t), sizeof(uint64_t)));
217 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0);
218 
219 #ifdef PANDA_TARGET_64
220 constexpr uint32_t ARRAY_LENGTH_OFFSET = 8U;
221 static_assert(ARRAY_LENGTH_OFFSET == panda::coretypes::Array::GetLengthOffset());
222 constexpr uint32_t ARRAY_DATA_OFFSET = 16U;
223 static_assert(ARRAY_DATA_OFFSET == panda::coretypes::Array::GetDataOffset());
224 #endif
225 }  // namespace panda::coretypes
226 
227 #endif  // PANDA_RUNTIME_CORETYPES_ARRAY_H_
228