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