• 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 
26 namespace ark::mem::ets {
27 
EtsReferenceProcessor(GC * gc)28 EtsReferenceProcessor::EtsReferenceProcessor(GC *gc) : gc_(gc) {}
29 
Initialize()30 void EtsReferenceProcessor::Initialize()
31 {
32     auto *vm = ark::ets::PandaEtsVM::GetCurrent();
33     ASSERT(vm != nullptr);
34     auto *undefinedObjHeader = vm->GetUndefinedObject();
35     undefinedObject_ = ark::ets::EtsObject::FromCoreType(undefinedObjHeader);
36     ASSERT(gc_->GetObjectAllocator()->IsObjectInNonMovableSpace(undefinedObject_->GetCoreType()));
37 }
38 
IsReference(const BaseClass * baseCls,const ObjectHeader * ref,const ReferenceCheckPredicateT & pred) const39 bool EtsReferenceProcessor::IsReference(const BaseClass *baseCls, const ObjectHeader *ref,
40                                         const ReferenceCheckPredicateT &pred) const
41 {
42     ASSERT(baseCls != nullptr);
43     ASSERT(ref != nullptr);
44     ASSERT(baseCls->GetSourceLang() == panda_file::SourceLang::ETS);
45 
46     const auto *objEtsClass = ark::ets::EtsClass::FromRuntimeClass(static_cast<const Class *>(baseCls));
47 
48     if (!objEtsClass->IsReference()) {
49         return false;
50     }
51     ASSERT(objEtsClass->IsWeakReference() || objEtsClass->IsFinalizerReference());
52 
53     const auto *etsRef = reinterpret_cast<const ark::ets::EtsWeakReference *>(ref);
54 
55     auto *referent = etsRef->GetReferent();
56     if (referent == nullptr || referent == undefinedObject_) {
57         LOG(DEBUG, REF_PROC) << "Treat " << GetDebugInfoAboutObject(ref)
58                              << " as normal object, because referent is nullish";
59         return false;
60     }
61 
62     if (!pred(referent->GetCoreType())) {
63         LOG(DEBUG, REF_PROC) << "Treat " << GetDebugInfoAboutObject(ref) << " as normal object, because referent "
64                              << std::hex << GetDebugInfoAboutObject(referent->GetCoreType())
65                              << " doesn't suit predicate";
66         return false;
67     }
68 
69     return !gc_->IsMarkedEx(referent->GetCoreType());
70 }
71 
HandleReference(GC * gc,GCMarkingStackType * objectsStack,const BaseClass * cls,const ObjectHeader * object,const ReferenceProcessPredicateT & pred)72 void EtsReferenceProcessor::HandleReference(GC *gc, GCMarkingStackType *objectsStack, const BaseClass *cls,
73                                             const ObjectHeader *object,
74                                             [[maybe_unused]] const ReferenceProcessPredicateT &pred)
75 {
76     LOG(DEBUG, REF_PROC) << GetDebugInfoAboutObject(object) << " is added to weak references set for processing";
77     weakReferences_.Insert(const_cast<ObjectHeader *>(object));
78     HandleOtherFields<false>(cls, object, [gc, objectsStack, object](void *reference) {
79         auto *refObject = reinterpret_cast<ObjectHeader *>(reference);
80         if (gc->MarkObjectIfNotMarked(refObject)) {
81             objectsStack->PushToStack(object, refObject);
82         }
83     });
84 }
85 
HandleReference(GC * gc,const BaseClass * cls,const ObjectHeader * object,const ReferenceProcessorT & processor)86 void EtsReferenceProcessor::HandleReference([[maybe_unused]] GC *gc, const BaseClass *cls, const ObjectHeader *object,
87                                             const ReferenceProcessorT &processor)
88 {
89     LOG(DEBUG, REF_PROC) << GetDebugInfoAboutObject(object) << " is added to weak references set for processing";
90     weakReferences_.Insert(const_cast<ObjectHeader *>(object));
91     HandleOtherFields<true>(cls, object, processor);
92 }
93 
94 template <bool USE_OBJECT_REF>
HandleOtherFields(const BaseClass * cls,const ObjectHeader * object,const ReferenceProcessorT & processor)95 void EtsReferenceProcessor::HandleOtherFields(const BaseClass *cls, const ObjectHeader *object,
96                                               const ReferenceProcessorT &processor)
97 {
98     auto *etsClass = ark::ets::EtsClass::FromRuntimeClass(static_cast<const Class *>(cls));
99     if (!etsClass->IsFinalizerReference()) {
100         return;
101     }
102     // Currently, only finalizer references' other fields are handled
103     ASSERT(etsClass->IsWeakReference());
104     auto *finalizableWeakRef = ark::ets::EtsFinalizableWeakRef::FromCoreType(object);
105     if constexpr (USE_OBJECT_REF) {
106         auto refHandler = [processor, finalizableWeakRef](auto *ref, size_t offset) {
107             if (ref == nullptr) {
108                 return;
109             }
110             ASSERT(ref->GetReferent() != nullptr);
111             processor(ToVoidPtr(ToUintPtr(finalizableWeakRef) + offset));
112         };
113         refHandler(finalizableWeakRef->GetPrev(), ark::ets::EtsFinalizableWeakRef::GetPrevOffset());
114         refHandler(finalizableWeakRef->GetNext(), ark::ets::EtsFinalizableWeakRef::GetNextOffset());
115     } else {
116         auto refHandler = [processor](auto *ref) {
117             if (ref == nullptr) {
118                 return;
119             }
120             ASSERT(ref->GetReferent() != nullptr);
121             processor(ref->GetCoreType());
122         };
123         refHandler(finalizableWeakRef->GetPrev());
124         refHandler(finalizableWeakRef->GetNext());
125     }
126 }
127 
ProcessReferences(bool concurrent,bool clearSoftReferences,GCPhase gcPhase,const mem::GC::ReferenceClearPredicateT & pred)128 void EtsReferenceProcessor::ProcessReferences([[maybe_unused]] bool concurrent,
129                                               [[maybe_unused]] bool clearSoftReferences,
130                                               [[maybe_unused]] GCPhase gcPhase,
131                                               const mem::GC::ReferenceClearPredicateT &pred)
132 {
133     ProcessReferences(pred, [this](auto *weakRefObj, auto *referentObj) {
134         if (gc_->IsMarked(referentObj)) {
135             LOG(DEBUG, REF_PROC) << "Don't process reference " << GetDebugInfoAboutObject(weakRefObj)
136                                  << " because referent " << GetDebugInfoAboutObject(referentObj) << " is marked";
137             return;
138         }
139         LOG(DEBUG, REF_PROC) << "In " << GetDebugInfoAboutObject(weakRefObj) << " clear referent";
140         auto *weakRef = static_cast<ark::ets::EtsWeakReference *>(ark::ets::EtsObject::FromCoreType(weakRefObj));
141         weakRef->ClearReferent();
142         EnqueueFinalizer(weakRef);
143     });
144 }
145 
ProcessReferencesAfterCompaction(const mem::GC::ReferenceClearPredicateT & pred)146 void EtsReferenceProcessor::ProcessReferencesAfterCompaction(const mem::GC::ReferenceClearPredicateT &pred)
147 {
148     ProcessReferences(pred, [this](auto *weakRefObj, auto *referentObj) {
149         auto *weakRef = static_cast<ark::ets::EtsWeakReference *>(ark::ets::EtsObject::FromCoreType(weakRefObj));
150         auto markword = referentObj->AtomicGetMark(std::memory_order_relaxed);
151         auto forwarded = markword.GetState() == MarkWord::ObjectState::STATE_GC;
152         if (forwarded) {
153             LOG(DEBUG, REF_PROC) << "Update " << GetDebugInfoAboutObject(weakRefObj) << " referent "
154                                  << GetDebugInfoAboutObject(referentObj) << " with forward address";
155             auto *newAddr = reinterpret_cast<ObjectHeader *>(markword.GetForwardingAddress());
156             weakRef->SetReferent(ark::ets::EtsObject::FromCoreType(newAddr));
157             return;
158         }
159         LOG(DEBUG, REF_PROC) << "In " << GetDebugInfoAboutObject(weakRefObj) << " clear referent";
160         weakRef->ClearReferent();
161         EnqueueFinalizer(weakRef);
162     });
163 }
164 
GetReferenceQueueSize() const165 size_t EtsReferenceProcessor::GetReferenceQueueSize() const
166 {
167     return weakReferences_.Size();
168 }
169 
ProcessFinalizers()170 void EtsReferenceProcessor::ProcessFinalizers()
171 {
172     auto finalizerIt = finalizerQueue_.begin();
173     while (finalizerIt != finalizerQueue_.end()) {
174         finalizerIt->Run();
175         finalizerIt = finalizerQueue_.erase(finalizerIt);
176     }
177 }
178 
EnqueueFinalizer(ark::ets::EtsWeakReference * weakRef)179 void EtsReferenceProcessor::EnqueueFinalizer(ark::ets::EtsWeakReference *weakRef)
180 {
181     auto *weakRefClass = weakRef->GetClass();
182     if (weakRefClass->IsFinalizerReference()) {
183         auto *finalizableWeakRef = ark::ets::EtsFinalizableWeakRef::FromEtsObject(weakRef);
184         auto finalizer = finalizableWeakRef->ReleaseFinalizer();
185         if (!finalizer.IsEmpty()) {
186             finalizerQueue_.push_back(finalizer);
187         }
188     }
189 }
190 
191 }  // namespace ark::mem::ets
192