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 16 #ifndef ECMASCRIPT_TAGGED_ARRAY_H 17 #define ECMASCRIPT_TAGGED_ARRAY_H 18 19 #include "ecmascript/ecma_macros.h" 20 #include "ecmascript/js_tagged_value.h" 21 #include "ecmascript/mem/barriers.h" 22 #include "ecmascript/mem/visitor.h" 23 24 namespace panda::ecmascript { 25 class ObjectFactory; 26 class JSThread; 27 28 class TaggedArray : public TaggedObject { 29 public: 30 static constexpr uint32_t MAX_ARRAY_INDEX = std::numeric_limits<uint32_t>::max(); 31 static constexpr uint32_t MAX_END_UNUSED = 4; 32 33 CAST_CHECK(TaggedArray, IsTaggedArray); 34 35 JSTaggedValue Get(uint32_t idx) const; 36 37 JSTaggedValue Get([[maybe_unused]] const JSThread *thread, uint32_t idx) const; 38 39 uint32_t GetIdx(const JSTaggedValue &value) const; 40 JSTaggedValue GetBit(uint32_t idx, uint32_t bitOffset) const; 41 42 template<typename T> 43 inline void Set(const JSThread *thread, uint32_t idx, const JSHandle<T> &value); 44 45 template <bool needBarrier = true> 46 inline void Set(const JSThread *thread, uint32_t idx, const JSTaggedValue &value); 47 48 void Set(uint32_t idx, const JSTaggedValue &value); 49 void SetBit(const JSThread* thread, uint32_t idx, uint32_t bitOffset, const JSTaggedValue& value); 50 51 static JSHandle<TaggedArray> Append(const JSThread *thread, const JSHandle<TaggedArray> &first, 52 const JSHandle<TaggedArray> &second); 53 static JSHandle<TaggedArray> AppendSkipHole(const JSThread *thread, const JSHandle<TaggedArray> &first, 54 const JSHandle<TaggedArray> &second, uint32_t copyLength); 55 ComputeSize(size_t elemSize,uint32_t length)56 static size_t ComputeSize(size_t elemSize, uint32_t length) 57 { 58 ASSERT(elemSize != 0); 59 size_t size = DATA_OFFSET + elemSize * length; 60 return size; 61 } 62 GetData()63 JSTaggedType *GetData() const 64 { 65 return reinterpret_cast<JSTaggedType *>(ToUintPtr(this) + DATA_OFFSET); 66 } 67 68 bool IsDictionaryMode() const; 69 70 bool HasDuplicateEntry() const; 71 72 bool IsGeneralNewAndNotMarking(const JSThread *thread); 73 74 static JSHandle<TaggedArray> SetCapacity(const JSThread *thread, const JSHandle<TaggedArray> &array, 75 uint32_t capa); 76 77 static JSHandle<TaggedArray> SetCapacityInOldSpace(const JSThread *thread, const JSHandle<TaggedArray> &array, 78 uint32_t capa); 79 80 static void RemoveElementByIndex(const JSThread *thread, JSHandle<TaggedArray> &srcArray, 81 uint32_t index, uint32_t effectiveLength, bool noNeedBarrier = false); 82 static void InsertElementByIndex(const JSThread *thread, JSHandle<TaggedArray> &srcArray, 83 const JSHandle<JSTaggedValue> &value, uint32_t index, uint32_t effectiveLength); 84 static void CopyTaggedArrayElement(const JSThread *thread, JSHandle<TaggedArray> &srcElements, 85 JSHandle<TaggedArray> &dstElements, uint32_t effectiveLength); 86 87 void InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t length, uint32_t extraLength = 0); 88 void FillRangeWithSpecialValue(JSTaggedValue initValue, uint32_t start, uint32_t end); 89 ShouldTrim(uint32_t oldLength,uint32_t newLength)90 static bool ShouldTrim(uint32_t oldLength, uint32_t newLength) 91 { 92 ASSERT(oldLength >= newLength); 93 return (oldLength - newLength > MAX_END_UNUSED); 94 } 95 void Trim(const JSThread *thread, uint32_t newLength); 96 97 static constexpr size_t LENGTH_OFFSET = TaggedObjectSize(); 98 ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, EXTRA_LENGTH_OFFSET) 99 ACCESSORS_PRIMITIVE_FIELD(ExtraLength, uint32_t, EXTRA_LENGTH_OFFSET, LAST_OFFSET) 100 DEFINE_ALIGN_SIZE(LAST_OFFSET); 101 static constexpr size_t DATA_OFFSET = SIZE; // DATA_OFFSET equal to Empty Array size 102 103 DECL_VISIT_ARRAY(DATA_OFFSET, GetLength(), GetLength()); 104 DECL_DUMP() 105 106 private: 107 friend class ObjectFactory; 108 }; 109 110 static_assert(TaggedArray::LENGTH_OFFSET == sizeof(TaggedObject)); 111 static_assert((TaggedArray::DATA_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0); 112 113 // Copy On Write TaggedArray is shared in the nonmovable space. 114 class COWTaggedArray : public TaggedArray { 115 public: 116 CAST_CHECK(COWTaggedArray, IsCOWArray) 117 DECL_DUMP() 118 private: 119 friend class ObjectFactory; 120 }; 121 122 // A Mutant of TaggedArray which has numbers directly stored in Data section. 123 // Used by JSArrays with specified elementsKind. 124 class MutantTaggedArray : public TaggedArray { 125 public: 126 void InitializeWithSpecialValue(JSTaggedType initValue, uint32_t length, uint32_t extraLength = 0); 127 128 DECL_VISIT_ARRAY(DATA_OFFSET, 0, GetLength()); 129 CAST_CHECK(MutantTaggedArray, IsMutantTaggedArray) 130 DECL_DUMP() 131 private: 132 friend class ObjectFactory; 133 }; 134 135 // Copy On Write MutantTaggedArray is shared in the nonmovable space. 136 // With raw numbers stored in Data section. 137 class COWMutantTaggedArray : public MutantTaggedArray { 138 public: 139 140 DECL_VISIT_ARRAY(DATA_OFFSET, 0, GetLength()); 141 CAST_CHECK(COWMutantTaggedArray, IsCOWArray) 142 DECL_DUMP() 143 private: 144 friend class ObjectFactory; 145 }; 146 147 } // namespace panda::ecmascript 148 #endif // ECMASCRIPT_TAGGED_ARRAY_H 149