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 #ifndef ECMASCRIPT_ECMA_GLOABL_STORAGE_INL_H
16 #define ECMASCRIPT_ECMA_GLOABL_STORAGE_INL_H
17
18 #include "ecmascript/ecma_global_storage.h"
19
20 namespace panda::ecmascript {
NodeToNodeList(EcmaGlobalStorage::Node * node)21 inline EcmaGlobalStorage::NodeList *EcmaGlobalStorage::NodeList::NodeToNodeList(
22 EcmaGlobalStorage::Node *node)
23 {
24 uintptr_t ptr = ToUintPtr(node) - node->GetIndex() * sizeof(EcmaGlobalStorage::Node);
25 return reinterpret_cast<NodeList *>(ptr);
26 }
27
NewNode(JSTaggedType value)28 EcmaGlobalStorage::Node *EcmaGlobalStorage::NodeList::NewNode(JSTaggedType value)
29 {
30 if (IsFull()) {
31 return nullptr;
32 }
33 Node *node = &nodeList_[index_++];
34 node->SetPrev(nullptr);
35 node->SetNext(usedList_);
36 node->SetObject(value);
37 node->SetFree(false);
38
39 if (usedList_ != nullptr) {
40 usedList_->SetPrev(node);
41 }
42 usedList_ = node;
43 return node;
44 }
45
FreeNode(EcmaGlobalStorage::Node * node)46 void EcmaGlobalStorage::NodeList::FreeNode(EcmaGlobalStorage::Node *node)
47 {
48 if (node->GetPrev() != nullptr) {
49 node->GetPrev()->SetNext(node->GetNext());
50 }
51 if (node->GetNext() != nullptr) {
52 node->GetNext()->SetPrev(node->GetPrev());
53 }
54 if (node == usedList_) {
55 usedList_ = node->GetNext();
56 }
57 node->SetPrev(nullptr);
58 node->SetNext(freeList_);
59 node->SetObject(JSTaggedValue::Undefined().GetRawData());
60 node->SetFree(true);
61
62 if (freeList_ != nullptr) {
63 freeList_->SetPrev(node);
64 }
65 freeList_ = node;
66 }
67
GetFreeNode(JSTaggedType value)68 EcmaGlobalStorage::Node *EcmaGlobalStorage::NodeList::GetFreeNode(JSTaggedType value)
69 {
70 Node *node = freeList_;
71 if (node != nullptr) {
72 freeList_ = node->GetNext();
73
74 node->SetPrev(nullptr);
75 node->SetNext(usedList_);
76 node->SetObject(value);
77 node->SetFree(false);
78
79 if (usedList_ != nullptr) {
80 usedList_->SetPrev(node);
81 }
82 usedList_ = node;
83 }
84 return node;
85 }
86
LinkTo(NodeList * prev)87 void EcmaGlobalStorage::NodeList::LinkTo(NodeList *prev)
88 {
89 next_ = nullptr;
90 prev_ = prev;
91 prev_->next_ = this;
92 }
93
RemoveList()94 void EcmaGlobalStorage::NodeList::RemoveList()
95 {
96 if (next_ != nullptr) {
97 next_->SetPrev(prev_);
98 }
99 if (prev_ != nullptr) {
100 prev_->SetNext(next_);
101 }
102 if (freeNext_ != nullptr) {
103 freeNext_->SetFreePrev(freePrev_);
104 }
105 if (freePrev_ != nullptr) {
106 freePrev_->SetFreeNext(freeNext_);
107 }
108 }
109
NewGlobalHandleImplement(NodeList ** storage,NodeList ** freeList,bool isWeak,JSTaggedType value)110 uintptr_t EcmaGlobalStorage::NewGlobalHandleImplement(NodeList **storage, NodeList **freeList,
111 bool isWeak, JSTaggedType value)
112 {
113 if ((*storage)->IsFull() && *freeList == nullptr) {
114 // alloc new block
115 auto block = allocator_->New<NodeList>(isWeak);
116 block->LinkTo(*storage);
117 *storage = block;
118 }
119
120 // use node in block first
121 Node *node = (*storage)->NewNode(value);
122 if (node != nullptr) {
123 return node->GetObjectAddress();
124 }
125
126 // use free_list node
127 node = (*freeList)->GetFreeNode(value);
128 ASSERT(node != nullptr);
129 if (!(*freeList)->HasFreeNode()) {
130 auto next = (*freeList)->GetFreeNext();
131 (*freeList)->SetFreeNext(nullptr);
132 (*freeList)->SetFreePrev(nullptr);
133 if (next != nullptr) {
134 next->SetFreePrev(nullptr);
135 }
136 *freeList = next;
137 }
138 return node->GetObjectAddress();
139 }
140
NewGlobalHandle(JSTaggedType value)141 inline uintptr_t EcmaGlobalStorage::NewGlobalHandle(JSTaggedType value)
142 {
143 return NewGlobalHandleImplement(&lastGlobalNodes_, &freeListNodes_, false, value);
144 }
145
DisposeGlobalHandle(uintptr_t nodeAddr)146 inline void EcmaGlobalStorage::DisposeGlobalHandle(uintptr_t nodeAddr)
147 {
148 Node *node = reinterpret_cast<Node *>(nodeAddr);
149 if (node->IsFree()) {
150 return;
151 }
152 NodeList *list = NodeList::NodeToNodeList(node);
153 list->FreeNode(node);
154
155 // If NodeList has no usage node, then delete NodeList
156 NodeList **freeList = nullptr;
157 NodeList **top = nullptr;
158 NodeList **last = nullptr;
159 if (list->IsWeak()) {
160 freeList = &weakFreeListNodes_;
161 top = &topWeakGlobalNodes_;
162 last = &lastWeakGlobalNodes_;
163 } else {
164 freeList = &freeListNodes_;
165 top = &topGlobalNodes_;
166 last = &lastGlobalNodes_;
167 }
168 if (!list->HasUsagedNode() && (*top != *last)) {
169 list->RemoveList();
170 if (*freeList == list) {
171 *freeList = list->GetFreeNext();
172 }
173 if (*top == list) {
174 *top = list->GetNext();
175 }
176 if (*last == list) {
177 *last = list->GetPrev();
178 }
179 allocator_->Delete(list);
180 } else {
181 // Add to freeList
182 if (list != *freeList && list->GetFreeNext() == nullptr && list->GetFreePrev() == nullptr) {
183 list->SetFreeNext(*freeList);
184 if (*freeList != nullptr) {
185 (*freeList)->SetFreePrev(list);
186 }
187 *freeList = list;
188 }
189 }
190 }
191
SetWeak(uintptr_t nodeAddr)192 inline uintptr_t EcmaGlobalStorage::SetWeak(uintptr_t nodeAddr)
193 {
194 auto value = reinterpret_cast<Node *>(nodeAddr)->GetObject();
195 DisposeGlobalHandle(nodeAddr);
196 return NewGlobalHandleImplement(&lastWeakGlobalNodes_, &weakFreeListNodes_, true, value);
197 }
198
ClearWeak(uintptr_t nodeAddr)199 inline uintptr_t EcmaGlobalStorage::ClearWeak(uintptr_t nodeAddr)
200 {
201 auto value = reinterpret_cast<Node *>(nodeAddr)->GetObject();
202 DisposeGlobalHandle(nodeAddr);
203 return NewGlobalHandleImplement(&lastGlobalNodes_, &freeListNodes_, false, value);
204 }
205
IsWeak(uintptr_t addr)206 inline bool EcmaGlobalStorage::IsWeak(uintptr_t addr) const
207 {
208 Node *node = reinterpret_cast<Node *>(addr);
209 NodeList *list = NodeList::NodeToNodeList(node);
210 return list->IsWeak();
211 }
212 } // namespace panda::ecmascript
213 #endif // ECMASCRIPT_ECMA_GLOABL_STORAGE_INL_H
214