• 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/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