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/marking_barrier.h"
16
17 #include "common_components/mutator/mutator.h"
18 #if defined(COMMON_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* MarkingBarrier::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* MarkingBarrier::ReadStaticRef(RefField<false>& field) const { return ReadRefField(nullptr, field); }
32
ReadStruct(HeapAddress dst,BaseObject * obj,HeapAddress src,size_t size) const33 void MarkingBarrier::ReadStruct(HeapAddress dst, BaseObject* obj, HeapAddress src, size_t size) const
34 {
35 CHECK_CC(memcpy_s(reinterpret_cast<void*>(dst), size, reinterpret_cast<void*>(src), size) == EOK);
36 }
37
WriteRoot(BaseObject * obj) const38 void MarkingBarrier::WriteRoot(BaseObject *obj) const
39 {
40 ASSERT(Heap::IsHeapAddress(obj));
41 Mutator *mutator = Mutator::GetMutator();
42 mutator->RememberObjectInSatbBuffer(obj);
43 DLOG(BARRIER, "write root obj %p", obj);
44 }
45
WriteRefField(BaseObject * obj,RefField<false> & field,BaseObject * ref) const46 void MarkingBarrier::WriteRefField(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
47 {
48 UpdateRememberSet(obj, ref);
49 RefField<> tmpField(field);
50 BaseObject* rememberedObject = nullptr;
51 rememberedObject = tmpField.GetTargetObject();
52 Mutator* mutator = Mutator::GetMutator();
53 if (rememberedObject != nullptr) {
54 mutator->RememberObjectInSatbBuffer(rememberedObject);
55 }
56 DLOG(BARRIER, "write obj %p ref-field@%p: %#zx -> %p", obj, &field, rememberedObject, ref);
57 std::atomic_thread_fence(std::memory_order_seq_cst);
58 RefField<> newField(ref);
59 field.SetFieldValue(newField.GetFieldValue());
60 }
61 #ifdef ARK_USE_SATB_BARRIER
WriteBarrier(BaseObject * obj,RefField<false> & field,BaseObject * ref) const62 void MarkingBarrier::WriteBarrier(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
63 {
64 RefField<> tmpField(field);
65 BaseObject* rememberedObject = nullptr;
66 rememberedObject = tmpField.GetTargetObject();
67 if (!Heap::IsTaggedObject(field.GetFieldValue())) {
68 return;
69 }
70 UpdateRememberSet(obj, ref);
71 Mutator* mutator = Mutator::GetMutator();
72 if (rememberedObject != nullptr) {
73 mutator->RememberObjectInSatbBuffer(rememberedObject);
74 }
75 if (ref != nullptr) {
76 if (!Heap::IsTaggedObject((HeapAddress)ref)) {
77 return;
78 }
79 ref = (BaseObject*)((uintptr_t)ref & ~(TAG_WEAK));
80 mutator->RememberObjectInSatbBuffer(ref);
81 }
82
83 DLOG(BARRIER, "write obj %p ref-field@%p: %#zx -> %p", obj, &field, rememberedObject, ref);
84 }
85 #else
WriteBarrier(BaseObject * obj,RefField<false> & field,BaseObject * ref) const86 void MarkingBarrier::WriteBarrier(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
87 {
88 if (!Heap::IsTaggedObject((HeapAddress)ref)) {
89 return;
90 }
91 if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) {
92 UpdateRememberSet(obj, ref);
93 }
94 ref = (BaseObject*)((uintptr_t)ref & ~(TAG_WEAK));
95 Mutator* mutator = Mutator::GetMutator();
96 mutator->RememberObjectInSatbBuffer(ref);
97 DLOG(BARRIER, "write obj %p ref-field@%p: -> %p", obj, &field, ref);
98 }
99 #endif
100
WriteStaticRef(RefField<false> & field,BaseObject * ref) const101 void MarkingBarrier::WriteStaticRef(RefField<false>& field, BaseObject* ref) const
102 {
103 std::atomic_thread_fence(std::memory_order_seq_cst);
104 RefField<> newField(ref);
105 field.SetFieldValue(newField.GetFieldValue());
106 }
107
WriteStruct(BaseObject * obj,HeapAddress dst,size_t dstLen,HeapAddress src,size_t srcLen) const108 void MarkingBarrier::WriteStruct(BaseObject* obj, HeapAddress dst, size_t dstLen, HeapAddress src, size_t srcLen) const
109 {
110 CHECK_CC(obj != nullptr);
111 if (obj != nullptr) { //LCOV_EXCL_BR_LINE
112 ASSERT_LOGF(dst > reinterpret_cast<HeapAddress>(obj), "WriteStruct struct addr is less than obj!");
113 Mutator* mutator = Mutator::GetMutator();
114 if (mutator != nullptr) {
115 obj->ForEachRefInStruct(
116 [=](RefField<>& refField) {
117 mutator->RememberObjectInSatbBuffer(ReadRefField(obj, refField));
118 },
119 dst, dst + dstLen);
120 }
121 }
122 std::atomic_thread_fence(std::memory_order_seq_cst);
123 CHECK_CC(memcpy_s(reinterpret_cast<void*>(dst), dstLen, reinterpret_cast<void*>(src), srcLen) == EOK);
124
125 #if defined(COMMON_TSAN_SUPPORT)
126 Sanitizer::TsanWriteMemoryRange(reinterpret_cast<void*>(dst), dstLen);
127 Sanitizer::TsanReadMemoryRange(reinterpret_cast<void*>(src), srcLen);
128 #endif
129 }
130
AtomicReadRefField(BaseObject * obj,RefField<true> & field,MemoryOrder order) const131 BaseObject* MarkingBarrier::AtomicReadRefField(BaseObject* obj, RefField<true>& field, MemoryOrder order) const
132 {
133 BaseObject* target = nullptr;
134 RefField<false> oldField(field.GetFieldValue(order));
135 target = (BaseObject*)(oldField.GetFieldValue());
136 DLOG(TBARRIER, "katomic read obj %p ref@%p: %#zx -> %p", obj, &field, oldField.GetFieldValue(), target);
137 return target;
138 }
139
AtomicWriteRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const140 void MarkingBarrier::AtomicWriteRefField(BaseObject* obj, RefField<true>& field, BaseObject* newRef,
141 MemoryOrder order) const
142 {
143 RefField<> oldField(field.GetFieldValue(order));
144 HeapAddress oldValue = oldField.GetFieldValue();
145 (void)oldValue;
146 BaseObject* oldRef = oldField.GetTargetObject();
147 RefField<> newField(newRef);
148 field.SetFieldValue(newField.GetFieldValue(), order);
149 Mutator* mutator = Mutator::GetMutator();
150 mutator->RememberObjectInSatbBuffer(oldRef);
151 if (obj != nullptr) {
152 DLOG(TBARRIER, "atomic write obj %p<%p>(%zu) ref@%p: %#zx -> %#zx", obj, obj->GetTypeInfo(), obj->GetSize(),
153 &field, oldValue, newField.GetFieldValue());
154 } else {
155 DLOG(TBARRIER, "atomic write static ref@%p: %#zx -> %#zx", &field, oldValue, newField.GetFieldValue());
156 }
157 }
158
AtomicSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const159 BaseObject* MarkingBarrier::AtomicSwapRefField(BaseObject* obj, RefField<true>& field, BaseObject* newRef,
160 MemoryOrder order) const
161 {
162 RefField<> newField(newRef);
163 HeapAddress oldValue = field.Exchange(newField.GetFieldValue(), order);
164 RefField<> oldField(oldValue);
165 BaseObject* oldRef = oldField.GetTargetObject();
166 Mutator* mutator = Mutator::GetMutator();
167 mutator->RememberObjectInSatbBuffer(oldRef);
168 DLOG(TRACE, "atomic swap obj %p<%p>(%zu) ref-field@%p: old %#zx(%p), new %#zx(%p)", obj, obj->GetTypeInfo(),
169 obj->GetSize(), &field, oldValue, oldRef, field.GetFieldValue(), newRef);
170 return oldRef;
171 }
172
CompareAndSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * oldRef,BaseObject * newRef,MemoryOrder succOrder,MemoryOrder failOrder) const173 bool MarkingBarrier::CompareAndSwapRefField(BaseObject* obj, RefField<true>& field, BaseObject* oldRef,
174 BaseObject* newRef, MemoryOrder succOrder, MemoryOrder failOrder) const
175 {
176 HeapAddress oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
177 RefField<false> oldField(oldFieldValue);
178 BaseObject* oldVersion = oldField.GetTargetObject();
179 RefField<> newField(newRef);
180
181 while (oldVersion == oldRef) {
182 if (field.CompareExchange(oldFieldValue, newField.GetFieldValue(), succOrder, failOrder)) {
183 Mutator* mutator = Mutator::GetMutator();
184 mutator->RememberObjectInSatbBuffer(oldRef);
185 return true;
186 }
187 oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
188 RefField<false> tmp(oldFieldValue);
189 oldVersion = tmp.GetTargetObject();
190 }
191
192 return false;
193 }
194
CopyStructArray(BaseObject * dstObj,HeapAddress dstField,MIndex dstSize,BaseObject * srcObj,HeapAddress srcField,MIndex srcSize) const195 void MarkingBarrier::CopyStructArray(BaseObject* dstObj, HeapAddress dstField, MIndex dstSize, BaseObject* srcObj,
196 HeapAddress srcField, MIndex srcSize) const
197 {
198 LOG_COMMON(FATAL) << "Unresolved fatal";
199 UNREACHABLE_CC();
200 }
201
202 } // namespace common
203