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