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/enum_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* EnumBarrier::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* EnumBarrier::ReadStaticRef(RefField<false>& field) const { return ReadRefField(nullptr, field); }
32
ReadStruct(HeapAddress dst,BaseObject * obj,HeapAddress src,size_t size) const33 void EnumBarrier::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 EnumBarrier::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 EnumBarrier::WriteRefField(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
47 {
48 UpdateRememberSet(obj, ref);
49 RefField<> tmpField(field);
50 BaseObject* remeberedObject = nullptr;
51 remeberedObject = tmpField.GetTargetObject();
52 Mutator* mutator = Mutator::GetMutator();
53 if (remeberedObject != nullptr) {
54 mutator->RememberObjectInSatbBuffer(remeberedObject);
55 }
56 if (ref != nullptr) { //LCOV_EXCL_BR_LINE
57 mutator->RememberObjectInSatbBuffer(ref);
58 }
59 DLOG(BARRIER, "write obj %p ref@%p: 0x%zx -> %p", obj, &field, remeberedObject, ref);
60 std::atomic_thread_fence(std::memory_order_seq_cst);
61 RefField<> newField(ref);
62 field.SetFieldValue(newField.GetFieldValue());
63 }
64 #ifdef ARK_USE_SATB_BARRIER
WriteBarrier(BaseObject * obj,RefField<false> & field,BaseObject * ref) const65 void EnumBarrier::WriteBarrier(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
66 {
67 RefField<> tmpField(field);
68 BaseObject* remeberedObject = nullptr;
69 //Because it is possible to read a Double,
70 // and the lower 48 bits happen to be a HeapAddress, we need to avoid this situation
71 if (!Heap::IsTaggedObject(field.GetFieldValue())) {
72 return;
73 }
74 UpdateRememberSet(obj, ref);
75 remeberedObject = tmpField.GetTargetObject();
76 Mutator* mutator = Mutator::GetMutator();
77 if (remeberedObject != nullptr) {
78 mutator->RememberObjectInSatbBuffer(remeberedObject);
79 }
80 if (ref != nullptr) {
81 // Wait Conccurent Enum Fix
82 // ref maybe not valid
83 // mutator->RememberObjectInSatbBuffer(ref)
84 }
85 DLOG(BARRIER, "write obj %p ref@%p: 0x%zx -> %p", obj, &field, remeberedObject, ref);
86 }
87 #else
WriteBarrier(BaseObject * obj,RefField<false> & field,BaseObject * ref) const88 void EnumBarrier::WriteBarrier(BaseObject* obj, RefField<false>& field, BaseObject* ref) const
89 {
90 if (!Heap::IsTaggedObject((HeapAddress)ref)) {
91 return;
92 }
93 if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) {
94 UpdateRememberSet(obj, ref);
95 }
96 ref = (BaseObject*)((uintptr_t)ref & ~(TAG_WEAK));
97 Mutator* mutator = Mutator::GetMutator();
98 mutator->RememberObjectInSatbBuffer(ref);
99 DLOG(BARRIER, "write obj %p ref-field@%p: -> %p", obj, &field, ref);
100 }
101 #endif
WriteStaticRef(RefField<false> & field,BaseObject * ref) const102 void EnumBarrier::WriteStaticRef(RefField<false>& field, BaseObject* ref) const
103 {
104 DLOG(BARRIER, "write static ref@%p: %p -|> %p", &field, field.GetTargetObject(), ref);
105 WriteRefField(nullptr, field, ref);
106 }
107
WriteStruct(BaseObject * obj,HeapAddress dst,size_t dstLen,HeapAddress src,size_t srcLen) const108 void EnumBarrier::WriteStruct(BaseObject* obj, HeapAddress dst, size_t dstLen, HeapAddress src, size_t srcLen) const
109 {
110 if (obj != nullptr) {
111 ASSERT_LOGF(dst > reinterpret_cast<HeapAddress>(obj), "WriteStruct struct addr is less than obj!");
112 Mutator* mutator = Mutator::GetMutator();
113 obj->ForEachRefInStruct(
114 [=](RefField<>& dstField) {
115 mutator->RememberObjectInSatbBuffer(ReadRefField(obj, dstField));
116 HeapAddress offset = reinterpret_cast<HeapAddress>(&dstField) - dst;
117 RefField<>* srcField = reinterpret_cast<RefField<>*>(src + offset);
118 mutator->RememberObjectInSatbBuffer(ReadRefField(nullptr, *srcField));
119 },
120 dst, dst + srcLen);
121 }
122 std::atomic_thread_fence(std::memory_order_seq_cst);
123 LOGF_CHECK(memcpy_s(reinterpret_cast<void*>(dst), dstLen, reinterpret_cast<void*>(src), srcLen) == EOK) <<
124 "memcpy_s failed";
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* EnumBarrier::AtomicReadRefField(BaseObject* obj, RefField<true>& field, MemoryOrder order) const
132 {
133 BaseObject* target = nullptr;
134 RefField<false> oldField(field.GetFieldValue(order));
135 target = ReadRefField(obj, oldField);
136 DLOG(EBARRIER, "atomic read obj %p ref@%p: %#zx -> %p", obj, &field, oldField.GetFieldValue(), target);
137 return target;
138 }
139
AtomicSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const140 BaseObject* EnumBarrier::AtomicSwapRefField(BaseObject* obj, RefField<true>& field, BaseObject* newRef,
141 MemoryOrder order) const
142 {
143 RefField<> newField(newRef);
144 HeapAddress oldValue = field.Exchange(newField.GetFieldValue(), order);
145 RefField<> oldField(oldValue);
146 BaseObject* oldRef = oldField.GetTargetObject();
147 Mutator* mutator = Mutator::GetMutator();
148 mutator->RememberObjectInSatbBuffer(oldRef);
149 mutator->RememberObjectInSatbBuffer(newRef);
150 DLOG(BARRIER, "atomic swap obj %p<%p>(%zu) ref@%p: old %#zx(%p), new %#zx(%p)", obj, obj->GetTypeInfo(),
151 obj->GetSize(), &field, oldValue, oldRef, field.GetFieldValue(), newRef);
152 return oldRef;
153 }
154
AtomicWriteRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const155 void EnumBarrier::AtomicWriteRefField(BaseObject* obj, RefField<true>& field, BaseObject* newRef,
156 MemoryOrder order) const
157 {
158 RefField<> oldField(field.GetFieldValue(order));
159 HeapAddress oldValue = oldField.GetFieldValue();
160 (void)oldValue;
161 BaseObject* oldRef = oldField.GetTargetObject();
162 RefField<> newField(newRef);
163 field.SetFieldValue(newField.GetFieldValue(), order);
164 Mutator* mutator = Mutator::GetMutator();
165 mutator->RememberObjectInSatbBuffer(oldRef);
166 mutator->RememberObjectInSatbBuffer(newRef);
167 if (obj != nullptr) {
168 DLOG(EBARRIER, "atomic write obj %p<%p>(%zu) ref@%p: %#zx -> %#zx", obj, obj->GetTypeInfo(), obj->GetSize(),
169 &field, oldValue, newField.GetFieldValue());
170 } else {
171 DLOG(EBARRIER, "atomic write static ref@%p: %#zx -> %#zx", &field, oldValue, newField.GetFieldValue());
172 }
173 }
174
CompareAndSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * oldRef,BaseObject * newRef,MemoryOrder sOrder,MemoryOrder fOrder) const175 bool EnumBarrier::CompareAndSwapRefField(BaseObject* obj, RefField<true>& field, BaseObject* oldRef,
176 BaseObject* newRef, MemoryOrder sOrder, MemoryOrder fOrder) const
177 {
178 RefField<> newField(newRef);
179 HeapAddress oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
180 RefField<false> oldField(oldFieldValue);
181 BaseObject* oldVersion = oldField.GetTargetObject();
182
183 while (oldVersion == oldRef) {
184 if (field.CompareExchange(oldFieldValue, newField.GetFieldValue(), sOrder, fOrder)) {
185 Mutator* mutator = Mutator::GetMutator();
186 mutator->RememberObjectInSatbBuffer(oldRef);
187 mutator->RememberObjectInSatbBuffer(newRef);
188 return true;
189 }
190 oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
191 RefField<false> tmp(oldFieldValue);
192 oldVersion = tmp.GetTargetObject();
193 }
194
195 return false;
196 }
197
CopyStructArray(BaseObject * dstObj,HeapAddress dstField,MIndex dstSize,BaseObject * srcObj,HeapAddress srcField,MIndex srcSize) const198 void EnumBarrier::CopyStructArray(BaseObject* dstObj, HeapAddress dstField, MIndex dstSize, BaseObject* srcObj,
199 HeapAddress srcField, MIndex srcSize) const
200 {
201 LOG_COMMON(FATAL) << "Unresolved fatal";
202 UNREACHABLE_CC();
203 }
204
205 } // namespace common
206