• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-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 "libpandabase/os/mutex.h"
17 #include "runtime/include/object_header.h"
18 #include "runtime/mem/gc/gc_phase.h"
19 #include "runtime/mem/object_helpers.h"
20 #include "plugins/ets/runtime/mem/ets_reference_processor.h"
21 #include "plugins/ets/runtime/types/ets_class.h"
22 #include "plugins/ets/runtime/types/ets_weak_reference.h"
23 #include "plugins/ets/runtime/types/ets_finalizable_weak_ref.h"
24 #include "plugins/ets/runtime/ets_vm.h"
25 #include "plugins/ets/runtime/ets_coroutine.h"
26 
27 namespace ark::mem::ets {
28 
EtsReferenceProcessor(GC * gc)29 EtsReferenceProcessor::EtsReferenceProcessor(GC *gc) : gc_(gc) {}
30 
Initialize()31 void EtsReferenceProcessor::Initialize()
32 {
33     auto *vm = ark::ets::PandaEtsVM::GetCurrent();
34     ASSERT(vm != nullptr);
35     auto *undefinedObjHeader = vm->GetUndefinedObject();
36     undefinedObject_ = ark::ets::EtsObject::FromCoreType(undefinedObjHeader);
37     ASSERT(gc_->GetObjectAllocator()->IsObjectInNonMovableSpace(undefinedObject_->GetCoreType()));
38 }
39 
IsReference(const BaseClass * baseCls,const ObjectHeader * ref,const ReferenceCheckPredicateT & pred) const40 bool EtsReferenceProcessor::IsReference(const BaseClass *baseCls, const ObjectHeader *ref,
41                                         const ReferenceCheckPredicateT &pred) const
42 {
43     ASSERT(baseCls != nullptr);
44     ASSERT(ref != nullptr);
45     ASSERT(baseCls->GetSourceLang() == panda_file::SourceLang::ETS);
46 
47     const auto *objEtsClass = ark::ets::EtsClass::FromRuntimeClass(static_cast<const Class *>(baseCls));
48 
49     if (!objEtsClass->IsReference()) {
50         return false;
51     }
52     ASSERT(objEtsClass->IsWeakReference() || objEtsClass->IsFinalizerReference());
53 
54     const auto *etsRef = reinterpret_cast<const ark::ets::EtsWeakReference *>(ref);
55 
56     auto *referent = etsRef->GetReferent();
57     if (referent == nullptr || referent == undefinedObject_) {
58         LOG(DEBUG, REF_PROC) << "Treat " << GetDebugInfoAboutObject(ref)
59                              << " as normal object, because referent is nullish";
60         return false;
61     }
62 
63     ASSERT(IsMarking(gc_->GetGCPhase()));
64     bool referentIsMarked = false;
65     if (pred(referent->GetCoreType())) {
66         referentIsMarked = gc_->IsMarked(referent->GetCoreType());
67     } else {
68         LOG(DEBUG, REF_PROC) << "Treat " << GetDebugInfoAboutObject(ref) << " as normal object, because referent "
69                              << std::hex << GetDebugInfoAboutObject(referent->GetCoreType())
70                              << " doesn't suit predicate";
71         referentIsMarked = true;
72     }
73     return !referentIsMarked;
74 }
75 
IsReference(const BaseClass * baseCls,const ObjectHeader * ref) const76 bool EtsReferenceProcessor::IsReference(const BaseClass *baseCls, const ObjectHeader *ref) const
77 {
78     ASSERT(baseCls != nullptr);
79     ASSERT(ref != nullptr);
80     ASSERT(baseCls->GetSourceLang() == panda_file::SourceLang::ETS);
81 
82     const auto *objEtsClass = ark::ets::EtsClass::FromRuntimeClass(static_cast<const Class *>(baseCls));
83 
84     if (!objEtsClass->IsReference()) {
85         return false;
86     }
87     ASSERT(objEtsClass->IsWeakReference() || objEtsClass->IsFinalizerReference());
88 
89     const auto *etsRef = reinterpret_cast<const ark::ets::EtsWeakReference *>(ref);
90 
91     auto *referent = etsRef->GetReferent();
92     if (referent == nullptr || referent == undefinedObject_) {
93         LOG(DEBUG, REF_PROC) << "Treat " << GetDebugInfoAboutObject(ref)
94                              << " as normal object, because referent is nullish";
95         return false;
96     }
97 
98     auto *referentObj = referent->GetCoreType();
99     if (!gc_->InGCSweepRange(referentObj)) {
100         return false;
101     }
102 
103     return referentObj->AtomicGetMark().GetState() != MarkWord::ObjectState::STATE_GC;
104 }
105 
HandleReference(GC * gc,GCMarkingStackType * objectsStack,const BaseClass * cls,const ObjectHeader * object,const ReferenceProcessPredicateT & pred)106 void EtsReferenceProcessor::HandleReference(GC *gc, GCMarkingStackType *objectsStack, const BaseClass *cls,
107                                             const ObjectHeader *object,
108                                             [[maybe_unused]] const ReferenceProcessPredicateT &pred)
109 {
110     os::memory::LockHolder lock(weakRefLock_);
111     LOG(DEBUG, REF_PROC) << GetDebugInfoAboutObject(object) << " is added to weak references set for processing";
112     weakReferences_.insert(const_cast<ObjectHeader *>(object));
113     HandleOtherFields(cls, object, [gc, objectsStack, object](void *reference) {
114         auto *refObject = reinterpret_cast<ObjectHeader *>(reference);
115         if (gc->MarkObjectIfNotMarked(refObject)) {
116             objectsStack->PushToStack(object, refObject);
117         }
118     });
119 }
120 
HandleReference(GC * gc,const BaseClass * cls,const ObjectHeader * object,const ReferenceProcessorT & processor)121 void EtsReferenceProcessor::HandleReference([[maybe_unused]] GC *gc, const BaseClass *cls, const ObjectHeader *object,
122                                             const ReferenceProcessorT &processor)
123 {
124     os::memory::LockHolder lock(weakRefLock_);
125     LOG(DEBUG, REF_PROC) << GetDebugInfoAboutObject(object) << " is added to weak references set for processing";
126     weakReferences_.insert(const_cast<ObjectHeader *>(object));
127     HandleOtherFields(cls, object, processor);
128 }
129 
HandleOtherFields(const BaseClass * cls,const ObjectHeader * object,const ReferenceProcessorT & processor)130 void EtsReferenceProcessor::HandleOtherFields(const BaseClass *cls, const ObjectHeader *object,
131                                               const ReferenceProcessorT &processor)
132 {
133     auto *etsClass = ark::ets::EtsClass::FromRuntimeClass(static_cast<const Class *>(cls));
134     if (etsClass->IsFinalizerReference()) {
135         ASSERT(etsClass->IsWeakReference());
136         auto *coro = ark::ets::EtsCoroutine::GetCurrent();
137         auto *finalizableWeakRef = ark::ets::EtsFinalizableWeakRef::FromCoreType(object);
138         auto refHandler = [this, coro, processor](auto *ref) {
139             if (ref == nullptr) {
140                 return;
141             }
142             ASSERT(ref->GetReferent() != nullptr);
143             if (ref->GetReferent() == undefinedObject_) {
144                 coro->GetPandaVM()->UnlinkFinalizableReference(coro, ref);
145                 return;
146             }
147             processor(ref->GetCoreType());
148         };
149         refHandler(finalizableWeakRef->GetPrev(coro));
150         refHandler(finalizableWeakRef->GetNext(coro));
151     }
152 }
153 
ProcessReferences(bool concurrent,bool clearSoftReferences,GCPhase gcPhase,const mem::GC::ReferenceClearPredicateT & pred)154 void EtsReferenceProcessor::ProcessReferences([[maybe_unused]] bool concurrent,
155                                               [[maybe_unused]] bool clearSoftReferences,
156                                               [[maybe_unused]] GCPhase gcPhase,
157                                               const mem::GC::ReferenceClearPredicateT &pred)
158 {
159     ProcessReferences(pred, [this](auto *weakRefObj, auto *referentObj) {
160         if (gc_->IsMarked(referentObj)) {
161             LOG(DEBUG, REF_PROC) << "Don't process reference " << GetDebugInfoAboutObject(weakRefObj)
162                                  << " because referent " << GetDebugInfoAboutObject(referentObj) << " is marked";
163             return;
164         }
165         LOG(DEBUG, REF_PROC) << "In " << GetDebugInfoAboutObject(weakRefObj) << " clear referent";
166         auto *weakRef = static_cast<ark::ets::EtsWeakReference *>(ark::ets::EtsObject::FromCoreType(weakRefObj));
167         weakRef->ClearReferent();
168         EnqueueFinalizer(weakRef);
169     });
170 }
171 
ProcessReferencesAfterCompaction(bool clearSoftReferences,const mem::GC::ReferenceClearPredicateT & pred)172 void EtsReferenceProcessor::ProcessReferencesAfterCompaction([[maybe_unused]] bool clearSoftReferences,
173                                                              const mem::GC::ReferenceClearPredicateT &pred)
174 {
175     ProcessReferences(pred, [this](auto *weakRefObj, auto *referentObj) {
176         auto *weakRef = static_cast<ark::ets::EtsWeakReference *>(ark::ets::EtsObject::FromCoreType(weakRefObj));
177         auto markword = referentObj->GetMark();
178         auto forwarded = markword.GetState() == MarkWord::ObjectState::STATE_GC;
179         if (forwarded) {
180             LOG(DEBUG, REF_PROC) << "Update " << GetDebugInfoAboutObject(weakRefObj) << " referent "
181                                  << GetDebugInfoAboutObject(referentObj) << " with forward address";
182             auto *newAddr = reinterpret_cast<ObjectHeader *>(markword.GetForwardingAddress());
183             weakRef->SetReferent(ark::ets::EtsObject::FromCoreType(newAddr));
184             return;
185         }
186         LOG(DEBUG, REF_PROC) << "In " << GetDebugInfoAboutObject(weakRefObj) << " clear referent";
187         weakRef->ClearReferent();
188         EnqueueFinalizer(weakRef);
189     });
190 }
191 
GetReferenceQueueSize() const192 size_t EtsReferenceProcessor::GetReferenceQueueSize() const
193 {
194     os::memory::LockHolder lock(weakRefLock_);
195     return weakReferences_.size();
196 }
197 
ProcessFinalizers()198 void EtsReferenceProcessor::ProcessFinalizers()
199 {
200     auto finalizerIt = finalizerQueue_.begin();
201     while (finalizerIt != finalizerQueue_.end()) {
202         finalizerIt->Run();
203         finalizerIt = finalizerQueue_.erase(finalizerIt);
204     }
205 }
206 
EnqueueFinalizer(ark::ets::EtsWeakReference * weakRef)207 void EtsReferenceProcessor::EnqueueFinalizer(ark::ets::EtsWeakReference *weakRef)
208 {
209     auto *weakRefClass = weakRef->GetClass();
210     if (weakRefClass->IsFinalizerReference()) {
211         auto *finalizableWeakRef = ark::ets::EtsFinalizableWeakRef::FromEtsObject(weakRef);
212         auto finalizer = finalizableWeakRef->ReleaseFinalizer();
213         if (!finalizer.IsEmpty()) {
214             finalizerQueue_.push_back(finalizer);
215         }
216     }
217 }
218 
219 }  // namespace ark::mem::ets
220