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/remark_barrier.h"
16 #include "common_components/heap/allocator/region_space.h"
17 #include "common_components/mutator/mutator.h"
18 #if defined(ARKCOMMON_TSAN_SUPPORT)
19 #include "common_components/sanitizer/sanitizer_interface.h"
20 #endif
21
22 namespace common {
23 // Because gc thread will also have impact on tagged pointer in enum and marking phase,
24 // so we don't expect reading barrier have the ability to modify the referent field.
ReadRefField(BaseObject * obj,RefField<false> & field) const25 BaseObject* RemarkBarrier::ReadRefField(BaseObject* obj, RefField<false>& field) const
26 {
27 RefField<> tmpField(field);
28 return reinterpret_cast<BaseObject*>(tmpField.GetFieldValue());
29 }
30
ReadStaticRef(RefField<false> & field) const31 BaseObject* RemarkBarrier::ReadStaticRef(RefField<false>& field) const { return ReadRefField(nullptr, field); }
32
33
34 // If the object is still alive, return it; if not, return nullptr
ReadStringTableStaticRef(RefField<false> & field) const35 BaseObject* RemarkBarrier::ReadStringTableStaticRef(RefField<false> &field) const
36 {
37 // Note: CMC GC assumes all objects in string table are not in young space. Based on the assumption, CMC GC skip
38 // read barrier in young GC
39 if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) {
40 return reinterpret_cast<BaseObject*>(field.GetFieldValue());
41 }
42
43 auto isSurvivor = [](BaseObject* obj) {
44 RegionDesc* region = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj));
45
46 return region->IsMarkedObject(obj) || region->IsNewObjectSinceMarking(obj);
47 };
48
49 auto obj = ReadRefField(nullptr, field);
50 if (obj != nullptr && isSurvivor(obj)) {
51 return obj;
52 } else {
53 return nullptr;
54 }
55 }
56
ReadStruct(HeapAddress dst,BaseObject * obj,HeapAddress src,size_t size) const57 void RemarkBarrier::ReadStruct(HeapAddress dst, BaseObject *obj, HeapAddress src, size_t size) const
58 {
59 CHECK_CC(memcpy_s(reinterpret_cast<void *>(dst), size, reinterpret_cast<void *>(src), size) == EOK);
60 }
61
WriteRoot(BaseObject * obj) const62 void RemarkBarrier::WriteRoot(BaseObject *obj) const
63 {
64 ASSERT(Heap::IsHeapAddress(obj));
65 Mutator *mutator = Mutator::GetMutator();
66 mutator->RememberObjectInSatbBuffer(obj);
67 DLOG(BARRIER, "write root obj %p", obj);
68 }
69
WriteRefField(BaseObject * obj,RefField<false> & field,BaseObject * ref) const70 void RemarkBarrier::WriteRefField(BaseObject *obj, RefField<false> &field, BaseObject *ref) const
71 {
72 UpdateRememberSet(obj, ref);
73 RefField<> tmpField(field);
74 BaseObject *rememberedObject = nullptr;
75 rememberedObject = tmpField.GetTargetObject();
76 Mutator *mutator = Mutator::GetMutator();
77 if (rememberedObject != nullptr) {
78 mutator->RememberObjectInSatbBuffer(rememberedObject);
79 }
80 DLOG(BARRIER, "write obj %p ref-field@%p: %#zx -> %p", obj, &field,
81 rememberedObject, ref);
82 std::atomic_thread_fence(std::memory_order_seq_cst);
83 RefField<> newField(ref);
84 field.SetFieldValue(newField.GetFieldValue());
85 }
86 #ifdef ARK_USE_SATB_BARRIER
WriteBarrier(BaseObject * obj,RefField<false> & field,BaseObject * ref) const87 void RemarkBarrier::WriteBarrier(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
88 {
89 RefField<> tmpField(field);
90 BaseObject* rememberedObject = nullptr;
91 rememberedObject = tmpField.GetTargetObject();
92 if (!Heap::IsTaggedObject(field.GetFieldValue())) {
93 return;
94 }
95 UpdateRememberSet(obj, ref);
96 Mutator* mutator = Mutator::GetMutator();
97 if (rememberedObject != nullptr) {
98 mutator->RememberObjectInSatbBuffer(rememberedObject);
99 }
100 if (ref != nullptr) {
101 if (!Heap::IsTaggedObject((HeapAddress)ref)) {
102 return;
103 }
104 ref = reinterpret_cast<BaseObject*>(reinterpret_cast<uintptr_t>(ref) & ~TAG_WEAK);
105 mutator->RememberObjectInSatbBuffer(ref);
106 }
107
108 DLOG(BARRIER, "write obj %p ref-field@%p: %#zx -> %p", obj, &field, rememberedObject, ref);
109 }
110 #else
WriteBarrier(BaseObject * obj,RefField<false> & field,BaseObject * ref) const111 void RemarkBarrier::WriteBarrier(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
112 {
113 if (!Heap::IsTaggedObject((HeapAddress)ref)) {
114 return;
115 }
116 UpdateRememberSet(obj, ref);
117 ref = reinterpret_cast<BaseObject*>(reinterpret_cast<uintptr_t>(ref) & ~TAG_WEAK);
118 Mutator* mutator = Mutator::GetMutator();
119 mutator->RememberObjectInSatbBuffer(ref);
120 DLOG(BARRIER, "write obj %p ref-field@%p: -> %p", obj, &field, ref);
121 }
122 #endif
123
WriteStaticRef(RefField<false> & field,BaseObject * ref) const124 void RemarkBarrier::WriteStaticRef(RefField<false>& field, BaseObject* ref) const
125 {
126 std::atomic_thread_fence(std::memory_order_seq_cst);
127 RefField<> newField(ref);
128 field.SetFieldValue(newField.GetFieldValue());
129 }
130
WriteStruct(BaseObject * obj,HeapAddress dst,size_t dstLen,HeapAddress src,size_t srcLen) const131 void RemarkBarrier::WriteStruct(BaseObject* obj, HeapAddress dst, size_t dstLen, HeapAddress src, size_t srcLen) const
132 {
133 CHECK_CC(obj != nullptr);
134 if (obj != nullptr) { //LCOV_EXCL_BR_LINE
135 ASSERT_LOGF(dst > reinterpret_cast<HeapAddress>(obj), "WriteStruct struct addr is less than obj!");
136 Mutator* mutator = Mutator::GetMutator();
137 if (mutator != nullptr) {
138 obj->ForEachRefInStruct(
139 [=](RefField<>& refField) {
140 mutator->RememberObjectInSatbBuffer(ReadRefField(obj, refField));
141 },
142 dst, dst + dstLen);
143 }
144 }
145 std::atomic_thread_fence(std::memory_order_seq_cst);
146 CHECK_CC(memcpy_s(reinterpret_cast<void*>(dst), dstLen, reinterpret_cast<void*>(src), srcLen) == EOK);
147
148 #if defined(ARKCOMMON_TSAN_SUPPORT)
149 Sanitizer::TsanWriteMemoryRange(reinterpret_cast<void*>(dst), dstLen);
150 Sanitizer::TsanReadMemoryRange(reinterpret_cast<void*>(src), srcLen);
151 #endif
152 }
153
AtomicReadRefField(BaseObject * obj,RefField<true> & field,MemoryOrder order) const154 BaseObject* RemarkBarrier::AtomicReadRefField(BaseObject* obj, RefField<true>& field, MemoryOrder order) const
155 {
156 BaseObject* target = nullptr;
157 RefField<false> oldField(field.GetFieldValue(order));
158 target = reinterpret_cast<BaseObject*>((oldField.GetFieldValue()));
159 DLOG(TBARRIER, "katomic read obj %p ref@%p: %#zx -> %p", obj, &field, oldField.GetFieldValue(), target);
160 return target;
161 }
162
AtomicWriteRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const163 void RemarkBarrier::AtomicWriteRefField(BaseObject *obj, RefField<true> &field,
164 BaseObject *newRef,
165 MemoryOrder order) const
166 {
167 RefField<> oldField(field.GetFieldValue(order));
168 HeapAddress oldValue = oldField.GetFieldValue();
169 BaseObject* oldRef = oldField.GetTargetObject();
170 RefField<> newField(newRef);
171 field.SetFieldValue(newField.GetFieldValue(), order);
172 Mutator* mutator = Mutator::GetMutator();
173 mutator->RememberObjectInSatbBuffer(oldRef);
174 if (obj != nullptr) {
175 DLOG(TBARRIER, "atomic write obj %p<%p>(%zu) ref@%p: %#zx -> %#zx", obj, obj->GetTypeInfo(), obj->GetSize(),
176 &field, oldValue, newField.GetFieldValue());
177 } else {
178 DLOG(TBARRIER, "atomic write static ref@%p: %#zx -> %#zx", &field, oldValue, newField.GetFieldValue());
179 }
180 }
181
AtomicSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const182 BaseObject *RemarkBarrier::AtomicSwapRefField(BaseObject *obj,
183 RefField<true> &field,
184 BaseObject *newRef,
185 MemoryOrder order) const
186 {
187 RefField<> newField(newRef);
188 HeapAddress oldValue = field.Exchange(newField.GetFieldValue(), order);
189 RefField<> oldField(oldValue);
190 BaseObject* oldRef = oldField.GetTargetObject();
191 Mutator* mutator = Mutator::GetMutator();
192 mutator->RememberObjectInSatbBuffer(oldRef);
193 DLOG(TRACE, "atomic swap obj %p<%p>(%zu) ref-field@%p: old %#zx(%p), new %#zx(%p)", obj, obj->GetTypeInfo(),
194 obj->GetSize(), &field, oldValue, oldRef, field.GetFieldValue(), newRef);
195 return oldRef;
196 }
197
CompareAndSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * oldRef,BaseObject * newRef,MemoryOrder succOrder,MemoryOrder failOrder) const198 bool RemarkBarrier::CompareAndSwapRefField(
199 BaseObject *obj, RefField<true> &field, BaseObject *oldRef,
200 BaseObject *newRef, MemoryOrder succOrder, MemoryOrder failOrder) const
201 {
202 HeapAddress oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
203 RefField<false> oldField(oldFieldValue);
204 BaseObject* oldVersion = oldField.GetTargetObject();
205 RefField<> newField(newRef);
206
207 while (oldVersion == oldRef) {
208 if (field.CompareExchange(oldFieldValue, newField.GetFieldValue(), succOrder, failOrder)) {
209 Mutator* mutator = Mutator::GetMutator();
210 mutator->RememberObjectInSatbBuffer(oldRef);
211 return true;
212 }
213 oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
214 RefField<false> tmp(oldFieldValue);
215 oldVersion = tmp.GetTargetObject();
216 }
217
218 return false;
219 }
220
CopyStructArray(BaseObject * dstObj,HeapAddress dstField,MIndex dstSize,BaseObject * srcObj,HeapAddress srcField,MIndex srcSize) const221 void RemarkBarrier::CopyStructArray(BaseObject *dstObj, HeapAddress dstField,
222 MIndex dstSize, BaseObject *srcObj,
223 HeapAddress srcField,
224 MIndex srcSize) const
225 {
226 LOG_COMMON(FATAL) << "Unresolved fatal";
227 }
228
229 } // namespace panda
230
231