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)
82 .first;
83 }
84
85 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)86 inline bool Array::CompareAndSetObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
87 std::memory_order memory_order, bool strong)
88 {
89 auto field_offset = GetDataOffset() + offset;
90 return ObjectAccessor::CompareAndSetFieldObject<need_write_barrier, is_dyn>(this, field_offset, old_value,
91 new_value, memory_order, strong)
92 .first;
93 }
94
95 template <typename T>
CompareAndExchangePrimitive(size_t offset,T old_value,T new_value,std::memory_order memory_order,bool strong)96 inline T Array::CompareAndExchangePrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order,
97 bool strong)
98 {
99 return ObjectAccessor::CompareAndSetFieldPrimitive(this, GetDataOffset() + offset, old_value, new_value,
100 memory_order, strong)
101 .second;
102 }
103
104 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)105 inline ObjectHeader *Array::CompareAndExchangeObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value,
106 std::memory_order memory_order, bool strong)
107 {
108 auto field_offset = GetDataOffset() + offset;
109 return ObjectAccessor::CompareAndSetFieldObject<need_write_barrier, is_dyn>(this, field_offset, old_value,
110 new_value, memory_order, strong)
111 .second;
112 }
113
114 template <typename T>
GetAndSetPrimitive(size_t offset,T value,std::memory_order memory_order)115 inline T Array::GetAndSetPrimitive(size_t offset, T value, std::memory_order memory_order)
116 {
117 return ObjectAccessor::GetAndSetFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
118 }
119
120 template <bool need_write_barrier /* = true */, bool is_dyn /* = false */>
GetAndSetObject(size_t offset,ObjectHeader * value,std::memory_order memory_order)121 inline ObjectHeader *Array::GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order)
122 {
123 return ObjectAccessor::GetAndSetFieldObject<need_write_barrier, is_dyn>(this, GetDataOffset() + offset, value,
124 memory_order);
125 }
126
127 template <typename T>
GetAndAddPrimitive(size_t offset,T value,std::memory_order memory_order)128 inline T Array::GetAndAddPrimitive(size_t offset, T value, std::memory_order memory_order)
129 {
130 return ObjectAccessor::GetAndAddFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
131 }
132
133 template <typename T>
GetAndBitwiseOrPrimitive(size_t offset,T value,std::memory_order memory_order)134 inline T Array::GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memory_order)
135 {
136 return ObjectAccessor::GetAndBitwiseOrFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
137 }
138
139 template <typename T>
GetAndBitwiseAndPrimitive(size_t offset,T value,std::memory_order memory_order)140 inline T Array::GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memory_order)
141 {
142 return ObjectAccessor::GetAndBitwiseAndFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
143 }
144
145 template <typename T>
GetAndBitwiseXorPrimitive(size_t offset,T value,std::memory_order memory_order)146 inline T Array::GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memory_order)
147 {
148 return ObjectAccessor::GetAndBitwiseXorFieldPrimitive(this, GetDataOffset() + offset, value, memory_order);
149 }
150
151 template <class T, bool need_write_barrier /* = true */, bool is_dyn /* = false */>
Set(array_size_t idx,T elem)152 inline void Array::Set(array_size_t idx, T elem)
153 {
154 constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
155
156 static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
157
158 size_t elem_size = (IS_REF && !is_dyn) ? sizeof(object_pointer_type) : sizeof(T);
159 size_t offset = elem_size * idx;
160
161 // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
162 // NOLINTNEXTLINE(readability-braces-around-statements)
163 if constexpr (IS_REF) {
164 ObjectAccessor::SetObject<false, need_write_barrier, is_dyn>(this, GetDataOffset() + offset, elem);
165 // NOLINTNEXTLINE(readability-misleading-indentation)
166 } else {
167 ObjectAccessor::SetPrimitive(this, GetDataOffset() + offset, elem);
168 }
169 }
170
171 template <class T, bool need_read_barrier /* = true */, bool is_dyn /* = false */>
Get(array_size_t idx)172 inline T Array::Get(array_size_t idx) const
173 {
174 constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
175
176 static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
177
178 size_t elem_size = (IS_REF && !is_dyn) ? sizeof(object_pointer_type) : sizeof(T);
179 size_t offset = elem_size * idx;
180
181 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
182 if constexpr (IS_REF) {
183 return ObjectAccessor::GetObject<false, need_read_barrier, is_dyn>(this, GetDataOffset() + offset);
184 }
185
186 return ObjectAccessor::GetPrimitive<T>(this, GetDataOffset() + offset);
187 }
188
189 template <class T, bool need_write_barrier /* = true */, bool is_dyn /* = false */>
Set(const ManagedThread * thread,array_size_t idx,T elem)190 inline void Array::Set([[maybe_unused]] const ManagedThread *thread, array_size_t idx, T elem)
191 {
192 constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
193
194 static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
195
196 size_t elem_size = (IS_REF && !is_dyn) ? sizeof(object_pointer_type) : sizeof(T);
197 size_t offset = elem_size * idx;
198
199 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
200 if constexpr (IS_REF) {
201 ObjectAccessor::SetObject<false, need_write_barrier, is_dyn>(thread, this, GetDataOffset() + offset, elem);
202 } else { // NOLINTNEXTLINE(readability-misleading-indentation)
203 ObjectAccessor::SetPrimitive(this, GetDataOffset() + offset, elem);
204 }
205 }
206
207 template <class T, bool need_read_barrier /* = true */, bool is_dyn /* = false */>
Get(const ManagedThread * thread,array_size_t idx)208 inline T Array::Get([[maybe_unused]] const ManagedThread *thread, array_size_t idx) const
209 {
210 constexpr bool IS_REF = std::is_pointer_v<T> && std::is_base_of_v<ObjectHeader, std::remove_pointer_t<T>>;
211
212 static_assert(std::is_arithmetic_v<T> || IS_REF, "T should be arithmetic type or pointer to managed object type");
213
214 size_t elem_size = (IS_REF && !is_dyn) ? sizeof(object_pointer_type) : sizeof(T);
215 size_t offset = elem_size * idx;
216
217 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
218 if constexpr (IS_REF) {
219 return ObjectAccessor::GetObject<false, need_read_barrier, is_dyn>(thread, this, GetDataOffset() + offset);
220 }
221 return ObjectAccessor::GetPrimitive<T>(this, GetDataOffset() + offset);
222 }
223
224 /* static */
225 template <class DimIterator>
CreateMultiDimensionalArray(ManagedThread * thread,panda::Class * klass,uint32_t nargs,const DimIterator & iter,size_t dim_idx)226 Array *Array::CreateMultiDimensionalArray(ManagedThread *thread, panda::Class *klass, uint32_t nargs,
227 const DimIterator &iter, size_t dim_idx)
228 {
229 auto arr_size = iter.Get(dim_idx);
230 if (arr_size < 0) {
231 panda::ThrowNegativeArraySizeException(arr_size);
232 return nullptr;
233 }
234 [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
235 // Will be added later special rule for CheckObjHeaderTypeRef and VMHandler.
236 // SUPPRESS_CSA_NEXTLINE(alpha.core.CheckObjHeaderTypeRef)
237 VMHandle<Array> handle(thread, Array::Create(klass, arr_size));
238
239 // avoid recursive OOM.
240 if (handle.GetPtr() == nullptr) {
241 return nullptr;
242 }
243 auto *component = klass->GetComponentType();
244
245 if (component->IsArrayClass() && dim_idx + 1 < nargs) {
246 for (int32_t idx = 0; idx < arr_size; idx++) {
247 auto *array = CreateMultiDimensionalArray(thread, component, nargs, iter, dim_idx + 1);
248
249 if (array == nullptr) {
250 return nullptr;
251 }
252
253 handle.GetPtr()->template Set<Array *>(idx, array);
254 }
255 }
256
257 return handle.GetPtr();
258 }
259 } // namespace panda::coretypes
260
261 #endif // PANDA_RUNTIME_CORETYPES_ARRAY_INL_H_
262