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_MEM_MARK_STACK_H
17#define ECMASCRIPT_MEM_MARK_STACK_H
18
19#include "ecmascript/js_tagged_value.h"
20#include "ecmascript/mem/area.h"
21#include "ecmascript/mem/ecma_list.h"
22#include "ecmascript/mem/native_area_allocator.h"
23#include "ecmascript/mem/space.h"
24
25namespace panda {
26namespace ecmascript {
27class Stack {
28public:
29    Stack() = default;
30    virtual ~Stack() = default;
31    NO_COPY_SEMANTIC(Stack);
32    NO_MOVE_SEMANTIC(Stack);
33    uintptr_t GetBegin() const
34    {
35        return begin_;
36    }
37
38    uintptr_t PopBackChecked()
39    {
40        if (UNLIKELY(top_ <= reinterpret_cast<uintptr_t *>(begin_))) {
41            return 0;
42        }
43        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
44        return *--top_;
45    }
46
47    void PushBackUnchecked(uintptr_t obj)
48    {
49        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
50        *top_++ = obj;
51    }
52
53    uintptr_t PopBackUnchecked()
54    {
55        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
56        return *--top_;
57    }
58
59    bool PushBackChecked(uintptr_t obj)
60    {
61        if (UNLIKELY(top_ >= end_)) {
62            return false;
63        }
64        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
65        *top_++ = obj;
66        return true;
67    }
68
69    bool IsEmpty() const
70    {
71        return top_ == reinterpret_cast<uintptr_t *>(begin_);
72    }
73
74    void ResetBegin(uintptr_t begin, uintptr_t end)
75    {
76        begin_ = begin;
77        top_ = reinterpret_cast<uintptr_t *>(begin);
78        end_ = reinterpret_cast<uintptr_t *>(end);
79    }
80
81    void ResetTop(uintptr_t begin, uintptr_t end)
82    {
83        begin_ = begin;
84        top_ = end_ = reinterpret_cast<uintptr_t *>(end);
85    }
86
87private:
88    template<class T>
89    friend class ContinuousStack;
90    friend class WorkNode;
91    uintptr_t begin_ {0};
92    uintptr_t *end_ {nullptr};
93    uintptr_t *top_ {nullptr};
94};
95
96template<class T>
97class ContinuousStack : public Stack {
98public:
99    ContinuousStack() = default;
100    ~ContinuousStack() override = default;
101    NO_COPY_SEMANTIC(ContinuousStack);
102    NO_MOVE_SEMANTIC(ContinuousStack);
103
104    inline void BeginMarking(ContinuousStack<T> *other)
105    {
106        currentArea_ = other->currentArea_;
107        if (currentArea_ == nullptr) {
108            currentArea_ = NativeAreaAllocator::AllocateSpace(DEFAULT_MARK_STACK_SIZE);
109        }
110        ResetBegin(currentArea_->GetBegin(), currentArea_->GetEnd());
111    }
112    inline void FinishMarking(ContinuousStack<T> *other)
113    {
114        other->currentArea_ = currentArea_;
115
116        while (!unusedList_.IsEmpty()) {
117            Area *node = unusedList_.PopBack();
118            NativeAreaAllocator::FreeSpace(node);
119        }
120    }
121
122    T *PopBack()
123    {
124        if (UNLIKELY(top_ <= reinterpret_cast<uintptr_t *>(begin_))) {
125            if (!areaList_.IsEmpty()) {
126                unusedList_.AddNode(currentArea_);
127                Area *last = areaList_.PopBack();
128                currentArea_ = last;
129                ResetTop(currentArea_->GetBegin(), currentArea_->GetEnd());
130            } else {
131                return nullptr;
132            }
133        }
134        return reinterpret_cast<T *>(PopBackUnchecked());
135    }
136
137    void PushBack(T *obj)
138    {
139        if (UNLIKELY(top_ >= end_)) {
140            Extend();
141        }
142        PushBackUnchecked(ToUintPtr(obj));
143    }
144
145    inline void Destroy()
146    {
147        if (currentArea_ != nullptr) {
148            NativeAreaAllocator::FreeSpace(currentArea_);
149            currentArea_ = nullptr;
150        }
151    }
152
153private:
154    inline void Extend()
155    {
156        auto area = NativeAreaAllocator::AllocateSpace(DEFAULT_MARK_STACK_SIZE);
157        areaList_.AddNode(currentArea_);
158        currentArea_ = area;
159        ResetBegin(currentArea_->GetBegin(), currentArea_->GetEnd());
160    }
161
162    Area *currentArea_ {nullptr};
163    EcmaList<Area> areaList_ {};
164    EcmaList<Area> unusedList_ {};
165};
166
167using MarkStack = ContinuousStack<TaggedObject>;
168using ProcessQueue = ContinuousStack<JSTaggedType>;
169}  // namespace ecmascript
170}  // namespace panda
171
172#endif  // ECMASCRIPT_MEM_MARK_STACK_H
173