1 /*
2  * Copyright (c) 2024 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/sustaining_js_handle.h"
17 
18 #include "ecmascript/ecma_context.h"
19 
20 namespace panda::ecmascript {
SustainingJSHandle(EcmaVM *vm)21 SustainingJSHandle::SustainingJSHandle(EcmaVM *vm) : vm_(vm)
22 {
23     context_ = vm_->GetJSThread()->GetCurrentEcmaContext();
24     context_->AddSustainingJSHandle(this);
25 }
26 
~SustainingJSHandle()27 SustainingJSHandle::~SustainingJSHandle()
28 {
29     context_->RemoveSustainingJSHandle(this);
30     for (auto block : handleBlocks_) {
31         delete block;
32     }
33     handleBlocks_.clear();
34 }
35 
GetJsHandleSlot(JSTaggedType value)36 uintptr_t SustainingJSHandle::GetJsHandleSlot(JSTaggedType value)
37 {
38     if (blockNext_ == blockLimit_) {
39         Expand();
40     }
41     ASSERT(blockNext_ != blockLimit_);
42 
43     *blockNext_ = value;
44     uintptr_t slot = reinterpret_cast<uintptr_t>(blockNext_);
45     blockNext_++;
46     return slot;
47 }
48 
Expand()49 uintptr_t SustainingJSHandle::Expand()
50 {
51     auto block = new std::array<JSTaggedType, BLOCK_SIZE>();
52     handleBlocks_.push_back(block);
53 
54     blockNext_ = &block->data()[0];
55     blockLimit_ = &block->data()[BLOCK_SIZE];
56     return reinterpret_cast<uintptr_t>(blockNext_);
57 }
58 
Iterate(const RootRangeVisitor &rv)59 void SustainingJSHandle::Iterate(const RootRangeVisitor &rv)
60 {
61     size_t size = handleBlocks_.size();
62     for (size_t i = 0; i < size; ++i) {
63         auto block = handleBlocks_.at(i);
64         auto start = block->data();
65         auto end = (i != (size - 1)) ? &(block->data()[BLOCK_SIZE]) : blockNext_;
66         rv(ecmascript::Root::ROOT_HANDLE, ObjectSlot(ToUintPtr(start)), ObjectSlot(ToUintPtr(end)));
67     }
68 }
69 
AddSustainingJSHandle(SustainingJSHandle *sustainingJSHandle)70 void SustainingJSHandleList::AddSustainingJSHandle(SustainingJSHandle *sustainingJSHandle)
71 {
72     LockHolder lock(mutex_);
73     if (sustainingJSHandle == nullptr) {
74         return;
75     }
76 
77     if (listHead_ == nullptr) {
78         listHead_ = sustainingJSHandle;
79         return;
80     }
81     sustainingJSHandle->next_ = listHead_;
82     listHead_->pre_ = sustainingJSHandle;
83     listHead_ = sustainingJSHandle;
84 }
85 
RemoveSustainingJSHandle(SustainingJSHandle *sustainingJSHandle)86 void SustainingJSHandleList::RemoveSustainingJSHandle(SustainingJSHandle *sustainingJSHandle)
87 {
88     LockHolder lock(mutex_);
89     if (sustainingJSHandle == nullptr) {
90         return;
91     }
92 
93     auto next = sustainingJSHandle->next_;
94     auto pre = sustainingJSHandle->pre_;
95     if (pre != nullptr) {
96         pre->next_ = next;
97     }
98     if (next != nullptr) {
99         next->pre_ = pre;
100     }
101 
102     if (listHead_ == sustainingJSHandle) {
103         listHead_ = sustainingJSHandle->next_;
104     }
105 }
106 
Iterate(const RootRangeVisitor &rv)107 void SustainingJSHandleList::Iterate(const RootRangeVisitor &rv)
108 {
109     LockHolder lock(mutex_);
110     for (auto handles = listHead_; handles != nullptr; handles = handles->next_) {
111         handles->Iterate(rv);
112     }
113 }
114 }  // namespace panda::ecmascript
115