1 /**
2 * Copyright (c) 2023 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
24 namespace panda::mem::ets {
25
EtsReferenceProcessor(GC * gc)26 EtsReferenceProcessor::EtsReferenceProcessor(GC *gc) : gc_(gc) {}
27
IsReference(const BaseClass * baseCls,const ObjectHeader * ref,const ReferenceCheckPredicateT & pred) const28 bool EtsReferenceProcessor::IsReference(const BaseClass *baseCls, const ObjectHeader *ref,
29 const ReferenceCheckPredicateT &pred) const
30 {
31 ASSERT(baseCls != nullptr);
32 ASSERT(ref != nullptr);
33 ASSERT(baseCls->GetSourceLang() == panda_file::SourceLang::ETS);
34
35 const auto *objEtsClass = panda::ets::EtsClass::FromRuntimeClass(static_cast<const Class *>(baseCls));
36
37 if (objEtsClass->IsWeakReference()) {
38 const auto *etsRef = reinterpret_cast<const panda::ets::EtsWeakReference *>(ref);
39
40 auto *referent = etsRef->GetReferent();
41 if (referent == nullptr) {
42 LOG(DEBUG, REF_PROC) << "Treat " << GetDebugInfoAboutObject(ref)
43 << " as normal object, because referent is null";
44 return false;
45 }
46
47 ASSERT(IsMarking(gc_->GetGCPhase()));
48 bool referentIsMarked = false;
49 if (pred(referent->GetCoreType())) {
50 referentIsMarked = gc_->IsMarked(referent->GetCoreType());
51 } else {
52 LOG(DEBUG, REF_PROC) << "Treat " << GetDebugInfoAboutObject(ref) << " as normal object, because referent "
53 << std::hex << GetDebugInfoAboutObject(referent->GetCoreType())
54 << " doesn't suit predicate";
55 referentIsMarked = true;
56 }
57 return !referentIsMarked;
58 }
59 return false;
60 }
61
HandleReference(GC * gc,GCMarkingStackType * objectsStack,const BaseClass * cls,const ObjectHeader * object,const ReferenceProcessPredicateT & pred)62 void EtsReferenceProcessor::HandleReference([[maybe_unused]] GC *gc, [[maybe_unused]] GCMarkingStackType *objectsStack,
63 [[maybe_unused]] const BaseClass *cls, const ObjectHeader *object,
64 [[maybe_unused]] const ReferenceProcessPredicateT &pred)
65 {
66 os::memory::LockHolder lock(weakRefLock_);
67 LOG(DEBUG, REF_PROC) << GetDebugInfoAboutObject(object) << " is added to weak references set for processing";
68 weakReferences_.insert(const_cast<ObjectHeader *>(object));
69 }
70
ProcessReferences(bool concurrent,bool clearSoftReferences,GCPhase gcPhase,const mem::GC::ReferenceClearPredicateT & pred)71 void EtsReferenceProcessor::ProcessReferences([[maybe_unused]] bool concurrent,
72 [[maybe_unused]] bool clearSoftReferences,
73 [[maybe_unused]] GCPhase gcPhase,
74 const mem::GC::ReferenceClearPredicateT &pred)
75 {
76 os::memory::LockHolder lock(weakRefLock_);
77 while (!weakReferences_.empty()) {
78 auto *weakRefObj = weakReferences_.extract(weakReferences_.begin()).value();
79 ASSERT(panda::ets::EtsClass::FromRuntimeClass(weakRefObj->ClassAddr<Class>())->IsWeakReference());
80 auto *weakRef = static_cast<panda::ets::EtsWeakReference *>(panda::ets::EtsObject::FromCoreType(weakRefObj));
81 auto *referent = weakRef->GetReferent();
82 if (referent == nullptr) {
83 LOG(DEBUG, REF_PROC) << "Don't process reference " << GetDebugInfoAboutObject(weakRefObj)
84 << " because referent is null";
85 continue;
86 }
87 auto *referentObj = referent->GetCoreType();
88 if (!pred(referentObj)) {
89 LOG(DEBUG, REF_PROC) << "Don't process reference " << GetDebugInfoAboutObject(weakRefObj)
90 << " because referent " << GetDebugInfoAboutObject(referentObj) << " failed predicate";
91 continue;
92 }
93 if (gc_->IsMarked(referentObj)) {
94 LOG(DEBUG, REF_PROC) << "Don't process reference " << GetDebugInfoAboutObject(weakRefObj)
95 << " because referent " << GetDebugInfoAboutObject(referentObj) << " is marked";
96 continue;
97 }
98 LOG(DEBUG, REF_PROC) << "In " << GetDebugInfoAboutObject(weakRefObj) << " clear referent";
99 weakRef->ClearReferent();
100 }
101 }
102
GetReferenceQueueSize() const103 size_t EtsReferenceProcessor::GetReferenceQueueSize() const
104 {
105 os::memory::LockHolder lock(weakRefLock_);
106 return weakReferences_.size();
107 }
108
109 } // namespace panda::mem::ets
110