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_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> 162 void Set(ArraySizeT idx, T elem); 163 164 template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false> 165 T Get(ArraySizeT idx) const; 166 167 template <class T, bool IS_DYN> 168 static constexpr size_t GetElementSize(); 169 170 template <class T> 171 T GetBase(); 172 173 // Pass thread parameter to speed up interpreter 174 template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 175 void Set([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx, T elem); 176 177 template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false> 178 T Get([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx) const; 179 ObjectSize(uint32_t componentSize)180 size_t ObjectSize(uint32_t componentSize) const 181 { 182 return ComputeSize(componentSize, length_); 183 } 184 GetLengthOffset()185 static constexpr uint32_t GetLengthOffset() 186 { 187 return MEMBER_OFFSET(Array, length_); 188 } 189 GetDataOffset()190 static constexpr uint32_t GetDataOffset() 191 { 192 return MEMBER_OFFSET(Array, data_); 193 } 194 195 template <bool IS_DYN> GetElementOffset(ArraySizeT idx)196 ArraySizeT GetElementOffset(ArraySizeT idx) const 197 { 198 size_t elemSize; 199 // NOLINTNEXTLINE(readability-braces-around-statements) 200 if constexpr (IS_DYN) { 201 elemSize = TaggedValue::TaggedTypeSize(); 202 } else { // NOLINT(readability-misleading-indentation) 203 elemSize = ClassAddr<ark::Class>()->GetComponentSize(); 204 } 205 return GetDataOffset() + idx * elemSize; 206 } 207 208 template <class DimIterator> 209 static Array *CreateMultiDimensionalArray(ManagedThread *thread, ark::Class *klass, uint32_t nargs, 210 const DimIterator &iter, size_t dimIdx = 0); 211 212 private: SetLength(ArraySizeT length)213 void SetLength(ArraySizeT length) 214 { 215 // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints 216 // imposed on other reads or writes 217 length_.store(length, std::memory_order_relaxed); 218 } 219 220 std::atomic<ArraySizeT> length_; 221 // Align by 64bits, because dynamic language data is always 64bits 222 __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0]; // NOLINT(modernize-avoid-c-arrays) 223 }; 224 225 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader)); 226 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(ArraySizeT), sizeof(uint64_t))); 227 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0); 228 229 #ifdef PANDA_TARGET_64 230 constexpr uint32_t ARRAY_LENGTH_OFFSET = 8U; 231 static_assert(ARRAY_LENGTH_OFFSET == ark::coretypes::Array::GetLengthOffset()); 232 constexpr uint32_t ARRAY_DATA_OFFSET = 16U; 233 static_assert(ARRAY_DATA_OFFSET == ark::coretypes::Array::GetDataOffset()); 234 #endif 235 } // namespace ark::coretypes 236 237 #endif // PANDA_RUNTIME_CORETYPES_ARRAY_H_ 238