• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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