• 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_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