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