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_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 panda { 34 class ManagedThread; 35 class PandaVM; 36 } // namespace panda 37 38 namespace panda::interpreter { 39 template <BytecodeInstruction::Format FORMAT, bool IS_DYNAMIC = false> 40 class DimIterator; 41 } // namespace panda::interpreter 42 43 namespace panda::coretypes { 44 class DynClass; 45 using ArraySizeT = panda::ArraySizeT; 46 using ArraySsizeT = panda::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(panda::Class *arrayClass, const uint8_t *data, ArraySizeT length, 59 panda::SpaceType spaceType = panda::SpaceType::SPACE_TYPE_OBJECT); 60 61 PANDA_PUBLIC_API static Array *Create(panda::Class *arrayClass, ArraySizeT length, 62 panda::SpaceType spaceType = panda::SpaceType::SPACE_TYPE_OBJECT); 63 64 PANDA_PUBLIC_API static Array *Create(DynClass *dynarrayclass, ArraySizeT length, 65 panda::SpaceType spaceType = panda::SpaceType::SPACE_TYPE_OBJECT); 66 67 static Array *CreateTagged(const PandaVM *vm, panda::BaseClass *arrayClass, ArraySizeT length, 68 panda::SpaceType spaceType = panda::SpaceType::SPACE_TYPE_OBJECT, 69 TaggedValue initValue = TaggedValue::Undefined()); 70 ComputeSize(size_t elemSize,ArraySizeT length)71 static size_t ComputeSize(size_t elemSize, ArraySizeT length) 72 { 73 ASSERT(elemSize != 0); 74 size_t size = sizeof(Array) + elemSize * length; 75 #ifdef PANDA_TARGET_32 76 // NOLINTNEXTLINE(clang-analyzer-core.DivideZero) 77 size_t sizeLimit = (std::numeric_limits<size_t>::max() - sizeof(Array)) / elemSize; 78 if (UNLIKELY(sizeLimit < static_cast<size_t>(length))) { 79 return 0; 80 } 81 #endif 82 return size; 83 } 84 GetLength()85 ArraySizeT GetLength() const 86 { 87 // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints 88 // imposed on other reads or writes 89 return length_.load(std::memory_order_relaxed); 90 } 91 GetData()92 uint32_t *GetData() 93 { 94 return data_; 95 } 96 GetData()97 const uint32_t *GetData() const 98 { 99 return data_; 100 } 101 102 template <class T, bool IS_VOLATILE = false> 103 T GetPrimitive(size_t offset) const; 104 105 template <class T, bool IS_VOLATILE = false> 106 void SetPrimitive(size_t offset, T value); 107 108 template <bool IS_VOLATILE = false, bool NEED_READ_BARRIER = true, bool IS_DYN = false> 109 ObjectHeader *GetObject(int offset) const; 110 111 template <bool IS_VOLATILE = false, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 112 void SetObject(size_t offset, ObjectHeader *value); 113 114 template <class T> 115 T GetPrimitive(size_t offset, std::memory_order memoryOrder) const; 116 117 template <class T> 118 void SetPrimitive(size_t offset, T value, std::memory_order memoryOrder); 119 120 template <bool NEED_READ_BARRIER = true, bool IS_DYN = false> 121 ObjectHeader *GetObject(size_t offset, std::memory_order memoryOrder) const; 122 123 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 124 void SetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 125 126 template <typename T> 127 bool CompareAndSetPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong); 128 129 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 130 bool CompareAndSetObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 131 std::memory_order memoryOrder, bool strong); 132 133 template <typename T> 134 T CompareAndExchangePrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong); 135 136 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 137 ObjectHeader *CompareAndExchangeObject(size_t offset, ObjectHeader *oldValue, ObjectHeader *newValue, 138 std::memory_order memoryOrder, bool strong); 139 140 template <typename T> 141 T GetAndSetPrimitive(size_t offset, T value, std::memory_order memoryOrder); 142 143 template <bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 144 ObjectHeader *GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memoryOrder); 145 146 template <typename T> 147 T GetAndAddPrimitive(size_t offset, T value, std::memory_order memoryOrder); 148 149 template <typename T> 150 T GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memoryOrder); 151 152 template <typename T> 153 T GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memoryOrder); 154 155 template <typename T> 156 T GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memoryOrder); 157 158 template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 159 void Set(ArraySizeT idx, T elem); 160 161 template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false> 162 T Get(ArraySizeT idx) const; 163 164 template <class T, bool IS_DYN> 165 static constexpr size_t GetElementSize(); 166 167 template <class T> 168 T GetBase(); 169 170 // Pass thread parameter to speed up interpreter 171 template <class T, bool NEED_WRITE_BARRIER = true, bool IS_DYN = false> 172 void Set([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx, T elem); 173 174 template <class T, bool NEED_READ_BARRIER = true, bool IS_DYN = false> 175 T Get([[maybe_unused]] const ManagedThread *thread, ArraySizeT idx) const; 176 ObjectSize(uint32_t componentSize)177 size_t ObjectSize(uint32_t componentSize) const 178 { 179 return ComputeSize(componentSize, length_); 180 } 181 GetLengthOffset()182 static constexpr uint32_t GetLengthOffset() 183 { 184 return MEMBER_OFFSET(Array, length_); 185 } 186 GetDataOffset()187 static constexpr uint32_t GetDataOffset() 188 { 189 return MEMBER_OFFSET(Array, data_); 190 } 191 192 template <bool IS_DYN> GetElementOffset(ArraySizeT idx)193 ArraySizeT GetElementOffset(ArraySizeT idx) const 194 { 195 size_t elemSize; 196 // NOLINTNEXTLINE(readability-braces-around-statements) 197 if constexpr (IS_DYN) { 198 elemSize = TaggedValue::TaggedTypeSize(); 199 } else { // NOLINT(readability-misleading-indentation) 200 elemSize = ClassAddr<panda::Class>()->GetComponentSize(); 201 } 202 return GetDataOffset() + idx * elemSize; 203 } 204 205 template <class DimIterator> 206 static Array *CreateMultiDimensionalArray(ManagedThread *thread, panda::Class *klass, uint32_t nargs, 207 const DimIterator &iter, size_t dimIdx = 0); 208 209 private: SetLength(ArraySizeT length)210 void SetLength(ArraySizeT length) 211 { 212 // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints 213 // imposed on other reads or writes 214 length_.store(length, std::memory_order_relaxed); 215 } 216 217 std::atomic<ArraySizeT> length_; 218 // Align by 64bits, because dynamic language data is always 64bits 219 __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0]; // NOLINT(modernize-avoid-c-arrays) 220 }; 221 222 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader)); 223 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(ArraySizeT), sizeof(uint64_t))); 224 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0); 225 226 #ifdef PANDA_TARGET_64 227 constexpr uint32_t ARRAY_LENGTH_OFFSET = 8U; 228 static_assert(ARRAY_LENGTH_OFFSET == panda::coretypes::Array::GetLengthOffset()); 229 constexpr uint32_t ARRAY_DATA_OFFSET = 16U; 230 static_assert(ARRAY_DATA_OFFSET == panda::coretypes::Array::GetDataOffset()); 231 #endif 232 } // namespace panda::coretypes 233 234 #endif // PANDA_RUNTIME_CORETYPES_ARRAY_H 235