1/*
2 * Copyright (c) 2024 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
16#ifndef ECMASCRIPT_CHECKPOINT_THREAD_STATE_TRANSITION_H
17#define ECMASCRIPT_CHECKPOINT_THREAD_STATE_TRANSITION_H
18
19#include "ecmascript/runtime.h"
20
21namespace panda::ecmascript {
22
23template<typename T, ThreadState newState>
24class ThreadStateTransitionScope final {
25    static_assert(std::is_base_of_v<JSThread, T>);
26    static_assert(!std::is_same_v<JitThread, T>);
27public:
28    explicit ThreadStateTransitionScope(T* self)
29        : self_(self)
30        {
31            ASSERT(self_ != nullptr);
32            oldState_ = self_->GetState();
33            if constexpr (std::is_same_v<DaemonThread, T>) {
34                if (oldState_ != newState) {
35                    ASSERT(hasSwitchState_ == false);
36                    hasSwitchState_ = true;
37                    if constexpr (newState == ThreadState::RUNNING) {
38                        self_->TransferDaemonThreadToRunning();
39                    } else {
40                        self_->UpdateState(newState);
41                    }
42                }
43            } else {
44#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
45                auto vm = self_->GetEcmaVM();
46                bool isCollectingStats = vm->IsCollectingScopeLockStats();
47                if (isCollectingStats) {
48                    vm->IncreaseEnterThreadManagedScopeCount();
49                }
50#endif
51                if (oldState_ != newState) {
52#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
53                    if (isCollectingStats) {
54                        vm->IncreaseUpdateThreadStateTransCount();
55                    }
56#endif
57                    ASSERT(hasSwitchState_ == false);
58                    hasSwitchState_ = true;
59                    self_->UpdateState(newState);
60                }
61            }
62        }
63
64    ~ThreadStateTransitionScope()
65    {
66        if (hasSwitchState_) {
67            if constexpr (std::is_same_v<DaemonThread, T>) {
68                if (oldState_ == ThreadState::RUNNING) {
69                    self_->TransferDaemonThreadToRunning();
70                } else {
71                    self_->UpdateState(oldState_);
72                }
73            } else {
74                self_->UpdateState(oldState_);
75            }
76        }
77    }
78
79private:
80    T* self_;
81    ThreadState oldState_;
82    bool hasSwitchState_ {false};
83    NO_COPY_SEMANTIC(ThreadStateTransitionScope);
84};
85
86class ThreadSuspensionScope final {
87public:
88    explicit ThreadSuspensionScope(JSThread* self) : scope_(self)
89    {
90        ASSERT(self->GetState() == ThreadState::IS_SUSPENDED);
91    }
92
93    ~ThreadSuspensionScope() = default;
94
95private:
96    ThreadStateTransitionScope<JSThread, ThreadState::IS_SUSPENDED> scope_;
97    NO_COPY_SEMANTIC(ThreadSuspensionScope);
98};
99
100class ThreadNativeScope final {
101public:
102    explicit ThreadNativeScope(JSThread* self) : scope_(self)
103    {
104        ASSERT(self->GetState() == ThreadState::NATIVE);
105    }
106
107    ~ThreadNativeScope() = default;
108
109private:
110    ThreadStateTransitionScope<JSThread, ThreadState::NATIVE> scope_;
111    NO_COPY_SEMANTIC(ThreadNativeScope);
112};
113
114template<typename T>
115class ThreadManagedScope final {
116    static_assert(std::is_base_of_v<JSThread, T>);
117    static_assert(!std::is_same_v<JitThread, T>);
118public:
119    explicit ThreadManagedScope(T* self) : scope_(self) {}
120
121    ~ThreadManagedScope() = default;
122
123private:
124    ThreadStateTransitionScope<T, ThreadState::RUNNING> scope_;
125    NO_COPY_SEMANTIC(ThreadManagedScope);
126};
127
128template<typename T>
129class SuspendAllScope final {
130    static_assert(std::is_base_of_v<JSThread, T>);
131    static_assert(!std::is_same_v<JitThread, T>);
132public:
133    explicit SuspendAllScope(T* self)
134        : self_(self), scope_(self)
135    {
136        TRACE_GC(GCStats::Scope::ScopeId::SuspendAll, SharedHeap::GetInstance()->GetEcmaGCStats());
137        ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SuspendAll");
138        Runtime::GetInstance()->SuspendAll(self_);
139    }
140    ~SuspendAllScope()
141    {
142        TRACE_GC(GCStats::Scope::ScopeId::ResumeAll, SharedHeap::GetInstance()->GetEcmaGCStats());
143        ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "ResumeAll");
144        Runtime::GetInstance()->ResumeAll(self_);
145    }
146private:
147    T* self_;
148    ThreadStateTransitionScope<T, ThreadState::IS_SUSPENDED> scope_;
149    NO_COPY_SEMANTIC(SuspendAllScope);
150};
151}  // namespace panda::ecmascript
152#endif  // ECMASCRIPT_CHECKPOINT_THREAD_STATE_TRANSITION_H
153