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