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 #include "ecmascript/weak_vector.h"
17
18 #include "ecmascript/object_factory.h"
19 #include "ecmascript/mem/space.h"
20
21 namespace panda::ecmascript {
Create(const JSThread * thread,uint32_t capacity,MemSpaceType type)22 JSHandle<WeakVector> WeakVector::Create(const JSThread *thread, uint32_t capacity, MemSpaceType type)
23 {
24 ASSERT(capacity < MAX_VECTOR_INDEX);
25
26 uint32_t length = VectorToArrayIndex(capacity);
27 JSHandle<WeakVector> vector;
28 if (type == MemSpaceType::NON_MOVABLE) {
29 vector = JSHandle<WeakVector>(thread->GetEcmaVM()->GetFactory()
30 ->NewTaggedArray(length, JSTaggedValue::Hole(), MemSpaceType::NON_MOVABLE));
31 } else {
32 vector = JSHandle<WeakVector>(thread->GetEcmaVM()->GetFactory()->NewTaggedArray(length));
33 }
34
35 vector->SetEnd(thread, 0);
36 return vector;
37 }
38
Delete(const JSThread * thread,uint32_t index)39 bool WeakVector::Delete(const JSThread *thread, uint32_t index)
40 {
41 uint32_t end = GetEnd();
42 if (index < end) {
43 Set(thread, index, JSTaggedValue::Hole());
44 return true;
45 }
46 return false;
47 }
48
Grow(const JSThread * thread,const JSHandle<WeakVector> & old,uint32_t newCapacity)49 JSHandle<WeakVector> WeakVector::Grow(const JSThread *thread, const JSHandle<WeakVector> &old, uint32_t newCapacity)
50 {
51 uint32_t oldCapacity = old->GetCapacity();
52 ASSERT(newCapacity > oldCapacity);
53 if (oldCapacity == MAX_VECTOR_INDEX) {
54 return old;
55 }
56
57 if (newCapacity > MAX_VECTOR_INDEX) {
58 newCapacity = MAX_VECTOR_INDEX;
59 }
60
61 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
62 JSHandle<TaggedArray> newVec = factory->CopyArray(JSHandle<TaggedArray>(old), VectorToArrayIndex(oldCapacity),
63 VectorToArrayIndex(newCapacity));
64
65 return JSHandle<WeakVector>(newVec);
66 }
67
Append(const JSThread * thread,const JSHandle<WeakVector> & vec,const JSHandle<JSTaggedValue> & value,ElementType type)68 JSHandle<WeakVector> WeakVector::Append(const JSThread *thread, const JSHandle<WeakVector> &vec,
69 const JSHandle<JSTaggedValue> &value, ElementType type)
70 {
71 if (!vec->Full()) {
72 JSTaggedValue storeVal = GetStoreVal(value, type);
73 vec->PushBack(thread, storeVal);
74 return vec;
75 }
76
77 return AppendToFullVec(thread, vec, value, type);
78 }
79
FillOrAppend(const JSThread * thread,const JSHandle<WeakVector> & vec,const JSHandle<JSTaggedValue> & value,ElementType type)80 JSHandle<WeakVector> WeakVector::FillOrAppend(const JSThread *thread, const JSHandle<WeakVector> &vec,
81 const JSHandle<JSTaggedValue> &value, ElementType type)
82 {
83 if (!vec->Full()) {
84 JSTaggedValue storeVal = GetStoreVal(value, type);
85 vec->PushBack(thread, storeVal);
86 return vec;
87 }
88
89 // if exist hole, use it.
90 uint32_t holeIndex = CheckHole(vec);
91 if (holeIndex != TaggedArray::MAX_ARRAY_INDEX) {
92 JSTaggedValue storeVal = GetStoreVal(value, type);
93 vec->Set(thread, holeIndex, storeVal);
94 return vec;
95 }
96
97 return AppendToFullVec(thread, vec, value, type);
98 }
99
AppendToFullVec(const JSThread * thread,const JSHandle<WeakVector> & vec,const JSHandle<JSTaggedValue> & value,ElementType type)100 JSHandle<WeakVector> WeakVector::AppendToFullVec(const JSThread *thread, const JSHandle<WeakVector> &vec,
101 const JSHandle<JSTaggedValue> &value, ElementType type)
102 {
103 uint32_t newCapacity = vec->GetCapacity() + DEFAULT_GROW_SIZE;
104 JSHandle<WeakVector> newVec = WeakVector::Grow(thread, JSHandle<WeakVector>(vec), newCapacity);
105 JSTaggedValue storeVal = GetStoreVal(value, type);
106 [[maybe_unused]] uint32_t index = newVec->PushBack(thread, storeVal);
107 ASSERT(index != TaggedArray::MAX_ARRAY_INDEX);
108 return newVec;
109 }
110
GetStoreVal(const JSHandle<JSTaggedValue> & value,ElementType type)111 JSTaggedValue WeakVector::GetStoreVal(const JSHandle<JSTaggedValue> &value, ElementType type)
112 {
113 if (type == ElementType::NORMAL) {
114 return value.GetTaggedValue();
115 }
116
117 if (value->IsHeapObject()) {
118 return value->CreateAndGetWeakRef();
119 }
120 return value.GetTaggedValue();
121 }
122
Copy(const JSThread * thread,const JSHandle<WeakVector> & vec,bool needExtend)123 JSHandle<WeakVector> WeakVector::Copy(const JSThread *thread, const JSHandle<WeakVector> &vec,
124 bool needExtend)
125 {
126 uint32_t capacity = vec->GetCapacity();
127 uint32_t oldLength = VectorToArrayIndex(capacity);
128 if (needExtend) {
129 capacity += DEFAULT_GROW_SIZE;
130 }
131 uint32_t newLength = VectorToArrayIndex(capacity);
132 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
133 JSHandle<TaggedArray> newVec = factory->CopyArray(JSHandle<TaggedArray>(vec), oldLength, newLength);
134 return JSHandle<WeakVector>(newVec);
135 }
136
CheckHole(const JSHandle<WeakVector> & vec)137 uint32_t WeakVector::CheckHole(const JSHandle<WeakVector> &vec)
138 {
139 for (uint32_t i = 0; i < vec->GetEnd(); i++) {
140 JSTaggedValue value = vec->Get(i);
141 if (value.IsHole()) {
142 return i;
143 }
144 }
145 return TaggedArray::MAX_ARRAY_INDEX;
146 }
147
PushBack(const JSThread * thread,JSTaggedValue value)148 uint32_t WeakVector::PushBack(const JSThread *thread, JSTaggedValue value)
149 {
150 uint32_t end = GetEnd();
151 if (end == GetCapacity()) {
152 return TaggedArray::MAX_ARRAY_INDEX;
153 }
154
155 Set(thread, end, value);
156 SetEnd(thread, end + 1);
157 return end;
158 }
159 } // namespace panda::ecmascript
160