• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 #include "common_components/heap/ark_collector/post_marking_barrier.h"
16 
17 #include "common_components/heap/allocator/region_space.h"
18 #include "common_components/mutator/mutator.h"
19 #include "heap/space/young_space.h"
20 #if defined(COMMON_TSAN_SUPPORT)
21 #include "common_components/sanitizer/sanitizer_interface.h"
22 #endif
23 
24 namespace common {
ReadRefField(BaseObject * obj,RefField<false> & field) const25 BaseObject* PostMarkingBarrier::ReadRefField(BaseObject* obj, RefField<false>& field) const
26 {
27     RefField<> tmpField(field);
28     return (BaseObject*)tmpField.GetFieldValue();
29 }
30 
ReadStaticRef(RefField<false> & field) const31 BaseObject* PostMarkingBarrier::ReadStaticRef(RefField<false>& field) const { return ReadRefField(nullptr, field); }
32 
33 // If the object is still alive, return it; if not, return nullptr
ReadStringTableStaticRef(RefField<false> & field) const34 BaseObject* PostMarkingBarrier::ReadStringTableStaticRef(RefField<false> &field) const
35 {
36     // Note: CMC GC assumes all objects in string table are not in young space. Based on the assumption, CMC GC skip
37     // read barrier in young GC
38     if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) {
39         return reinterpret_cast<BaseObject*>(field.GetFieldValue());
40     }
41 
42     auto isSurvivor = [](BaseObject* obj) {
43         RegionDesc* region = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj));
44 
45         return region->IsMarkedObject(obj) || region->IsNewObjectSinceMarking(obj);
46     };
47 
48     auto obj = ReadRefField(nullptr, field);
49     if (obj != nullptr && isSurvivor(obj)) {
50         return obj;
51     } else {
52         return nullptr;
53     }
54 }
55 
ReadStruct(HeapAddress dst,BaseObject * obj,HeapAddress src,size_t size) const56 void PostMarkingBarrier::ReadStruct(HeapAddress dst, BaseObject* obj, HeapAddress src, size_t size) const
57 {
58     CHECK_CC(memcpy_s(reinterpret_cast<void*>(dst), size, reinterpret_cast<void*>(src), size) == EOK);
59 }
60 
WriteRefField(BaseObject * obj,RefField<false> & field,BaseObject * ref) const61 void PostMarkingBarrier::WriteRefField(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
62 {
63     RefField<> newField(ref);
64     UpdateRememberSet(obj, ref);
65     field.SetFieldValue(newField.GetFieldValue());
66 }
67 
WriteBarrier(BaseObject * obj,RefField<false> & field,BaseObject * ref) const68 void PostMarkingBarrier::WriteBarrier(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
69 {
70     if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) {
71         UpdateRememberSet(obj, ref);
72     }
73 }
74 
WriteStaticRef(RefField<false> & field,BaseObject * ref) const75 void PostMarkingBarrier::WriteStaticRef(RefField<false>& field, BaseObject* ref) const
76 {
77     RefField<> newField(ref);
78     field.SetFieldValue(newField.GetFieldValue());
79 }
80 
WriteStruct(BaseObject * obj,HeapAddress dst,size_t dstLen,HeapAddress src,size_t srcLen) const81 void PostMarkingBarrier::WriteStruct(BaseObject* obj, HeapAddress dst, size_t dstLen,
82                                      HeapAddress src, size_t srcLen) const
83 {
84     CHECK_CC(obj != nullptr);
85     CHECK_CC(memcpy_s(reinterpret_cast<void*>(dst), dstLen, reinterpret_cast<void*>(src), srcLen) == EOK);
86 
87 #if defined(COMMON_TSAN_SUPPORT)
88     Sanitizer::TsanWriteMemoryRange(reinterpret_cast<void*>(dst), dstLen);
89     Sanitizer::TsanReadMemoryRange(reinterpret_cast<void*>(src), srcLen);
90 #endif
91 }
92 
AtomicReadRefField(BaseObject * obj,RefField<true> & field,MemoryOrder order) const93 BaseObject* PostMarkingBarrier::AtomicReadRefField(BaseObject* obj, RefField<true>& field, MemoryOrder order) const
94 {
95     BaseObject* target = nullptr;
96     RefField<false> oldField(field.GetFieldValue(order));
97 
98     target = ReadRefField(nullptr, oldField);
99     DLOG(TBARRIER, "katomic read obj %p ref@%p: %#zx -> %p", obj, &field, oldField.GetFieldValue(), target);
100     return target;
101 }
102 
AtomicWriteRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const103 void PostMarkingBarrier::AtomicWriteRefField(BaseObject* obj, RefField<true>& field, BaseObject* newRef,
104                                              MemoryOrder order) const
105 {
106     RefField<> oldField(field.GetFieldValue(order));
107     HeapAddress oldValue = oldField.GetFieldValue();
108     (void)oldValue;
109     RefField<> newField(newRef);
110     field.SetFieldValue(newField.GetFieldValue(), order);
111     if (obj != nullptr) {
112         DLOG(TBARRIER, "atomic write obj %p<%p>(%zu) ref@%p: %#zx -> %#zx", obj, obj->GetTypeInfo(), obj->GetSize(),
113              &field, oldValue, newField.GetFieldValue());
114     } else {
115         DLOG(TBARRIER, "atomic write static ref@%p: %#zx -> %#zx", &field, oldValue, newField.GetFieldValue());
116     }
117 }
118 
AtomicSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const119 BaseObject* PostMarkingBarrier::AtomicSwapRefField(BaseObject* obj, RefField<true>& field, BaseObject* newRef,
120                                                    MemoryOrder order) const
121 {
122     RefField<> newField(newRef);
123     HeapAddress oldValue = field.Exchange(newField.GetFieldValue(), order);
124     RefField<> oldField(oldValue);
125     BaseObject* oldRef = oldField.GetTargetObject();
126     DLOG(TRACE, "atomic swap obj %p<%p>(%zu) ref-field@%p: old %#zx(%p), new %#zx(%p)", obj, obj->GetTypeInfo(),
127          obj->GetSize(), &field, oldValue, oldRef, field.GetFieldValue(), newRef);
128     return oldRef;
129 }
130 
CompareAndSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * oldRef,BaseObject * newRef,MemoryOrder succOrder,MemoryOrder failOrder) const131 bool PostMarkingBarrier::CompareAndSwapRefField(BaseObject* obj, RefField<true>& field, BaseObject* oldRef,
132                                                 BaseObject* newRef, MemoryOrder succOrder, MemoryOrder failOrder) const
133 {
134     HeapAddress oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
135     RefField<false> oldField(oldFieldValue);
136     BaseObject* oldVersion = oldField.GetTargetObject();
137     RefField<> newField(newRef);
138     while (oldVersion == oldRef) {
139         if (field.CompareExchange(oldFieldValue, newField.GetFieldValue(), succOrder, failOrder)) {
140             return true;
141         }
142         oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
143         RefField<false> tmpField(oldFieldValue);
144         oldVersion = tmpField.GetTargetObject();
145     }
146     return false;
147 }
148 
CopyStructArray(BaseObject * dstObj,HeapAddress dstField,MIndex dstSize,BaseObject * srcObj,HeapAddress srcField,MIndex srcSize) const149 void PostMarkingBarrier::CopyStructArray(BaseObject* dstObj, HeapAddress dstField, MIndex dstSize, BaseObject* srcObj,
150                                          HeapAddress srcField, MIndex srcSize) const
151 {
152 #ifndef NDEBUG
153     if (!dstObj->HasRefField()) {
154         LOG_COMMON(FATAL) << "array " << dstObj << " doesn't have class-type element";
155         return;
156     }
157 #endif
158     LOGF_CHECK(memmove_s(reinterpret_cast<void*>(dstField), dstSize, reinterpret_cast<void*>(srcField), srcSize) ==
159                      EOK) << "memmove_s failed";
160 
161 #if defined(COMMON_TSAN_SUPPORT)
162     Sanitizer::TsanWriteMemoryRange(reinterpret_cast<void*>(dstField), dstSize);
163     Sanitizer::TsanReadMemoryRange(reinterpret_cast<void*>(srcField), srcSize);
164 #endif
165 }
166 } // namespace common
167