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