#include "Base/Types.h"
#include "Common/TypeDef.h"
#if defined(_WIN64)
#define NOGDI
#include <windows.h>
#endif
#include "Collector/CopyCollector.h"
#include "Common/ScopedObjectAccess.h"
#include "Concurrency/ConcurrencyModel.h"
#include "ObjectModel/RefField.inline.h"
#include "MutatorManager.h"
#include "StackManager.h"
#include "ExceptionManager.h"
#include "schedule.h"
#ifdef _WIN64
#include "WinModuleManager.h"
#endif
#include "CpuProfiler/CpuProfiler.h"
#include "Base/LogFile.h"
#include "Interpreter/InterpreterSpecific.h"
namespace MapleRuntime {
extern "C" uintptr_t MRT_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 tlDataAddr;
}
extern "C" bool MRT_EnterSaferegion(bool updateUnwindContext)
{
Mutator* mutator = Mutator::GetMutator();
if (mutator == nullptr) {
return false;
}
return mutator->EnterSaferegion(updateUnwindContext);
}
extern "C" bool MRT_LeaveSaferegion()
{
Mutator* mutator = Mutator::GetMutator();
if (mutator == nullptr) {
return false;
}
return mutator->LeaveSaferegion();
}
extern "C" void MRT_SetGrowFlag(bool flag)
{
if (!CJThreadSetStackGrow(flag)) {
return;
}
LOG(RTLOG_ERROR, "Set flag of GROWStack faild.");
}
extern "C" intptr_t MRT_StackGrow(intptr_t frameBase, uint32_t adjustedSize, void* ip)
{
#ifdef __arm__
if (adjustedSize != 0) {
LOG(RTLOG_FAIL, "Unsupported stack grow for arm32");
}
uintptr_t threadData = MRT_GetThreadLocalData();
uint32_t protectAddr = reinterpret_cast<uint32_t>(reinterpret_cast<ThreadLocalData*>(threadData)->protectAddr);
constexpr uint32_t PRESERVE_SIZE = 256;
if (protectAddr >= frameBase - PRESERVE_SIZE) {
void* fa = __builtin_frame_address(0);
static_cast<FrameAddress*>(fa)->returnAddress = static_cast<uint32_t*>(ip);
ExceptionManager::StackOverflow(adjustedSize, ip);
return 0;
}
return 0;
#else
Mutator* mutator = Mutator::GetMutator();
if (mutator == nullptr) {
return false;
}
return mutator->FixExtendedStack(frameBase, adjustedSize, ip);
#endif
}
extern "C" void MRT_FreeOldStack(intptr_t offset)
{
if (offset == 0) { return; }
Mutator* mutator = Mutator::GetMutator();
if (mutator == nullptr) {
return;
}
CJThreadOldStackFree(reinterpret_cast<void*>(mutator->GetStackTopAddr()), mutator->GetStackSize());
mutator->SetStackTopAddr(reinterpret_cast<uintptr_t>(CJThreadStackAddrGet()));
mutator->SetStackSize(CJThreadStackSizeGet());
mutator->SetStackBaseAddr(reinterpret_cast<uintptr_t>(CJThreadStackBaseAddrGet()));
}
extern "C" void MRT_SetStackGrow(bool enableStackScale)
{
if (ThreadLocal::GetThreadType() == ThreadType::FP_THREAD) {
return;
}
if (!CJThreadSetStackGrow(enableStackScale)) {
return;
} else {
#if not defined (__OHOS__) && not defined (_WIN64)
LOG(RTLOG_ERROR, "CJThread Set StackScale failed");
#endif
}
}
#ifdef INTERPRETER_ENABLED
void Mutator::InitInterpreterPart()
{
if (isRuntimeMutator) {
return;
}
DLOG(INTERPRETER, "[Mutator] init interpreter part for cjThread %p\n", this);
InterpreterCJThreadStart(&(this->interpreterCJThreadData));
}
void Mutator::DestroyInterpreterPart()
{
if (isRuntimeMutator) {
return;
}
DLOG(INTERPRETER, "[Mutator] destruct interpreter part for cjThread %p\n", this);
InterpreterCJThreadDestroy(&(this->interpreterCJThreadData));
}
#endif
void Mutator::InitProtectStackAddr()
{
#if defined(_WIN64)
_TEB* teb = NtCurrentTeb();
stackBoundAddr = reinterpret_cast<void*>(reinterpret_cast<NT_TIB64*>(teb)->StackLimit);
#elif defined(__APPLE__)
stackBoundAddr = pthread_get_stackaddr_np(pthread_self());
#else
pthread_attr_t attr;
pthread_t thread = pthread_self();
CHECK_PTHREAD_CALL(pthread_getattr_np, (thread, &attr), "get thread attr failed");
uintptr_t sSize = 0;
CHECK_PTHREAD_CALL(pthread_attr_getstack, (&attr, &stackBoundAddr, &sSize), "get thread stack attr failed");
CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attr), "destroy pthread attr");
#endif
size_t reversedSize = Runtime::Current().GetConcurrencyModel().GetReservedStackSize();
ThreadLocal::SetProtectAddr(reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(stackBoundAddr) + reversedSize));
}
void Mutator::SetManagedContext(bool isManagedContext)
{
inManagedContext.store(isManagedContext, std::memory_order_release);
}
void Mutator::HandleSuspensionRequest()
{
for (;;) {
SetInSaferegion(SAFE_REGION_TRUE);
if (HasSuspensionRequest(SUSPENSION_FOR_GC_PHASE)) {
TransitionGCPhase(true);
} else if (HasSuspensionRequest(SUSPENSION_FOR_CPU_PROFILE)) {
TransitionToCpuProfile(true);
} else if (HasSuspensionRequest(SUSPENSION_FOR_SYNC)) {
SuspendForSync();
if (HasSuspensionRequest(SUSPENSION_FOR_GC_PHASE)) {
TransitionGCPhase(true);
} else if (HasSuspensionRequest(SUSPENSION_FOR_CPU_PROFILE)) {
TransitionToCpuProfile(true);
}
} else if (HasPreemptRequest()) {
SuspendForPreempt();
SetInSaferegion(SAFE_REGION_FALSE);
return;
} else if (HasSuspensionRequest(SUSPENSION_FOR_EXIT)) {
while (true) {
sleep(INT_MAX);
}
}
SetInSaferegion(SAFE_REGION_FALSE);
if (MutatorManager::Instance().SyncTriggered()) {
SetSuspensionFlag(SUSPENSION_FOR_SYNC);
}
if (LIKELY(!HasAnySuspensionRequest() && !HasObserver())) {
return;
}
}
}
void Mutator::SuspendForSync()
{
ClearSuspensionFlag(SUSPENSION_FOR_SYNC);
int curCount = static_cast<int>(MutatorManager::Instance().GetSyncFutexWordValue());
if (curCount > 0) {
#if defined(_WIN64) || defined(__APPLE__)
MutatorManager::Instance().MutatorWait();
#else
int* countAddr = MutatorManager::Instance().GetSyncFutexWord();
(void)Futex(countAddr, FUTEX_WAIT, curCount);
#endif
}
}
#if defined(GCINFO_DEBUG) && GCINFO_DEBUG
void Mutator::CreateCurrentGCInfo() { gcInfos.CreateCurrentGCInfo(); }
#endif
void Mutator::VisitStackRoots(const RootVisitor& func)
{
MutatorLock();
if (!IsManagedContext()) {
MutatorUnlock();
return;
}
IncObserver();
#if defined(GCINFO_DEBUG) && GCINFO_DEBUG
CreateCurrentGCInfo();
#endif
StackManager::VisitStackRoots(uwContext, func, *this);
VisitRawObjects(func);
DecObserver();
MutatorUnlock();
}
void Mutator::VisitExceptionRoots(const RootVisitor& func)
{
func(reinterpret_cast<ObjectRef&>(exceptionWrapper.GetExceptionRef()));
}
void Mutator::VisitRawObjects(const RootVisitor& func)
{
if (rawObject.object != nullptr) {
func(rawObject);
}
}
void Mutator::VisitHeapReferencesOnStack(const RootVisitor& rootVisitor, const DerivedPtrVisitor& derivedPtrVisitor)
{
MutatorLock();
if (!IsManagedContext()) {
MutatorUnlock();
return;
}
IncObserver();
#if defined(GCINFO_DEBUG) && GCINFO_DEBUG
CreateCurrentGCInfo();
#endif
StackManager::VisitHeapReferencesOnStack(uwContext, rootVisitor, derivedPtrVisitor, *this);
VisitRawObjects(rootVisitor);
DecObserver();
MutatorUnlock();
}
void Mutator::VisitHeapReferences(const RootVisitor& rootVisitor, const DerivedPtrVisitor& derivedPtrVisitor)
{
VisitHeapReferencesOnStack(rootVisitor, derivedPtrVisitor);
VisitExceptionRoots(rootVisitor);
}
Mutator* Mutator::GetMutator() noexcept
{
Mutator* mutator = ThreadLocal::GetMutator();
if (mutator == nullptr) {
mutator = ConcurrencyModel::GetMutator();
}
return mutator;
}
void Mutator::StackGuardExpand() const
{
if (!IsRuntimeThread()) {
CJThreadStackGuardExpand();
if (Runtime::Current().GetConcurrencyModel().GetStackGuardCheckFlag()) {
void* topAddr = reinterpret_cast<uint8_t*>(CJThreadStackAddrGet()) - MapleRuntime::MRT_PAGE_SIZE;
#ifdef _WIN64
DWORD oldProt = 0;
int ret = VirtualProtect(topAddr, MapleRuntime::MRT_PAGE_SIZE, PAGE_READWRITE, &oldProt);
if (ret == 0) {
LOG(RTLOG_ERROR, "Enable stack protect page failed");
}
#else
int ret = mprotect(topAddr, MapleRuntime::MRT_PAGE_SIZE, PROT_READ | PROT_WRITE);
if (ret != 0) {
LOG(RTLOG_ERROR, "Enable stack protect page failed");
}
#endif
}
} else {
ThreadLocal::SetProtectAddr(static_cast<uint8_t*>(stackBoundAddr));
}
}
void Mutator::StackGuardRecover() const
{
if (!IsRuntimeThread()) {
CJThreadStackGuardRecover();
if (Runtime::Current().GetConcurrencyModel().GetStackGuardCheckFlag()) {
void* topAddr = reinterpret_cast<uint8_t*>(CJThreadStackAddrGet()) - MapleRuntime::MRT_PAGE_SIZE;
#ifdef _WIN64
DWORD oldProt = 0;
int ret = VirtualProtect(topAddr, MapleRuntime::MRT_PAGE_SIZE, PAGE_NOACCESS, &oldProt);
if (ret == 0) {
LOG(RTLOG_ERROR, "Disable stack protect page failed");
}
#else
int ret = mprotect(topAddr, MapleRuntime::MRT_PAGE_SIZE, PROT_NONE);
if (ret != 0) {
LOG(RTLOG_ERROR, "Disable stack protect page failed");
}
#endif
}
} else {
size_t reversedSize = Runtime::Current().GetConcurrencyModel().GetReservedStackSize();
ThreadLocal::SetProtectAddr(
reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(stackBoundAddr) + reversedSize));
}
}
void Mutator::InitStackInfo(ThreadLocalData* threadData)
{
CJThread* cjthread = reinterpret_cast<CJThread*>(threadData->cjthread);
SetStackTopAddr(reinterpret_cast<uintptr_t>(CJThreadStackAddrGetByCJThrd(cjthread)));
SetStackSize(CJThreadStackSizeGetByCJThrd(cjthread));
SetStackBaseAddr(reinterpret_cast<uintptr_t>(CJThreadStackBaseAddrGetByCJThrd(cjthread)));
}
bool Mutator::IsStackAddr(uintptr_t addr)
{
if (addr > GetStackTopAddr() && addr < GetStackTopAddr() + GetStackSize()) {
return true;
} else {
return false;
}
}
void Mutator::RecordStackPtrs(std::set<BaseObject**>& resSet)
{
std::stack<BaseObject**, std::deque<BaseObject**, StdContainerAllocator<BaseObject**, STACK_PTR>>> rootList;
StackPtrVisitor traceAndFixPtrVisitor = [&rootList, this](ObjectRef& oldStackAddr) {
if (IsStackAddr(reinterpret_cast<uintptr_t>(oldStackAddr.object))) {
rootList.push(reinterpret_cast<BaseObject**>(&oldStackAddr));
}
};
StackPtrVisitor fixPtrVisitor = [&resSet, this](ObjectRef& oldStackAddr) {
if (IsStackAddr(reinterpret_cast<uintptr_t>(oldStackAddr.object))) {
resSet.insert(reinterpret_cast<BaseObject**>(&oldStackAddr));
}
};
DerivedPtrVisitor derivedPtrVisitor =
[&resSet, this](BasePtrType basePtr __attribute__((unused)), DerivedPtrType& derivedPtr) {
if (IsStackAddr(reinterpret_cast<uintptr_t>(reinterpret_cast<ObjectRef&>(derivedPtr).object))) {
resSet.insert(reinterpret_cast<BaseObject**>(&derivedPtr));
}
};
StackManager::VisitStackPtrMap(uwContext, traceAndFixPtrVisitor, fixPtrVisitor, derivedPtrVisitor, *this);
RefFieldVisitor refVisitor = [&rootList, this](RefField<>& oldRefFieldAddr) {
if (IsStackAddr(reinterpret_cast<uintptr_t>(oldRefFieldAddr.GetTargetObject()))) {
rootList.push(reinterpret_cast<BaseObject**>(&oldRefFieldAddr));
}
};
for (;;) {
if (rootList.empty()) {
break;
}
BaseObject** objSlot = rootList.top();
rootList.pop();
resSet.insert(objSlot);
BaseObject* obj = *objSlot;
if (!obj->IsValidObject() || !obj->HasRefField()) {
continue;
} else {
obj->ForEachRefField(refVisitor);
}
}
}
intptr_t Mutator::FixExtendedStack(intptr_t frameBase, uint32_t adjustedSize, void* ip)
{
if (!IsRuntimeThread()) {
#if defined(_WIN64)
stackGrowFrameSize = adjustedSize;
#endif
intptr_t stackOffset;
#ifdef INTERPRETER_ENABLED
uintptr_t currentIp = reinterpret_cast<uintptr_t>(ip);
bool isInterpreterC2I = IsC2IStubAddr(currentIp);
bool isInterpreterPrologue = !isInterpreterC2I && IsInterpreterPrologueAddr(currentIp);
#endif
if (frameBase == 0) {
stackOffset = CJThreadStackGrow(CJTHREAD_MAX_STACK_SIZE);
if (stackOffset == 0 || stackOffset == -1) {
return 0;
}
#ifdef INTERPRETER_ENABLED
} else if (isInterpreterC2I || isInterpreterPrologue) {
DLOG(INTERPRETER, "Stack overflow happened in %s, stack size: %zu",
isInterpreterPrologue ? "interpreter prologue" : "C2I", stackSize);
uintptr_t callerFrameBase = static_cast<uintptr_t>(*reinterpret_cast<intptr_t*>(frameBase));
size_t requiredSize = stackBaseAddr - callerFrameBase + adjustedSize;
size_t newSize = stackSize + stackSize;
while (requiredSize > newSize - CJThreadStackReversedGet()) {
newSize += newSize;
}
DLOG(INTERPRETER, " try to grow stack size: %zu -> %zu", stackSize, newSize);
stackOffset = CJThreadStackGrow(newSize);
if (stackOffset == -1 || stackOffset == 0) {
DLOG(INTERPRETER, " stack overflow at %p", ip);
ExceptionManager::StackOverflow(adjustedSize, ip);
return 0;
}
#endif
} else {
UnwindContext& stackGrowContext = Mutator::GetMutator()->GetUnwindContext();
UnwindContext caller;
#ifdef _WIN64
UnwindContextStatus ucs = stackGrowContext.GetUnwindContextStatus();
stackGrowContext.frameInfo.mFrame.UnwindToCallerMachineFrame(caller.frameInfo, ucs);
#else
stackGrowContext.frameInfo.mFrame.UnwindToCallerMachineFrame(caller.frameInfo.mFrame);
#endif
caller.frameInfo.ResolveProcInfo();
#ifdef __APPLE__
FuncDescRef funcDesc = MFuncDesc::GetFuncDesc(caller.frameInfo.mFrame.GetFA());
#else
FuncDescRef funcDesc = MFuncDesc::GetFuncDesc(reinterpret_cast<Uptr>(caller.frameInfo.GetFuncStartPC()));
#endif
Uptr* stackMapEntry = funcDesc->GetStackMap();
uint32_t validPos = 0;
uint32_t frameSize = EHFrameInfo::ReadVarInt(&stackMapEntry, validPos);
#if defined(__x86_64__)
uint64_t callerSp = *reinterpret_cast<intptr_t*>(frameBase) - frameSize + 8;
#elif defined(__aarch64__)
uint64_t callerSp = *reinterpret_cast<intptr_t*>(frameBase) - frameSize;
#elif defined(__arm__)
uint64_t callerSp = *reinterpret_cast<intptr_t*>(frameBase) - frameSize;
#endif
size_t newSize = stackSize + stackSize;
while (stackBaseAddr - callerSp > newSize - CJThreadStackReversedGet()) {
newSize += newSize;
}
stackOffset = CJThreadStackGrow(newSize);
if (stackOffset == -1 || stackOffset == 0) {
ExceptionManager::StackOverflow(adjustedSize, ip);
return 0;
}
}
std::set<BaseObject**> resSet;
RecordStackPtrs(resSet);
intptr_t* newStackAddr;
const int byteSize = 8;
for (BaseObject** oldAddr : resSet) {
newStackAddr = reinterpret_cast<intptr_t*>(oldAddr + stackOffset / byteSize);
*newStackAddr += stackOffset;
}
uwContext.anchorFA = reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(uwContext.anchorFA) + stackOffset);
return stackOffset;
}
return 0;
}
inline void CheckAndPush(BaseObject* obj, std::set<BaseObject*>& rootSet, std::stack<BaseObject*>& rootStack)
{
if (rootSet.insert(obj).second && obj->IsValidObject() && obj->HasRefField()) {
rootStack.push(obj);
}
}
inline void Mutator::GcPhaseEnum(GCPhase newPhase)
{
std::set<BaseObject*> rootSet;
std::stack<BaseObject*> rootStack;
RefFieldVisitor refVisitor = [&rootSet, &rootStack, this](RefField<>& refFieldAddr) {
BaseObject* obj = refFieldAddr.GetTargetObject();
if (Heap::IsHeapAddress(obj)) {
AllocBuffer* buffer = AllocBuffer::GetOrCreateAllocBuffer();
buffer->PushRoot(obj);
DLOG(ENUM, "enum stack root RefField @%p: %p", &refFieldAddr, obj);
} else if (IsStackAddr(reinterpret_cast<uintptr_t>(obj))) {
CheckAndPush(obj, rootSet, rootStack);
}
};
RootVisitor visitor = [&rootSet, &rootStack, this, &refVisitor](ObjectRef& root) {
BaseObject* obj = root.object;
if (Heap::IsHeapAddress(obj)) {
AllocBuffer* buffer = AllocBuffer::GetOrCreateAllocBuffer();
buffer->PushRoot(obj);
DLOG(ENUM, "enum stack root @%p: %p", &root, obj);
} else if (IsStackAddr(reinterpret_cast<uintptr_t>(obj))) {
CheckAndPush(obj, rootSet, rootStack);
}
while (!rootStack.empty()) {
BaseObject* obj = rootStack.top();
rootStack.pop();
obj->ForEachRefField(refVisitor);
}
};
VisitMutatorRoots(visitor);
}
inline void Mutator::GCPhasePreForward(GCPhase newPhase)
{
std::set<BaseObject*> rootSet;
std::set<void*> rootFieldSet;
std::stack<BaseObject*> rootStack;
Collector& collector = reinterpret_cast<Collector&>(Heap::GetHeap().GetCollector());
RefFieldVisitor refVisitor = [&rootSet, &rootFieldSet, &rootStack, &collector, this](RefField<>& refFieldAddr) {
BaseObject* oldObj = refFieldAddr.GetTargetObject();
if (Heap::IsHeapAddress(oldObj) && collector.IsGhostFromObject(oldObj) &&
!collector.IsUnmovableFromObject(oldObj)) {
if (!rootFieldSet.insert((void*)(&refFieldAddr)).second) {
return;
}
BaseObject* toObj = collector.ForwardObject(oldObj);
if (oldObj != toObj) { refFieldAddr.SetTargetObject(toObj); }
} else if (IsStackAddr(reinterpret_cast<uintptr_t>(oldObj))) {
CheckAndPush(oldObj, rootSet, rootStack);
}
};
RootVisitor visitor = [&rootSet, &rootFieldSet, &rootStack, &collector, this, &refVisitor](ObjectRef& root) {
BaseObject* oldObj = root.object;
if (Heap::IsHeapAddress(oldObj) && collector.IsGhostFromObject(oldObj) &&
!collector.IsUnmovableFromObject(oldObj)) {
if (!rootFieldSet.insert((void*)(&root)).second) {
return;
}
BaseObject* toObj = collector.ForwardObject(oldObj);
if (oldObj != toObj) { root.object = toObj; }
} else if (IsStackAddr(reinterpret_cast<uintptr_t>(oldObj))) {
CheckAndPush(oldObj, rootSet, rootStack);
}
while (!rootStack.empty()) {
BaseObject* obj = rootStack.top();
rootStack.pop();
obj->ForEachRefField(refVisitor);
}
};
DerivedPtrVisitor derivedPtrVisitor = [&collector](BasePtrType basePtr, DerivedPtrType& derivedPtr) {
BaseObject* fromVersion = reinterpret_cast<BaseObject*>(basePtr);
if (!Heap::IsHeapAddress(fromVersion) || !collector.IsGhostFromObject(fromVersion) ||
collector.IsUnmovableFromObject(fromVersion)) {
return;
}
BaseObject* toVersion = collector.FindLatestVersion(fromVersion);
if (fromVersion != toVersion) {
DerivedPtrType toDerived = reinterpret_cast<BasePtrType>(toVersion) + (derivedPtr - basePtr);
derivedPtr = toDerived;
}
};
VisitHeapReferences(visitor, derivedPtrVisitor);
}
inline void Mutator::HandleGCPhase(GCPhase newPhase)
{
if (newPhase == GCPhase::GC_PHASE_FINISH || newPhase == GCPhase::GC_PHASE_FORWARD) {
std::lock_guard<std::mutex> lg(mutatorLock);
if (satbNode != nullptr) {
satbNode->Clear();
}
} else if (newPhase == GCPhase::GC_PHASE_ENUM) {
GcPhaseEnum(newPhase);
} else if (newPhase == GCPhase::GC_PHASE_PREFORWARD) {
GCPhasePreForward(newPhase);
} else if (newPhase == GCPhase::GC_PHASE_CLEAR_SATB_BUFFER || newPhase == GCPhase::GC_PHASE_RECLAIM_SATB_NODE) {
std::lock_guard<std::mutex> lg(mutatorLock);
if (satbNode != nullptr) {
SatbBuffer::Instance().RetireNode(satbNode);
satbNode = nullptr;
}
} else if (newPhase == GCPhase::GC_PHASE_IDLE) {
HandleGCPhaseIDLE();
}
}
inline void Mutator::HandleGCPhaseIDLE()
{
if (IsForeignThreadExit()) {
ReleaseForeignThread();
} else {
#if defined(__OHOS__) && (__OHOS__ == 1)
if (foreignThreadInfo.allocBuffer != nullptr) {
auto status = GetUnwindContext().GetUnwindContextStatus();
if (status == UnwindContextStatus::RISKY) {
foreignThreadInfo.allocBuffer->FlushRegion();
}
}
#endif
}
}
void Mutator::TransitionToGCPhaseExclusive(GCPhase newPhase)
{
HandleGCPhase(newPhase);
SetSafepointActive(false);
ClearSuspensionFlag(SUSPENSION_FOR_GC_PHASE);
mutatorPhase.store(newPhase, std::memory_order_release);
}
inline void Mutator::HandleCpuProfile()
{
MutatorLock();
if (!IsManagedContext()) {
MutatorUnlock();
return;
}
IncObserver();
StackManager::PrintStackTraceForCpuProfile(&(GetUnwindContext()), GetCJThreadId());
DecObserver();
MutatorUnlock();
}
void Mutator::TransitionToCpuProfileExclusive()
{
HandleCpuProfile();
SetSafepointActive(false);
ClearSuspensionFlag(SUSPENSION_FOR_CPU_PROFILE);
}
void Mutator::ReleaseForeignThread()
{
AllocBuffer* buffer = foreignThreadInfo.allocBuffer;
foreignThreadInfo.allocBuffer = nullptr;
if (buffer != nullptr) {
buffer->Fini();
delete buffer;
}
}
}