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 21 namespace panda::ecmascript { 22 23 template<typename T, ThreadState newState> 24 class ThreadStateTransitionScope final { 25 static_assert(std::is_base_of_v<JSThread, T>); 26 static_assert(!std::is_same_v<JitThread, T>); 27 public: ThreadStateTransitionScope(T * self)28 explicit ThreadStateTransitionScope(T* self) 29 : self_(self) 30 { 31 ASSERT(self_ != nullptr); 32 if (LIKELY(!self_->IsEnableCMCGC())) { 33 if constexpr (std::is_same_v<DaemonThread, T>) { 34 oldState_ = self_->GetState(); 35 if (oldState_ != newState) { 36 ASSERT(hasSwitchState_ == false); 37 hasSwitchState_ = true; 38 if constexpr (newState == ThreadState::RUNNING) { 39 self_->TransferDaemonThreadToRunning(); 40 } else { 41 self_->UpdateState(newState); 42 } 43 } 44 } else { 45 #if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT 46 auto vm = self_->GetEcmaVM(); 47 bool isCollectingStats = vm->IsCollectingScopeLockStats(); 48 if (isCollectingStats) { 49 vm->IncreaseEnterThreadManagedScopeCount(); 50 } 51 #endif 52 if constexpr (newState == ThreadState::RUNNING) { 53 oldState_ = self_->TransferToRunningIfNonRunning(); 54 } else { 55 oldState_ = self_->TransferToNonRunning(newState); 56 } 57 ASSERT(hasSwitchState_ == false); 58 hasSwitchState_ = oldState_ != newState; 59 #if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT 60 if (hasSwitchState_) { 61 if (isCollectingStats) { 62 vm->IncreaseUpdateThreadStateTransCount(); 63 } 64 } 65 #endif 66 } 67 } else { 68 isEnbaleCMCGC_ = true; 69 if constexpr (newState == ThreadState::RUNNING) { 70 hasSwitchState_ = self_->GetThreadHolder()->TransferToRunningIfInNative(); 71 } else { 72 hasSwitchState_ = self_->GetThreadHolder()->TransferToNativeIfInRunning(); 73 } 74 } 75 } 76 ~ThreadStateTransitionScope()77 ~ThreadStateTransitionScope() 78 { 79 if (LIKELY(hasSwitchState_)) { 80 if (LIKELY(!isEnbaleCMCGC_)) { 81 if constexpr (std::is_same_v<DaemonThread, T>) { 82 if (oldState_ == ThreadState::RUNNING) { 83 self_->TransferDaemonThreadToRunning(); 84 } else { 85 self_->UpdateState(oldState_); 86 } 87 } else { 88 if constexpr (newState == ThreadState::RUNNING) { 89 self_->TransferToNonRunningInRunning(oldState_); 90 } else { 91 self_->TransferInNonRunning(oldState_); 92 } 93 } 94 } else { 95 if constexpr (newState == ThreadState::RUNNING) { 96 self_->GetThreadHolder()->TransferToNative(); 97 } else { 98 self_->GetThreadHolder()->TransferToRunning(); 99 } 100 } 101 } 102 } 103 104 private: 105 T* self_; 106 ThreadState oldState_; 107 uint32_t isEnbaleCMCGC_ {0}; 108 uint32_t hasSwitchState_ {0}; 109 NO_COPY_SEMANTIC(ThreadStateTransitionScope); 110 }; 111 112 class ThreadSuspensionScope final { 113 public: ThreadSuspensionScope(JSThread * self)114 explicit ThreadSuspensionScope(JSThread* self) : scope_(self) 115 { 116 ASSERT(!g_isEnableCMCGC || !self->IsInRunningState()); 117 ASSERT(g_isEnableCMCGC || self->GetState() == ThreadState::IS_SUSPENDED); 118 } 119 120 ~ThreadSuspensionScope() = default; 121 122 private: 123 ThreadStateTransitionScope<JSThread, ThreadState::IS_SUSPENDED> scope_; 124 NO_COPY_SEMANTIC(ThreadSuspensionScope); 125 }; 126 127 class ThreadNativeScope final { 128 public: ThreadNativeScope(JSThread * self)129 explicit ThreadNativeScope(JSThread* self) : scope_(self) 130 { 131 ASSERT(!self->IsInRunningState()); 132 } 133 134 ~ThreadNativeScope() = default; 135 136 private: 137 ThreadStateTransitionScope<JSThread, ThreadState::NATIVE> scope_; 138 NO_COPY_SEMANTIC(ThreadNativeScope); 139 }; 140 141 template<typename T> 142 class ThreadManagedScope final { 143 static_assert(std::is_base_of_v<JSThread, T>); 144 static_assert(!std::is_same_v<JitThread, T>); 145 public: ThreadManagedScope(T * self)146 explicit ThreadManagedScope(T* self) : scope_(self) {} 147 148 ~ThreadManagedScope() = default; 149 150 private: 151 ThreadStateTransitionScope<T, ThreadState::RUNNING> scope_; 152 NO_COPY_SEMANTIC(ThreadManagedScope); 153 }; 154 155 template<typename T> 156 class SuspendAllScope final { 157 static_assert(std::is_base_of_v<JSThread, T>); 158 static_assert(!std::is_same_v<JitThread, T>); 159 public: SuspendAllScope(T * self)160 explicit SuspendAllScope(T* self) 161 : self_(self), scope_(self) 162 { 163 TRACE_GC(GCStats::Scope::ScopeId::SuspendAll, SharedHeap::GetInstance()->GetEcmaGCStats()); 164 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "SuspendAll", ""); 165 Runtime::GetInstance()->SuspendAll(self_); 166 } ~SuspendAllScope()167 ~SuspendAllScope() 168 { 169 TRACE_GC(GCStats::Scope::ScopeId::ResumeAll, SharedHeap::GetInstance()->GetEcmaGCStats()); 170 ECMA_BYTRACE_NAME(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, "ResumeAll", ""); 171 Runtime::GetInstance()->ResumeAll(self_); 172 } 173 private: 174 T* self_; 175 ThreadStateTransitionScope<T, ThreadState::IS_SUSPENDED> scope_; 176 NO_COPY_SEMANTIC(SuspendAllScope); 177 }; 178 } // namespace panda::ecmascript 179 #endif // ECMASCRIPT_CHECKPOINT_THREAD_STATE_TRANSITION_H 180