* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cstdint>
#include <stack>
#include <unistd.h>
#include "common_components/common_runtime/hooks.h"
#include "common_components/common/type_def.h"
#if defined(_WIN64)
#define NOGDI
#include <windows.h>
#endif
#include "common_components/heap/allocator/region_manager.h"
#include "common_components/heap/collector/marking_collector.h"
#include "common_components/common/scoped_object_access.h"
#include "common_components/mutator/mutator_manager.h"
namespace common {
ThreadLocalData *GetThreadLocalData()
{
uintptr_t tlDataAddr = reinterpret_cast<uintptr_t>(ThreadLocal::GetThreadLocalData());
#if defined(__aarch64__)
if (Heap::GetHeap().IsGcStarted()) {
tlDataAddr = tlDataAddr | (static_cast<uint64_t>(Heap::GetHeap().GetGCPhase()) << 56);
}
#endif
return reinterpret_cast<ThreadLocalData *>(tlDataAddr);
}
bool MutatorBase::TransitionGCPhase(bool bySelf)
{
do {
GCPhaseTransitionState state = transitionState_.load();
if (state == FINISH_TRANSITION) {
bool result = mutatorPhase_.load() == Heap::GetHeap().GetGCPhase();
#ifndef CMC_LCOV_EXCL
if (!bySelf && !result) {
LOG_COMMON(FATAL) << "Unresolved fatal";
UNREACHABLE_CC();
}
#endif
return result;
}
#ifndef CMC_LCOV_EXCL
if (state == IN_TRANSITION) {
if (bySelf) {
WaitForPhaseTransition();
return true;
} else {
return false;
}
}
#endif
if (!bySelf && state == NO_TRANSITION) {
return true;
}
CHECK_CC(state == NEED_TRANSITION);
if (transitionState_.compare_exchange_weak(state, IN_TRANSITION)) {
TransitionToGCPhaseExclusive(Heap::GetHeap().GetGCPhase());
transitionState_.store(FINISH_TRANSITION, std::memory_order_release);
return true;
}
} while (true);
}
void MutatorBase::HandleSuspensionRequest()
{
for (;;) {
SetInSaferegion(SAFE_REGION_TRUE);
if (HasSuspensionRequest(SUSPENSION_FOR_STW)) {
SuspendForStw();
if (HasSuspensionRequest(SUSPENSION_FOR_GC_PHASE)) {
TransitionGCPhase(true);
} else if (HasSuspensionRequest(SUSPENSION_FOR_CPU_PROFILE)) {
TransitionToCpuProfile(true);
}
} else if (HasSuspensionRequest(SUSPENSION_FOR_GC_PHASE)) {
TransitionGCPhase(true);
} else if (HasSuspensionRequest(SUSPENSION_FOR_CPU_PROFILE)) {
TransitionToCpuProfile(true);
} else if (HasSuspensionRequest(SUSPENSION_FOR_EXIT)) {
while (true) {
sleep(INT_MAX);
}
} else if (HasSuspensionRequest(SUSPENSION_FOR_PENDING_CALLBACK)) {
reinterpret_cast<Mutator*>(mutator_)->TryRunFlipFunction();
} else if (HasSuspensionRequest(SUSPENSION_FOR_RUNNING_CALLBACK)) {
reinterpret_cast<Mutator*>(mutator_)->WaitFlipFunctionFinish();
}
SetInSaferegion(SAFE_REGION_FALSE);
if (LIKELY_CC(!HasAnySuspensionRequestExceptCallbacks() && !HasObserver())) {
if (HasSuspensionRequest(SUSPENSION_FOR_FINALIZE)) {
ClearFinalizeRequest();
HandleJSGCCallback();
}
return;
}
}
}
void MutatorBase::HandleJSGCCallback()
{
#ifndef CMC_LCOV_EXCL
if (mutator_ != nullptr) {
void *vm = reinterpret_cast<Mutator*>(mutator_)->GetEcmaVMPtr();
if (vm != nullptr) {
JSGCCallback(vm);
}
}
#endif
}
void MutatorBase::SuspendForStw()
{
ClearSuspensionFlag(SUSPENSION_FOR_STW);
int curCount = static_cast<int>(MutatorManager::Instance().GetStwFutexWordValue());
if (curCount > 0) {
#if defined(_WIN64) || defined(__APPLE__)
MutatorManager::Instance().MutatorWait();
#else
int* countAddr = MutatorManager::Instance().GetStwFutexWord();
(void)Futex(countAddr, FUTEX_WAIT, curCount);
#endif
}
SetInSaferegion(SAFE_REGION_FALSE);
if (MutatorManager::Instance().StwTriggered()) {
SetSuspensionFlag(SUSPENSION_FOR_STW);
}
}
#if defined(GCINFO_DEBUG) && GCINFO_DEBUG
void Mutator::CreateCurrentGCInfo() { gcInfos_.CreateCurrentGCInfo(); }
#endif
void Mutator::VisitRawObjects(const RootVisitor& func)
{
if (rawObject_.object != nullptr) {
func(rawObject_);
}
}
Mutator* Mutator::GetMutator() noexcept
{
return ThreadLocal::GetMutator();
}
inline void CheckAndPush(BaseObject* obj, std::set<BaseObject*>& rootSet, std::stack<BaseObject*>& rootStack)
{
auto search = rootSet.find(obj);
if (search == rootSet.end()) {
rootSet.insert(obj);
if (obj->IsValidObject() && obj->HasRefField()) {
rootStack.push(obj);
}
}
}
inline void MutatorBase::GcPhaseEnum(GCPhase newPhase)
{
}
inline void MutatorBase::GCPhasePreForward(GCPhase newPhase)
{
}
inline void MutatorBase::HandleGCPhase(GCPhase newPhase)
{
if (newPhase == GCPhase::GC_PHASE_POST_MARK) {
std::lock_guard<std::mutex> lg(mutatorBaseLock_);
Mutator *actMutator = reinterpret_cast<Mutator*>(mutator_);
if (actMutator->satbNode_ != nullptr) {
DCHECK_CC(actMutator->satbNode_->IsEmpty());
SatbBuffer::Instance().RetireNode(actMutator->satbNode_);
actMutator->satbNode_ = nullptr;
}
} else if (newPhase == GCPhase::GC_PHASE_ENUM) {
GcPhaseEnum(newPhase);
} else if (newPhase == GCPhase::GC_PHASE_PRECOPY) {
GCPhasePreForward(newPhase);
} else if (newPhase == GCPhase::GC_PHASE_REMARK_SATB || newPhase == GCPhase::GC_PHASE_FINAL_MARK) {
std::lock_guard<std::mutex> lg(mutatorBaseLock_);
Mutator *actMutator = reinterpret_cast<Mutator*>(mutator_);
if (actMutator->satbNode_ != nullptr) {
SatbBuffer::Instance().RetireNode(actMutator->satbNode_);
actMutator->satbNode_ = nullptr;
}
}
}
void MutatorBase::TransitionToGCPhaseExclusive(GCPhase newPhase)
{
HandleGCPhase(newPhase);
SetSafepointActive(false);
mutatorPhase_.store(newPhase, std::memory_order_relaxed);
if (jsThread_ != nullptr) {
SynchronizeGCPhaseToJSThread(jsThread_, newPhase);
}
ClearSuspensionFlag(SUSPENSION_FOR_GC_PHASE);
}
inline void MutatorBase::HandleCpuProfile()
{
LOG_COMMON(FATAL) << "Unresolved fatal";
UNREACHABLE_CC();
}
void MutatorBase::TransitionToCpuProfileExclusive()
{
HandleCpuProfile();
SetSafepointActive(false);
ClearSuspensionFlag(SUSPENSION_FOR_CPU_PROFILE);
}
void PreRunManagedCode(Mutator* mutator, int layers, ThreadLocalData* threadData)
{
if (UNLIKELY_CC(MutatorManager::Instance().StwTriggered())) {
mutator->SetSuspensionFlag(Mutator::SuspensionType::SUSPENSION_FOR_STW);
mutator->EnterSaferegion(false);
}
mutator->LeaveSaferegion();
mutator->SetMutatorPhase(Heap::GetHeap().GetGCPhase());
}
}