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_INL_H_
16 #define PANDA_RUNTIME_CORETYPES_ARRAY_INL_H_
17
18 #include <type_traits>
19
20 #include "runtime/include/coretypes/array.h"
21 #include "runtime/include/exceptions.h"
22 #include "runtime/include/object_accessor-inl.h"
23 #include "runtime/handle_scope.h"
24 #include "runtime/mem/vm_handle.h"
25
26 namespace panda::coretypes {
27
28 template <class T, bool is_volatile /* = false */>
GetPrimitive(size_t offset)29 inline T Array::GetPrimitive(size_t offset) const
30 {
31 return ObjectAccessor::GetPrimitive<T, is_volatile>(this, GetDataOffset() + offset);
32 }
33
34 template <class T, bool is_volatile /* = false */>
SetPrimitive(size_t offset,T value)35 inline void Array::SetPrimitive(size_t offset, T value)
36 {
37 ObjectAccessor::SetPrimitive<T, is_volatile>(this, GetDataOffset() + offset, value);
38 }
39
40 template <bool is_volatile /* = false */, bool need_read_barrier /* = true */, bool is_dyn /* = false */>
GetObject(int offset)41 inline ObjectHeader *Array::GetObject(int offset) const
42 {
43 return ObjectAccessor::GetObject<is_volatile, need_read_barrier, is_dyn>(this, GetDataOffset() + offset);
44 }
45
46 template <bool is_volatile /* = false */, bool need_write_barrier /* = true */, bool is_dyn /* = false */>
SetObject(size_t offset,ObjectHeader * value)47 inline void Array::SetObject(size_t offset, ObjectHeader *value)
48 {
49 ObjectAccessor::SetObject<is_volatile, need_write_barrier, is_dyn>(this, GetDataOffset() + offset, value);
50 }
51
52 template <class T>
GetPrimitive(size_t offset,std::memory_order memory_order)53 inline T Array::GetPrimitive(size_t offset, std::memory_order memory_order) const
54 {
55 return ObjectAccessor::GetFieldPrimitive<T>(this, GetDataOffset() + offset, memory_order);
56 }
57
58 template <class T>
SetPrimitive(size_t offset,T value,std::memory_order memory_order)59 inline void Array::SetPrimitive(size_t offset, T value, std::memory_order memory_order)
60 {
61 ObjectAccessor::SetFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
62 }
63
64 template <bool need_read_barrier /* = true */, bool is_dyn /* = false */>
GetObject(size_t offset,std::memory_order memory_order)65 inline ObjectHeader *Array::GetObject(size_t offset, std::memory_order memory_order) const
66 {
67 return ObjectAccessor::GetFieldObject<need_read_barrier, is_dyn>(this, GetDataOffset() + offset, memory_order);
68 }
69
70 template <bool need_write_barrier /* = true */, bool is_dyn /* = false */>
SetObject(size_t offset,ObjectHeader * value,std::memory_order memory_order)71 inline void Array::SetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order)
72 {
73 ObjectAccessor::SetFieldObject<need_write_barrier, is_dyn>(this, GetDataOffset() + offset, value, memory_order);
74 }
75
76 template <typename T>
CompareAndSetPrimitive(size_t offset,T old_value,T new_value,std::memory_order memory_order,bool strong)77 inline bool Array::CompareAndSetPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order,
78 bool strong)
79 {
80 return ObjectAccessor::CompareAndSetFieldPrimitive(this, GetDataOffset() + offset, old_value, new_value,
81 memory_order, strong).first;
82 }
83
84 template <bool need_write_barrier /* = true */, bool is_dyn /* = false */>
CompareAndSetObject(size_t offset,ObjectHeader * old_value,ObjectHeader * new_value,std::memory_order memory_order,bool strong)85 inline bool Array::CompareAndSetObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
86 std::memory_order memory_order, bool strong)
87 {
88 auto field_offset = GetDataOffset() + offset;
89 return ObjectAccessor::CompareAndSetFieldObject<need_write_barrier, is_dyn>(this, field_offset, old_value,
90 new_value, memory_order, strong).first;
91 }
92
93 template <typename T>
CompareAndExchangePrimitive(size_t offset,T old_value,T new_value,std::memory_order memory_order,bool strong)94 inline T Array::CompareAndExchangePrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order,
95 bool strong)
96 {
97 return ObjectAccessor::CompareAndSetFieldPrimitive(this, GetDataOffset() + offset, old_value, new_value,
98 memory_order, strong).second;
99 }
100
101 template <bool need_write_barrier /* = true */, bool is_dyn /* = false */>
CompareAndExchangeObject(size_t offset,ObjectHeader * old_value,ObjectHeader * new_value,std::memory_order memory_order,bool strong)102 inline ObjectHeader *Array::CompareAndExchangeObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
103 std::memory_order memory_order, bool strong)
104 {
105 auto field_offset = GetDataOffset() + offset;
106 return ObjectAccessor::CompareAndSetFieldObject<need_write_barrier, is_dyn>(this, field_offset, old_value,
107 new_value, memory_order, strong).second;
108 }
109
110 template <typename T>
GetAndSetPrimitive(size_t offset,T value,std::memory_order memory_order)111 inline T Array::GetAndSetPrimitive(size_t offset, T value, std::memory_order memory_order)
112 {
113 return ObjectAccessor::GetAndSetFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
114 }
115
116 template <bool need_write_barrier /* = true */, bool is_dyn /* = false */>
GetAndSetObject(size_t offset,ObjectHeader * value,std::memory_order memory_order)117 inline ObjectHeader *Array::GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order)
118 {
119 return ObjectAccessor::GetAndSetFieldObject<need_write_barrier, is_dyn>(this, GetDataOffset() + offset, value,
120 memory_order);
121 }
122
123 template <typename T>
GetAndAddPrimitive(size_t offset,T value,std::memory_order memory_order)124 inline T Array::GetAndAddPrimitive(size_t offset, T value, std::memory_order memory_order)
125 {
126 return ObjectAccessor::GetAndAddFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
127 }
128
129 template <typename T>
GetAndBitwiseOrPrimitive(size_t offset,T value,std::memory_order memory_order)130 inline T Array::GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memory_order)
131 {
132 return ObjectAccessor::GetAndBitwiseOrFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
133 }
134
135 template <typename T>
GetAndBitwiseAndPrimitive(size_t offset,T value,std::memory_order memory_order)136 inline T Array::GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memory_order)
137 {
138 return ObjectAccessor::GetAndBitwiseAndFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
139 }
140
141 template <typename T>
GetAndBitwiseXorPrimitive(size_t offset,T value,std::memory_order memory_order)142 inline T Array::GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memory_order)
143 {
144 return ObjectAccessor::GetAndBitwiseXorFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
145 }
146
147 template <class T, bool need_write_barrier /* = true */, bool is_dyn /* = false */>
Set(array_size_t idx,T elem)148 inline void Array::Set(array_size_t idx, T elem)
149 {
150 constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
151
152 static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
153
154 size_t elem_size = (IS_REF && !is_dyn) ? sizeof(object_pointer_type) : sizeof(T);
155 size_t offset = elem_size * idx;
156
157 // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
158 // NOLINTNEXTLINE(readability-braces-around-statements)
159 if constexpr (IS_REF) {
160 ObjectAccessor::SetObject<false, need_write_barrier, is_dyn>(this, GetDataOffset() + offset, elem);
161 // NOLINTNEXTLINE(readability-misleading-indentation)
162 } else {
163 ObjectAccessor::SetPrimitive(this, GetDataOffset() + offset, elem);
164 }
165 }
166
167 template <class T, bool need_read_barrier /* = true */, bool is_dyn /* = false */>
Get(array_size_t idx)168 inline T Array::Get(array_size_t idx) const
169 {
170 constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
171
172 static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
173
174 size_t elem_size = (IS_REF && !is_dyn) ? sizeof(object_pointer_type) : sizeof(T);
175 size_t offset = elem_size * idx;
176
177 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
178 if constexpr (IS_REF) {
179 return ObjectAccessor::GetObject<false, need_read_barrier, is_dyn>(this, GetDataOffset() + offset);
180 }
181
182 return ObjectAccessor::GetPrimitive<T>(this, GetDataOffset() + offset);
183 }
184
185 template <class T, bool need_write_barrier /* = true */, bool is_dyn /* = false */>
Set(const ManagedThread * thread,array_size_t idx,T elem)186 inline void Array::Set([[maybe_unused]] const ManagedThread *thread, array_size_t idx, T elem)
187 {
188 constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
189
190 static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
191
192 size_t elem_size = (IS_REF && !is_dyn) ? sizeof(object_pointer_type) : sizeof(T);
193 size_t offset = elem_size * idx;
194
195 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
196 if constexpr (IS_REF) {
197 ObjectAccessor::SetObject<false, need_write_barrier, is_dyn>(thread, this, GetDataOffset() + offset, elem);
198 } else { // NOLINTNEXTLINE(readability-misleading-indentation)
199 ObjectAccessor::SetPrimitive(this, GetDataOffset() + offset, elem);
200 }
201 }
202
203 template <class T, bool need_read_barrier /* = true */, bool is_dyn /* = false */>
Get(const ManagedThread * thread,array_size_t idx)204 inline T Array::Get([[maybe_unused]] const ManagedThread *thread, array_size_t idx) const
205 {
206 constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
207
208 static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
209
210 size_t elem_size = (IS_REF && !is_dyn) ? sizeof(object_pointer_type) : sizeof(T);
211 size_t offset = elem_size * idx;
212
213 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
214 if constexpr (IS_REF) {
215 return ObjectAccessor::GetObject<false, need_read_barrier, is_dyn>(thread, this, GetDataOffset() + offset);
216 }
217 return ObjectAccessor::GetPrimitive<T>(this, GetDataOffset() + offset);
218 }
219
220 /* static */
221 template <class DimIterator>
CreateMultiDimensionalArray(ManagedThread * thread,panda::Class * klass,uint32_t nargs,const DimIterator & iter,size_t dim_idx)222 Array *Array::CreateMultiDimensionalArray(ManagedThread *thread, panda::Class *klass, uint32_t nargs,
223 const DimIterator &iter, size_t dim_idx)
224 {
225 auto arr_size = iter.Get(dim_idx);
226 if (arr_size < 0) {
227 panda::ThrowNegativeArraySizeException(arr_size);
228 return nullptr;
229 }
230 [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
231 // Will be added later special rule for CheckObjHeaderTypeRef and VMHandler.
232 // SUPPRESS_CSA_NEXTLINE(alpha.core.CheckObjHeaderTypeRef)
233 VMHandle<Array> handle(thread, Array::Create(klass, arr_size));
234
235 // avoid recursive OOM.
236 if (handle.GetPtr() == nullptr) {
237 return nullptr;
238 }
239 auto *component = klass->GetComponentType();
240
241 if (component->IsArrayClass() && dim_idx + 1 < nargs) {
242 for (int32_t idx = 0; idx < arr_size; idx++) {
243 auto *array = CreateMultiDimensionalArray(thread, component, nargs, iter, dim_idx + 1);
244
245 if (array == nullptr) {
246 return nullptr;
247 }
248
249 handle.GetPtr()->template Set<Array *>(idx, array);
250 }
251 }
252
253 return handle.GetPtr();
254 }
255 } // namespace panda::coretypes
256
257 #endif // PANDA_RUNTIME_CORETYPES_ARRAY_INL_H_
258