1 /* 2 * Copyright (c) 2021 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 16 #ifndef PANDA_RUNTIME_INCLUDE_CORETYPES_ARRAY_H_ 17 #define PANDA_RUNTIME_INCLUDE_CORETYPES_ARRAY_H_ 18 19 #include <securec.h> 20 #include <cstddef> 21 #include <cstdint> 22 23 #include "libpandabase/macros.h" 24 #include "libpandabase/mem/mem.h" 25 #include "libpandabase/mem/space.h" 26 #include "libpandabase/utils/span.h" 27 #include "libpandafile/bytecode_instruction-inl.h" 28 #include "runtime/include/class-inl.h" 29 #include "runtime/include/language_context.h" 30 #include "runtime/include/object_header.h" 31 #include "runtime/mem/heap_manager.h" 32 #include "runtime/include/coretypes/tagged_value.h" 33 34 namespace panda { 35 class ManagedThread; 36 class PandaVM; 37 } // namespace panda 38 39 namespace panda::interpreter { 40 template <BytecodeInstruction::Format format> 41 class DimIterator; 42 } // namespace panda::interpreter 43 44 namespace panda::coretypes { 45 class DynClass; 46 using array_size_t = panda::array_size_t; 47 using array_ssize_t = panda::array_ssize_t; 48 49 class Array : public ObjectHeader { 50 public: 51 static constexpr array_size_t MAX_ARRAY_INDEX = std::numeric_limits<array_size_t>::max(); 52 Cast(ObjectHeader * object)53 static Array *Cast(ObjectHeader *object) 54 { 55 return reinterpret_cast<Array *>(object); 56 } 57 58 static Array *Create(panda::Class *array_class, const uint8_t *data, array_size_t length, 59 panda::SpaceType space_type = panda::SpaceType::SPACE_TYPE_OBJECT); 60 61 static Array *Create(panda::Class *array_class, array_size_t length, 62 panda::SpaceType space_type = panda::SpaceType::SPACE_TYPE_OBJECT); 63 64 static Array *Create(DynClass *dynarrayclass, array_size_t length, 65 panda::SpaceType space_type = panda::SpaceType::SPACE_TYPE_OBJECT); 66 67 static Array *CreateTagged(const PandaVM *vm, panda::BaseClass *array_class, array_size_t length, 68 panda::SpaceType space_type = panda::SpaceType::SPACE_TYPE_OBJECT, 69 TaggedValue init_value = TaggedValue::Undefined()); 70 ComputeSize(size_t elem_size,array_size_t length)71 static size_t ComputeSize(size_t elem_size, array_size_t length) 72 { 73 ASSERT(elem_size != 0); 74 size_t size = sizeof(Array) + elem_size * length; 75 #ifdef PANDA_TARGET_32 76 size_t size_limit = (std::numeric_limits<size_t>::max() - sizeof(Array)) / elem_size; 77 if (UNLIKELY(size_limit < static_cast<size_t>(length))) { 78 return 0; 79 } 80 #endif 81 return size; 82 } 83 GetLength()84 array_size_t GetLength() const 85 { 86 return length_.load(std::memory_order_relaxed); 87 } 88 GetData()89 uint32_t *GetData() 90 { 91 return data_; 92 } 93 GetData()94 const uint32_t *GetData() const 95 { 96 return data_; 97 } 98 99 template <class T, bool is_volatile = false> 100 T GetPrimitive(size_t offset) const; 101 102 template <class T, bool is_volatile = false> 103 void SetPrimitive(size_t offset, T value); 104 105 template <bool is_volatile = false, bool need_read_barrier = true, bool is_dyn = false> 106 ObjectHeader *GetObject(int offset) const; 107 108 template <bool is_volatile = false, bool need_write_barrier = true, bool is_dyn = false> 109 void SetObject(size_t offset, ObjectHeader *value); 110 111 template <class T> 112 T GetPrimitive(size_t offset, std::memory_order memory_order) const; 113 114 template <class T> 115 void SetPrimitive(size_t offset, T value, std::memory_order memory_order); 116 117 template <bool need_read_barrier = true, bool is_dyn = false> 118 ObjectHeader *GetObject(size_t offset, std::memory_order memory_order) const; 119 120 template <bool need_write_barrier = true, bool is_dyn = false> 121 void SetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order); 122 123 template <typename T> 124 bool CompareAndSetPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, bool strong); 125 126 template <bool need_write_barrier = true, bool is_dyn = false> 127 bool CompareAndSetObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value, 128 std::memory_order memory_order, bool strong); 129 130 template <typename T> 131 T CompareAndExchangePrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, bool strong); 132 133 template <bool need_write_barrier = true, bool is_dyn = false> 134 ObjectHeader *CompareAndExchangeObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value, 135 std::memory_order memory_order, bool strong); 136 137 template <typename T> 138 T GetAndSetPrimitive(size_t offset, T value, std::memory_order memory_order); 139 140 template <bool need_write_barrier = true, bool is_dyn = false> 141 ObjectHeader *GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order); 142 143 template <typename T> 144 T GetAndAddPrimitive(size_t offset, T value, std::memory_order memory_order); 145 146 template <typename T> 147 T GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memory_order); 148 149 template <typename T> 150 T GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memory_order); 151 152 template <typename T> 153 T GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memory_order); 154 155 template <class T, bool need_write_barrier = true, bool is_dyn = false> 156 void Set(array_size_t idx, T elem); 157 158 template <class T, bool need_read_barrier = true, bool is_dyn = false> 159 T Get(array_size_t idx) const; 160 161 // Pass thread parameter to speed up interpreter 162 template <class T, bool need_write_barrier = true, bool is_dyn = false> 163 void Set([[maybe_unused]] const ManagedThread *thread, array_size_t idx, T elem); 164 165 template <class T, bool need_read_barrier = true, bool is_dyn = false> 166 T Get([[maybe_unused]] const ManagedThread *thread, array_size_t idx) const; 167 ObjectSize()168 size_t ObjectSize() const 169 { 170 return ComputeSize(ClassAddr<panda::Class>()->GetComponentSize(), length_); 171 } 172 GetLengthOffset()173 static constexpr uint32_t GetLengthOffset() 174 { 175 return MEMBER_OFFSET(Array, length_); 176 } 177 GetDataOffset()178 static constexpr uint32_t GetDataOffset() 179 { 180 return MEMBER_OFFSET(Array, data_); 181 } 182 183 template <class DimIterator> 184 static Array *CreateMultiDimensionalArray(ManagedThread *thread, panda::Class *klass, uint32_t nargs, 185 const DimIterator &iter, size_t dim_idx = 0); 186 187 private: SetLength(array_size_t length)188 void SetLength(array_size_t length) 189 { 190 length_.store(length, std::memory_order_relaxed); 191 } 192 193 std::atomic<array_size_t> length_; 194 // Align with 64bits, because dynamic language data is always 64bits 195 __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0]; // NOLINT(modernize-avoid-c-arrays) 196 }; 197 198 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader)); 199 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(array_size_t), sizeof(uint64_t))); 200 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0); 201 202 #ifdef PANDA_TARGET_64 203 constexpr uint32_t ARRAY_LENGTH_OFFSET = 8U; 204 static_assert(ARRAY_LENGTH_OFFSET == panda::coretypes::Array::GetLengthOffset()); 205 constexpr uint32_t ARRAY_DATA_OFFSET = 16U; 206 static_assert(ARRAY_DATA_OFFSET == panda::coretypes::Array::GetDataOffset()); 207 #endif 208 209 } // namespace panda::coretypes 210 211 #endif // PANDA_RUNTIME_INCLUDE_CORETYPES_ARRAY_H_ 212