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 #define ECMASCRIPT_TAGGED_ARRAY_CPP
17
18 #include "ecmascript/tagged_array.h"
19 #include "ecmascript/tagged_array-inl.h"
20
21 #include "ecmascript/object_factory.h"
22
23 namespace panda::ecmascript {
24
Get(const JSThread * thread,uint32_t idx) const25 JSTaggedValue TaggedArray::Get([[maybe_unused]] const JSThread *thread, uint32_t idx) const
26 {
27 return Get(idx);
28 }
29
GetIdx(const JSTaggedValue & value) const30 uint32_t TaggedArray::GetIdx(const JSTaggedValue &value) const
31 {
32 uint32_t length = GetLength();
33
34 for (uint32_t i = 0; i < length; i++) {
35 if (JSTaggedValue::SameValue(Get(i), value)) {
36 return i;
37 }
38 }
39 return TaggedArray::MAX_ARRAY_INDEX;
40 }
41
GetBit(uint32_t idx,uint32_t bitOffset) const42 JSTaggedValue TaggedArray::GetBit(uint32_t idx, uint32_t bitOffset) const
43 {
44 ASSERT(idx < GetLength());
45 JSTaggedType element = Get(idx).GetRawData();
46 return JSTaggedValue(int((element >> bitOffset) & 1ULL));
47 }
48
49
SetBit(const JSThread * thread,uint32_t idx,uint32_t bitOffset,const JSTaggedValue & value)50 void TaggedArray::SetBit(const JSThread *thread, uint32_t idx, uint32_t bitOffset, const JSTaggedValue &value)
51 {
52 ASSERT(idx < GetLength());
53 JSTaggedType element = Get(idx).GetRawData();
54 if (value.IsZero()) {
55 element &= ~(1ULL << bitOffset);
56 } else {
57 element |= (1ULL << bitOffset);
58 }
59 Set<false>(thread, idx, JSTaggedValue(element));
60 }
61
Append(const JSThread * thread,const JSHandle<TaggedArray> & first,const JSHandle<TaggedArray> & second)62 JSHandle<TaggedArray> TaggedArray::Append(const JSThread *thread, const JSHandle<TaggedArray> &first,
63 const JSHandle<TaggedArray> &second)
64 {
65 uint32_t firstLength = first->GetLength();
66 uint32_t secondLength = second->GetLength();
67 uint32_t length = firstLength + secondLength;
68 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
69 JSHandle<TaggedArray> argument = factory->NewTaggedArray(length);
70 uint32_t index = 0;
71 for (; index < firstLength; ++index) {
72 argument->Set(thread, index, first->Get(index));
73 }
74 for (; index < length; ++index) {
75 argument->Set(thread, index, second->Get(index - firstLength));
76 }
77 return argument;
78 }
79
AppendSkipHole(const JSThread * thread,const JSHandle<TaggedArray> & first,const JSHandle<TaggedArray> & second,uint32_t copyLength)80 JSHandle<TaggedArray> TaggedArray::AppendSkipHole(const JSThread *thread, const JSHandle<TaggedArray> &first,
81 const JSHandle<TaggedArray> &second, uint32_t copyLength)
82 {
83 uint32_t firstLength = first->GetLength();
84 uint32_t secondLength = second->GetLength();
85 ASSERT(firstLength + secondLength >= copyLength);
86
87 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
88 JSHandle<TaggedArray> argument = factory->NewTaggedArray(copyLength);
89 uint32_t index = 0;
90 for (; index < firstLength; ++index) {
91 JSTaggedValue val = first->Get(index);
92 if (val.IsHole()) {
93 break;
94 }
95 argument->Set(thread, index, val);
96 ASSERT(copyLength >= index);
97 }
98 for (uint32_t i = 0; i < secondLength; ++i) {
99 JSTaggedValue val = second->Get(i);
100 if (val.IsHole()) {
101 break;
102 }
103 argument->Set(thread, index++, val);
104 ASSERT(copyLength >= index);
105 }
106 return argument;
107 }
108
HasDuplicateEntry() const109 bool TaggedArray::HasDuplicateEntry() const
110 {
111 uint32_t length = GetLength();
112 for (uint32_t i = 0; i < length; i++) {
113 for (uint32_t j = i + 1; j < length; j++) {
114 if (JSTaggedValue::SameValue(Get(i), Get(j))) {
115 return true;
116 }
117 }
118 }
119 return false;
120 }
121
InitializeWithSpecialValue(JSTaggedValue initValue,uint32_t length,uint32_t extraLength)122 void TaggedArray::InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t length, uint32_t extraLength)
123 {
124 SetLength(length);
125 SetExtraLength(extraLength);
126 FillRangeWithSpecialValue(initValue, 0, length);
127 }
128
FillRangeWithSpecialValue(JSTaggedValue initValue,uint32_t start,uint32_t end)129 void TaggedArray::FillRangeWithSpecialValue(JSTaggedValue initValue, uint32_t start, uint32_t end)
130 {
131 ASSERT(initValue.IsSpecial());
132 for (uint32_t i = start; i < end; i++) {
133 size_t offset = JSTaggedValue::TaggedTypeSize() * i;
134 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, initValue.GetRawData());
135 }
136 }
137
SetCapacity(const JSThread * thread,const JSHandle<TaggedArray> & array,uint32_t capa)138 JSHandle<TaggedArray> TaggedArray::SetCapacity(const JSThread *thread, const JSHandle<TaggedArray> &array,
139 uint32_t capa)
140 {
141 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
142 uint32_t oldLength = array->GetLength();
143 JSHandle<TaggedArray> newArray = factory->CopyArray(array, oldLength, capa);
144 return newArray;
145 }
146
SetCapacityInOldSpace(const JSThread * thread,const JSHandle<TaggedArray> & array,uint32_t capa)147 JSHandle<TaggedArray> TaggedArray::SetCapacityInOldSpace(const JSThread *thread,
148 const JSHandle<TaggedArray> &array, uint32_t capa)
149 {
150 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
151 uint32_t oldLength = array->GetLength();
152 JSHandle<TaggedArray> newArray =
153 factory->CopyArray(array, oldLength, capa, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
154 return newArray;
155 }
156
RemoveElementByIndex(const JSThread * thread,JSHandle<TaggedArray> & srcArray,uint32_t index,uint32_t effectiveLength,bool noNeedBarrier)157 void TaggedArray::RemoveElementByIndex(const JSThread *thread, JSHandle<TaggedArray> &srcArray,
158 uint32_t index, uint32_t effectiveLength, bool noNeedBarrier)
159 {
160 ASSERT(0 <= index || index < effectiveLength);
161 ASSERT(effectiveLength > 0);
162 if (noNeedBarrier) {
163 size_t taggedTypeSize = JSTaggedValue::TaggedTypeSize();
164 size_t offset = taggedTypeSize * index;
165 auto *addr = reinterpret_cast<JSTaggedType *>(ToUintPtr(srcArray->GetData()) + offset);
166 while (index < effectiveLength - 1) {
167 *addr = *(addr + 1);
168 addr++;
169 index++;
170 }
171 } else {
172 while (index < effectiveLength - 1) {
173 srcArray->Set(thread, index, srcArray->Get(index + 1));
174 index++;
175 }
176 }
177 srcArray->Set(thread, effectiveLength - 1, JSTaggedValue::Hole());
178 }
179
InsertElementByIndex(const JSThread * thread,JSHandle<TaggedArray> & srcArray,const JSHandle<JSTaggedValue> & value,uint32_t index,uint32_t effectiveLength)180 void TaggedArray::InsertElementByIndex(const JSThread *thread, JSHandle<TaggedArray> &srcArray,
181 const JSHandle<JSTaggedValue> &value, uint32_t index, uint32_t effectiveLength)
182 {
183 ASSERT(0 <= index || index <= effectiveLength);
184 ASSERT(effectiveLength < srcArray->GetLength());
185 while (effectiveLength != index && effectiveLength > 0) {
186 JSTaggedValue oldValue = srcArray->Get(effectiveLength - 1);
187 srcArray->Set(thread, effectiveLength, oldValue);
188 effectiveLength--;
189 }
190 srcArray->Set(thread, index, value.GetTaggedValue());
191 }
192
CopyTaggedArrayElement(const JSThread * thread,JSHandle<TaggedArray> & srcElements,JSHandle<TaggedArray> & dstElements,uint32_t effectiveLength)193 void TaggedArray::CopyTaggedArrayElement(const JSThread *thread, JSHandle<TaggedArray> &srcElements,
194 JSHandle<TaggedArray> &dstElements, uint32_t effectiveLength)
195 {
196 ASSERT(effectiveLength <= srcElements->GetLength());
197 ASSERT(effectiveLength <= dstElements->GetLength());
198 dstElements->Copy(thread, 0, 0, srcElements.GetObject<TaggedArray>(), effectiveLength);
199 }
200
IsDictionaryMode() const201 bool TaggedArray::IsDictionaryMode() const
202 {
203 return GetClass()->IsDictionary();
204 }
205
IsYoungAndNotMarking(const JSThread * thread)206 bool TaggedArray::IsYoungAndNotMarking(const JSThread *thread)
207 {
208 Region *region = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(this));
209 return region->InYoungSpace() && !thread->IsConcurrentMarkingOrFinished();
210 }
211
Trim(const JSThread * thread,uint32_t newLength)212 void TaggedArray::Trim(const JSThread *thread, uint32_t newLength)
213 {
214 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
215 uint32_t oldLength = GetLength();
216 ASSERT(oldLength > newLength);
217 size_t trimBytes = (oldLength - newLength) * JSTaggedValue::TaggedTypeSize();
218 size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength);
219 factory->FillFreeObject(ToUintPtr(this) + size, trimBytes, RemoveSlots::YES, ToUintPtr(this));
220 SetLength(newLength);
221 }
222
InitializeWithSpecialValue(JSTaggedType initValue,uint32_t length,uint32_t extraLength)223 void MutantTaggedArray::InitializeWithSpecialValue(JSTaggedType initValue, uint32_t length, uint32_t extraLength)
224 {
225 SetLength(length);
226 SetExtraLength(extraLength);
227 for (uint32_t i = 0; i < length; i++) {
228 size_t offset = JSTaggedValue::TaggedTypeSize() * i;
229 // NOLINTNEXTLINE(readability-misleading-indentation)
230 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, initValue);
231 }
232 }
233 } // namespace panda::ecmascript
234