• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 
16 #ifndef PANDA_RUNTIME_INCLUDE_CORETYPES_ARRAY_H_
17 #define PANDA_RUNTIME_INCLUDE_CORETYPES_ARRAY_H_
18 
19 #include <securec.h>
20 #include <cstddef>
21 #include <cstdint>
22 
23 #include "libpandabase/macros.h"
24 #include "libpandabase/mem/mem.h"
25 #include "libpandabase/mem/space.h"
26 #include "libpandabase/utils/span.h"
27 #include "libpandafile/bytecode_instruction-inl.h"
28 #include "runtime/include/class-inl.h"
29 #include "runtime/include/language_context.h"
30 #include "runtime/include/object_header.h"
31 #include "runtime/mem/heap_manager.h"
32 #include "runtime/include/coretypes/tagged_value.h"
33 
34 namespace panda {
35 class ManagedThread;
36 class PandaVM;
37 }  // namespace panda
38 
39 namespace panda::interpreter {
40 template <BytecodeInstruction::Format format>
41 class DimIterator;
42 }  // namespace panda::interpreter
43 
44 namespace panda::coretypes {
45 class DynClass;
46 using array_size_t = panda::array_size_t;
47 using array_ssize_t = panda::array_ssize_t;
48 
49 class Array : public ObjectHeader {
50 public:
51     static constexpr array_size_t MAX_ARRAY_INDEX = std::numeric_limits<array_size_t>::max();
52 
Cast(ObjectHeader * object)53     static Array *Cast(ObjectHeader *object)
54     {
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         return length_.load(std::memory_order_relaxed);
87     }
88 
GetData()89     uint32_t *GetData()
90     {
91         return data_;
92     }
93 
GetData()94     const uint32_t *GetData() const
95     {
96         return data_;
97     }
98 
99     template <class T, bool is_volatile = false>
100     T GetPrimitive(size_t offset) const;
101 
102     template <class T, bool is_volatile = false>
103     void SetPrimitive(size_t offset, T value);
104 
105     template <bool is_volatile = false, bool need_read_barrier = true, bool is_dyn = false>
106     ObjectHeader *GetObject(int offset) const;
107 
108     template <bool is_volatile = false, bool need_write_barrier = true, bool is_dyn = false>
109     void SetObject(size_t offset, ObjectHeader *value);
110 
111     template <class T>
112     T GetPrimitive(size_t offset, std::memory_order memory_order) const;
113 
114     template <class T>
115     void SetPrimitive(size_t offset, T value, std::memory_order memory_order);
116 
117     template <bool need_read_barrier = true, bool is_dyn = false>
118     ObjectHeader *GetObject(size_t offset, std::memory_order memory_order) const;
119 
120     template <bool need_write_barrier = true, bool is_dyn = false>
121     void SetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order);
122 
123     template <typename T>
124     bool CompareAndSetPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, bool strong);
125 
126     template <bool need_write_barrier = true, bool is_dyn = false>
127     bool CompareAndSetObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
128                              std::memory_order memory_order, bool strong);
129 
130     template <typename T>
131     T CompareAndExchangePrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, bool strong);
132 
133     template <bool need_write_barrier = true, bool is_dyn = false>
134     ObjectHeader *CompareAndExchangeObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
135                                            std::memory_order memory_order, bool strong);
136 
137     template <typename T>
138     T GetAndSetPrimitive(size_t offset, T value, std::memory_order memory_order);
139 
140     template <bool need_write_barrier = true, bool is_dyn = false>
141     ObjectHeader *GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order);
142 
143     template <typename T>
144     T GetAndAddPrimitive(size_t offset, T value, std::memory_order memory_order);
145 
146     template <typename T>
147     T GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memory_order);
148 
149     template <typename T>
150     T GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memory_order);
151 
152     template <typename T>
153     T GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memory_order);
154 
155     template <class T, bool need_write_barrier = true, bool is_dyn = false>
156     void Set(array_size_t idx, T elem);
157 
158     template <class T, bool need_read_barrier = true, bool is_dyn = false>
159     T Get(array_size_t idx) const;
160 
161     // Pass thread parameter to speed up interpreter
162     template <class T, bool need_write_barrier = true, bool is_dyn = false>
163     void Set([[maybe_unused]] const ManagedThread *thread, array_size_t idx, T elem);
164 
165     template <class T, bool need_read_barrier = true, bool is_dyn = false>
166     T Get([[maybe_unused]] const ManagedThread *thread, array_size_t idx) const;
167 
ObjectSize()168     size_t ObjectSize() const
169     {
170         return ComputeSize(ClassAddr<panda::Class>()->GetComponentSize(), length_);
171     }
172 
GetLengthOffset()173     static constexpr uint32_t GetLengthOffset()
174     {
175         return MEMBER_OFFSET(Array, length_);
176     }
177 
GetDataOffset()178     static constexpr uint32_t GetDataOffset()
179     {
180         return MEMBER_OFFSET(Array, data_);
181     }
182 
183     template <class DimIterator>
184     static Array *CreateMultiDimensionalArray(ManagedThread *thread, panda::Class *klass, uint32_t nargs,
185                                               const DimIterator &iter, size_t dim_idx = 0);
186 
187 private:
SetLength(array_size_t length)188     void SetLength(array_size_t length)
189     {
190         length_.store(length, std::memory_order_relaxed);
191     }
192 
193     std::atomic<array_size_t> length_;
194     // Align with 64bits, because dynamic language data is always 64bits
195     __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0];  // NOLINT(modernize-avoid-c-arrays)
196 };
197 
198 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader));
199 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(array_size_t), sizeof(uint64_t)));
200 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0);
201 
202 #ifdef PANDA_TARGET_64
203 constexpr uint32_t ARRAY_LENGTH_OFFSET = 8U;
204 static_assert(ARRAY_LENGTH_OFFSET == panda::coretypes::Array::GetLengthOffset());
205 constexpr uint32_t ARRAY_DATA_OFFSET = 16U;
206 static_assert(ARRAY_DATA_OFFSET == panda::coretypes::Array::GetDataOffset());
207 #endif
208 
209 }  // namespace panda::coretypes
210 
211 #endif  // PANDA_RUNTIME_INCLUDE_CORETYPES_ARRAY_H_
212