1 /*
2 * Copyright (c) 2022 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 "ecmascript/runtime.h"
16
17 namespace panda::ecmascript {
UpdateWithoutEden(const JSThread *thread, uintptr_t slotAddr, Region *objectRegion, TaggedObject *value, Region *valueRegion, WriteBarrierType writeType)18 void Barriers::UpdateWithoutEden(const JSThread *thread, uintptr_t slotAddr, Region *objectRegion, TaggedObject *value,
19 Region *valueRegion, WriteBarrierType writeType)
20 {
21 ASSERT(!valueRegion->InSharedHeap());
22 auto heap = thread->GetEcmaVM()->GetHeap();
23 if (heap->IsConcurrentFullMark()) {
24 if (valueRegion->InCollectSet() && !objectRegion->InGeneralNewSpaceOrCSet()) {
25 objectRegion->AtomicInsertCrossRegionRSet(slotAddr);
26 }
27 } else {
28 if (!valueRegion->InYoungSpace()) {
29 return;
30 }
31 }
32
33 // Weak ref record and concurrent mark record maybe conflict.
34 // This conflict is solved by keeping alive weak reference. A small amount of floating garbage may be added.
35 TaggedObject *heapValue = JSTaggedValue(value).GetHeapObject();
36 if (valueRegion->IsFreshRegion()) {
37 valueRegion->NonAtomicMark(heapValue);
38 } else if (writeType != WriteBarrierType::DESERIALIZE && valueRegion->AtomicMark(heapValue)) {
39 heap->GetWorkManager()->Push(MAIN_THREAD_INDEX, heapValue);
40 }
41 }
42
Update(const JSThread *thread, uintptr_t slotAddr, Region *objectRegion, TaggedObject *value, Region *valueRegion, WriteBarrierType writeType)43 void Barriers::Update(const JSThread *thread, uintptr_t slotAddr, Region *objectRegion, TaggedObject *value,
44 Region *valueRegion, WriteBarrierType writeType)
45 {
46 if (valueRegion->InSharedHeap()) {
47 return;
48 }
49 auto heap = thread->GetEcmaVM()->GetHeap();
50 if (heap->IsConcurrentFullMark()) {
51 if (valueRegion->InCollectSet() && !objectRegion->InGeneralNewSpaceOrCSet()) {
52 objectRegion->AtomicInsertCrossRegionRSet(slotAddr);
53 }
54 } else if (heap->IsYoungMark()) {
55 if (!valueRegion->InGeneralNewSpace()) {
56 return;
57 }
58 } else {
59 if (!valueRegion->InEdenSpace()) {
60 return;
61 }
62 }
63
64 // Weak ref record and concurrent mark record maybe conflict.
65 // This conflict is solved by keeping alive weak reference. A small amount of floating garbage may be added.
66 TaggedObject *heapValue = JSTaggedValue(value).GetHeapObject();
67 if (valueRegion->IsFreshRegion()) {
68 valueRegion->NonAtomicMark(heapValue);
69 } else if (writeType != WriteBarrierType::DESERIALIZE && valueRegion->AtomicMark(heapValue)) {
70 heap->GetWorkManager()->Push(MAIN_THREAD_INDEX, heapValue);
71 }
72 }
73
UpdateShared(const JSThread *thread, TaggedObject *value, Region *valueRegion)74 void Barriers::UpdateShared(const JSThread *thread, TaggedObject *value, Region *valueRegion)
75 {
76 ASSERT(DaemonThread::GetInstance()->IsConcurrentMarkingOrFinished());
77 ASSERT(valueRegion->InSharedSweepableSpace());
78
79 // Weak ref record and concurrent mark record maybe conflict.
80 // This conflict is solved by keeping alive weak reference. A small amount of floating garbage may be added.
81 TaggedObject *heapValue = JSTaggedValue(value).GetHeapObject();
82 if (valueRegion->AtomicMark(heapValue)) {
83 Heap *heap = const_cast<Heap*>(thread->GetEcmaVM()->GetHeap());
84 WorkNode *&localBuffer = heap->GetMarkingObjectLocalBuffer();
85 SharedHeap::GetInstance()->GetWorkManager()->PushToLocalMarkingBuffer(localBuffer, heapValue);
86 }
87 }
88
89
90 template <Region::RegionSpaceKind kind>
BatchBitSet([[maybe_unused]] const JSThread* thread, Region* objectRegion, JSTaggedValue* dst, size_t count)91 ARK_NOINLINE bool BatchBitSet([[maybe_unused]] const JSThread* thread, Region* objectRegion, JSTaggedValue* dst,
92 size_t count)
93 {
94 bool allValueNotHeap = true;
95 Region::Updater updater = objectRegion->GetBatchRSetUpdater<kind>(ToUintPtr(dst));
96 for (size_t i = 0; i < count; i++, updater.Next()) {
97 JSTaggedValue taggedValue = dst[i];
98 if (!taggedValue.IsHeapObject()) {
99 continue;
100 }
101 allValueNotHeap = false;
102 const Region* valueRegion = Region::ObjectAddressToRange(taggedValue.GetTaggedObject());
103 #if ECMASCRIPT_ENABLE_BARRIER_CHECK
104 ASSERT(taggedValue.GetRawData() != JSTaggedValue::VALUE_UNDEFINED);
105 if (!thread->GetEcmaVM()->GetHeap()->IsAlive(taggedValue.GetHeapObject())) {
106 LOG_FULL(FATAL) << "WriteBarrier checked value:" << taggedValue.GetRawData() << " is invalid!";
107 }
108 #endif
109 if (valueRegion->InSharedSweepableSpace()) {
110 #ifndef NDEBUG
111 if (UNLIKELY(taggedValue.IsWeakForHeapObject())) {
112 CHECK_NO_LOCAL_TO_SHARE_WEAK_REF_HANDLE;
113 }
114 #endif
115 updater.UpdateLocalToShare();
116 continue;
117 }
118 if constexpr (kind == Region::InYoung) {
119 if (valueRegion->InEdenSpace()) {
120 updater.UpdateNewToEden();
121 continue;
122 }
123 } else if constexpr (kind == Region::InGeneralOld) {
124 if (valueRegion->InGeneralNewSpace()) {
125 updater.UpdateOldToNew();
126 continue;
127 }
128 }
129 }
130 return allValueNotHeap;
131 }
132
133 template bool BatchBitSet<Region::InYoung>(const JSThread*, Region*, JSTaggedValue*, size_t);
134 template bool BatchBitSet<Region::InGeneralOld>(const JSThread*, Region*, JSTaggedValue*, size_t);
135 template bool BatchBitSet<Region::Other>(const JSThread*, Region*, JSTaggedValue*, size_t);
136
137 } // namespace panda::ecmascript
138