1 /*
2 * Copyright (c) 2021 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_INL_H
17 #define ECMASCRIPT_TAGGED_ARRAY_INL_H
18
19 #include "ecmascript/mem/barriers-inl.h"
20 #include "ecmascript/js_tagged_value-inl.h"
21 #include "ecmascript/js_thread.h"
22 #include "ecmascript/mem/region-inl.h"
23 #include "ecmascript/object_factory.h"
24 #include "ecmascript/tagged_array.h"
25
26 namespace panda::ecmascript {
Get(uint32_t idx)27 inline JSTaggedValue TaggedArray::Get(uint32_t idx) const
28 {
29 ASSERT(idx < GetLength());
30 // Note: Here we can't statically decide the element type is a primitive or heap object, especially for
31 // dynamically-typed languages like JavaScript. So we simply skip the read-barrier.
32 size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
33 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
34 return JSTaggedValue(Barriers::GetValue<JSTaggedType>(GetData(), offset));
35 }
36
Get(const JSThread * thread,uint32_t idx)37 inline JSTaggedValue TaggedArray::Get([[maybe_unused]] const JSThread *thread, uint32_t idx) const
38 {
39 return Get(idx);
40 }
41
GetIdx(const JSTaggedValue & value)42 inline uint32_t TaggedArray::GetIdx(const JSTaggedValue &value) const
43 {
44 uint32_t length = GetLength();
45
46 for (uint32_t i = 0; i < length; i++) {
47 if (JSTaggedValue::SameValue(Get(i), value)) {
48 return i;
49 }
50 }
51 return TaggedArray::MAX_ARRAY_INDEX;
52 }
53
54 template<typename T>
Set(const JSThread * thread,uint32_t idx,const JSHandle<T> & value)55 inline void TaggedArray::Set(const JSThread *thread, uint32_t idx, const JSHandle<T> &value)
56 {
57 ASSERT(idx < GetLength());
58 size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
59
60 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
61 if (value.GetTaggedValue().IsHeapObject()) {
62 Barriers::SetObject<true>(thread, GetData(), offset, value.GetTaggedValue().GetRawData());
63 } else { // NOLINTNEXTLINE(readability-misleading-indentation)
64 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, value.GetTaggedValue().GetRawData());
65 }
66 }
67
68 template <bool needBarrier>
Set(const JSThread * thread,uint32_t idx,const JSTaggedValue & value)69 inline void TaggedArray::Set(const JSThread *thread, uint32_t idx, const JSTaggedValue &value)
70 {
71 ASSERT(idx < GetLength());
72 size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
73
74 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
75 if (needBarrier && value.IsHeapObject()) {
76 Barriers::SetObject<true>(thread, GetData(), offset, value.GetRawData());
77 } else { // NOLINTNEXTLINE(readability-misleading-indentation)
78 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, value.GetRawData());
79 }
80 }
81
Append(const JSThread * thread,const JSHandle<TaggedArray> & first,const JSHandle<TaggedArray> & second)82 JSHandle<TaggedArray> TaggedArray::Append(const JSThread *thread, const JSHandle<TaggedArray> &first,
83 const JSHandle<TaggedArray> &second)
84 {
85 uint32_t firstLength = first->GetLength();
86 uint32_t secondLength = second->GetLength();
87 uint32_t length = firstLength + secondLength;
88 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
89 JSHandle<TaggedArray> argument = factory->NewTaggedArray(length);
90 uint32_t index = 0;
91 for (; index < firstLength; ++index) {
92 argument->Set(thread, index, first->Get(index));
93 }
94 for (; index < length; ++index) {
95 argument->Set(thread, index, second->Get(index - firstLength));
96 }
97 return argument;
98 }
99
AppendSkipHole(const JSThread * thread,const JSHandle<TaggedArray> & first,const JSHandle<TaggedArray> & second,uint32_t copyLength)100 JSHandle<TaggedArray> TaggedArray::AppendSkipHole(const JSThread *thread, const JSHandle<TaggedArray> &first,
101 const JSHandle<TaggedArray> &second, uint32_t copyLength)
102 {
103 uint32_t firstLength = first->GetLength();
104 uint32_t secondLength = second->GetLength();
105 ASSERT(firstLength + secondLength >= copyLength);
106
107 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
108 JSHandle<TaggedArray> argument = factory->NewTaggedArray(copyLength);
109 uint32_t index = 0;
110 for (; index < firstLength; ++index) {
111 JSTaggedValue val = first->Get(index);
112 if (val.IsHole()) {
113 break;
114 }
115 argument->Set(thread, index, val);
116 ASSERT(copyLength >= index);
117 }
118 for (uint32_t i = 0; i < secondLength; ++i) {
119 JSTaggedValue val = second->Get(i);
120 if (val.IsHole()) {
121 break;
122 }
123 argument->Set(thread, index++, val);
124 ASSERT(copyLength >= index);
125 }
126 return argument;
127 }
128
HasDuplicateEntry()129 inline bool TaggedArray::HasDuplicateEntry() const
130 {
131 uint32_t length = GetLength();
132 for (uint32_t i = 0; i < length; i++) {
133 for (uint32_t j = i + 1; j < length; j++) {
134 if (JSTaggedValue::SameValue(Get(i), Get(j))) {
135 return true;
136 }
137 }
138 }
139 return false;
140 }
141
InitializeWithSpecialValue(JSTaggedValue initValue,uint32_t length,uint32_t extraLength)142 void TaggedArray::InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t length, uint32_t extraLength)
143 {
144 ASSERT(initValue.IsSpecial());
145 SetLength(length);
146 SetExtraLength(extraLength);
147 for (uint32_t i = 0; i < length; i++) {
148 size_t offset = JSTaggedValue::TaggedTypeSize() * i;
149 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, initValue.GetRawData());
150 }
151 }
152
SetCapacity(const JSThread * thread,const JSHandle<TaggedArray> & array,uint32_t capa)153 inline JSHandle<TaggedArray> TaggedArray::SetCapacity(const JSThread *thread, const JSHandle<TaggedArray> &array,
154 uint32_t capa)
155 {
156 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
157 uint32_t oldLength = array->GetLength();
158 JSHandle<TaggedArray> newArray = factory->CopyArray(array, oldLength, capa);
159 return newArray;
160 }
161
SetCapacityInOldSpace(const JSThread * thread,const JSHandle<TaggedArray> & array,uint32_t capa)162 inline JSHandle<TaggedArray> TaggedArray::SetCapacityInOldSpace(const JSThread *thread,
163 const JSHandle<TaggedArray> &array, uint32_t capa)
164 {
165 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
166 uint32_t oldLength = array->GetLength();
167 JSHandle<TaggedArray> newArray =
168 factory->CopyArray(array, oldLength, capa, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
169 return newArray;
170 }
171
RemoveElementByIndex(const JSThread * thread,JSHandle<TaggedArray> & srcArray,uint32_t index,uint32_t effectiveLength)172 void TaggedArray::RemoveElementByIndex(const JSThread *thread, JSHandle<TaggedArray> &srcArray,
173 uint32_t index, uint32_t effectiveLength)
174 {
175 ASSERT(0 <= index || index < effectiveLength);
176 Region *region = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(*srcArray));
177 if (region->InYoungSpace() && !thread->IsConcurrentMarkingOrFinished()) {
178 size_t taggedTypeSize = JSTaggedValue::TaggedTypeSize();
179 size_t offset = taggedTypeSize * index;
180 auto *addr = reinterpret_cast<JSTaggedType *>(ToUintPtr(srcArray->GetData()) + offset);
181 while (index < effectiveLength - 1) {
182 *addr = *(addr + 1);
183 addr++;
184 index++;
185 }
186 } else {
187 while (index < effectiveLength - 1) {
188 srcArray->Set(thread, index, srcArray->Get(index + 1));
189 index++;
190 }
191 }
192 srcArray->Set(thread, effectiveLength - 1, JSTaggedValue::Hole());
193 }
194
InsertElementByIndex(const JSThread * thread,JSHandle<TaggedArray> & srcArray,const JSHandle<JSTaggedValue> & value,uint32_t index,uint32_t effectiveLength)195 void TaggedArray::InsertElementByIndex(const JSThread *thread, JSHandle<TaggedArray> &srcArray,
196 const JSHandle<JSTaggedValue> &value, uint32_t index, uint32_t effectiveLength)
197 {
198 ASSERT(0 <= index || index <= effectiveLength);
199 ASSERT(effectiveLength < srcArray->GetLength());
200 Region *region = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(*srcArray));
201 if (region->InYoungSpace() && !thread->IsConcurrentMarkingOrFinished()) {
202 size_t taggedTypeSize = JSTaggedValue::TaggedTypeSize();
203 size_t offset = taggedTypeSize * effectiveLength;
204 auto *addr = reinterpret_cast<JSTaggedType *>(ToUintPtr(srcArray->GetData()) + offset);
205 while (effectiveLength != index && effectiveLength > 0) {
206 *addr = *(addr - 1);
207 addr--;
208 effectiveLength--;
209 }
210 } else {
211 while (effectiveLength != index && effectiveLength > 0) {
212 JSTaggedValue oldValue = srcArray->Get(effectiveLength - 1);
213 srcArray->Set(thread, effectiveLength, oldValue);
214 effectiveLength--;
215 }
216 }
217 srcArray->Set(thread, index, value.GetTaggedValue());
218 }
219
CopyTaggedArrayElement(const JSThread * thread,JSHandle<TaggedArray> & srcElements,JSHandle<TaggedArray> & dstElements,uint32_t effectiveLength)220 void TaggedArray::CopyTaggedArrayElement(const JSThread *thread, JSHandle<TaggedArray> &srcElements,
221 JSHandle<TaggedArray> &dstElements, uint32_t effectiveLength)
222 {
223 ASSERT(effectiveLength <= srcElements->GetLength());
224 ASSERT(effectiveLength <= dstElements->GetLength());
225 Region *region = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(*dstElements));
226 if (region->InYoungSpace() && !thread->IsConcurrentMarkingOrFinished()) {
227 size_t size = effectiveLength * sizeof(JSTaggedType);
228 if (memcpy_s(reinterpret_cast<void *>(dstElements->GetData()), size,
229 reinterpret_cast<void *>(srcElements->GetData()), size) != EOK) {
230 LOG_FULL(FATAL) << "memcpy_s failed" << " size: " << size;
231 }
232 } else {
233 for (uint32_t i = 0; i < effectiveLength; i++) {
234 dstElements->Set(thread, i, srcElements->Get(i));
235 }
236 }
237 }
238
IsDictionaryMode()239 inline bool TaggedArray::IsDictionaryMode() const
240 {
241 return GetClass()->IsDictionary();
242 }
243
Trim(const JSThread * thread,uint32_t newLength)244 void TaggedArray::Trim(const JSThread *thread, uint32_t newLength)
245 {
246 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
247 uint32_t oldLength = GetLength();
248 ASSERT(oldLength > newLength);
249 size_t trimBytes = (oldLength - newLength) * JSTaggedValue::TaggedTypeSize();
250 size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength);
251 factory->FillFreeObject(ToUintPtr(this) + size, trimBytes, RemoveSlots::YES, ToUintPtr(this));
252 SetLength(newLength);
253 }
254
InitializeWithSpecialValue(JSTaggedType initValue,uint32_t length,uint32_t extraLength)255 void MutantTaggedArray::InitializeWithSpecialValue(JSTaggedType initValue, uint32_t length, uint32_t extraLength)
256 {
257 SetLength(length);
258 SetExtraLength(extraLength);
259 for (uint32_t i = 0; i < length; i++) {
260 size_t offset = JSTaggedValue::TaggedTypeSize() * i;
261 // NOLINTNEXTLINE(readability-misleading-indentation)
262 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, initValue);
263 }
264 }
265 } // namespace panda::ecmascript
266 #endif // ECMASCRIPT_TAGGED_ARRAY_INL_H
267