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 17namespace panda::ecmascript { 18void 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 43void 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 74void 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 90template <Region::RegionSpaceKind kind> 91ARK_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 133template bool BatchBitSet<Region::InYoung>(const JSThread*, Region*, JSTaggedValue*, size_t); 134template bool BatchBitSet<Region::InGeneralOld>(const JSThread*, Region*, JSTaggedValue*, size_t); 135template bool BatchBitSet<Region::Other>(const JSThread*, Region*, JSTaggedValue*, size_t); 136 137} // namespace panda::ecmascript 138