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_RUNTIME_CORETYPES_ARRAY_H_ 16 #define PANDA_RUNTIME_CORETYPES_ARRAY_H_ 17 18 #include <securec.h> 19 #include <cstddef> 20 #include <cstdint> 21 22 #include "libpandabase/macros.h" 23 #include "libpandabase/mem/mem.h" 24 #include "libpandabase/mem/space.h" 25 #include "libpandabase/utils/span.h" 26 #include "libpandafile/bytecode_instruction-inl.h" 27 #include "runtime/include/class-inl.h" 28 #include "runtime/include/language_context.h" 29 #include "runtime/include/object_header.h" 30 #include "runtime/mem/heap_manager.h" 31 #include "runtime/include/coretypes/tagged_value.h" 32 33 namespace ark { 34 class ManagedThread; 35 class PandaVM; 36 } // namespace ark 37 38 namespace ark::interpreter { 39 template <BytecodeInstruction::Format FORMAT, bool IS_DYNAMIC = false> 40 class DimIterator; 41 } // namespace ark::interpreter 42 43 namespace ark::coretypes { 44 class DynClass; 45 using ArraySizeT = ark::ArraySizeT; 46 using ArraySsizeT = ark::ArraySsizeT; 47 48 class Array : public ObjectHeader { 49 public: 50 static constexpr ArraySizeT MAX_ARRAY_INDEX = std::numeric_limits<ArraySizeT>::max(); 51 Cast(ObjectHeader * object)52 static Array *Cast(ObjectHeader *object) 53 { 54 // NOTE(linxiang) to do assert 55 return reinterpret_cast<Array *>(object); 56 } 57 58 PANDA_PUBLIC_API static Array *Create(ark::Class *arrayClass, const uint8_t *data, ArraySizeT length, 59 ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT, 60 bool pinned = false); 61 62 PANDA_PUBLIC_API static Array *Create(ark::Class *arrayClass, ArraySizeT length, 63 ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT, 64 bool pinned = false); 65 66 PANDA_PUBLIC_API static Array *Create(DynClass *dynarrayclass, ArraySizeT length, 67 ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT, 68 bool pinned = false); 69 70 static Array *CreateTagged(const PandaVM *vm, ark::BaseClass *arrayClass, ArraySizeT length, 71 ark::SpaceType spaceType = ark::SpaceType::SPACE_TYPE_OBJECT, 72 TaggedValue initValue = TaggedValue::Undefined()); 73 ComputeSize(size_t elemSize,ArraySizeT length)74 static size_t ComputeSize(size_t elemSize, ArraySizeT length) 75 { 76 ASSERT(elemSize != 0); 77 size_t size = sizeof(Array) + elemSize * length; 78 #ifdef PANDA_TARGET_32 79 // NOLINTNEXTLINE(clang-analyzer-core.DivideZero) 80 size_t sizeLimit = (std::numeric_limits<size_t>::max() - sizeof(Array)) / elemSize; 81 if (UNLIKELY(sizeLimit < static_cast<size_t>(length))) { 82 return 0; 83 } 84 #endif 85 return size; 86 } 87 GetLength()88 ArraySizeT GetLength() const 89 { 90 // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints 91 // imposed on other reads or writes 92 return length_.load(std::memory_order_relaxed); 93 } 94 GetData()95 uint32_t *GetData() 96 { 97 return data_; 98 } 99 GetData()100 const uint32_t *GetData() const 101 { 102 return data_; 103 } 104 105 template <class T, bool IS_VOLATILE = false> 106 T GetPrimitive(size_t offset) const; 107 108 template <class T, bool IS_VOLATILE = false> 109 void SetPrimitive(size_t offset, T value); 110 111 template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true, bool IS_DYN = false> 112 ObjectHeader *GetObject(int offset) const; 113 114 template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 115 void SetObject(size_t offset, ObjectHeader *value); 116 117 template <class T> 118 T GetPrimitive(size_t offset, std::memory_order memoryOrder) const; 119 120 template <class T> 121 void SetPrimitive(size_t offset, T value, std::memory_order memoryOrder); 122 123 template <bool NEED_READ_BARRIER = true, bool IS_DYN = false> 124 ObjectHeader *GetObject(size_t offset, std::memory_order memoryOrder) const; 125 126 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 127 void SetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 128 129 template <typename T> 130 bool CompareAndSetPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong); 131 132 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 133 bool CompareAndSetObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 134 std::memory_order memoryOrder, bool strong); 135 136 template <typename T> 137 T CompareAndExchangePrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong); 138 139 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 140 ObjectHeader *CompareAndExchangeObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 141 std::memory_order memoryOrder, bool strong); 142 143 template <typename T> 144 T GetAndSetPrimitive(size_t offset, T value, std::memory_order memoryOrder); 145 146 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 147 ObjectHeader *GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 148 149 template <typename T> 150 T GetAndAddPrimitive(size_t offset, T value, std::memory_order memoryOrder); 151 152 template <typename T> 153 T GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memoryOrder); 154 155 template <typename T> 156 T GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memoryOrder); 157 158 template <typename T> 159 T GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memoryOrder); 160 161 template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false, bool IS_VOLATILE = false> 162 std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, void> Set(ArraySizeT idx, T elem, 163 uint32_t byteOffset = 0); 164 165 template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false, bool IS_VOLATILE = false> 166 std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, T> Get(ArraySizeT idx, uint32_t byteOffset = 0) const; 167 168 template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 169 std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, std::pair<bool, T>> CompareAndExchange( 170 ArraySizeT idx, T oldValue, T newValue, std::memory_order memoryOrder, bool strong, uint32_t byteOffset = 0); 171 172 template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 173 std::enable_if_t<std::is_arithmetic_v<T> || is_object_v<T>, T> Exchange(ArraySizeT idx, T value, 174 std::memory_order memoryOrder, 175 uint32_t byteOffset = 0); 176 177 template <class T> 178 std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndAdd(ArraySizeT idx, T value, std::memory_order memoryOrder, 179 uint32_t byteOffset = 0); 180 181 template <class T> 182 std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndSub(ArraySizeT idx, T value, std::memory_order memoryOrder, 183 uint32_t byteOffset = 0); 184 185 template <class T> 186 std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndBitwiseOr(ArraySizeT idx, T value, std::memory_order memoryOrder, 187 uint32_t byteOffset = 0); 188 189 template <class T> 190 std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndBitwiseAnd(ArraySizeT idx, T value, 191 std::memory_order memoryOrder, 192 uint32_t byteOffset = 0); 193 194 template <class T> 195 std::enable_if_t<std::is_arithmetic_v<T>, T> GetAndBitwiseXor(ArraySizeT idx, T value, 196 std::memory_order memoryOrder, 197 uint32_t byteOffset = 0); 198 199 template <class T, bool IS_DYN> 200 static constexpr size_t GetElementSize(); 201 202 template <class T> 203 T GetBase(); 204 205 // Pass thread parameter to speed up interpreter 206 template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 207 void Set([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx, T elem); 208 209 template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false> 210 T Get([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx) const; 211 212 template <class T, bool NEED_BARRIER = true, bool IS_DYN = false> 213 void Fill(T elem, ArraySizeT start, ArraySizeT end); 214 ObjectSize(uint32_t componentSize)215 size_t ObjectSize(uint32_t componentSize) const 216 { 217 return ComputeSize(componentSize, length_); 218 } 219 GetLengthOffset()220 static constexpr uint32_t GetLengthOffset() 221 { 222 return MEMBER_OFFSET(Array, length_); 223 } 224 GetDataOffset()225 static constexpr uint32_t GetDataOffset() 226 { 227 return MEMBER_OFFSET(Array, data_); 228 } 229 230 template <bool IS_DYN> GetElementOffset(ArraySizeT idx)231 ArraySizeT GetElementOffset(ArraySizeT idx) const 232 { 233 size_t elemSize; 234 // NOLINTNEXTLINE(readability-braces-around-statements) 235 if constexpr (IS_DYN) { 236 elemSize = TaggedValue::TaggedTypeSize(); 237 } else { // NOLINT(readability-misleading-indentation) 238 elemSize = ClassAddr<ark::Class>()->GetComponentSize(); 239 } 240 return GetDataOffset() + idx * elemSize; 241 } 242 243 template <class DimIterator> 244 static Array *CreateMultiDimensionalArray(ManagedThread *thread, ark::Class *klass, uint32_t nargs, 245 const DimIterator &iter, size_t dimIdx = 0); 246 247 private: SetLength(ArraySizeT length)248 void SetLength(ArraySizeT length) 249 { 250 // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints 251 // imposed on other reads or writes 252 length_.store(length, std::memory_order_relaxed); 253 } 254 255 template <class T> 256 void FillPrimitiveElem(T elem, ArraySizeT start, ArraySizeT end, size_t elemSize); 257 258 std::atomic<ArraySizeT> length_; 259 // Align by 64bits, because dynamic language data is always 64bits 260 __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0]; // NOLINT(modernize-avoid-c-arrays) 261 }; 262 263 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader)); 264 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(ArraySizeT), sizeof(uint64_t))); 265 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0); 266 267 constexpr uint32_t ARRAY_LENGTH_OFFSET = sizeof(ObjectHeader); 268 static_assert(ARRAY_LENGTH_OFFSET == ark::coretypes::Array::GetLengthOffset()); 269 constexpr uint32_t ARRAY_DATA_OFFSET = ARRAY_LENGTH_OFFSET + sizeof(uint64_t); 270 static_assert(ARRAY_DATA_OFFSET == ark::coretypes::Array::GetDataOffset()); 271 272 } // namespace ark::coretypes 273 274 #endif // PANDA_RUNTIME_CORETYPES_ARRAY_H_ 275