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