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/tagged_array.h"
22
23 namespace panda::ecmascript {
Get(uint32_t idx)24 inline JSTaggedValue TaggedArray::Get(uint32_t idx) const
25 {
26 ASSERT(idx < GetLength());
27 // Note: Here we can't statically decide the element type is a primitive or heap object, especially for
28 // dynamically-typed languages like JavaScript. So we simply skip the read-barrier.
29 size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
30 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
31 return JSTaggedValue(Barriers::GetDynValue<JSTaggedType>(GetData(), offset));
32 }
33
Get(const JSThread * thread,uint32_t idx)34 inline JSTaggedValue TaggedArray::Get([[maybe_unused]] const JSThread *thread, uint32_t idx) const
35 {
36 return Get(idx);
37 }
38
GetIdx(const JSTaggedValue & value)39 inline uint32_t TaggedArray::GetIdx(const JSTaggedValue &value) const
40 {
41 uint32_t length = GetLength();
42
43 for (uint32_t i = 0; i < length; i++) {
44 if (JSTaggedValue::SameValue(Get(i), value)) {
45 return i;
46 }
47 }
48 return TaggedArray::MAX_ARRAY_INDEX;
49 }
50
51 template<typename T>
Set(const JSThread * thread,uint32_t idx,const JSHandle<T> & value)52 inline void TaggedArray::Set(const JSThread *thread, uint32_t idx, const JSHandle<T> &value)
53 {
54 ASSERT(idx < GetLength());
55 size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
56
57 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
58 if (value.GetTaggedValue().IsHeapObject()) {
59 Barriers::SetDynObject<true>(thread, GetData(), offset, value.GetTaggedValue().GetRawData());
60 } else { // NOLINTNEXTLINE(readability-misleading-indentation)
61 Barriers::SetDynPrimitive<JSTaggedType>(GetData(), offset, value.GetTaggedValue().GetRawData());
62 }
63 }
64
Set(const JSThread * thread,uint32_t idx,const JSTaggedValue & value)65 inline void TaggedArray::Set(const JSThread *thread, uint32_t idx, const JSTaggedValue &value)
66 {
67 ASSERT(idx < GetLength());
68 size_t offset = JSTaggedValue::TaggedTypeSize() * idx;
69
70 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
71 if (value.IsHeapObject()) {
72 Barriers::SetDynObject<true>(thread, GetData(), offset, value.GetRawData());
73 } else { // NOLINTNEXTLINE(readability-misleading-indentation)
74 Barriers::SetDynPrimitive<JSTaggedType>(GetData(), offset, value.GetRawData());
75 }
76 }
77
Append(const JSThread * thread,const JSHandle<TaggedArray> & first,const JSHandle<TaggedArray> & second)78 JSHandle<TaggedArray> TaggedArray::Append(const JSThread *thread, const JSHandle<TaggedArray> &first,
79 const JSHandle<TaggedArray> &second)
80 {
81 uint32_t firstLength = first->GetLength();
82 uint32_t secondLength = second->GetLength();
83 uint32_t length = firstLength + secondLength;
84 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
85 JSHandle<TaggedArray> argument = factory->NewTaggedArray(length);
86 uint32_t index = 0;
87 for (; index < firstLength; ++index) {
88 argument->Set(thread, index, first->Get(index));
89 }
90 for (; index < length; ++index) {
91 argument->Set(thread, index, second->Get(index - firstLength));
92 }
93 return argument;
94 }
95
AppendSkipHole(const JSThread * thread,const JSHandle<TaggedArray> & first,const JSHandle<TaggedArray> & second,uint32_t copyLength)96 JSHandle<TaggedArray> TaggedArray::AppendSkipHole(const JSThread *thread, const JSHandle<TaggedArray> &first,
97 const JSHandle<TaggedArray> &second, uint32_t copyLength)
98 {
99 uint32_t firstLength = first->GetLength();
100 uint32_t secondLength = second->GetLength();
101 ASSERT(firstLength + secondLength >= copyLength);
102
103 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
104 JSHandle<TaggedArray> argument = factory->NewTaggedArray(copyLength);
105 uint32_t index = 0;
106 for (; index < firstLength; ++index) {
107 JSTaggedValue val = first->Get(index);
108 if (val.IsHole()) {
109 break;
110 }
111 argument->Set(thread, index, val);
112 ASSERT(copyLength >= index);
113 }
114 for (uint32_t i = 0; i < secondLength; ++i) {
115 JSTaggedValue val = second->Get(i);
116 if (val.IsHole()) {
117 break;
118 }
119 argument->Set(thread, index++, val);
120 ASSERT(copyLength >= index);
121 }
122 return argument;
123 }
124
HasDuplicateEntry()125 inline bool TaggedArray::HasDuplicateEntry() const
126 {
127 uint32_t length = GetLength();
128 for (uint32_t i = 0; i < length; i++) {
129 for (uint32_t j = i + 1; j < length; j++) {
130 if (JSTaggedValue::SameValue(Get(i), Get(j))) {
131 return true;
132 }
133 }
134 }
135 return false;
136 }
137
InitializeWithSpecialValue(JSTaggedValue initValue,uint32_t length)138 void TaggedArray::InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t length)
139 {
140 ASSERT(initValue.IsSpecial());
141 SetLength(length);
142 for (uint32_t i = 0; i < length; i++) {
143 size_t offset = JSTaggedValue::TaggedTypeSize() * i;
144 Barriers::SetDynPrimitive<JSTaggedType>(GetData(), offset, initValue.GetRawData());
145 }
146 }
147
SetCapacity(const JSThread * thread,const JSHandle<TaggedArray> & array,uint32_t capa)148 inline JSHandle<TaggedArray> TaggedArray::SetCapacity(const JSThread *thread, const JSHandle<TaggedArray> &array,
149 uint32_t capa)
150 {
151 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
152 uint32_t oldLength = array->GetLength();
153 JSHandle<TaggedArray> newArray = factory->CopyArray(array, oldLength, capa);
154 return newArray;
155 }
156
IsDictionaryMode()157 inline bool TaggedArray::IsDictionaryMode() const
158 {
159 return GetClass()->IsDictionary();
160 }
161
Trim(JSThread * thread,uint32_t newLength)162 void TaggedArray::Trim(JSThread *thread, uint32_t newLength)
163 {
164 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
165 uint32_t oldLength = GetLength();
166 ASSERT(oldLength > newLength);
167 size_t trimBytes = (oldLength - newLength) * JSTaggedValue::TaggedTypeSize();
168 size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength);
169 factory->FillFreeObject(ToUintPtr(this) + size, trimBytes, RemoveSlots::YES);
170 SetLength(newLength);
171 }
172 } // namespace panda::ecmascript
173 #endif // ECMASCRIPT_TAGGED_ARRAY_INL_H
174