• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     static constexpr uint32_t EXTEND_PADDING_LENGTH = 16U;
34 
35     CAST_CHECK(TaggedArray, IsTaggedArray);
36 
37     template <RBMode mode = RBMode::DEFAULT_RB>
Get(const JSThread * thread,uint32_t idx)38     JSTaggedValue Get(const JSThread *thread, uint32_t idx) const
39     {
40         ASSERT(idx < GetLength());
41         // Note: Here we can't statically decide the element type is a primitive or heap object, especially for
42         //       dynamically-typed languages like JavaScript. So we simply skip the read-barrier.
43         size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
44         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
45         return JSTaggedValue(Barriers::GetTaggedValue<mode>(thread, reinterpret_cast<JSTaggedType *>(ToUintPtr(this)),
46                                                             DATA_OFFSET + offset));
47     }
48 
GetPrimitive(uint32_t idx)49     JSTaggedValue GetPrimitive(uint32_t idx) const
50     {
51         ASSERT(idx < GetLength());
52         size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
53         // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
54         return JSTaggedValue(Barriers::GetPrimitive<JSTaggedType>(reinterpret_cast<JSTaggedType *>(ToUintPtr(this)),
55                                                                   DATA_OFFSET + offset));
56     }
57 
58     uint32_t GetIdx(const JSThread *thread, const JSTaggedValue &value) const;
59     JSTaggedValue GetBit(const JSThread *thread, uint32_t idx, uint32_t bitOffset) const;
60 
61     template<bool needBarrier = true, typename T = JSTaggedValue>
62     inline void Set(const JSThread *thread, uint32_t idx, const T &value);
63 
64     void SetBit(const JSThread* thread, uint32_t idx, uint32_t bitOffset, const JSTaggedValue &value);
65 
66     template <bool needBarrier = true, bool maybeOverlap = false>
67     inline void Copy(const JSThread* thread, uint32_t dstStart, uint32_t srcStart,
68                                   const TaggedArray *srcArray, uint32_t count);
69 
70     static JSHandle<TaggedArray> Append(const JSThread *thread, const JSHandle<TaggedArray> &first,
71                                                const JSHandle<TaggedArray> &second);
72     static JSHandle<TaggedArray> AppendSkipHole(const JSThread *thread, const JSHandle<TaggedArray> &first,
73                                                        const JSHandle<TaggedArray> &second, uint32_t copyLength);
74 
ExtendCapacityWithPadding(uint32_t oldCapacity)75     static inline uint32_t ExtendCapacityWithPadding(uint32_t oldCapacity)
76     {
77         return oldCapacity + (oldCapacity >> 1U) + EXTEND_PADDING_LENGTH;
78     }
79 
ComputeSize(size_t elemSize,uint32_t length)80     static size_t ComputeSize(size_t elemSize, uint32_t length)
81     {
82         ASSERT(elemSize != 0);
83         size_t size = DATA_OFFSET + elemSize * length;
84         return size;
85     }
86 
GetData()87     JSTaggedType *GetData() const
88     {
89         return reinterpret_cast<JSTaggedType *>(ToUintPtr(this) + DATA_OFFSET);
90     }
91 
GetThis()92     JSTaggedType *GetThis() const
93     {
94         return reinterpret_cast<JSTaggedType *>(ToUintPtr(this));
95     }
96 
97     bool IsDictionaryMode() const;
98 
99     bool HasDuplicateEntry(const JSThread *thread) const;
100 
101     bool IsYoungAndNotMarking(const JSThread *thread);
102 
103     static JSHandle<TaggedArray> SetCapacity(const JSThread *thread, const JSHandle<TaggedArray> &array,
104                                              uint32_t capa);
105 
106     static JSHandle<TaggedArray> SetCapacityInOldSpace(const JSThread *thread, const JSHandle<TaggedArray> &array,
107                                                        uint32_t capa);
108 
109     static void RemoveElementByIndex(const JSThread *thread, JSHandle<TaggedArray> &srcArray,
110                                             uint32_t index, uint32_t effectiveLength, bool noNeedBarrier = false);
111     static void InsertElementByIndex(const JSThread *thread, JSHandle<TaggedArray> &srcArray,
112         const JSHandle<JSTaggedValue> &value, uint32_t index, uint32_t effectiveLength);
113     static void CopyTaggedArrayElement(const JSThread *thread, JSHandle<TaggedArray> &srcElements,
114                                               JSHandle<TaggedArray> &dstElements, uint32_t effectiveLength);
115 
116     void InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t length, uint32_t extraLength = 0);
117     void FillRangeWithSpecialValue(JSTaggedValue initValue, uint32_t start, uint32_t end);
118 
ShouldTrim(uint32_t oldLength,uint32_t newLength)119     static bool ShouldTrim(uint32_t oldLength, uint32_t newLength)
120     {
121         ASSERT(oldLength >= newLength);
122         return (oldLength - newLength > MAX_END_UNUSED);
123     }
124     void Trim(const JSThread *thread, uint32_t newLength);
125 
126     static constexpr size_t LENGTH_OFFSET = TaggedObjectSize();
127     ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, EXTRA_LENGTH_OFFSET)
128     ACCESSORS_PRIMITIVE_FIELD(ExtraLength, uint32_t, EXTRA_LENGTH_OFFSET, LAST_OFFSET)
129     DEFINE_ALIGN_SIZE(LAST_OFFSET);
130     static constexpr size_t DATA_OFFSET = SIZE;  // DATA_OFFSET equal to Empty Array size
131 
132     DECL_VISIT_ARRAY(DATA_OFFSET, GetLength(), GetLength());
133     DECL_DUMP()
134 
135 private:
136     friend class ObjectFactory;
137 };
138 
139 static_assert(TaggedArray::LENGTH_OFFSET == sizeof(TaggedObject));
140 static_assert((TaggedArray::DATA_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0);
141 
142 // Copy On Write TaggedArray is shared in the nonmovable space.
143 class COWTaggedArray : public TaggedArray {
144 public:
145     CAST_CHECK(COWTaggedArray, IsCOWArray)
146     DECL_DUMP()
147 private:
148     friend class ObjectFactory;
149 };
150 
151 // A Mutant of TaggedArray which has numbers directly stored in Data section.
152 // Used by JSArrays with specified elementsKind.
153 class MutantTaggedArray : public TaggedArray {
154 public:
155     void InitializeWithSpecialValue(JSTaggedType initValue, uint32_t length, uint32_t extraLength = 0);
156 
157     DECL_VISIT_ARRAY(DATA_OFFSET, 0, GetLength());
158     CAST_CHECK(MutantTaggedArray, IsMutantTaggedArray)
159     DECL_DUMP()
160 private:
161     friend class ObjectFactory;
162 };
163 
164 // Copy On Write MutantTaggedArray is shared in the nonmovable space.
165 // With raw numbers stored in Data section.
166 class COWMutantTaggedArray : public MutantTaggedArray {
167 public:
168 
169     DECL_VISIT_ARRAY(DATA_OFFSET, 0, GetLength());
170     CAST_CHECK(COWMutantTaggedArray, IsCOWArray)
171     DECL_DUMP()
172 private:
173     friend class ObjectFactory;
174 };
175 
176 }  // namespace panda::ecmascript
177 #endif  // ECMASCRIPT_TAGGED_ARRAY_H
178