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