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 array_size_t = panda::array_size_t; 46 using array_ssize_t = panda::array_ssize_t; 47 48 class Array : public ObjectHeader { 49 public: 50 static constexpr array_size_t MAX_ARRAY_INDEX = std::numeric_limits<array_size_t>::max(); 51 Cast(ObjectHeader * object)52 static Array *Cast(ObjectHeader *object) 53 { 54 // TODO(linxiang) to do assert 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 // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints 87 // imposed on other reads or writes 88 return length_.load(std::memory_order_relaxed); 89 } 90 GetData()91 uint32_t *GetData() 92 { 93 return data_; 94 } 95 GetData()96 const uint32_t *GetData() const 97 { 98 return data_; 99 } 100 101 template <class T, bool is_volatile = false> 102 T GetPrimitive(size_t offset) const; 103 104 template <class T, bool is_volatile = false> 105 void SetPrimitive(size_t offset, T value); 106 107 template <bool is_volatile = false, bool need_read_barrier = true, bool is_dyn = false> 108 ObjectHeader *GetObject(int offset) const; 109 110 template <bool is_volatile = false, bool need_write_barrier = true, bool is_dyn = false> 111 void SetObject(size_t offset, ObjectHeader *value); 112 113 template <class T> 114 T GetPrimitive(size_t offset, std::memory_order memory_order) const; 115 116 template <class T> 117 void SetPrimitive(size_t offset, T value, std::memory_order memory_order); 118 119 template <bool need_read_barrier = true, bool is_dyn = false> 120 ObjectHeader *GetObject(size_t offset, std::memory_order memory_order) const; 121 122 template <bool need_write_barrier = true, bool is_dyn = false> 123 void SetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order); 124 125 template <typename T> 126 bool CompareAndSetPrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, bool strong); 127 128 template <bool need_write_barrier = true, bool is_dyn = false> 129 bool CompareAndSetObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value, 130 std::memory_order memory_order, bool strong); 131 132 template <typename T> 133 T CompareAndExchangePrimitive(size_t offset, T old_value, T new_value, std::memory_order memory_order, bool strong); 134 135 template <bool need_write_barrier = true, bool is_dyn = false> 136 ObjectHeader *CompareAndExchangeObject(size_t offset, ObjectHeader *old_value, ObjectHeader *new_value, 137 std::memory_order memory_order, bool strong); 138 139 template <typename T> 140 T GetAndSetPrimitive(size_t offset, T value, std::memory_order memory_order); 141 142 template <bool need_write_barrier = true, bool is_dyn = false> 143 ObjectHeader *GetAndSetObject(size_t offset, ObjectHeader *value, std::memory_order memory_order); 144 145 template <typename T> 146 T GetAndAddPrimitive(size_t offset, T value, std::memory_order memory_order); 147 148 template <typename T> 149 T GetAndBitwiseOrPrimitive(size_t offset, T value, std::memory_order memory_order); 150 151 template <typename T> 152 T GetAndBitwiseAndPrimitive(size_t offset, T value, std::memory_order memory_order); 153 154 template <typename T> 155 T GetAndBitwiseXorPrimitive(size_t offset, T value, std::memory_order memory_order); 156 157 template <class T, bool need_write_barrier = true, bool is_dyn = false> 158 void Set(array_size_t idx, T elem); 159 160 template <class T, bool need_read_barrier = true, bool is_dyn = false> 161 T Get(array_size_t idx) const; 162 163 // Pass thread parameter to speed up interpreter 164 template <class T, bool need_write_barrier = true, bool is_dyn = false> 165 void Set([[maybe_unused]] const ManagedThread *thread, array_size_t idx, T elem); 166 167 template <class T, bool need_read_barrier = true, bool is_dyn = false> 168 T Get([[maybe_unused]] const ManagedThread *thread, array_size_t idx) const; 169 ObjectSize(uint32_t component_size)170 size_t ObjectSize(uint32_t component_size) const 171 { 172 return ComputeSize(component_size, length_); 173 } 174 GetLengthOffset()175 static constexpr uint32_t GetLengthOffset() 176 { 177 return MEMBER_OFFSET(Array, length_); 178 } 179 GetDataOffset()180 static constexpr uint32_t GetDataOffset() 181 { 182 return MEMBER_OFFSET(Array, data_); 183 } 184 185 template <bool is_dyn> GetElementOffset(array_size_t idx)186 uint32_t GetElementOffset(array_size_t idx) const 187 { 188 size_t elem_size; 189 // NOLINTNEXTLINE(readability-braces-around-statements) 190 if constexpr (is_dyn) { 191 elem_size = TaggedValue::TaggedTypeSize(); 192 } else { // NOLINT(readability-misleading-indentation) 193 elem_size = ClassAddr<panda::Class>()->GetComponentSize(); 194 } 195 return GetDataOffset() + idx * elem_size; 196 } 197 198 template <class DimIterator> 199 static Array *CreateMultiDimensionalArray(ManagedThread *thread, panda::Class *klass, uint32_t nargs, 200 const DimIterator &iter, size_t dim_idx = 0); 201 202 private: SetLength(array_size_t length)203 void SetLength(array_size_t length) 204 { 205 // Atomic with relaxed order reason: data race with length_ with no synchronization or ordering constraints 206 // imposed on other reads or writes 207 length_.store(length, std::memory_order_relaxed); 208 } 209 210 std::atomic<array_size_t> length_; 211 // Align by 64bits, because dynamic language data is always 64bits 212 __extension__ alignas(sizeof(uint64_t)) uint32_t data_[0]; // NOLINT(modernize-avoid-c-arrays) 213 }; 214 215 static_assert(Array::GetLengthOffset() == sizeof(ObjectHeader)); 216 static_assert(Array::GetDataOffset() == AlignUp(Array::GetLengthOffset() + sizeof(array_size_t), sizeof(uint64_t))); 217 static_assert(Array::GetDataOffset() % sizeof(uint64_t) == 0); 218 219 #ifdef PANDA_TARGET_64 220 constexpr uint32_t ARRAY_LENGTH_OFFSET = 8U; 221 static_assert(ARRAY_LENGTH_OFFSET == panda::coretypes::Array::GetLengthOffset()); 222 constexpr uint32_t ARRAY_DATA_OFFSET = 16U; 223 static_assert(ARRAY_DATA_OFFSET == panda::coretypes::Array::GetDataOffset()); 224 #endif 225 } // namespace panda::coretypes 226 227 #endif // PANDA_RUNTIME_CORETYPES_ARRAY_H_ 228