• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_ARRAY_H_
16 #define PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_ARRAY_H_
17 
18 #include "libpandabase/macros.h"
19 #include "libpandabase/mem/space.h"
20 #include "runtime/include/coretypes/array.h"
21 #include "plugins/ets/runtime/types/ets_class.h"
22 #include "plugins/ets/runtime/types/ets_primitives.h"
23 #include "plugins/ets/runtime/types/ets_object.h"
24 #include "plugins/ets/runtime/ets_class_root.h"
25 #include "plugins/ets/runtime/ets_vm.h"
26 
27 namespace ark::ets {
28 
29 // Private inheritance, because need to disallow implicit conversion to core type
30 class EtsArray : private coretypes::Array {
31 public:
32     EtsArray() = delete;
33     ~EtsArray() = delete;
34 
GetLength()35     PANDA_PUBLIC_API size_t GetLength() const
36     {
37         return GetCoreType()->GetLength();
38     }
39 
GetElementSize()40     size_t GetElementSize() const
41     {
42         return GetCoreType()->ClassAddr<Class>()->GetComponentSize();
43     }
44 
ObjectSize()45     size_t ObjectSize() const
46     {
47         return GetCoreType()->ObjectSize(GetElementSize());
48     }
49 
50     template <class T>
GetData()51     T *GetData()
52     {
53         return reinterpret_cast<T *>(GetCoreType()->GetData());
54     }
55 
56     template <class T>
GetData()57     const T *GetData() const
58     {
59         return reinterpret_cast<const T *>(GetCoreType()->GetData());
60     }
61 
GetClass()62     EtsClass *GetClass() const
63     {
64         return EtsClass::FromRuntimeClass(GetCoreType()->ClassAddr<Class>());
65     }
66 
IsPrimitive()67     bool IsPrimitive() const
68     {
69         auto componentType = GetCoreType()->ClassAddr<Class>()->GetComponentType();
70         ASSERT(componentType != nullptr);
71         return componentType->IsPrimitive();
72     }
73 
GetDataOffset()74     static constexpr uint32_t GetDataOffset()
75     {
76         return coretypes::Array::GetDataOffset();
77     }
78 
FromEtsObject(EtsObject * object)79     static EtsArray *FromEtsObject(EtsObject *object)
80     {
81         ASSERT(object->IsArrayClass());
82         return reinterpret_cast<EtsArray *>(object);
83     }
84 
AsObject()85     EtsObject *AsObject()
86     {
87         return reinterpret_cast<EtsObject *>(this);
88     }
89 
AsObject()90     const EtsObject *AsObject() const
91     {
92         return reinterpret_cast<const EtsObject *>(this);
93     }
94 
GetCoreType()95     coretypes::Array *GetCoreType()
96     {
97         return reinterpret_cast<coretypes::Array *>(this);
98     }
99 
GetCoreType()100     const coretypes::Array *GetCoreType() const
101     {
102         return reinterpret_cast<const coretypes::Array *>(this);
103     }
104 
105     NO_COPY_SEMANTIC(EtsArray);
106     NO_MOVE_SEMANTIC(EtsArray);
107 
108 protected:
109     // Use type alias to allow using into derived classes
110     using ObjectHeader = ::ark::ObjectHeader;
111 
112     template <class T>
113     static T *Create(EtsClass *arrayClass, uint32_t length, SpaceType spaceType = SpaceType::SPACE_TYPE_OBJECT,
114                      bool pinned = false)
115     {
116         return reinterpret_cast<T *>(
117             coretypes::Array::Create(arrayClass->GetRuntimeClass(), length, spaceType, pinned));
118     }
119 
120     template <class T, bool IS_VOLATILE = false>
121     void SetImpl(uint32_t idx, T elem, uint32_t byteOffset = 0)
122     {
123         GetCoreType()->Set<T, true, false, IS_VOLATILE>(idx, elem, byteOffset);
124     }
125 
126     template <class T, bool IS_VOLATILE = false>
127     T GetImpl(uint32_t idx, uint32_t byteOffset = 0) const
128     {
129         return GetCoreType()->Get<T, true, false, IS_VOLATILE>(idx, byteOffset);
130     }
131 
132     template <class T>
FillImpl(T elem,uint32_t start,uint32_t end)133     void FillImpl(T elem, uint32_t start, uint32_t end)
134     {
135         GetCoreType()->Fill(elem, start, end);
136     }
137 
138     template <class T>
139     std::pair<bool, T> CompareAndExchangeImpl(uint32_t idx, T oldElemValue, T newValue, bool strong,
140                                               uint32_t byteOffset = 0)
141     {
142         return GetCoreType()->CompareAndExchange(idx, oldElemValue, newValue, std::memory_order_seq_cst, strong,
143                                                  byteOffset);
144     }
145 
146     template <class T>
147     T ExchangeImpl(uint32_t idx, T val, uint32_t byteOffset = 0)
148     {
149         return GetCoreType()->Exchange(idx, val, std::memory_order_seq_cst, byteOffset);
150     }
151 
152     template <class T>
153     T GetAndAddImpl(uint32_t idx, T value, uint32_t byteOffset = 0)
154     {
155         return GetCoreType()->GetAndAdd(idx, value, std::memory_order_seq_cst, byteOffset);
156     }
157 
158     template <class T>
159     T GetAndSubImpl(uint32_t idx, T value, uint32_t byteOffset = 0)
160     {
161         return GetCoreType()->GetAndSub(idx, value, std::memory_order_seq_cst, byteOffset);
162     }
163 
164     template <class T>
165     T GetAndBitwiseOrImpl(uint32_t idx, T value, uint32_t byteOffset = 0)
166     {
167         return GetCoreType()->GetAndBitwiseOr(idx, value, std::memory_order_seq_cst, byteOffset);
168     }
169 
170     template <class T>
171     T GetAndBitwiseAndImpl(uint32_t idx, T value, uint32_t byteOffset = 0)
172     {
173         return GetCoreType()->GetAndBitwiseAnd(idx, value, std::memory_order_seq_cst, byteOffset);
174     }
175 
176     template <class T>
177     T GetAndBitwiseXorImpl(uint32_t idx, T value, uint32_t byteOffset = 0)
178     {
179         return GetCoreType()->GetAndBitwiseXor(idx, value, std::memory_order_seq_cst, byteOffset);
180     }
181 };
182 
183 template <typename Component>
184 class EtsTypedObjectArray : public EtsArray {
185 public:
186     using ValueType = Component *;
187 
188     static EtsTypedObjectArray *Create(EtsClass *objectClass, uint32_t length,
189                                        ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT)
190     {
191         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
192         // Generate Array class name  "[L<object_class>;"
193         EtsClassLinker *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
194         ASSERT(objectClass != nullptr);
195         PandaString arrayClassName = PandaString("[") + objectClass->GetDescriptor();
196         EtsClass *arrayClass = classLinker->GetClass(arrayClassName.c_str(), true, objectClass->GetLoadContext());
197         if (arrayClass == nullptr) {
198             return nullptr;
199         }
200         return EtsArray::Create<EtsTypedObjectArray>(arrayClass, length, spaceType);
201     }
202 
Set(uint32_t index,Component * element)203     void Set(uint32_t index, Component *element)
204     {
205         if (element == nullptr) {
206             SetImpl<ObjectHeader *>(index, nullptr);
207         } else {
208             SetImpl(index, element->GetCoreType());
209         }
210     }
211 
Get(uint32_t index)212     PANDA_PUBLIC_API Component *Get(uint32_t index) const
213     {
214         return reinterpret_cast<Component *>(
215             GetImpl<std::invoke_result_t<decltype(&Component::GetCoreType), Component>>(index));
216     }
217 
Fill(Component * element,uint32_t start,uint32_t end)218     void Fill(Component *element, uint32_t start, uint32_t end)
219     {
220         if (element == nullptr) {
221             FillImpl<ObjectHeader *>(nullptr, start, end);
222         } else {
223             FillImpl(element->GetCoreType(), start, end);
224         }
225     }
226 
Set(uint32_t index,Component * element,std::memory_order memoryOrder)227     void Set(uint32_t index, Component *element, std::memory_order memoryOrder)
228     {
229         auto offset = index * sizeof(ObjectPointerType);
230         GetCoreType()->SetObject(offset, element == nullptr ? nullptr : element->GetCoreType(), memoryOrder);
231     }
232 
Get(uint32_t index,std::memory_order memoryOrder)233     Component *Get(uint32_t index, std::memory_order memoryOrder) const
234     {
235         auto offset = index * sizeof(ObjectPointerType);
236         return Component::FromCoreType(GetCoreType()->GetObject(offset, memoryOrder));
237     }
238 
FromEtsObject(EtsObject * object)239     static EtsTypedObjectArray *FromEtsObject(EtsObject *object)
240     {
241         ASSERT(object->IsArrayClass());
242         return reinterpret_cast<EtsTypedObjectArray *>(object);
243     }
244 
FromCoreType(ObjectHeader * objectHeader)245     static EtsTypedObjectArray *FromCoreType(ObjectHeader *objectHeader)
246     {
247         return reinterpret_cast<EtsTypedObjectArray *>(objectHeader);
248     }
249 
CopyDataTo(EtsTypedObjectArray * dst)250     void CopyDataTo(EtsTypedObjectArray *dst) const
251     {
252         ASSERT(dst != nullptr);
253         ASSERT(GetLength() <= dst->GetLength());
254 
255         if (std::size_t count = GetLength() * OBJECT_POINTER_SIZE) {
256             Span<const uint8_t> srcSpan(GetData<uint8_t>(), count);
257             Span<uint8_t> dstSpan(dst->GetData<uint8_t>(), count);
258             CopyData(srcSpan, dstSpan);
259             // Call barriers.
260             // PreBarrier isn't needed as links inside the source object arn't changed.
261             auto *barrierSet = ManagedThread::GetCurrent()->GetBarrierSet();
262             if (!mem::IsEmptyBarrier(barrierSet->GetPostType())) {
263                 barrierSet->PostBarrier(dst, GetDataOffset(), count);
264             }
265         }
266     }
267 
268     EtsTypedObjectArray() = delete;
269     ~EtsTypedObjectArray() = delete;
270 
271 private:
272     NO_COPY_SEMANTIC(EtsTypedObjectArray);
273     NO_MOVE_SEMANTIC(EtsTypedObjectArray);
274 
275     using WordType = uintptr_t;
276     using AtomicWord = std::atomic<WordType>;
277     using AtomicRef = std::atomic<ark::ObjectPointerType>;
278 
279     static constexpr const std::size_t WORD_SIZE = sizeof(WordType);
280 
CopyData(Span<const uint8_t> & src,Span<uint8_t> & dst)281     void CopyData(Span<const uint8_t> &src, Span<uint8_t> &dst) const
282     {
283         ASSERT((src.Size() % OBJECT_POINTER_SIZE) == 0);
284         ASSERT(src.Size() <= dst.Size());
285 
286         // WORDs and REFERENCEs must be loaded/stored atomically
287         constexpr const std::memory_order ORDER = std::memory_order_relaxed;
288         // 1. copy by words if any
289         std::size_t i = 0;
290         std::size_t stop = (src.Size() / WORD_SIZE) * WORD_SIZE;
291         for (; i < stop; i += WORD_SIZE) {
292             // Atomic with parameterized order reason: memory order defined as constexpr
293             reinterpret_cast<AtomicWord *>(&dst[i])->store(reinterpret_cast<const AtomicWord *>(&src[i])->load(ORDER),
294                                                            ORDER);
295         }
296         // 2. copy by references if any
297         stop = src.Size();
298         for (; i < stop; i += OBJECT_POINTER_SIZE) {
299             // Atomic with parameterized order reason: memory order defined as constexpr
300             reinterpret_cast<AtomicRef *>(&dst[i])->store(reinterpret_cast<const AtomicRef *>(&src[i])->load(ORDER),
301                                                           ORDER);
302         }
303     }
304 };
305 
306 using EtsObjectArray = EtsTypedObjectArray<EtsObject>;
307 
308 template <class ClassType, EtsClassRoot ETS_CLASS_ROOT>
309 class EtsPrimitiveArray : public EtsArray {
310 public:
311     using ValueType = ClassType;
312 
FromCoreType(const ObjectHeader * object)313     static constexpr const EtsPrimitiveArray<ClassType, ETS_CLASS_ROOT> *FromCoreType(const ObjectHeader *object)
314     {
315         return reinterpret_cast<const EtsPrimitiveArray<ClassType, ETS_CLASS_ROOT> *>(object);
316     }
317 
FromEtsObject(EtsObject * object)318     static constexpr EtsPrimitiveArray<ClassType, ETS_CLASS_ROOT> *FromEtsObject(EtsObject *object)
319     {
320         return reinterpret_cast<EtsPrimitiveArray<ClassType, ETS_CLASS_ROOT> *>(object);
321     }
322 
323     static EtsPrimitiveArray *Create(uint32_t length, SpaceType spaceType = SpaceType::SPACE_TYPE_OBJECT,
324                                      bool pinned = false)
325     {
326         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
327         return EtsArray::Create<EtsPrimitiveArray>(GetComponentClass(), length, spaceType, pinned);
328     }
Set(uint32_t index,ClassType element)329     void Set(uint32_t index, ClassType element)
330     {
331         SetImpl(index, element);
332     }
Get(uint32_t index)333     ClassType Get(uint32_t index) const
334     {
335         return GetImpl<ClassType>(index);
336     }
SetVolatile(uint32_t index,uint32_t byteOffset,ClassType element)337     void SetVolatile(uint32_t index, uint32_t byteOffset, ClassType element)
338     {
339         SetImpl<ClassType, true>(index, element, byteOffset);
340     }
GetVolatile(uint32_t index,uint32_t byteOffset)341     ClassType GetVolatile(uint32_t index, uint32_t byteOffset) const
342     {
343         return GetImpl<ClassType, true>(index, byteOffset);
344     }
CompareAndExchange(uint32_t index,uint32_t byteOffset,ClassType oldVal,ClassType newVal,bool strong)345     std::pair<bool, ClassType> CompareAndExchange(uint32_t index, uint32_t byteOffset, ClassType oldVal,
346                                                   ClassType newVal, bool strong)
347     {
348         return CompareAndExchangeImpl(index, oldVal, newVal, strong, byteOffset);
349     }
Exchange(uint32_t index,uint32_t byteOffset,ClassType val)350     ClassType Exchange(uint32_t index, uint32_t byteOffset, ClassType val)
351     {
352         return ExchangeImpl(index, val, byteOffset);
353     }
GetAndAdd(uint32_t index,uint32_t byteOffset,ClassType val)354     ClassType GetAndAdd(uint32_t index, uint32_t byteOffset, ClassType val)
355     {
356         return GetAndAddImpl(index, val, byteOffset);
357     }
GetAndSub(uint32_t index,uint32_t byteOffset,ClassType val)358     ClassType GetAndSub(uint32_t index, uint32_t byteOffset, ClassType val)
359     {
360         return GetAndSubImpl(index, val, byteOffset);
361     }
GetAndBitwiseAnd(uint32_t index,uint32_t byteOffset,ClassType val)362     ClassType GetAndBitwiseAnd(uint32_t index, uint32_t byteOffset, ClassType val)
363     {
364         return GetAndBitwiseAndImpl(index, val, byteOffset);
365     }
GetAndBitwiseOr(uint32_t index,uint32_t byteOffset,ClassType val)366     ClassType GetAndBitwiseOr(uint32_t index, uint32_t byteOffset, ClassType val)
367     {
368         return GetAndBitwiseOrImpl(index, val, byteOffset);
369     }
GetAndBitwiseXor(uint32_t index,uint32_t byteOffset,ClassType val)370     ClassType GetAndBitwiseXor(uint32_t index, uint32_t byteOffset, ClassType val)
371     {
372         return GetAndBitwiseXorImpl(index, val, byteOffset);
373     }
374 
GetComponentClass()375     static EtsClass *GetComponentClass()
376     {
377         return PandaEtsVM::GetCurrent()->GetClassLinker()->GetClassRoot(ETS_CLASS_ROOT);
378     }
379 
380     EtsPrimitiveArray() = delete;
381     ~EtsPrimitiveArray() = delete;
382 
383 private:
384     NO_COPY_SEMANTIC(EtsPrimitiveArray);
385     NO_MOVE_SEMANTIC(EtsPrimitiveArray);
386 };
387 
388 using EtsBooleanArray = EtsPrimitiveArray<EtsBoolean, EtsClassRoot::BOOLEAN_ARRAY>;
389 using EtsByteArray = EtsPrimitiveArray<EtsByte, EtsClassRoot::BYTE_ARRAY>;
390 using EtsCharArray = EtsPrimitiveArray<EtsChar, EtsClassRoot::CHAR_ARRAY>;
391 using EtsShortArray = EtsPrimitiveArray<EtsShort, EtsClassRoot::SHORT_ARRAY>;
392 using EtsUintArray = EtsPrimitiveArray<EtsUint, EtsClassRoot::UINT_ARRAY>;
393 using EtsIntArray = EtsPrimitiveArray<EtsInt, EtsClassRoot::INT_ARRAY>;
394 using EtsUlongArray = EtsPrimitiveArray<EtsUlong, EtsClassRoot::ULONG_ARRAY>;
395 using EtsLongArray = EtsPrimitiveArray<EtsLong, EtsClassRoot::LONG_ARRAY>;
396 using EtsFloatArray = EtsPrimitiveArray<EtsFloat, EtsClassRoot::FLOAT_ARRAY>;
397 using EtsDoubleArray = EtsPrimitiveArray<EtsDouble, EtsClassRoot::DOUBLE_ARRAY>;
398 
399 }  // namespace ark::ets
400 
401 #endif  // PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_ARRAY_H_
402