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