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