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/allocator/region_space.h"
16 #include "common_components/heap/ark_collector/copy_barrier.h"
17 #include "common_components/base/sys_call.h"
18 #include "common_components/common/scoped_object_lock.h"
19 #include "common_components/mutator/mutator.h"
20 #include "heap/collector/collector_proxy.h"
21 #if defined(COMMON_TSAN_SUPPORT)
22 #include "common_components/sanitizer/sanitizer_interface.h"
23 #endif
24
25 namespace common {
ReadRefField(BaseObject * obj,RefField<false> & field) const26 BaseObject* CopyBarrier::ReadRefField(BaseObject* obj, RefField<false>& field) const
27 {
28 do {
29 RefField<> tmpField(field);
30 BaseObject* oldRef = reinterpret_cast<BaseObject *>(tmpField.GetAddress());
31 if (LIKELY_CC(!static_cast<CollectorProxy *>(&theCollector)->IsFromObject(oldRef))) {
32 return oldRef;
33 }
34
35 auto weakMask = reinterpret_cast<MAddress>(oldRef) & TAG_WEAK;
36 oldRef = reinterpret_cast<BaseObject *>(reinterpret_cast<MAddress>(oldRef) & (~TAG_WEAK));
37 BaseObject* toObj = nullptr;
38 if (static_cast<CollectorProxy *>(&theCollector)->TryForwardRefField(obj, field, toObj)) {
39 return (BaseObject*)((uintptr_t)toObj | weakMask);
40 }
41 } while (true);
42 // unreachable path.
43 return nullptr;
44 }
45
ReadStaticRef(RefField<false> & field) const46 BaseObject* CopyBarrier::ReadStaticRef(RefField<false>& field) const { return ReadRefField(nullptr, field); }
47
48 // If the object is still alive, return its toSpace object; if not, return nullptr
ReadStringTableStaticRef(RefField<false> & field) const49 BaseObject* CopyBarrier::ReadStringTableStaticRef(RefField<false>& field) const
50 {
51 // Note: CMC GC assumes all objects in string table are not in young space. Based on the assumption, CMC GC skip
52 // read barrier in young GC
53 if (Heap::GetHeap().GetGCReason() == GC_REASON_YOUNG) {
54 return reinterpret_cast<BaseObject*>(field.GetFieldValue());
55 }
56
57 auto isSurvivor = [](BaseObject* obj) {
58 RegionDesc *regionInfo = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj));
59 return (regionInfo->IsNewObjectSinceMarking(obj) ||
60 regionInfo->IsToRegion() || regionInfo->IsMarkedObject(obj));
61 };
62
63 RefField<> tmpField(field);
64 BaseObject* obj = tmpField.GetTargetObject();
65 if (obj != nullptr && isSurvivor(obj)) {
66 return ReadRefField(nullptr, field);
67 } else {
68 return nullptr;
69 }
70 }
71
ReadStruct(HeapAddress dst,BaseObject * obj,HeapAddress src,size_t size) const72 void CopyBarrier::ReadStruct(HeapAddress dst, BaseObject* obj, HeapAddress src, size_t size) const
73 {
74 CHECK_CC(!Heap::IsHeapAddress(dst));
75 if (obj != nullptr) { //LCOV_EXCL_BR_LINE
76 obj->ForEachRefInStruct(
77 [this, obj](RefField<false>& field) {
78 BaseObject* target = ReadRefField(obj, field);
79 (void)target;
80 },
81 src, src + size);
82 }
83 CHECK_CC(memcpy_s(reinterpret_cast<void*>(dst), size, reinterpret_cast<void*>(src), size) == EOK);
84 }
85
AtomicReadRefField(BaseObject * obj,RefField<true> & field,MemoryOrder order) const86 BaseObject* CopyBarrier::AtomicReadRefField(BaseObject* obj, RefField<true>& field, MemoryOrder order) const
87 {
88 RefField<false> tmpField(field.GetFieldValue(order));
89 BaseObject* target = ReadRefField(nullptr, tmpField);
90 DLOG(FBARRIER, "atomic read obj %p ref-field@%p: %#zx -> %p", obj, &field, tmpField.GetFieldValue(), target);
91 return target;
92 }
93
AtomicWriteRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const94 void CopyBarrier::AtomicWriteRefField(BaseObject* obj, RefField<true>& field, BaseObject* newRef,
95 MemoryOrder order) const
96 {
97 RefField<> newField(newRef);
98 field.SetFieldValue(newField.GetFieldValue(), order);
99 if (obj != nullptr) { //LCOV_EXCL_BR_LINE
100 DLOG(FBARRIER, "atomic write obj %p<%p>(%zu) ref@%p: %#zx", obj, obj->GetTypeInfo(), obj->GetSize(), &field,
101 newField.GetFieldValue());
102 } else { //LCOV_EXCL_BR_LINE
103 DLOG(FBARRIER, "atomic write static ref@%p: %#zx", &field, newField.GetFieldValue());
104 }
105 }
106
AtomicSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * newRef,MemoryOrder order) const107 BaseObject* CopyBarrier::AtomicSwapRefField(BaseObject* obj, RefField<true>& field, BaseObject* newRef,
108 MemoryOrder order) const
109 {
110 HeapAddress oldValue = field.Exchange(newRef, order);
111 RefField<> oldField(oldValue);
112 BaseObject* oldRef = ReadRefField(nullptr, oldField);
113 DLOG(BARRIER, "atomic swap obj %p<%p>(%zu) ref-field@%p: old %#zx(%p), new %#zx(%p)", obj, obj->GetTypeInfo(),
114 obj->GetSize(), &field, oldValue, oldRef, field.GetFieldValue(), newRef);
115 return oldRef;
116 }
117
CompareAndSwapRefField(BaseObject * obj,RefField<true> & field,BaseObject * oldRef,BaseObject * newRef,MemoryOrder succOrder,MemoryOrder failOrder) const118 bool CopyBarrier::CompareAndSwapRefField(BaseObject* obj, RefField<true>& field, BaseObject* oldRef,
119 BaseObject* newRef, MemoryOrder succOrder, MemoryOrder failOrder) const
120 {
121 HeapAddress oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
122 RefField<false> oldField(oldFieldValue);
123 BaseObject* oldVersion = ReadRefField(nullptr, oldField);
124 while (oldVersion == oldRef) { //LCOV_EXCL_BR_LINE
125 RefField<> newField(newRef);
126 if (field.CompareExchange(oldFieldValue, newField.GetFieldValue(), succOrder, failOrder)) { //LCOV_EXCL_BR_LINE
127 return true;
128 }
129 oldFieldValue = field.GetFieldValue(std::memory_order_seq_cst);
130 RefField<false> tmp(oldFieldValue);
131 oldVersion = ReadRefField(nullptr, tmp);
132 }
133
134 return false;
135 }
136
CopyStructArray(BaseObject * dstObj,HeapAddress dstField,MIndex dstSize,BaseObject * srcObj,HeapAddress srcField,MIndex srcSize) const137 void CopyBarrier::CopyStructArray(BaseObject* dstObj, HeapAddress dstField, MIndex dstSize, BaseObject* srcObj,
138 HeapAddress srcField, MIndex srcSize) const
139 {
140 LOG_COMMON(FATAL) << "Unresolved fatal";
141 UNREACHABLE_CC();
142 }
143 } // namespace common
144