• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 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_box_primitive.h"
24 #include "plugins/ets/runtime/types/ets_object.h"
25 #include "plugins/ets/runtime/ets_class_root.h"
26 #include "plugins/ets/runtime/ets_vm.h"
27 
28 namespace ark::ets {
29 
30 // Private inheritance, because need to disallow implicit conversion to core type
31 class EtsArray : private coretypes::Array {
32 public:
33     EtsArray() = delete;
34     ~EtsArray() = delete;
35 
GetLength()36     PANDA_PUBLIC_API size_t GetLength()
37     {
38         return GetCoreType()->GetLength();
39     }
40 
GetElementSize()41     size_t GetElementSize()
42     {
43         return GetCoreType()->ClassAddr<Class>()->GetComponentSize();
44     }
45 
ObjectSize()46     size_t ObjectSize()
47     {
48         return GetCoreType()->ObjectSize(GetElementSize());
49     }
50 
51     template <class T>
GetData()52     T *GetData()
53     {
54         return reinterpret_cast<T *>(GetCoreType()->GetData());
55     }
56 
GetClass()57     EtsClass *GetClass()
58     {
59         return EtsClass::FromRuntimeClass(GetCoreType()->ClassAddr<Class>());
60     }
61 
IsPrimitive()62     bool IsPrimitive()
63     {
64         auto componentType = GetCoreType()->ClassAddr<Class>()->GetComponentType();
65         ASSERT(componentType != nullptr);
66         return componentType->IsPrimitive();
67     }
68 
GetDataOffset()69     static constexpr uint32_t GetDataOffset()
70     {
71         return coretypes::Array::GetDataOffset();
72     }
73 
AsObject()74     EtsObject *AsObject()
75     {
76         return reinterpret_cast<EtsObject *>(this);
77     }
78 
AsObject()79     const EtsObject *AsObject() const
80     {
81         return reinterpret_cast<const EtsObject *>(this);
82     }
83 
GetCoreType()84     coretypes::Array *GetCoreType()
85     {
86         return reinterpret_cast<coretypes::Array *>(this);
87     }
88 
89     NO_COPY_SEMANTIC(EtsArray);
90     NO_MOVE_SEMANTIC(EtsArray);
91 
92 protected:
93     // Use type alias to allow using into derived classes
94     using ObjectHeader = ::ark::ObjectHeader;
95 
96     template <class T>
97     static T *Create(EtsClass *arrayClass, uint32_t length, SpaceType spaceType = SpaceType::SPACE_TYPE_OBJECT,
98                      bool pinned = false)
99     {
100         return reinterpret_cast<T *>(
101             coretypes::Array::Create(arrayClass->GetRuntimeClass(), length, spaceType, pinned));
102     }
103 
104     template <class T>
SetImpl(uint32_t idx,T elem)105     void SetImpl(uint32_t idx, T elem)
106     {
107         GetCoreType()->Set(idx, elem);
108     }
109 
110     template <class T>
GetImpl(uint32_t idx)111     T GetImpl(uint32_t idx)
112     {
113         return GetCoreType()->Get<T>(idx);
114     }
115 };
116 
117 template <typename Component>
118 class EtsTypedObjectArray : public EtsArray {
119 public:
120     using ValueType = Component *;
121 
122     static EtsTypedObjectArray *Create(EtsClass *objectClass, uint32_t length,
123                                        ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT)
124     {
125         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
126         // Generate Array class name  "[L<object_class>;"
127         EtsClassLinker *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
128         PandaString arrayClassName = PandaString("[") + objectClass->GetDescriptor();
129         EtsClass *arrayClass = classLinker->GetClass(arrayClassName.c_str(), true, objectClass->GetLoadContext());
130         if (arrayClass == nullptr) {
131             return nullptr;
132         }
133         return EtsArray::Create<EtsTypedObjectArray>(arrayClass, length, spaceType);
134     }
135 
Set(uint32_t index,Component * element)136     void Set(uint32_t index, Component *element)
137     {
138         if (element == nullptr) {
139             SetImpl<ObjectHeader *>(index, nullptr);
140         } else {
141             SetImpl(index, element->GetCoreType());
142         }
143     }
144 
Get(uint32_t index)145     PANDA_PUBLIC_API Component *Get(uint32_t index)
146     {
147         return reinterpret_cast<Component *>(
148             GetImpl<std::invoke_result_t<decltype(&Component::GetCoreType), Component>>(index));
149     }
150 
Set(uint32_t index,Component * element,std::memory_order memoryOrder)151     void Set(uint32_t index, Component *element, std::memory_order memoryOrder)
152     {
153         auto offset = index * sizeof(ObjectPointerType);
154         GetCoreType()->SetObject(offset, element == nullptr ? nullptr : element->GetCoreType(), memoryOrder);
155     }
156 
Get(uint32_t index,std::memory_order memoryOrder)157     Component *Get(uint32_t index, std::memory_order memoryOrder)
158     {
159         auto offset = index * sizeof(ObjectPointerType);
160         return Component::FromCoreType(GetCoreType()->GetObject(offset, memoryOrder));
161     }
162 
FromCoreType(ObjectHeader * objectHeader)163     static EtsTypedObjectArray *FromCoreType(ObjectHeader *objectHeader)
164     {
165         return reinterpret_cast<EtsTypedObjectArray *>(objectHeader);
166     }
167 
CopyDataTo(EtsTypedObjectArray * dst)168     void CopyDataTo(EtsTypedObjectArray *dst)
169     {
170         ASSERT(dst != nullptr);
171         ASSERT(GetLength() <= dst->GetLength());
172 
173         if (std::size_t count = GetLength() * OBJECT_POINTER_SIZE) {
174             Span<uint8_t> srcSpan(GetData<uint8_t>(), count);
175             Span<uint8_t> dstSpan(dst->GetData<uint8_t>(), count);
176             CopyData(srcSpan, dstSpan);
177             // Call barriers.
178             // PreBarrier isn't needed as links inside the source object arn't changed.
179             auto *barrierSet = ManagedThread::GetCurrent()->GetBarrierSet();
180             if (!mem::IsEmptyBarrier(barrierSet->GetPostType())) {
181                 barrierSet->PostBarrier(dst, GetDataOffset(), count);
182             }
183         }
184     }
185 
186     EtsTypedObjectArray() = delete;
187     ~EtsTypedObjectArray() = delete;
188 
189 private:
190     NO_COPY_SEMANTIC(EtsTypedObjectArray);
191     NO_MOVE_SEMANTIC(EtsTypedObjectArray);
192 
193     using WordType = uintptr_t;
194     using AtomicWord = std::atomic<WordType>;
195     using AtomicRef = std::atomic<ark::ObjectPointerType>;
196 
197     static constexpr const std::size_t WORD_SIZE = sizeof(WordType);
198 
CopyData(Span<uint8_t> & src,Span<uint8_t> & dst)199     void CopyData(Span<uint8_t> &src, Span<uint8_t> &dst)
200     {
201         ASSERT((src.Size() % OBJECT_POINTER_SIZE) == 0);
202         ASSERT(src.Size() <= dst.Size());
203 
204         // WORDs and REFERENCEs must be loaded/stored atomically
205         constexpr const std::memory_order ORDER = std::memory_order_relaxed;
206         // 1. copy by words if any
207         std::size_t i = 0;
208         std::size_t stop = (src.Size() / WORD_SIZE) * WORD_SIZE;
209         for (; i < stop; i += WORD_SIZE) {
210             // Atomic with parameterized order reason: memory order defined as constexpr
211             reinterpret_cast<AtomicWord *>(&dst[i])->store(reinterpret_cast<AtomicWord *>(&src[i])->load(ORDER), ORDER);
212         }
213         // 2. copy by references if any
214         stop = src.Size();
215         for (; i < stop; i += OBJECT_POINTER_SIZE) {
216             // Atomic with parameterized order reason: memory order defined as constexpr
217             reinterpret_cast<AtomicRef *>(&dst[i])->store(reinterpret_cast<AtomicRef *>(&src[i])->load(ORDER), ORDER);
218         }
219     }
220 };
221 
222 using EtsObjectArray = EtsTypedObjectArray<EtsObject>;
223 
224 template <class ClassType, EtsClassRoot ETS_CLASS_ROOT>
225 class EtsPrimitiveArray : public EtsArray {
226 public:
227     using ValueType = ClassType;
228 
229     static EtsPrimitiveArray *Create(uint32_t length, SpaceType spaceType = SpaceType::SPACE_TYPE_OBJECT,
230                                      bool pinned = false)
231     {
232         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
233         return EtsArray::Create<EtsPrimitiveArray>(GetComponentClass(), length, spaceType, pinned);
234     }
Set(uint32_t index,ClassType element)235     void Set(uint32_t index, ClassType element)
236     {
237         SetImpl(index, element);
238     }
Get(uint32_t index)239     ClassType Get(uint32_t index)
240     {
241         return GetImpl<ClassType>(index);
242     }
GetComponentClass()243     static EtsClass *GetComponentClass()
244     {
245         return PandaEtsVM::GetCurrent()->GetClassLinker()->GetClassRoot(ETS_CLASS_ROOT);
246     }
247 
248     EtsPrimitiveArray() = delete;
249     ~EtsPrimitiveArray() = delete;
250 
251 private:
252     NO_COPY_SEMANTIC(EtsPrimitiveArray);
253     NO_MOVE_SEMANTIC(EtsPrimitiveArray);
254 };
255 
256 using EtsBooleanArray = EtsPrimitiveArray<EtsBoolean, EtsClassRoot::BOOLEAN_ARRAY>;
257 using EtsByteArray = EtsPrimitiveArray<EtsByte, EtsClassRoot::BYTE_ARRAY>;
258 using EtsCharArray = EtsPrimitiveArray<EtsChar, EtsClassRoot::CHAR_ARRAY>;
259 using EtsShortArray = EtsPrimitiveArray<EtsShort, EtsClassRoot::SHORT_ARRAY>;
260 using EtsUintArray = EtsPrimitiveArray<EtsUint, EtsClassRoot::UINT_ARRAY>;
261 using EtsIntArray = EtsPrimitiveArray<EtsInt, EtsClassRoot::INT_ARRAY>;
262 using EtsUlongArray = EtsPrimitiveArray<EtsUlong, EtsClassRoot::ULONG_ARRAY>;
263 using EtsLongArray = EtsPrimitiveArray<EtsLong, EtsClassRoot::LONG_ARRAY>;
264 using EtsFloatArray = EtsPrimitiveArray<EtsFloat, EtsClassRoot::FLOAT_ARRAY>;
265 using EtsDoubleArray = EtsPrimitiveArray<EtsDouble, EtsClassRoot::DOUBLE_ARRAY>;
266 
267 namespace test {
268 template <class ElementType>
269 class EtsArrayObjectMembers;
270 }  // namespace test
271 
272 // Mirror class for Array<T> from ETS stdlib
273 template <class ElementType>
274 class EtsArrayObject : public EtsObject {
275 public:
276     EtsArrayObject() = delete;
277     ~EtsArrayObject() = delete;
278 
279     NO_COPY_SEMANTIC(EtsArrayObject);
280     NO_MOVE_SEMANTIC(EtsArrayObject);
281 
FromEtsObject(EtsObject * etsObj)282     static EtsArrayObject *FromEtsObject(EtsObject *etsObj)
283     {
284         return reinterpret_cast<EtsArrayObject *>(etsObj);
285     }
286 
GetData()287     EtsTypedObjectArray<ElementType> *GetData()
288     {
289         return reinterpret_cast<EtsTypedObjectArray<ElementType> *>(GetFieldObject(GetBufferOffset()));
290     }
291 
GetActualLength()292     uint32_t GetActualLength()
293     {
294         return helpers::ToUnsigned(GetFieldPrimitive<EtsInt>(GetActualLengthOffset()));
295     }
296 
GetBufferOffset()297     static constexpr size_t GetBufferOffset()
298     {
299         return MEMBER_OFFSET(EtsArrayObject, buffer_);
300     }
301 
GetActualLengthOffset()302     static constexpr size_t GetActualLengthOffset()
303     {
304         return MEMBER_OFFSET(EtsArrayObject, actualLength_);
305     }
306 
307 private:
308     ObjectPointer<EtsTypedObjectArray<ElementType>> buffer_;
309     EtsInt actualLength_;
310 
311     friend class test::EtsArrayObjectMembers<ElementType>;
312 };
313 
314 using EtsBoxedBooleanArray = EtsArrayObject<EtsBoxPrimitive<EtsBoolean>>;
315 using EtsBoxedByteArray = EtsArrayObject<EtsBoxPrimitive<EtsByte>>;
316 using EtsBoxedCharArray = EtsArrayObject<EtsBoxPrimitive<EtsChar>>;
317 using EtsBoxedShortArray = EtsArrayObject<EtsBoxPrimitive<EtsShort>>;
318 using EtsBoxedIntArray = EtsArrayObject<EtsBoxPrimitive<EtsInt>>;
319 using EtsBoxedLongArray = EtsArrayObject<EtsBoxPrimitive<EtsLong>>;
320 using EtsBoxedFloatArray = EtsArrayObject<EtsBoxPrimitive<EtsFloat>>;
321 using EtsBoxedDoubleArray = EtsArrayObject<EtsBoxPrimitive<EtsDouble>>;
322 }  // namespace ark::ets
323 
324 #endif  // PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_ARRAY_H_
325