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
Set(const JSThread * thread,uint32_t idx,const JSTaggedValue & value)66 inline void TaggedArray::Set(const JSThread *thread, uint32_t idx, const JSTaggedValue &value)
67 {
68 ASSERT(idx < GetLength());
69 size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
70
71 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
72 if (value.IsHeapObject()) {
73 Barriers::SetObject<true>(thread, GetData(), offset, value.GetRawData());
74 } else { // NOLINTNEXTLINE(readability-misleading-indentation)
75 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, value.GetRawData());
76 }
77 }
78
Append(const JSThread * thread,const JSHandle<TaggedArray> & first,const JSHandle<TaggedArray> & second)79 JSHandle<TaggedArray> TaggedArray::Append(const JSThread *thread, const JSHandle<TaggedArray> &first,
80 const JSHandle<TaggedArray> &second)
81 {
82 uint32_t firstLength = first->GetLength();
83 uint32_t secondLength = second->GetLength();
84 uint32_t length = firstLength + secondLength;
85 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
86 JSHandle<TaggedArray> argument = factory->NewTaggedArray(length);
87 uint32_t index = 0;
88 for (; index < firstLength; ++index) {
89 argument->Set(thread, index, first->Get(index));
90 }
91 for (; index < length; ++index) {
92 argument->Set(thread, index, second->Get(index - firstLength));
93 }
94 return argument;
95 }
96
AppendSkipHole(const JSThread * thread,const JSHandle<TaggedArray> & first,const JSHandle<TaggedArray> & second,uint32_t copyLength)97 JSHandle<TaggedArray> TaggedArray::AppendSkipHole(const JSThread *thread, const JSHandle<TaggedArray> &first,
98 const JSHandle<TaggedArray> &second, uint32_t copyLength)
99 {
100 uint32_t firstLength = first->GetLength();
101 uint32_t secondLength = second->GetLength();
102 ASSERT(firstLength + secondLength >= copyLength);
103
104 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
105 JSHandle<TaggedArray> argument = factory->NewTaggedArray(copyLength);
106 uint32_t index = 0;
107 for (; index < firstLength; ++index) {
108 JSTaggedValue val = first->Get(index);
109 if (val.IsHole()) {
110 break;
111 }
112 argument->Set(thread, index, val);
113 ASSERT(copyLength >= index);
114 }
115 for (uint32_t i = 0; i < secondLength; ++i) {
116 JSTaggedValue val = second->Get(i);
117 if (val.IsHole()) {
118 break;
119 }
120 argument->Set(thread, index++, val);
121 ASSERT(copyLength >= index);
122 }
123 return argument;
124 }
125
HasDuplicateEntry()126 inline bool TaggedArray::HasDuplicateEntry() const
127 {
128 uint32_t length = GetLength();
129 for (uint32_t i = 0; i < length; i++) {
130 for (uint32_t j = i + 1; j < length; j++) {
131 if (JSTaggedValue::SameValue(Get(i), Get(j))) {
132 return true;
133 }
134 }
135 }
136 return false;
137 }
138
InitializeWithSpecialValue(JSTaggedValue initValue,uint32_t length,uint32_t extraLength)139 void TaggedArray::InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t length, uint32_t extraLength)
140 {
141 ASSERT(initValue.IsSpecial());
142 SetLength(length);
143 SetExtraLength(extraLength);
144 for (uint32_t i = 0; i < length; i++) {
145 size_t offset = JSTaggedValue::TaggedTypeSize() * i;
146 Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, initValue.GetRawData());
147 }
148 }
149
SetCapacity(const JSThread * thread,const JSHandle<TaggedArray> & array,uint32_t capa)150 inline JSHandle<TaggedArray> TaggedArray::SetCapacity(const JSThread *thread, const JSHandle<TaggedArray> &array,
151 uint32_t capa)
152 {
153 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
154 uint32_t oldLength = array->GetLength();
155 JSHandle<TaggedArray> newArray = factory->CopyArray(array, oldLength, capa);
156 return newArray;
157 }
158
SetCapacityInOldSpace(const JSThread * thread,const JSHandle<TaggedArray> & array,uint32_t capa)159 inline JSHandle<TaggedArray> TaggedArray::SetCapacityInOldSpace(const JSThread *thread,
160 const JSHandle<TaggedArray> &array, uint32_t capa)
161 {
162 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
163 uint32_t oldLength = array->GetLength();
164 JSHandle<TaggedArray> newArray =
165 factory->CopyArray(array, oldLength, capa, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
166 return newArray;
167 }
168
IsDictionaryMode()169 inline bool TaggedArray::IsDictionaryMode() const
170 {
171 return GetClass()->IsDictionary();
172 }
173
Trim(JSThread * thread,uint32_t newLength)174 void TaggedArray::Trim(JSThread *thread, uint32_t newLength)
175 {
176 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
177 uint32_t oldLength = GetLength();
178 ASSERT(oldLength > newLength);
179 size_t trimBytes = (oldLength - newLength) * JSTaggedValue::TaggedTypeSize();
180 size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength);
181 factory->FillFreeObject(ToUintPtr(this) + size, trimBytes, RemoveSlots::YES, ToUintPtr(this));
182 SetLength(newLength);
183 }
184 } // namespace panda::ecmascript
185 #endif // ECMASCRIPT_TAGGED_ARRAY_INL_H
186