• 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_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 panda::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()
36     {
37         return GetCoreType()->GetLength();
38     }
39 
GetElementSize()40     size_t GetElementSize()
41     {
42         return GetCoreType()->ClassAddr<Class>()->GetComponentSize();
43     }
44 
ObjectSize()45     size_t ObjectSize()
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 
GetClass()56     EtsClass *GetClass()
57     {
58         return EtsClass::FromRuntimeClass(GetCoreType()->ClassAddr<Class>());
59     }
60 
IsPrimitive()61     bool IsPrimitive()
62     {
63         auto componentType = GetCoreType()->ClassAddr<Class>()->GetComponentType();
64         ASSERT(componentType != nullptr);
65         return componentType->IsPrimitive();
66     }
67 
GetDataOffset()68     static constexpr uint32_t GetDataOffset()
69     {
70         return coretypes::Array::GetDataOffset();
71     }
72 
AsObject()73     EtsObject *AsObject()
74     {
75         return reinterpret_cast<EtsObject *>(this);
76     }
77 
AsObject()78     const EtsObject *AsObject() const
79     {
80         return reinterpret_cast<const EtsObject *>(this);
81     }
82 
GetCoreType()83     coretypes::Array *GetCoreType()
84     {
85         return reinterpret_cast<coretypes::Array *>(this);
86     }
87 
88     template <class T>
89     static T *Create(EtsClass *arrayClass, uint32_t length, SpaceType spaceType = SpaceType::SPACE_TYPE_OBJECT)
90     {
91         return reinterpret_cast<T *>(coretypes::Array::Create(arrayClass->GetRuntimeClass(), length, spaceType));
92     }
93 
94     template <class T>
95     static T *CreateForPrimitive(EtsClassRoot root, uint32_t length, SpaceType spaceType = SpaceType::SPACE_TYPE_OBJECT)
96     {
97         EtsClass *arrayClass = PandaEtsVM::GetCurrent()->GetClassLinker()->GetClassRoot(root);
98         return Create<T>(arrayClass, length, spaceType);
99     }
100 
101     NO_COPY_SEMANTIC(EtsArray);
102     NO_MOVE_SEMANTIC(EtsArray);
103 
104 protected:
105     // Use type alias to allow using into derived classes
106     using ObjectHeader = ::panda::ObjectHeader;
107 
108     template <class T>
SetImpl(uint32_t idx,T elem)109     void SetImpl(uint32_t idx, T elem)
110     {
111         GetCoreType()->Set(idx, elem);
112     }
113 
114     template <class T>
GetImpl(uint32_t idx)115     T GetImpl(uint32_t idx)
116     {
117         return GetCoreType()->Get<T>(idx);
118     }
119 };
120 
121 class EtsObjectArray : public EtsArray {
122 public:
123     static EtsObjectArray *Create(EtsClass *objectClass, uint32_t length,
124                                   panda::SpaceType spaceType = panda::SpaceType::SPACE_TYPE_OBJECT)
125     {
126         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
127         // Generate Array class name  "[L<object_class>;"
128         EtsClassLinker *classLinker = PandaEtsVM::GetCurrent()->GetClassLinker();
129         PandaString arrayClassName = PandaString("[") + objectClass->GetDescriptor();
130         EtsClass *arrayClass = classLinker->GetClass(arrayClassName.c_str(), true, objectClass->GetClassLoader());
131         if (arrayClass == nullptr) {
132             return nullptr;
133         }
134         return EtsArray::Create<EtsObjectArray>(arrayClass, length, spaceType);
135     }
136 
Set(uint32_t index,EtsObject * element)137     void Set(uint32_t index, EtsObject *element)
138     {
139         if (element == nullptr) {
140             SetImpl<ObjectHeader *>(index, nullptr);
141         } else {
142             SetImpl(index, element->GetCoreType());
143         }
144     }
145 
Get(uint32_t index)146     PANDA_PUBLIC_API EtsObject *Get(uint32_t index)
147     {
148         return reinterpret_cast<EtsObject *>(
149             GetImpl<std::invoke_result_t<decltype(&EtsObject::GetCoreType), EtsObject>>(index));
150     }
151 
FromCoreType(ObjectHeader * objectHeader)152     static EtsObjectArray *FromCoreType(ObjectHeader *objectHeader)
153     {
154         return reinterpret_cast<EtsObjectArray *>(objectHeader);
155     }
156 
CopyDataTo(EtsObjectArray * dst)157     void CopyDataTo(EtsObjectArray *dst)
158     {
159         ASSERT(dst != nullptr);
160         ASSERT(GetLength() <= dst->GetLength());
161 
162         if (std::size_t count = GetLength() * OBJECT_POINTER_SIZE) {
163             Span<uint8_t> srcSpan(GetData<uint8_t>(), count);
164             Span<uint8_t> dstSpan(dst->GetData<uint8_t>(), count);
165             CopyData(srcSpan, dstSpan);
166             // Call barriers.
167             // PreBarrier isn't needed as links inside the source object arn't changed.
168             auto *barrierSet = ManagedThread::GetCurrent()->GetBarrierSet();
169             if (!mem::IsEmptyBarrier(barrierSet->GetPostType())) {
170                 barrierSet->PostBarrier(dst, 0, dst->ObjectSize());
171             }
172         }
173     }
174 
175     EtsObjectArray() = delete;
176     ~EtsObjectArray() = delete;
177 
178 private:
179     NO_COPY_SEMANTIC(EtsObjectArray);
180     NO_MOVE_SEMANTIC(EtsObjectArray);
181 
182     using WordType = uintptr_t;
183     using AtomicWord = std::atomic<WordType>;
184     using AtomicRef = std::atomic<panda::ObjectPointerType>;
185 
186     static constexpr const std::size_t WORD_SIZE = sizeof(WordType);
187 
CopyData(Span<uint8_t> & src,Span<uint8_t> & dst)188     void CopyData(Span<uint8_t> &src, Span<uint8_t> &dst)
189     {
190         ASSERT((src.Size() % OBJECT_POINTER_SIZE) == 0);
191         ASSERT(src.Size() <= dst.Size());
192 
193         // WORDs and REFERENCEs must be loaded/stored atomically
194         constexpr const std::memory_order ORDER = std::memory_order_relaxed;
195         // 1. copy by words if any
196         std::size_t i = 0;
197         std::size_t stop = (src.Size() / WORD_SIZE) * WORD_SIZE;
198         for (; i < stop; i += WORD_SIZE) {
199             // Atomic with parameterized order reason: memory order defined as constexpr
200             reinterpret_cast<AtomicWord *>(&dst[i])->store(reinterpret_cast<AtomicWord *>(&src[i])->load(ORDER), ORDER);
201         }
202         // 2. copy by references if any
203         stop = ((src.Size() - i) / OBJECT_POINTER_SIZE) * OBJECT_POINTER_SIZE;
204         for (; i < stop; i += OBJECT_POINTER_SIZE) {
205             // Atomic with parameterized order reason: memory order defined as constexpr
206             reinterpret_cast<AtomicRef *>(&dst[i])->store(reinterpret_cast<AtomicRef *>(&src[i])->load(ORDER), ORDER);
207         }
208     }
209 };
210 
211 template <class ClassType, EtsClassRoot ETS_CLASS_ROOT>
212 class EtsPrimitiveArray : public EtsArray {
213 public:
214     using ValueType = ClassType;
215 
216     static EtsPrimitiveArray *Create(uint32_t length, SpaceType spaceType = SpaceType::SPACE_TYPE_OBJECT)
217     {
218         ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS();
219         // NOLINTNEXTLINE(readability-magic-numbers)
220         return EtsArray::CreateForPrimitive<EtsPrimitiveArray>(ETS_CLASS_ROOT, length, spaceType);
221     }
Set(uint32_t index,ClassType element)222     void Set(uint32_t index, ClassType element)
223     {
224         SetImpl(index, element);
225     }
Get(uint32_t index)226     ClassType Get(uint32_t index)
227     {
228         return GetImpl<ClassType>(index);
229     }
230 
231     EtsPrimitiveArray() = delete;
232     ~EtsPrimitiveArray() = delete;
233 
234 private:
235     NO_COPY_SEMANTIC(EtsPrimitiveArray);
236     NO_MOVE_SEMANTIC(EtsPrimitiveArray);
237 };
238 
239 using EtsBooleanArray = EtsPrimitiveArray<EtsBoolean, EtsClassRoot::BOOLEAN_ARRAY>;
240 using EtsByteArray = EtsPrimitiveArray<EtsByte, EtsClassRoot::BYTE_ARRAY>;
241 using EtsCharArray = EtsPrimitiveArray<EtsChar, EtsClassRoot::CHAR_ARRAY>;
242 using EtsShortArray = EtsPrimitiveArray<EtsShort, EtsClassRoot::SHORT_ARRAY>;
243 using EtsIntArray = EtsPrimitiveArray<EtsInt, EtsClassRoot::INT_ARRAY>;
244 using EtsLongArray = EtsPrimitiveArray<EtsLong, EtsClassRoot::LONG_ARRAY>;
245 using EtsFloatArray = EtsPrimitiveArray<EtsFloat, EtsClassRoot::FLOAT_ARRAY>;
246 using EtsDoubleArray = EtsPrimitiveArray<EtsDouble, EtsClassRoot::DOUBLE_ARRAY>;
247 
248 }  // namespace panda::ets
249 
250 #endif  // PANDA_PLUGINS_ETS_RUNTIME_FFI_CLASSES_ETS_ARRAY_H
251