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