1 /**
2 * Copyright (c) 2021-2022 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 "runtime/mem/gc/gc_adaptive_stack.h"
17 #include "runtime/mem/gc/gc.h"
18 #include "runtime/mem/gc/gc_workers_thread_pool.h"
19
20 namespace panda::mem {
21
GCAdaptiveStack(GC * gc,size_t stack_size_limit,size_t new_task_stack_size_limit,GCWorkersTaskTypes task,PandaStack<const ObjectHeader * > * stack_src)22 GCAdaptiveStack::GCAdaptiveStack(GC *gc, size_t stack_size_limit, size_t new_task_stack_size_limit,
23 GCWorkersTaskTypes task, PandaStack<const ObjectHeader *> *stack_src)
24 : stack_size_limit_(stack_size_limit),
25 new_task_stack_size_limit_(new_task_stack_size_limit),
26 task_type_(task),
27 gc_(gc)
28 {
29 initial_stack_size_limit_ = stack_size_limit_;
30 auto allocator = gc_->GetInternalAllocator();
31 ASSERT((stack_size_limit == 0) || (gc->GetWorkersPool() != nullptr));
32 if (stack_src != nullptr) {
33 stack_src_ = stack_src;
34 } else {
35 stack_src_ = allocator->template New<PandaStack<const ObjectHeader *>>(allocator->Adapter());
36 }
37 stack_dst_ = allocator->template New<PandaStack<const ObjectHeader *>>(allocator->Adapter());
38 }
39
~GCAdaptiveStack()40 GCAdaptiveStack::~GCAdaptiveStack()
41 {
42 gc_->GetInternalAllocator()->Delete(stack_src_);
43 gc_->GetInternalAllocator()->Delete(stack_dst_);
44 }
45
Empty()46 bool GCAdaptiveStack::Empty()
47 {
48 return stack_src_->empty() && stack_dst_->empty();
49 }
50
Size()51 size_t GCAdaptiveStack::Size()
52 {
53 return stack_src_->size() + stack_dst_->size();
54 }
55
MoveStacksPointers()56 PandaStack<const ObjectHeader *> *GCAdaptiveStack::MoveStacksPointers()
57 {
58 ASSERT(stack_src_ != nullptr);
59 PandaStack<const ObjectHeader *> *return_value = stack_src_;
60 stack_src_ = nullptr;
61 return return_value;
62 }
63
PushToStack(const ObjectHeader * from_object,const ObjectHeader * object)64 void GCAdaptiveStack::PushToStack(const ObjectHeader *from_object, const ObjectHeader *object)
65 {
66 LOG(DEBUG, GC) << "Add object to stack: " << GetDebugInfoAboutObject(object)
67 << " accessed from object: " << from_object;
68 ValidateObject(from_object, object);
69 PushToStack(object);
70 }
71
PushToStack(RootType root_type,const ObjectHeader * object)72 void GCAdaptiveStack::PushToStack(RootType root_type, const ObjectHeader *object)
73 {
74 LOG(DEBUG, GC) << "Add object to stack: " << GetDebugInfoAboutObject(object)
75 << " accessed as a root: " << root_type;
76 ValidateObject(root_type, object);
77 PushToStack(object);
78 }
79
PushToStack(const ObjectHeader * element)80 void GCAdaptiveStack::PushToStack(const ObjectHeader *element)
81 {
82 ASSERT(element != nullptr);
83 ASSERT(IsInObjectsAddressSpace(ToUintPtr(element)));
84 if ((stack_size_limit_ > 0) && ((stack_dst_->size() + 1) == stack_size_limit_)) {
85 // Try to create a new task only once
86 // Create a new stack and send a new task to GC
87 LOG(DEBUG, GC) << "GCAdaptiveStack: Try to add new task " << GCWorkersTaskTypesToString(task_type_)
88 << " for worker";
89 ASSERT(gc_->GetWorkersPool() != nullptr);
90 ASSERT(task_type_ != GCWorkersTaskTypes::TASK_EMPTY);
91 auto allocator = gc_->GetInternalAllocator();
92 // New tasks will be created with the same new_task_stack_size_limit_ and stack_size_limit_
93 auto new_stack = allocator->New<GCAdaptiveStack>(gc_, new_task_stack_size_limit_, new_task_stack_size_limit_,
94 task_type_, stack_dst_);
95 if (gc_->GetWorkersPool()->AddTask(task_type_, new_stack)) {
96 LOG(DEBUG, GC) << "GCAdaptiveStack: Successfully add new task " << GCWorkersTaskTypesToString(task_type_)
97 << " for worker";
98 stack_dst_ = allocator->template New<PandaStack<const ObjectHeader *>>(allocator->Adapter());
99 } else {
100 // We will try to create a new task later
101 stack_size_limit_ += stack_size_limit_;
102 LOG(DEBUG, GC) << "GCAdaptiveStack: Failed to add new task " << GCWorkersTaskTypesToString(task_type_)
103 << " for worker";
104 [[maybe_unused]] auto src_stack = new_stack->MoveStacksPointers();
105 ASSERT(src_stack == stack_dst_);
106 allocator->Delete(new_stack);
107 }
108 }
109 stack_dst_->push(element);
110 }
111
PopFromStack()112 const ObjectHeader *GCAdaptiveStack::PopFromStack()
113 {
114 if (stack_src_->empty()) {
115 ASSERT(!stack_dst_->empty());
116 auto temp = stack_src_;
117 stack_src_ = stack_dst_;
118 stack_dst_ = temp;
119 if (stack_size_limit_ != 0) {
120 // We may increase the current limit, so return it to the default value
121 stack_size_limit_ = initial_stack_size_limit_;
122 }
123 }
124 ASSERT(!stack_src_->empty());
125 const ObjectHeader *element = stack_src_->top();
126 stack_src_->pop();
127 return element;
128 }
129
IsWorkersTaskSupported()130 bool GCAdaptiveStack::IsWorkersTaskSupported()
131 {
132 return task_type_ != GCWorkersTaskTypes::TASK_EMPTY;
133 }
134
Clear()135 void GCAdaptiveStack::Clear()
136 {
137 *stack_src_ = PandaStack<const ObjectHeader *>();
138 *stack_dst_ = PandaStack<const ObjectHeader *>();
139 }
140
141 } // namespace panda::mem
142