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