14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/js_thread.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/runtime.h" 194514f5e3Sopenharmony_ci#include "ecmascript/debugger/js_debugger_manager.h" 204514f5e3Sopenharmony_ci#include "ecmascript/js_object-inl.h" 214514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value.h" 224514f5e3Sopenharmony_ci#include "ecmascript/runtime_call_id.h" 234514f5e3Sopenharmony_ci#include "ecmascript/pgo_profiler/pgo_profiler_manager.h" 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_ci#if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS) 264514f5e3Sopenharmony_ci#include <sys/resource.h> 274514f5e3Sopenharmony_ci#endif 284514f5e3Sopenharmony_ci 294514f5e3Sopenharmony_ci#if defined(ENABLE_EXCEPTION_BACKTRACE) 304514f5e3Sopenharmony_ci#include "ecmascript/platform/backtrace.h" 314514f5e3Sopenharmony_ci#endif 324514f5e3Sopenharmony_ci#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 334514f5e3Sopenharmony_ci#include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" 344514f5e3Sopenharmony_ci#endif 354514f5e3Sopenharmony_ci#include "ecmascript/dfx/vm_thread_control.h" 364514f5e3Sopenharmony_ci#include "ecmascript/ecma_global_storage.h" 374514f5e3Sopenharmony_ci#include "ecmascript/ic/properties_cache.h" 384514f5e3Sopenharmony_ci#include "ecmascript/interpreter/interpreter.h" 394514f5e3Sopenharmony_ci#include "ecmascript/mem/concurrent_marker.h" 404514f5e3Sopenharmony_ci#include "ecmascript/platform/file.h" 414514f5e3Sopenharmony_ci#include "ecmascript/jit/jit.h" 424514f5e3Sopenharmony_ci 434514f5e3Sopenharmony_cinamespace panda::ecmascript { 444514f5e3Sopenharmony_ciusing CommonStubCSigns = panda::ecmascript::kungfu::CommonStubCSigns; 454514f5e3Sopenharmony_ciusing BytecodeStubCSigns = panda::ecmascript::kungfu::BytecodeStubCSigns; 464514f5e3Sopenharmony_ci 474514f5e3Sopenharmony_cithread_local JSThread *currentThread = nullptr; 484514f5e3Sopenharmony_ci 494514f5e3Sopenharmony_ciJSThread *JSThread::GetCurrent() 504514f5e3Sopenharmony_ci{ 514514f5e3Sopenharmony_ci return currentThread; 524514f5e3Sopenharmony_ci} 534514f5e3Sopenharmony_ci 544514f5e3Sopenharmony_ci// static 554514f5e3Sopenharmony_civoid JSThread::RegisterThread(JSThread *jsThread) 564514f5e3Sopenharmony_ci{ 574514f5e3Sopenharmony_ci Runtime::GetInstance()->RegisterThread(jsThread); 584514f5e3Sopenharmony_ci // If it is not true, we created a new thread for future fork 594514f5e3Sopenharmony_ci if (currentThread == nullptr) { 604514f5e3Sopenharmony_ci currentThread = jsThread; 614514f5e3Sopenharmony_ci jsThread->UpdateState(ThreadState::NATIVE); 624514f5e3Sopenharmony_ci } 634514f5e3Sopenharmony_ci} 644514f5e3Sopenharmony_ci 654514f5e3Sopenharmony_civoid JSThread::UnregisterThread(JSThread *jsThread) 664514f5e3Sopenharmony_ci{ 674514f5e3Sopenharmony_ci if (currentThread == jsThread) { 684514f5e3Sopenharmony_ci jsThread->UpdateState(ThreadState::TERMINATED); 694514f5e3Sopenharmony_ci currentThread = nullptr; 704514f5e3Sopenharmony_ci } else { 714514f5e3Sopenharmony_ci // We have created this JSThread instance but hadn't forked it. 724514f5e3Sopenharmony_ci ASSERT(jsThread->GetState() == ThreadState::CREATED); 734514f5e3Sopenharmony_ci jsThread->UpdateState(ThreadState::TERMINATED); 744514f5e3Sopenharmony_ci } 754514f5e3Sopenharmony_ci Runtime::GetInstance()->UnregisterThread(jsThread); 764514f5e3Sopenharmony_ci} 774514f5e3Sopenharmony_ci 784514f5e3Sopenharmony_ci// static 794514f5e3Sopenharmony_ciJSThread *JSThread::Create(EcmaVM *vm) 804514f5e3Sopenharmony_ci{ 814514f5e3Sopenharmony_ci auto jsThread = new JSThread(vm); 824514f5e3Sopenharmony_ci 834514f5e3Sopenharmony_ci AsmInterParsedOption asmInterOpt = vm->GetJSOptions().GetAsmInterParsedOption(); 844514f5e3Sopenharmony_ci if (asmInterOpt.enableAsm) { 854514f5e3Sopenharmony_ci jsThread->EnableAsmInterpreter(); 864514f5e3Sopenharmony_ci } 874514f5e3Sopenharmony_ci 884514f5e3Sopenharmony_ci jsThread->nativeAreaAllocator_ = vm->GetNativeAreaAllocator(); 894514f5e3Sopenharmony_ci jsThread->heapRegionAllocator_ = vm->GetHeapRegionAllocator(); 904514f5e3Sopenharmony_ci // algin with 16 914514f5e3Sopenharmony_ci size_t maxStackSize = vm->GetEcmaParamConfiguration().GetMaxStackSize(); 924514f5e3Sopenharmony_ci jsThread->glueData_.frameBase_ = static_cast<JSTaggedType *>( 934514f5e3Sopenharmony_ci vm->GetNativeAreaAllocator()->Allocate(sizeof(JSTaggedType) * maxStackSize)); 944514f5e3Sopenharmony_ci jsThread->glueData_.currentFrame_ = jsThread->glueData_.frameBase_ + maxStackSize; 954514f5e3Sopenharmony_ci EcmaInterpreter::InitStackFrame(jsThread); 964514f5e3Sopenharmony_ci 974514f5e3Sopenharmony_ci jsThread->glueData_.stackLimit_ = GetAsmStackLimit(); 984514f5e3Sopenharmony_ci jsThread->glueData_.stackStart_ = GetCurrentStackPosition(); 994514f5e3Sopenharmony_ci jsThread->glueData_.isEnableElementsKind_ = vm->IsEnableElementsKind(); 1004514f5e3Sopenharmony_ci jsThread->glueData_.isEnableForceIC_ = ecmascript::pgo::PGOProfilerManager::GetInstance()->IsEnableForceIC(); 1014514f5e3Sopenharmony_ci jsThread->SetThreadId(); 1024514f5e3Sopenharmony_ci 1034514f5e3Sopenharmony_ci RegisterThread(jsThread); 1044514f5e3Sopenharmony_ci return jsThread; 1054514f5e3Sopenharmony_ci} 1064514f5e3Sopenharmony_ci 1074514f5e3Sopenharmony_ciJSThread::JSThread(EcmaVM *vm) : id_(os::thread::GetCurrentThreadId()), vm_(vm) 1084514f5e3Sopenharmony_ci{ 1094514f5e3Sopenharmony_ci auto chunk = vm->GetChunk(); 1104514f5e3Sopenharmony_ci if (!vm_->GetJSOptions().EnableGlobalLeakCheck()) { 1114514f5e3Sopenharmony_ci globalStorage_ = chunk->New<EcmaGlobalStorage<Node>>(this, vm->GetNativeAreaAllocator()); 1124514f5e3Sopenharmony_ci newGlobalHandle_ = [this](JSTaggedType value) { return globalStorage_->NewGlobalHandle(value); }; 1134514f5e3Sopenharmony_ci disposeGlobalHandle_ = [this](uintptr_t nodeAddr) { globalStorage_->DisposeGlobalHandle(nodeAddr); }; 1144514f5e3Sopenharmony_ci setWeak_ = [this](uintptr_t nodeAddr, void *ref, WeakClearCallback freeGlobalCallBack, 1154514f5e3Sopenharmony_ci WeakClearCallback nativeFinalizeCallBack) { 1164514f5e3Sopenharmony_ci return globalStorage_->SetWeak(nodeAddr, ref, freeGlobalCallBack, nativeFinalizeCallBack); 1174514f5e3Sopenharmony_ci }; 1184514f5e3Sopenharmony_ci clearWeak_ = [this](uintptr_t nodeAddr) { return globalStorage_->ClearWeak(nodeAddr); }; 1194514f5e3Sopenharmony_ci isWeak_ = [this](uintptr_t addr) { return globalStorage_->IsWeak(addr); }; 1204514f5e3Sopenharmony_ci } else { 1214514f5e3Sopenharmony_ci globalDebugStorage_ = chunk->New<EcmaGlobalStorage<DebugNode>>(this, vm->GetNativeAreaAllocator()); 1224514f5e3Sopenharmony_ci newGlobalHandle_ = [this](JSTaggedType value) { return globalDebugStorage_->NewGlobalHandle(value); }; 1234514f5e3Sopenharmony_ci disposeGlobalHandle_ = [this](uintptr_t nodeAddr) { globalDebugStorage_->DisposeGlobalHandle(nodeAddr); }; 1244514f5e3Sopenharmony_ci setWeak_ = [this](uintptr_t nodeAddr, void *ref, WeakClearCallback freeGlobalCallBack, 1254514f5e3Sopenharmony_ci WeakClearCallback nativeFinalizeCallBack) { 1264514f5e3Sopenharmony_ci return globalDebugStorage_->SetWeak(nodeAddr, ref, freeGlobalCallBack, nativeFinalizeCallBack); 1274514f5e3Sopenharmony_ci }; 1284514f5e3Sopenharmony_ci clearWeak_ = [this](uintptr_t nodeAddr) { return globalDebugStorage_->ClearWeak(nodeAddr); }; 1294514f5e3Sopenharmony_ci isWeak_ = [this](uintptr_t addr) { return globalDebugStorage_->IsWeak(addr); }; 1304514f5e3Sopenharmony_ci } 1314514f5e3Sopenharmony_ci vmThreadControl_ = new VmThreadControl(this); 1324514f5e3Sopenharmony_ci SetBCStubStatus(BCStubStatus::NORMAL_BC_STUB); 1334514f5e3Sopenharmony_ci} 1344514f5e3Sopenharmony_ci 1354514f5e3Sopenharmony_ciJSThread::JSThread(EcmaVM *vm, ThreadType threadType) : id_(os::thread::GetCurrentThreadId()), 1364514f5e3Sopenharmony_ci vm_(vm), threadType_(threadType) 1374514f5e3Sopenharmony_ci{ 1384514f5e3Sopenharmony_ci ASSERT(threadType == ThreadType::JIT_THREAD); 1394514f5e3Sopenharmony_ci // jit thread no need GCIterating 1404514f5e3Sopenharmony_ci readyForGCIterating_ = false; 1414514f5e3Sopenharmony_ci RegisterThread(this); 1424514f5e3Sopenharmony_ci}; 1434514f5e3Sopenharmony_ci 1444514f5e3Sopenharmony_ciJSThread::JSThread(ThreadType threadType) : threadType_(threadType) 1454514f5e3Sopenharmony_ci{ 1464514f5e3Sopenharmony_ci ASSERT(threadType == ThreadType::DAEMON_THREAD); 1474514f5e3Sopenharmony_ci // daemon thread no need GCIterating 1484514f5e3Sopenharmony_ci readyForGCIterating_ = false; 1494514f5e3Sopenharmony_ci} 1504514f5e3Sopenharmony_ci 1514514f5e3Sopenharmony_ciJSThread::~JSThread() 1524514f5e3Sopenharmony_ci{ 1534514f5e3Sopenharmony_ci readyForGCIterating_ = false; 1544514f5e3Sopenharmony_ci if (globalStorage_ != nullptr) { 1554514f5e3Sopenharmony_ci GetEcmaVM()->GetChunk()->Delete(globalStorage_); 1564514f5e3Sopenharmony_ci globalStorage_ = nullptr; 1574514f5e3Sopenharmony_ci } 1584514f5e3Sopenharmony_ci if (globalDebugStorage_ != nullptr) { 1594514f5e3Sopenharmony_ci GetEcmaVM()->GetChunk()->Delete(globalDebugStorage_); 1604514f5e3Sopenharmony_ci globalDebugStorage_ = nullptr; 1614514f5e3Sopenharmony_ci } 1624514f5e3Sopenharmony_ci 1634514f5e3Sopenharmony_ci for (auto item : contexts_) { 1644514f5e3Sopenharmony_ci GetNativeAreaAllocator()->Free(item->GetFrameBase(), sizeof(JSTaggedType) * 1654514f5e3Sopenharmony_ci vm_->GetEcmaParamConfiguration().GetMaxStackSize()); 1664514f5e3Sopenharmony_ci item->SetFrameBase(nullptr); 1674514f5e3Sopenharmony_ci delete item; 1684514f5e3Sopenharmony_ci } 1694514f5e3Sopenharmony_ci contexts_.clear(); 1704514f5e3Sopenharmony_ci GetNativeAreaAllocator()->FreeArea(regExpCache_); 1714514f5e3Sopenharmony_ci 1724514f5e3Sopenharmony_ci glueData_.frameBase_ = nullptr; 1734514f5e3Sopenharmony_ci nativeAreaAllocator_ = nullptr; 1744514f5e3Sopenharmony_ci heapRegionAllocator_ = nullptr; 1754514f5e3Sopenharmony_ci regExpCache_ = nullptr; 1764514f5e3Sopenharmony_ci if (vmThreadControl_ != nullptr) { 1774514f5e3Sopenharmony_ci delete vmThreadControl_; 1784514f5e3Sopenharmony_ci vmThreadControl_ = nullptr; 1794514f5e3Sopenharmony_ci } 1804514f5e3Sopenharmony_ci // DaemonThread will be unregistered when the binding std::thread release. 1814514f5e3Sopenharmony_ci if (!IsDaemonThread()) { 1824514f5e3Sopenharmony_ci UnregisterThread(this); 1834514f5e3Sopenharmony_ci } 1844514f5e3Sopenharmony_ci} 1854514f5e3Sopenharmony_ci 1864514f5e3Sopenharmony_ciThreadId JSThread::GetCurrentThreadId() 1874514f5e3Sopenharmony_ci{ 1884514f5e3Sopenharmony_ci return GetCurrentThreadOrTaskId(); 1894514f5e3Sopenharmony_ci} 1904514f5e3Sopenharmony_ci 1914514f5e3Sopenharmony_civoid JSThread::SetException(JSTaggedValue exception) 1924514f5e3Sopenharmony_ci{ 1934514f5e3Sopenharmony_ci glueData_.exception_ = exception; 1944514f5e3Sopenharmony_ci#if defined(ENABLE_EXCEPTION_BACKTRACE) 1954514f5e3Sopenharmony_ci if (vm_->GetJSOptions().EnableExceptionBacktrace()) { 1964514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "SetException:" << exception.GetRawData(); 1974514f5e3Sopenharmony_ci std::ostringstream stack; 1984514f5e3Sopenharmony_ci Backtrace(stack); 1994514f5e3Sopenharmony_ci LOG_ECMA(INFO) << stack.str(); 2004514f5e3Sopenharmony_ci } 2014514f5e3Sopenharmony_ci#endif 2024514f5e3Sopenharmony_ci} 2034514f5e3Sopenharmony_ci 2044514f5e3Sopenharmony_civoid JSThread::ClearException() 2054514f5e3Sopenharmony_ci{ 2064514f5e3Sopenharmony_ci glueData_.exception_ = JSTaggedValue::Hole(); 2074514f5e3Sopenharmony_ci} 2084514f5e3Sopenharmony_ci 2094514f5e3Sopenharmony_civoid JSThread::SetEnableForceIC(bool isEnableForceIC) 2104514f5e3Sopenharmony_ci{ 2114514f5e3Sopenharmony_ci glueData_.isEnableForceIC_ = isEnableForceIC; 2124514f5e3Sopenharmony_ci} 2134514f5e3Sopenharmony_ci 2144514f5e3Sopenharmony_cibool JSThread::IsEnableForceIC() const 2154514f5e3Sopenharmony_ci{ 2164514f5e3Sopenharmony_ci return glueData_.isEnableForceIC_; 2174514f5e3Sopenharmony_ci} 2184514f5e3Sopenharmony_ci 2194514f5e3Sopenharmony_ciJSTaggedValue JSThread::GetCurrentLexenv() const 2204514f5e3Sopenharmony_ci{ 2214514f5e3Sopenharmony_ci FrameHandler frameHandler(this); 2224514f5e3Sopenharmony_ci return frameHandler.GetEnv(); 2234514f5e3Sopenharmony_ci} 2244514f5e3Sopenharmony_ci 2254514f5e3Sopenharmony_ciJSTaggedValue JSThread::GetCurrentFunction() const 2264514f5e3Sopenharmony_ci{ 2274514f5e3Sopenharmony_ci FrameHandler frameHandler(this); 2284514f5e3Sopenharmony_ci return frameHandler.GetFunction(); 2294514f5e3Sopenharmony_ci} 2304514f5e3Sopenharmony_ci 2314514f5e3Sopenharmony_ciconst JSTaggedType *JSThread::GetCurrentFrame() const 2324514f5e3Sopenharmony_ci{ 2334514f5e3Sopenharmony_ci if (IsAsmInterpreter()) { 2344514f5e3Sopenharmony_ci return GetLastLeaveFrame(); 2354514f5e3Sopenharmony_ci } 2364514f5e3Sopenharmony_ci return GetCurrentSPFrame(); 2374514f5e3Sopenharmony_ci} 2384514f5e3Sopenharmony_ci 2394514f5e3Sopenharmony_civoid JSThread::SetCurrentFrame(JSTaggedType *sp) 2404514f5e3Sopenharmony_ci{ 2414514f5e3Sopenharmony_ci if (IsAsmInterpreter()) { 2424514f5e3Sopenharmony_ci return SetLastLeaveFrame(sp); 2434514f5e3Sopenharmony_ci } 2444514f5e3Sopenharmony_ci return SetCurrentSPFrame(sp); 2454514f5e3Sopenharmony_ci} 2464514f5e3Sopenharmony_ci 2474514f5e3Sopenharmony_ciconst JSTaggedType *JSThread::GetCurrentInterpretedFrame() const 2484514f5e3Sopenharmony_ci{ 2494514f5e3Sopenharmony_ci if (IsAsmInterpreter()) { 2504514f5e3Sopenharmony_ci auto frameHandler = FrameHandler(this); 2514514f5e3Sopenharmony_ci return frameHandler.GetSp(); 2524514f5e3Sopenharmony_ci } 2534514f5e3Sopenharmony_ci return GetCurrentSPFrame(); 2544514f5e3Sopenharmony_ci} 2554514f5e3Sopenharmony_ci 2564514f5e3Sopenharmony_civoid JSThread::InvokeWeakNodeFreeGlobalCallBack() 2574514f5e3Sopenharmony_ci{ 2584514f5e3Sopenharmony_ci while (!weakNodeFreeGlobalCallbacks_.empty()) { 2594514f5e3Sopenharmony_ci auto callbackPair = weakNodeFreeGlobalCallbacks_.back(); 2604514f5e3Sopenharmony_ci weakNodeFreeGlobalCallbacks_.pop_back(); 2614514f5e3Sopenharmony_ci ASSERT(callbackPair.first != nullptr && callbackPair.second != nullptr); 2624514f5e3Sopenharmony_ci auto callback = callbackPair.first; 2634514f5e3Sopenharmony_ci (*callback)(callbackPair.second); 2644514f5e3Sopenharmony_ci } 2654514f5e3Sopenharmony_ci} 2664514f5e3Sopenharmony_ci 2674514f5e3Sopenharmony_civoid JSThread::InvokeWeakNodeNativeFinalizeCallback() 2684514f5e3Sopenharmony_ci{ 2694514f5e3Sopenharmony_ci // the second callback may lead to another GC, if this, return directly; 2704514f5e3Sopenharmony_ci if (runningNativeFinalizeCallbacks_) { 2714514f5e3Sopenharmony_ci return; 2724514f5e3Sopenharmony_ci } 2734514f5e3Sopenharmony_ci runningNativeFinalizeCallbacks_ = true; 2744514f5e3Sopenharmony_ci ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "InvokeNativeFinalizeCallbacks num:" 2754514f5e3Sopenharmony_ci + std::to_string(weakNodeNativeFinalizeCallbacks_.size())); 2764514f5e3Sopenharmony_ci while (!weakNodeNativeFinalizeCallbacks_.empty()) { 2774514f5e3Sopenharmony_ci auto callbackPair = weakNodeNativeFinalizeCallbacks_.back(); 2784514f5e3Sopenharmony_ci weakNodeNativeFinalizeCallbacks_.pop_back(); 2794514f5e3Sopenharmony_ci ASSERT(callbackPair.first != nullptr && callbackPair.second != nullptr); 2804514f5e3Sopenharmony_ci auto callback = callbackPair.first; 2814514f5e3Sopenharmony_ci (*callback)(callbackPair.second); 2824514f5e3Sopenharmony_ci } 2834514f5e3Sopenharmony_ci if (finalizeTaskCallback_ != nullptr) { 2844514f5e3Sopenharmony_ci finalizeTaskCallback_(); 2854514f5e3Sopenharmony_ci } 2864514f5e3Sopenharmony_ci runningNativeFinalizeCallbacks_ = false; 2874514f5e3Sopenharmony_ci} 2884514f5e3Sopenharmony_ci 2894514f5e3Sopenharmony_cibool JSThread::IsStartGlobalLeakCheck() const 2904514f5e3Sopenharmony_ci{ 2914514f5e3Sopenharmony_ci return GetEcmaVM()->GetJSOptions().IsStartGlobalLeakCheck(); 2924514f5e3Sopenharmony_ci} 2934514f5e3Sopenharmony_ci 2944514f5e3Sopenharmony_cibool JSThread::EnableGlobalObjectLeakCheck() const 2954514f5e3Sopenharmony_ci{ 2964514f5e3Sopenharmony_ci return GetEcmaVM()->GetJSOptions().EnableGlobalObjectLeakCheck(); 2974514f5e3Sopenharmony_ci} 2984514f5e3Sopenharmony_ci 2994514f5e3Sopenharmony_cibool JSThread::EnableGlobalPrimitiveLeakCheck() const 3004514f5e3Sopenharmony_ci{ 3014514f5e3Sopenharmony_ci return GetEcmaVM()->GetJSOptions().EnableGlobalPrimitiveLeakCheck(); 3024514f5e3Sopenharmony_ci} 3034514f5e3Sopenharmony_ci 3044514f5e3Sopenharmony_cibool JSThread::IsInRunningStateOrProfiling() const 3054514f5e3Sopenharmony_ci{ 3064514f5e3Sopenharmony_ci bool result = IsInRunningState(); 3074514f5e3Sopenharmony_ci#if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER) 3084514f5e3Sopenharmony_ci result |= vm_->GetHeapProfile() != nullptr; 3094514f5e3Sopenharmony_ci#endif 3104514f5e3Sopenharmony_ci#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 3114514f5e3Sopenharmony_ci result |= GetIsProfiling(); 3124514f5e3Sopenharmony_ci#endif 3134514f5e3Sopenharmony_ci return result; 3144514f5e3Sopenharmony_ci} 3154514f5e3Sopenharmony_ci 3164514f5e3Sopenharmony_civoid JSThread::WriteToStackTraceFd(std::ostringstream &buffer) const 3174514f5e3Sopenharmony_ci{ 3184514f5e3Sopenharmony_ci if (stackTraceFd_ < 0) { 3194514f5e3Sopenharmony_ci return; 3204514f5e3Sopenharmony_ci } 3214514f5e3Sopenharmony_ci buffer << std::endl; 3224514f5e3Sopenharmony_ci DPrintf(reinterpret_cast<fd_t>(stackTraceFd_), buffer.str()); 3234514f5e3Sopenharmony_ci buffer.str(""); 3244514f5e3Sopenharmony_ci} 3254514f5e3Sopenharmony_ci 3264514f5e3Sopenharmony_civoid JSThread::SetStackTraceFd(int32_t fd) 3274514f5e3Sopenharmony_ci{ 3284514f5e3Sopenharmony_ci stackTraceFd_ = fd; 3294514f5e3Sopenharmony_ci} 3304514f5e3Sopenharmony_ci 3314514f5e3Sopenharmony_civoid JSThread::CloseStackTraceFd() 3324514f5e3Sopenharmony_ci{ 3334514f5e3Sopenharmony_ci if (stackTraceFd_ != -1) { 3344514f5e3Sopenharmony_ci FSync(reinterpret_cast<fd_t>(stackTraceFd_)); 3354514f5e3Sopenharmony_ci Close(reinterpret_cast<fd_t>(stackTraceFd_)); 3364514f5e3Sopenharmony_ci stackTraceFd_ = -1; 3374514f5e3Sopenharmony_ci } 3384514f5e3Sopenharmony_ci} 3394514f5e3Sopenharmony_ci 3404514f5e3Sopenharmony_civoid JSThread::SetJitCodeMap(JSTaggedType exception, MachineCode* machineCode, std::string &methodName, 3414514f5e3Sopenharmony_ci uintptr_t offset) 3424514f5e3Sopenharmony_ci{ 3434514f5e3Sopenharmony_ci auto it = jitCodeMaps_.find(exception); 3444514f5e3Sopenharmony_ci if (it != jitCodeMaps_.end()) { 3454514f5e3Sopenharmony_ci it->second->push_back(std::make_tuple(machineCode, methodName, offset)); 3464514f5e3Sopenharmony_ci } else { 3474514f5e3Sopenharmony_ci JitCodeVector *jitCode = new JitCodeVector {std::make_tuple(machineCode, methodName, offset)}; 3484514f5e3Sopenharmony_ci jitCodeMaps_.emplace(exception, jitCode); 3494514f5e3Sopenharmony_ci } 3504514f5e3Sopenharmony_ci} 3514514f5e3Sopenharmony_ci 3524514f5e3Sopenharmony_civoid JSThread::Iterate(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor, 3534514f5e3Sopenharmony_ci const RootBaseAndDerivedVisitor &derivedVisitor) 3544514f5e3Sopenharmony_ci{ 3554514f5e3Sopenharmony_ci if (!glueData_.exception_.IsHole()) { 3564514f5e3Sopenharmony_ci visitor(Root::ROOT_VM, ObjectSlot(ToUintPtr(&glueData_.exception_))); 3574514f5e3Sopenharmony_ci } 3584514f5e3Sopenharmony_ci rangeVisitor( 3594514f5e3Sopenharmony_ci Root::ROOT_VM, ObjectSlot(glueData_.builtinEntries_.Begin()), ObjectSlot(glueData_.builtinEntries_.End())); 3604514f5e3Sopenharmony_ci 3614514f5e3Sopenharmony_ci EcmaContext *tempContext = glueData_.currentContext_; 3624514f5e3Sopenharmony_ci for (EcmaContext *context : contexts_) { 3634514f5e3Sopenharmony_ci // visit stack roots 3644514f5e3Sopenharmony_ci SwitchCurrentContext(context, true); 3654514f5e3Sopenharmony_ci FrameHandler frameHandler(this); 3664514f5e3Sopenharmony_ci frameHandler.Iterate(visitor, rangeVisitor, derivedVisitor); 3674514f5e3Sopenharmony_ci context->Iterate(visitor, rangeVisitor); 3684514f5e3Sopenharmony_ci } 3694514f5e3Sopenharmony_ci SwitchCurrentContext(tempContext, true); 3704514f5e3Sopenharmony_ci // visit tagged handle storage roots 3714514f5e3Sopenharmony_ci if (vm_->GetJSOptions().EnableGlobalLeakCheck()) { 3724514f5e3Sopenharmony_ci IterateHandleWithCheck(visitor, rangeVisitor); 3734514f5e3Sopenharmony_ci } else { 3744514f5e3Sopenharmony_ci size_t globalCount = 0; 3754514f5e3Sopenharmony_ci globalStorage_->IterateUsageGlobal([visitor, &globalCount](Node *node) { 3764514f5e3Sopenharmony_ci JSTaggedValue value(node->GetObject()); 3774514f5e3Sopenharmony_ci if (value.IsHeapObject()) { 3784514f5e3Sopenharmony_ci visitor(ecmascript::Root::ROOT_HANDLE, ecmascript::ObjectSlot(node->GetObjectAddress())); 3794514f5e3Sopenharmony_ci } 3804514f5e3Sopenharmony_ci globalCount++; 3814514f5e3Sopenharmony_ci }); 3824514f5e3Sopenharmony_ci static bool hasCheckedGlobalCount = false; 3834514f5e3Sopenharmony_ci static const size_t WARN_GLOBAL_COUNT = 100000; 3844514f5e3Sopenharmony_ci if (!hasCheckedGlobalCount && globalCount >= WARN_GLOBAL_COUNT) { 3854514f5e3Sopenharmony_ci LOG_ECMA(WARN) << "Global reference count is " << globalCount << ",It exceed the upper limit 100000!"; 3864514f5e3Sopenharmony_ci hasCheckedGlobalCount = true; 3874514f5e3Sopenharmony_ci } 3884514f5e3Sopenharmony_ci } 3894514f5e3Sopenharmony_ci} 3904514f5e3Sopenharmony_civoid JSThread::IterateJitCodeMap(const JitCodeMapVisitor &jitCodeMapVisitor) 3914514f5e3Sopenharmony_ci{ 3924514f5e3Sopenharmony_ci jitCodeMapVisitor(jitCodeMaps_); 3934514f5e3Sopenharmony_ci} 3944514f5e3Sopenharmony_ci 3954514f5e3Sopenharmony_civoid JSThread::IterateHandleWithCheck(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) 3964514f5e3Sopenharmony_ci{ 3974514f5e3Sopenharmony_ci size_t handleCount = 0; 3984514f5e3Sopenharmony_ci for (EcmaContext *context : contexts_) { 3994514f5e3Sopenharmony_ci handleCount += context->IterateHandle(rangeVisitor); 4004514f5e3Sopenharmony_ci } 4014514f5e3Sopenharmony_ci 4024514f5e3Sopenharmony_ci size_t globalCount = 0; 4034514f5e3Sopenharmony_ci static const int JS_TYPE_LAST = static_cast<int>(JSType::TYPE_LAST); 4044514f5e3Sopenharmony_ci int typeCount[JS_TYPE_LAST] = { 0 }; 4054514f5e3Sopenharmony_ci int primitiveCount = 0; 4064514f5e3Sopenharmony_ci bool isStopObjectLeakCheck = EnableGlobalObjectLeakCheck() && !IsStartGlobalLeakCheck() && stackTraceFd_ > 0; 4074514f5e3Sopenharmony_ci bool isStopPrimitiveLeakCheck = EnableGlobalPrimitiveLeakCheck() && !IsStartGlobalLeakCheck() && stackTraceFd_ > 0; 4084514f5e3Sopenharmony_ci std::ostringstream buffer; 4094514f5e3Sopenharmony_ci globalDebugStorage_->IterateUsageGlobal([this, visitor, &globalCount, &typeCount, &primitiveCount, 4104514f5e3Sopenharmony_ci isStopObjectLeakCheck, isStopPrimitiveLeakCheck, &buffer](DebugNode *node) { 4114514f5e3Sopenharmony_ci node->MarkCount(); 4124514f5e3Sopenharmony_ci JSTaggedValue value(node->GetObject()); 4134514f5e3Sopenharmony_ci if (value.IsHeapObject()) { 4144514f5e3Sopenharmony_ci visitor(ecmascript::Root::ROOT_HANDLE, ecmascript::ObjectSlot(node->GetObjectAddress())); 4154514f5e3Sopenharmony_ci TaggedObject *object = value.GetTaggedObject(); 4164514f5e3Sopenharmony_ci MarkWord word(value.GetTaggedObject()); 4174514f5e3Sopenharmony_ci if (word.IsForwardingAddress()) { 4184514f5e3Sopenharmony_ci object = word.ToForwardingAddress(); 4194514f5e3Sopenharmony_ci } 4204514f5e3Sopenharmony_ci typeCount[static_cast<int>(object->GetClass()->GetObjectType())]++; 4214514f5e3Sopenharmony_ci 4224514f5e3Sopenharmony_ci // Print global information about possible memory leaks. 4234514f5e3Sopenharmony_ci // You can print the global new stack within the range of the leaked global number. 4244514f5e3Sopenharmony_ci if (isStopObjectLeakCheck && node->GetGlobalNumber() > 0 && node->GetMarkCount() > 0) { 4254514f5e3Sopenharmony_ci buffer << "Global maybe leak object address:" << std::hex << object << 4264514f5e3Sopenharmony_ci ", type:" << JSHClass::DumpJSType(JSType(object->GetClass()->GetObjectType())) << 4274514f5e3Sopenharmony_ci ", node address:" << node << ", number:" << std::dec << node->GetGlobalNumber() << 4284514f5e3Sopenharmony_ci ", markCount:" << node->GetMarkCount(); 4294514f5e3Sopenharmony_ci WriteToStackTraceFd(buffer); 4304514f5e3Sopenharmony_ci } 4314514f5e3Sopenharmony_ci } else { 4324514f5e3Sopenharmony_ci primitiveCount++; 4334514f5e3Sopenharmony_ci if (isStopPrimitiveLeakCheck && node->GetGlobalNumber() > 0 && node->GetMarkCount() > 0) { 4344514f5e3Sopenharmony_ci buffer << "Global maybe leak primitive:" << std::hex << value.GetRawData() << 4354514f5e3Sopenharmony_ci ", node address:" << node << ", number:" << std::dec << node->GetGlobalNumber() << 4364514f5e3Sopenharmony_ci ", markCount:" << node->GetMarkCount(); 4374514f5e3Sopenharmony_ci WriteToStackTraceFd(buffer); 4384514f5e3Sopenharmony_ci } 4394514f5e3Sopenharmony_ci } 4404514f5e3Sopenharmony_ci globalCount++; 4414514f5e3Sopenharmony_ci }); 4424514f5e3Sopenharmony_ci 4434514f5e3Sopenharmony_ci if (isStopObjectLeakCheck || isStopPrimitiveLeakCheck) { 4444514f5e3Sopenharmony_ci buffer << "Global leak check success!"; 4454514f5e3Sopenharmony_ci WriteToStackTraceFd(buffer); 4464514f5e3Sopenharmony_ci CloseStackTraceFd(); 4474514f5e3Sopenharmony_ci } 4484514f5e3Sopenharmony_ci // Determine whether memory leakage by checking handle and global count. 4494514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "Iterate root handle count:" << handleCount << ", global handle count:" << globalCount; 4504514f5e3Sopenharmony_ci OPTIONAL_LOG(GetEcmaVM(), INFO) << "Global type Primitive count:" << primitiveCount; 4514514f5e3Sopenharmony_ci // Print global object type statistic. 4524514f5e3Sopenharmony_ci static const int MIN_COUNT_THRESHOLD = 50; 4534514f5e3Sopenharmony_ci for (int i = 0; i < JS_TYPE_LAST; i++) { 4544514f5e3Sopenharmony_ci if (typeCount[i] > MIN_COUNT_THRESHOLD) { 4554514f5e3Sopenharmony_ci OPTIONAL_LOG(GetEcmaVM(), INFO) << "Global type " << JSHClass::DumpJSType(JSType(i)) 4564514f5e3Sopenharmony_ci << " count:" << typeCount[i]; 4574514f5e3Sopenharmony_ci } 4584514f5e3Sopenharmony_ci } 4594514f5e3Sopenharmony_ci} 4604514f5e3Sopenharmony_ci 4614514f5e3Sopenharmony_civoid JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor, GCKind gcKind) 4624514f5e3Sopenharmony_ci{ 4634514f5e3Sopenharmony_ci auto callBack = [this, visitor, gcKind](WeakNode *node) { 4644514f5e3Sopenharmony_ci JSTaggedValue value(node->GetObject()); 4654514f5e3Sopenharmony_ci if (!value.IsHeapObject()) { 4664514f5e3Sopenharmony_ci return; 4674514f5e3Sopenharmony_ci } 4684514f5e3Sopenharmony_ci auto object = value.GetTaggedObject(); 4694514f5e3Sopenharmony_ci auto fwd = visitor(object); 4704514f5e3Sopenharmony_ci if (fwd == nullptr) { 4714514f5e3Sopenharmony_ci // undefind 4724514f5e3Sopenharmony_ci node->SetObject(JSTaggedValue::Undefined().GetRawData()); 4734514f5e3Sopenharmony_ci auto nativeFinalizeCallback = node->GetNativeFinalizeCallback(); 4744514f5e3Sopenharmony_ci if (nativeFinalizeCallback) { 4754514f5e3Sopenharmony_ci weakNodeNativeFinalizeCallbacks_.push_back(std::make_pair(nativeFinalizeCallback, 4764514f5e3Sopenharmony_ci node->GetReference())); 4774514f5e3Sopenharmony_ci } 4784514f5e3Sopenharmony_ci auto freeGlobalCallBack = node->GetFreeGlobalCallback(); 4794514f5e3Sopenharmony_ci if (!freeGlobalCallBack) { 4804514f5e3Sopenharmony_ci // If no callback, dispose global immediately 4814514f5e3Sopenharmony_ci DisposeGlobalHandle(ToUintPtr(node)); 4824514f5e3Sopenharmony_ci } else if (gcKind == GCKind::SHARED_GC) { 4834514f5e3Sopenharmony_ci // For shared GC, free global should defer execute in its own thread 4844514f5e3Sopenharmony_ci weakNodeFreeGlobalCallbacks_.push_back(std::make_pair(freeGlobalCallBack, node->GetReference())); 4854514f5e3Sopenharmony_ci } else { 4864514f5e3Sopenharmony_ci node->CallFreeGlobalCallback(); 4874514f5e3Sopenharmony_ci } 4884514f5e3Sopenharmony_ci } else if (fwd != object) { 4894514f5e3Sopenharmony_ci // update 4904514f5e3Sopenharmony_ci node->SetObject(JSTaggedValue(fwd).GetRawData()); 4914514f5e3Sopenharmony_ci } 4924514f5e3Sopenharmony_ci }; 4934514f5e3Sopenharmony_ci if (!vm_->GetJSOptions().EnableGlobalLeakCheck()) { 4944514f5e3Sopenharmony_ci globalStorage_->IterateWeakUsageGlobal(callBack); 4954514f5e3Sopenharmony_ci } else { 4964514f5e3Sopenharmony_ci globalDebugStorage_->IterateWeakUsageGlobal(callBack); 4974514f5e3Sopenharmony_ci } 4984514f5e3Sopenharmony_ci} 4994514f5e3Sopenharmony_ci 5004514f5e3Sopenharmony_civoid JSThread::UpdateJitCodeMapReference(const WeakRootVisitor &visitor) 5014514f5e3Sopenharmony_ci{ 5024514f5e3Sopenharmony_ci auto it = jitCodeMaps_.begin(); 5034514f5e3Sopenharmony_ci while (it != jitCodeMaps_.end()) { 5044514f5e3Sopenharmony_ci auto obj = reinterpret_cast<TaggedObject *>(it->first); 5054514f5e3Sopenharmony_ci auto fwd = visitor(obj); 5064514f5e3Sopenharmony_ci if (fwd == nullptr) { 5074514f5e3Sopenharmony_ci delete it->second; 5084514f5e3Sopenharmony_ci it = jitCodeMaps_.erase(it); 5094514f5e3Sopenharmony_ci } else if (fwd != obj) { 5104514f5e3Sopenharmony_ci jitCodeMaps_.emplace(JSTaggedValue(fwd).GetRawData(), it->second); 5114514f5e3Sopenharmony_ci it = jitCodeMaps_.erase(it); 5124514f5e3Sopenharmony_ci } else { 5134514f5e3Sopenharmony_ci ++it; 5144514f5e3Sopenharmony_ci } 5154514f5e3Sopenharmony_ci } 5164514f5e3Sopenharmony_ci} 5174514f5e3Sopenharmony_ci 5184514f5e3Sopenharmony_cibool JSThread::DoStackOverflowCheck(const JSTaggedType *sp) 5194514f5e3Sopenharmony_ci{ 5204514f5e3Sopenharmony_ci // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 5214514f5e3Sopenharmony_ci if (UNLIKELY(!IsCrossThreadExecutionEnable() && sp <= glueData_.frameBase_ + RESERVE_STACK_SIZE)) { 5224514f5e3Sopenharmony_ci vm_->CheckThread(); 5234514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Stack overflow! Remaining stack size is: " << (sp - glueData_.frameBase_); 5244514f5e3Sopenharmony_ci if (LIKELY(!HasPendingException())) { 5254514f5e3Sopenharmony_ci ObjectFactory *factory = GetEcmaVM()->GetFactory(); 5264514f5e3Sopenharmony_ci JSHandle<JSObject> error = factory->GetJSError(base::ErrorType::RANGE_ERROR, 5274514f5e3Sopenharmony_ci "Stack overflow!", StackCheck::NO); 5284514f5e3Sopenharmony_ci SetException(error.GetTaggedValue()); 5294514f5e3Sopenharmony_ci } 5304514f5e3Sopenharmony_ci return true; 5314514f5e3Sopenharmony_ci } 5324514f5e3Sopenharmony_ci return false; 5334514f5e3Sopenharmony_ci} 5344514f5e3Sopenharmony_ci 5354514f5e3Sopenharmony_cibool JSThread::DoStackLimitCheck() 5364514f5e3Sopenharmony_ci{ 5374514f5e3Sopenharmony_ci if (UNLIKELY(!IsCrossThreadExecutionEnable() && GetCurrentStackPosition() < GetStackLimit())) { 5384514f5e3Sopenharmony_ci vm_->CheckThread(); 5394514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Stack overflow! current:" << GetCurrentStackPosition() << " limit:" << GetStackLimit(); 5404514f5e3Sopenharmony_ci if (LIKELY(!HasPendingException())) { 5414514f5e3Sopenharmony_ci ObjectFactory *factory = GetEcmaVM()->GetFactory(); 5424514f5e3Sopenharmony_ci JSHandle<JSObject> error = factory->GetJSError(base::ErrorType::RANGE_ERROR, 5434514f5e3Sopenharmony_ci "Stack overflow!", StackCheck::NO); 5444514f5e3Sopenharmony_ci SetException(error.GetTaggedValue()); 5454514f5e3Sopenharmony_ci } 5464514f5e3Sopenharmony_ci return true; 5474514f5e3Sopenharmony_ci } 5484514f5e3Sopenharmony_ci return false; 5494514f5e3Sopenharmony_ci} 5504514f5e3Sopenharmony_ci 5514514f5e3Sopenharmony_ciuintptr_t *JSThread::ExpandHandleStorage() 5524514f5e3Sopenharmony_ci{ 5534514f5e3Sopenharmony_ci return GetCurrentEcmaContext()->ExpandHandleStorage(); 5544514f5e3Sopenharmony_ci} 5554514f5e3Sopenharmony_ci 5564514f5e3Sopenharmony_civoid JSThread::ShrinkHandleStorage(int prevIndex) 5574514f5e3Sopenharmony_ci{ 5584514f5e3Sopenharmony_ci GetCurrentEcmaContext()->ShrinkHandleStorage(prevIndex); 5594514f5e3Sopenharmony_ci} 5604514f5e3Sopenharmony_ci 5614514f5e3Sopenharmony_civoid JSThread::NotifyStableArrayElementsGuardians(JSHandle<JSObject> receiver, StableArrayChangeKind changeKind) 5624514f5e3Sopenharmony_ci{ 5634514f5e3Sopenharmony_ci if (!glueData_.stableArrayElementsGuardians_) { 5644514f5e3Sopenharmony_ci return; 5654514f5e3Sopenharmony_ci } 5664514f5e3Sopenharmony_ci if (!receiver->GetJSHClass()->IsPrototype() && !receiver->IsJSArray()) { 5674514f5e3Sopenharmony_ci return; 5684514f5e3Sopenharmony_ci } 5694514f5e3Sopenharmony_ci auto env = GetEcmaVM()->GetGlobalEnv(); 5704514f5e3Sopenharmony_ci if (receiver.GetTaggedValue() == env->GetObjectFunctionPrototype().GetTaggedValue() || 5714514f5e3Sopenharmony_ci receiver.GetTaggedValue() == env->GetArrayPrototype().GetTaggedValue()) { 5724514f5e3Sopenharmony_ci glueData_.stableArrayElementsGuardians_ = false; 5734514f5e3Sopenharmony_ci return; 5744514f5e3Sopenharmony_ci } 5754514f5e3Sopenharmony_ci if (changeKind == StableArrayChangeKind::PROTO && receiver->IsJSArray()) { 5764514f5e3Sopenharmony_ci glueData_.stableArrayElementsGuardians_ = false; 5774514f5e3Sopenharmony_ci } 5784514f5e3Sopenharmony_ci} 5794514f5e3Sopenharmony_ci 5804514f5e3Sopenharmony_civoid JSThread::ResetGuardians() 5814514f5e3Sopenharmony_ci{ 5824514f5e3Sopenharmony_ci glueData_.stableArrayElementsGuardians_ = true; 5834514f5e3Sopenharmony_ci} 5844514f5e3Sopenharmony_ci 5854514f5e3Sopenharmony_civoid JSThread::SetInitialBuiltinHClass( 5864514f5e3Sopenharmony_ci BuiltinTypeId type, JSHClass *builtinHClass, JSHClass *instanceHClass, 5874514f5e3Sopenharmony_ci JSHClass *prototypeHClass, JSHClass *prototypeOfPrototypeHClass, JSHClass *extraHClass) 5884514f5e3Sopenharmony_ci{ 5894514f5e3Sopenharmony_ci size_t index = BuiltinHClassEntries::GetEntryIndex(type); 5904514f5e3Sopenharmony_ci auto &entry = glueData_.builtinHClassEntries_.entries[index]; 5914514f5e3Sopenharmony_ci LOG_ECMA(DEBUG) << "JSThread::SetInitialBuiltinHClass: " 5924514f5e3Sopenharmony_ci << "Builtin = " << ToString(type) 5934514f5e3Sopenharmony_ci << ", builtinHClass = " << builtinHClass 5944514f5e3Sopenharmony_ci << ", instanceHClass = " << instanceHClass 5954514f5e3Sopenharmony_ci << ", prototypeHClass = " << prototypeHClass 5964514f5e3Sopenharmony_ci << ", prototypeOfPrototypeHClass = " << prototypeOfPrototypeHClass 5974514f5e3Sopenharmony_ci << ", extraHClass = " << extraHClass; 5984514f5e3Sopenharmony_ci entry.builtinHClass = builtinHClass; 5994514f5e3Sopenharmony_ci entry.instanceHClass = instanceHClass; 6004514f5e3Sopenharmony_ci entry.prototypeHClass = prototypeHClass; 6014514f5e3Sopenharmony_ci entry.prototypeOfPrototypeHClass = prototypeOfPrototypeHClass; 6024514f5e3Sopenharmony_ci entry.extraHClass = extraHClass; 6034514f5e3Sopenharmony_ci} 6044514f5e3Sopenharmony_ci 6054514f5e3Sopenharmony_civoid JSThread::SetInitialBuiltinGlobalHClass( 6064514f5e3Sopenharmony_ci JSHClass *builtinHClass, GlobalIndex globalIndex) 6074514f5e3Sopenharmony_ci{ 6084514f5e3Sopenharmony_ci auto &map = ctorHclassEntries_; 6094514f5e3Sopenharmony_ci map[builtinHClass] = globalIndex; 6104514f5e3Sopenharmony_ci} 6114514f5e3Sopenharmony_ci 6124514f5e3Sopenharmony_ciJSHClass *JSThread::GetBuiltinHClass(BuiltinTypeId type) const 6134514f5e3Sopenharmony_ci{ 6144514f5e3Sopenharmony_ci size_t index = BuiltinHClassEntries::GetEntryIndex(type); 6154514f5e3Sopenharmony_ci return glueData_.builtinHClassEntries_.entries[index].builtinHClass; 6164514f5e3Sopenharmony_ci} 6174514f5e3Sopenharmony_ci 6184514f5e3Sopenharmony_ciJSHClass *JSThread::GetBuiltinInstanceHClass(BuiltinTypeId type) const 6194514f5e3Sopenharmony_ci{ 6204514f5e3Sopenharmony_ci size_t index = BuiltinHClassEntries::GetEntryIndex(type); 6214514f5e3Sopenharmony_ci return glueData_.builtinHClassEntries_.entries[index].instanceHClass; 6224514f5e3Sopenharmony_ci} 6234514f5e3Sopenharmony_ci 6244514f5e3Sopenharmony_ciJSHClass *JSThread::GetBuiltinExtraHClass(BuiltinTypeId type) const 6254514f5e3Sopenharmony_ci{ 6264514f5e3Sopenharmony_ci size_t index = BuiltinHClassEntries::GetEntryIndex(type); 6274514f5e3Sopenharmony_ci return glueData_.builtinHClassEntries_.entries[index].extraHClass; 6284514f5e3Sopenharmony_ci} 6294514f5e3Sopenharmony_ci 6304514f5e3Sopenharmony_ciJSHClass *JSThread::GetArrayInstanceHClass(ElementsKind kind, bool isPrototype) const 6314514f5e3Sopenharmony_ci{ 6324514f5e3Sopenharmony_ci auto iter = GetArrayHClassIndexMap().find(kind); 6334514f5e3Sopenharmony_ci ASSERT(iter != GetArrayHClassIndexMap().end()); 6344514f5e3Sopenharmony_ci auto index = isPrototype ? static_cast<size_t>(iter->second.second) : static_cast<size_t>(iter->second.first); 6354514f5e3Sopenharmony_ci auto exceptArrayHClass = GlobalConstants()->GetGlobalConstantObject(index); 6364514f5e3Sopenharmony_ci auto exceptRecvHClass = JSHClass::Cast(exceptArrayHClass.GetTaggedObject()); 6374514f5e3Sopenharmony_ci ASSERT(exceptRecvHClass->IsJSArray()); 6384514f5e3Sopenharmony_ci return exceptRecvHClass; 6394514f5e3Sopenharmony_ci} 6404514f5e3Sopenharmony_ci 6414514f5e3Sopenharmony_ciJSHClass *JSThread::GetBuiltinPrototypeHClass(BuiltinTypeId type) const 6424514f5e3Sopenharmony_ci{ 6434514f5e3Sopenharmony_ci size_t index = BuiltinHClassEntries::GetEntryIndex(type); 6444514f5e3Sopenharmony_ci return glueData_.builtinHClassEntries_.entries[index].prototypeHClass; 6454514f5e3Sopenharmony_ci} 6464514f5e3Sopenharmony_ci 6474514f5e3Sopenharmony_ciJSHClass *JSThread::GetBuiltinPrototypeOfPrototypeHClass(BuiltinTypeId type) const 6484514f5e3Sopenharmony_ci{ 6494514f5e3Sopenharmony_ci size_t index = BuiltinHClassEntries::GetEntryIndex(type); 6504514f5e3Sopenharmony_ci return glueData_.builtinHClassEntries_.entries[index].prototypeOfPrototypeHClass; 6514514f5e3Sopenharmony_ci} 6524514f5e3Sopenharmony_ci 6534514f5e3Sopenharmony_cisize_t JSThread::GetBuiltinHClassOffset(BuiltinTypeId type, bool isArch32) 6544514f5e3Sopenharmony_ci{ 6554514f5e3Sopenharmony_ci return GetGlueDataOffset() + GlueData::GetBuiltinHClassOffset(type, isArch32); 6564514f5e3Sopenharmony_ci} 6574514f5e3Sopenharmony_ci 6584514f5e3Sopenharmony_cisize_t JSThread::GetBuiltinPrototypeHClassOffset(BuiltinTypeId type, bool isArch32) 6594514f5e3Sopenharmony_ci{ 6604514f5e3Sopenharmony_ci return GetGlueDataOffset() + GlueData::GetBuiltinPrototypeHClassOffset(type, isArch32); 6614514f5e3Sopenharmony_ci} 6624514f5e3Sopenharmony_ci 6634514f5e3Sopenharmony_civoid JSThread::CheckSwitchDebuggerBCStub() 6644514f5e3Sopenharmony_ci{ 6654514f5e3Sopenharmony_ci auto isDebug = GetEcmaVM()->GetJsDebuggerManager()->IsDebugMode(); 6664514f5e3Sopenharmony_ci if (LIKELY(!isDebug)) { 6674514f5e3Sopenharmony_ci if (glueData_.bcStubEntries_.Get(0) == glueData_.bcStubEntries_.Get(1)) { 6684514f5e3Sopenharmony_ci for (size_t i = 0; i < BCStubEntries::BC_HANDLER_COUNT; i++) { 6694514f5e3Sopenharmony_ci auto stubEntry = glueData_.bcDebuggerStubEntries_.Get(i); 6704514f5e3Sopenharmony_ci auto debuggerStubEbtry = glueData_.bcStubEntries_.Get(i); 6714514f5e3Sopenharmony_ci glueData_.bcStubEntries_.Set(i, stubEntry); 6724514f5e3Sopenharmony_ci glueData_.bcDebuggerStubEntries_.Set(i, debuggerStubEbtry); 6734514f5e3Sopenharmony_ci } 6744514f5e3Sopenharmony_ci } 6754514f5e3Sopenharmony_ci } else { 6764514f5e3Sopenharmony_ci if (glueData_.bcDebuggerStubEntries_.Get(0) == glueData_.bcDebuggerStubEntries_.Get(1)) { 6774514f5e3Sopenharmony_ci for (size_t i = 0; i < BCStubEntries::BC_HANDLER_COUNT; i++) { 6784514f5e3Sopenharmony_ci auto stubEntry = glueData_.bcStubEntries_.Get(i); 6794514f5e3Sopenharmony_ci auto debuggerStubEbtry = glueData_.bcDebuggerStubEntries_.Get(i); 6804514f5e3Sopenharmony_ci glueData_.bcDebuggerStubEntries_.Set(i, stubEntry); 6814514f5e3Sopenharmony_ci glueData_.bcStubEntries_.Set(i, debuggerStubEbtry); 6824514f5e3Sopenharmony_ci } 6834514f5e3Sopenharmony_ci } 6844514f5e3Sopenharmony_ci } 6854514f5e3Sopenharmony_ci} 6864514f5e3Sopenharmony_ci 6874514f5e3Sopenharmony_civoid JSThread::CheckOrSwitchPGOStubs() 6884514f5e3Sopenharmony_ci{ 6894514f5e3Sopenharmony_ci bool isSwitch = false; 6904514f5e3Sopenharmony_ci if (IsPGOProfilerEnable()) { 6914514f5e3Sopenharmony_ci if (GetBCStubStatus() == BCStubStatus::NORMAL_BC_STUB) { 6924514f5e3Sopenharmony_ci SetBCStubStatus(BCStubStatus::PROFILE_BC_STUB); 6934514f5e3Sopenharmony_ci isSwitch = true; 6944514f5e3Sopenharmony_ci } 6954514f5e3Sopenharmony_ci } else { 6964514f5e3Sopenharmony_ci if (GetBCStubStatus() == BCStubStatus::PROFILE_BC_STUB) { 6974514f5e3Sopenharmony_ci SetBCStubStatus(BCStubStatus::NORMAL_BC_STUB); 6984514f5e3Sopenharmony_ci isSwitch = true; 6994514f5e3Sopenharmony_ci } 7004514f5e3Sopenharmony_ci } 7014514f5e3Sopenharmony_ci if (isSwitch) { 7024514f5e3Sopenharmony_ci Address curAddress; 7034514f5e3Sopenharmony_ci#define SWITCH_PGO_STUB_ENTRY(fromName, toName, ...) \ 7044514f5e3Sopenharmony_ci curAddress = GetBCStubEntry(BytecodeStubCSigns::ID_##fromName); \ 7054514f5e3Sopenharmony_ci SetBCStubEntry(BytecodeStubCSigns::ID_##fromName, GetBCStubEntry(BytecodeStubCSigns::ID_##toName)); \ 7064514f5e3Sopenharmony_ci SetBCStubEntry(BytecodeStubCSigns::ID_##toName, curAddress); 7074514f5e3Sopenharmony_ci ASM_INTERPRETER_BC_PROFILER_STUB_LIST(SWITCH_PGO_STUB_ENTRY) 7084514f5e3Sopenharmony_ci#undef SWITCH_PGO_STUB_ENTRY 7094514f5e3Sopenharmony_ci } 7104514f5e3Sopenharmony_ci} 7114514f5e3Sopenharmony_ci 7124514f5e3Sopenharmony_civoid JSThread::SwitchJitProfileStubs(bool isEnablePgo) 7134514f5e3Sopenharmony_ci{ 7144514f5e3Sopenharmony_ci if (isEnablePgo) { 7154514f5e3Sopenharmony_ci SetPGOProfilerEnable(true); 7164514f5e3Sopenharmony_ci CheckOrSwitchPGOStubs(); 7174514f5e3Sopenharmony_ci return; 7184514f5e3Sopenharmony_ci } 7194514f5e3Sopenharmony_ci bool isSwitch = false; 7204514f5e3Sopenharmony_ci if (GetBCStubStatus() == BCStubStatus::NORMAL_BC_STUB) { 7214514f5e3Sopenharmony_ci SetBCStubStatus(BCStubStatus::JIT_PROFILE_BC_STUB); 7224514f5e3Sopenharmony_ci isSwitch = true; 7234514f5e3Sopenharmony_ci } 7244514f5e3Sopenharmony_ci if (isSwitch) { 7254514f5e3Sopenharmony_ci Address curAddress; 7264514f5e3Sopenharmony_ci#define SWITCH_PGO_STUB_ENTRY(fromName, toName, ...) \ 7274514f5e3Sopenharmony_ci curAddress = GetBCStubEntry(BytecodeStubCSigns::ID_##fromName); \ 7284514f5e3Sopenharmony_ci SetBCStubEntry(BytecodeStubCSigns::ID_##fromName, GetBCStubEntry(BytecodeStubCSigns::ID_##toName)); \ 7294514f5e3Sopenharmony_ci SetBCStubEntry(BytecodeStubCSigns::ID_##toName, curAddress); 7304514f5e3Sopenharmony_ci ASM_INTERPRETER_BC_JIT_PROFILER_STUB_LIST(SWITCH_PGO_STUB_ENTRY) 7314514f5e3Sopenharmony_ci#undef SWITCH_PGO_STUB_ENTRY 7324514f5e3Sopenharmony_ci } 7334514f5e3Sopenharmony_ci} 7344514f5e3Sopenharmony_ci 7354514f5e3Sopenharmony_civoid JSThread::TerminateExecution() 7364514f5e3Sopenharmony_ci{ 7374514f5e3Sopenharmony_ci // set the TERMINATE_ERROR to exception 7384514f5e3Sopenharmony_ci ObjectFactory *factory = GetEcmaVM()->GetFactory(); 7394514f5e3Sopenharmony_ci JSHandle<JSObject> error = factory->GetJSError(ErrorType::TERMINATION_ERROR, 7404514f5e3Sopenharmony_ci "Terminate execution!", StackCheck::NO); 7414514f5e3Sopenharmony_ci SetException(error.GetTaggedValue()); 7424514f5e3Sopenharmony_ci} 7434514f5e3Sopenharmony_ci 7444514f5e3Sopenharmony_civoid JSThread::CheckAndPassActiveBarrier() 7454514f5e3Sopenharmony_ci{ 7464514f5e3Sopenharmony_ci ThreadStateAndFlags oldStateAndFlags; 7474514f5e3Sopenharmony_ci oldStateAndFlags.asNonvolatileInt = glueData_.stateAndFlags_.asInt; 7484514f5e3Sopenharmony_ci if ((oldStateAndFlags.asNonvolatileStruct.flags & ThreadFlag::ACTIVE_BARRIER) != 0) { 7494514f5e3Sopenharmony_ci PassSuspendBarrier(); 7504514f5e3Sopenharmony_ci } 7514514f5e3Sopenharmony_ci} 7524514f5e3Sopenharmony_ci 7534514f5e3Sopenharmony_cibool JSThread::PassSuspendBarrier() 7544514f5e3Sopenharmony_ci{ 7554514f5e3Sopenharmony_ci // Use suspendLock_ to avoid data-race between suspend-all-thread and suspended-threads. 7564514f5e3Sopenharmony_ci LockHolder lock(suspendLock_); 7574514f5e3Sopenharmony_ci if (suspendBarrier_ != nullptr) { 7584514f5e3Sopenharmony_ci suspendBarrier_->PassStrongly(); 7594514f5e3Sopenharmony_ci suspendBarrier_ = nullptr; 7604514f5e3Sopenharmony_ci ClearFlag(ThreadFlag::ACTIVE_BARRIER); 7614514f5e3Sopenharmony_ci return true; 7624514f5e3Sopenharmony_ci } 7634514f5e3Sopenharmony_ci return false; 7644514f5e3Sopenharmony_ci} 7654514f5e3Sopenharmony_ci 7664514f5e3Sopenharmony_cibool JSThread::CheckSafepoint() 7674514f5e3Sopenharmony_ci{ 7684514f5e3Sopenharmony_ci ResetCheckSafePointStatus(); 7694514f5e3Sopenharmony_ci 7704514f5e3Sopenharmony_ci if (HasTerminationRequest()) { 7714514f5e3Sopenharmony_ci TerminateExecution(); 7724514f5e3Sopenharmony_ci SetVMTerminated(true); 7734514f5e3Sopenharmony_ci SetTerminationRequest(false); 7744514f5e3Sopenharmony_ci } 7754514f5e3Sopenharmony_ci 7764514f5e3Sopenharmony_ci if (HasSuspendRequest()) { 7774514f5e3Sopenharmony_ci WaitSuspension(); 7784514f5e3Sopenharmony_ci } 7794514f5e3Sopenharmony_ci 7804514f5e3Sopenharmony_ci // vmThreadControl_ 's thread_ is current JSThread's this. 7814514f5e3Sopenharmony_ci if (VMNeedSuspension()) { 7824514f5e3Sopenharmony_ci vmThreadControl_->SuspendVM(); 7834514f5e3Sopenharmony_ci } 7844514f5e3Sopenharmony_ci if (HasInstallMachineCode()) { 7854514f5e3Sopenharmony_ci vm_->GetJit()->InstallTasks(this); 7864514f5e3Sopenharmony_ci SetInstallMachineCode(false); 7874514f5e3Sopenharmony_ci } 7884514f5e3Sopenharmony_ci 7894514f5e3Sopenharmony_ci#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) 7904514f5e3Sopenharmony_ci if (needProfiling_.load() && !isProfiling_) { 7914514f5e3Sopenharmony_ci DFXJSNApi::StartCpuProfilerForFile(vm_, profileName_, CpuProfiler::INTERVAL_OF_INNER_START); 7924514f5e3Sopenharmony_ci SetNeedProfiling(false); 7934514f5e3Sopenharmony_ci } 7944514f5e3Sopenharmony_ci#endif // ECMASCRIPT_SUPPORT_CPUPROFILER 7954514f5e3Sopenharmony_ci bool gcTriggered = false; 7964514f5e3Sopenharmony_ci#ifndef NDEBUG 7974514f5e3Sopenharmony_ci if (vm_->GetJSOptions().EnableForceGC()) { 7984514f5e3Sopenharmony_ci GetEcmaVM()->CollectGarbage(TriggerGCType::FULL_GC); 7994514f5e3Sopenharmony_ci gcTriggered = true; 8004514f5e3Sopenharmony_ci } 8014514f5e3Sopenharmony_ci#endif 8024514f5e3Sopenharmony_ci auto heap = const_cast<Heap *>(GetEcmaVM()->GetHeap()); 8034514f5e3Sopenharmony_ci // Handle exit app senstive scene 8044514f5e3Sopenharmony_ci heap->HandleExitHighSensitiveEvent(); 8054514f5e3Sopenharmony_ci 8064514f5e3Sopenharmony_ci // After concurrent mark finish, should trigger gc here to avoid create much floating garbage 8074514f5e3Sopenharmony_ci // except in serialize or high sensitive event 8084514f5e3Sopenharmony_ci if (IsMarkFinished() && heap->GetConcurrentMarker()->IsTriggeredConcurrentMark() 8094514f5e3Sopenharmony_ci && !heap->GetOnSerializeEvent() && !heap->InSensitiveStatus()) { 8104514f5e3Sopenharmony_ci heap->SetCanThrowOOMError(false); 8114514f5e3Sopenharmony_ci heap->GetConcurrentMarker()->HandleMarkingFinished(); 8124514f5e3Sopenharmony_ci heap->SetCanThrowOOMError(true); 8134514f5e3Sopenharmony_ci gcTriggered = true; 8144514f5e3Sopenharmony_ci } 8154514f5e3Sopenharmony_ci return gcTriggered; 8164514f5e3Sopenharmony_ci} 8174514f5e3Sopenharmony_ci 8184514f5e3Sopenharmony_civoid JSThread::CheckJSTaggedType(JSTaggedType value) const 8194514f5e3Sopenharmony_ci{ 8204514f5e3Sopenharmony_ci if (JSTaggedValue(value).IsHeapObject() && 8214514f5e3Sopenharmony_ci !GetEcmaVM()->GetHeap()->IsAlive(reinterpret_cast<TaggedObject *>(value))) { 8224514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "value:" << value << " is invalid!"; 8234514f5e3Sopenharmony_ci } 8244514f5e3Sopenharmony_ci} 8254514f5e3Sopenharmony_ci 8264514f5e3Sopenharmony_cibool JSThread::CpuProfilerCheckJSTaggedType(JSTaggedType value) const 8274514f5e3Sopenharmony_ci{ 8284514f5e3Sopenharmony_ci if (JSTaggedValue(value).IsHeapObject() && 8294514f5e3Sopenharmony_ci !GetEcmaVM()->GetHeap()->IsAlive(reinterpret_cast<TaggedObject *>(value))) { 8304514f5e3Sopenharmony_ci return false; 8314514f5e3Sopenharmony_ci } 8324514f5e3Sopenharmony_ci return true; 8334514f5e3Sopenharmony_ci} 8344514f5e3Sopenharmony_ci 8354514f5e3Sopenharmony_ci// static 8364514f5e3Sopenharmony_cisize_t JSThread::GetAsmStackLimit() 8374514f5e3Sopenharmony_ci{ 8384514f5e3Sopenharmony_ci#if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS) 8394514f5e3Sopenharmony_ci // js stack limit 8404514f5e3Sopenharmony_ci size_t result = GetCurrentStackPosition() - EcmaParamConfiguration::GetDefalutStackSize(); 8414514f5e3Sopenharmony_ci int ret = -1; 8424514f5e3Sopenharmony_ci void *stackAddr = nullptr; 8434514f5e3Sopenharmony_ci size_t size = 0; 8444514f5e3Sopenharmony_ci#if defined(ENABLE_FFRT_INTERFACES) 8454514f5e3Sopenharmony_ci if (!ffrt_get_current_coroutine_stack(&stackAddr, &size)) { 8464514f5e3Sopenharmony_ci pthread_attr_t attr; 8474514f5e3Sopenharmony_ci ret = pthread_getattr_np(pthread_self(), &attr); 8484514f5e3Sopenharmony_ci if (ret != 0) { 8494514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Get current thread attr failed"; 8504514f5e3Sopenharmony_ci return result; 8514514f5e3Sopenharmony_ci } 8524514f5e3Sopenharmony_ci ret = pthread_attr_getstack(&attr, &stackAddr, &size); 8534514f5e3Sopenharmony_ci if (pthread_attr_destroy(&attr) != 0) { 8544514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Destroy current thread attr failed"; 8554514f5e3Sopenharmony_ci } 8564514f5e3Sopenharmony_ci if (ret != 0) { 8574514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Get current thread stack size failed"; 8584514f5e3Sopenharmony_ci return result; 8594514f5e3Sopenharmony_ci } 8604514f5e3Sopenharmony_ci } 8614514f5e3Sopenharmony_ci#else 8624514f5e3Sopenharmony_ci pthread_attr_t attr; 8634514f5e3Sopenharmony_ci ret = pthread_getattr_np(pthread_self(), &attr); 8644514f5e3Sopenharmony_ci if (ret != 0) { 8654514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Get current thread attr failed"; 8664514f5e3Sopenharmony_ci return result; 8674514f5e3Sopenharmony_ci } 8684514f5e3Sopenharmony_ci ret = pthread_attr_getstack(&attr, &stackAddr, &size); 8694514f5e3Sopenharmony_ci if (pthread_attr_destroy(&attr) != 0) { 8704514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Destroy current thread attr failed"; 8714514f5e3Sopenharmony_ci } 8724514f5e3Sopenharmony_ci if (ret != 0) { 8734514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Get current thread stack size failed"; 8744514f5e3Sopenharmony_ci return result; 8754514f5e3Sopenharmony_ci } 8764514f5e3Sopenharmony_ci#endif 8774514f5e3Sopenharmony_ci 8784514f5e3Sopenharmony_ci bool isMainThread = IsMainThread(); 8794514f5e3Sopenharmony_ci uintptr_t threadStackLimit = reinterpret_cast<uintptr_t>(stackAddr); 8804514f5e3Sopenharmony_ci uintptr_t threadStackStart = threadStackLimit + size; 8814514f5e3Sopenharmony_ci if (isMainThread) { 8824514f5e3Sopenharmony_ci struct rlimit rl; 8834514f5e3Sopenharmony_ci ret = getrlimit(RLIMIT_STACK, &rl); 8844514f5e3Sopenharmony_ci if (ret != 0) { 8854514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Get current thread stack size failed"; 8864514f5e3Sopenharmony_ci return result; 8874514f5e3Sopenharmony_ci } 8884514f5e3Sopenharmony_ci if (rl.rlim_cur > DEFAULT_MAX_SYSTEM_STACK_SIZE) { 8894514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "Get current thread stack size exceed " << DEFAULT_MAX_SYSTEM_STACK_SIZE 8904514f5e3Sopenharmony_ci << " : " << rl.rlim_cur; 8914514f5e3Sopenharmony_ci return result; 8924514f5e3Sopenharmony_ci } 8934514f5e3Sopenharmony_ci threadStackLimit = threadStackStart - rl.rlim_cur; 8944514f5e3Sopenharmony_ci } 8954514f5e3Sopenharmony_ci 8964514f5e3Sopenharmony_ci if (result < threadStackLimit) { 8974514f5e3Sopenharmony_ci result = threadStackLimit; 8984514f5e3Sopenharmony_ci } 8994514f5e3Sopenharmony_ci 9004514f5e3Sopenharmony_ci LOG_INTERPRETER(DEBUG) << "Current thread stack start: " << reinterpret_cast<void *>(threadStackStart); 9014514f5e3Sopenharmony_ci LOG_INTERPRETER(DEBUG) << "Used stack before js stack start: " 9024514f5e3Sopenharmony_ci << reinterpret_cast<void *>(threadStackStart - GetCurrentStackPosition()); 9034514f5e3Sopenharmony_ci LOG_INTERPRETER(DEBUG) << "Current thread asm stack limit: " << reinterpret_cast<void *>(result); 9044514f5e3Sopenharmony_ci 9054514f5e3Sopenharmony_ci // To avoid too much times of stack overflow checking, we only check stack overflow before push vregs or 9064514f5e3Sopenharmony_ci // parameters of variable length. So we need a reserved size of stack to make sure stack won't be overflowed 9074514f5e3Sopenharmony_ci // when push other data. 9084514f5e3Sopenharmony_ci result += EcmaParamConfiguration::GetDefaultReservedStackSize(); 9094514f5e3Sopenharmony_ci if (threadStackStart <= result) { 9104514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "Too small stackSize to run jsvm"; 9114514f5e3Sopenharmony_ci } 9124514f5e3Sopenharmony_ci return result; 9134514f5e3Sopenharmony_ci#else 9144514f5e3Sopenharmony_ci return 0; 9154514f5e3Sopenharmony_ci#endif 9164514f5e3Sopenharmony_ci} 9174514f5e3Sopenharmony_ci 9184514f5e3Sopenharmony_cibool JSThread::IsLegalAsmSp(uintptr_t sp) const 9194514f5e3Sopenharmony_ci{ 9204514f5e3Sopenharmony_ci uint64_t bottom = GetStackLimit() - EcmaParamConfiguration::GetDefaultReservedStackSize(); 9214514f5e3Sopenharmony_ci uint64_t top = GetStackStart() + EcmaParamConfiguration::GetAllowedUpperStackDiff(); 9224514f5e3Sopenharmony_ci return (bottom <= sp && sp <= top); 9234514f5e3Sopenharmony_ci} 9244514f5e3Sopenharmony_ci 9254514f5e3Sopenharmony_cibool JSThread::IsLegalThreadSp(uintptr_t sp) const 9264514f5e3Sopenharmony_ci{ 9274514f5e3Sopenharmony_ci uintptr_t bottom = reinterpret_cast<uintptr_t>(glueData_.frameBase_); 9284514f5e3Sopenharmony_ci size_t maxStackSize = vm_->GetEcmaParamConfiguration().GetMaxStackSize(); 9294514f5e3Sopenharmony_ci uintptr_t top = bottom + maxStackSize; 9304514f5e3Sopenharmony_ci return (bottom <= sp && sp <= top); 9314514f5e3Sopenharmony_ci} 9324514f5e3Sopenharmony_ci 9334514f5e3Sopenharmony_cibool JSThread::IsLegalSp(uintptr_t sp) const 9344514f5e3Sopenharmony_ci{ 9354514f5e3Sopenharmony_ci return IsLegalAsmSp(sp) || IsLegalThreadSp(sp); 9364514f5e3Sopenharmony_ci} 9374514f5e3Sopenharmony_ci 9384514f5e3Sopenharmony_cibool JSThread::IsMainThread() 9394514f5e3Sopenharmony_ci{ 9404514f5e3Sopenharmony_ci#if !defined(PANDA_TARGET_WINDOWS) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS) 9414514f5e3Sopenharmony_ci return getpid() == syscall(SYS_gettid); 9424514f5e3Sopenharmony_ci#else 9434514f5e3Sopenharmony_ci return true; 9444514f5e3Sopenharmony_ci#endif 9454514f5e3Sopenharmony_ci} 9464514f5e3Sopenharmony_ci 9474514f5e3Sopenharmony_civoid JSThread::PushContext(EcmaContext *context) 9484514f5e3Sopenharmony_ci{ 9494514f5e3Sopenharmony_ci const_cast<Heap *>(vm_->GetHeap())->WaitAllTasksFinished(); 9504514f5e3Sopenharmony_ci contexts_.emplace_back(context); 9514514f5e3Sopenharmony_ci 9524514f5e3Sopenharmony_ci if (!glueData_.currentContext_) { 9534514f5e3Sopenharmony_ci // The first context in ecma vm. 9544514f5e3Sopenharmony_ci glueData_.currentContext_ = context; 9554514f5e3Sopenharmony_ci context->SetFramePointers(const_cast<JSTaggedType *>(GetCurrentSPFrame()), 9564514f5e3Sopenharmony_ci const_cast<JSTaggedType *>(GetLastLeaveFrame()), 9574514f5e3Sopenharmony_ci const_cast<JSTaggedType *>(GetLastFp())); 9584514f5e3Sopenharmony_ci context->SetFrameBase(glueData_.frameBase_); 9594514f5e3Sopenharmony_ci context->SetStackLimit(glueData_.stackLimit_); 9604514f5e3Sopenharmony_ci context->SetStackStart(glueData_.stackStart_); 9614514f5e3Sopenharmony_ci } else { 9624514f5e3Sopenharmony_ci // algin with 16 9634514f5e3Sopenharmony_ci size_t maxStackSize = vm_->GetEcmaParamConfiguration().GetMaxStackSize(); 9644514f5e3Sopenharmony_ci context->SetFrameBase(static_cast<JSTaggedType *>( 9654514f5e3Sopenharmony_ci vm_->GetNativeAreaAllocator()->Allocate(sizeof(JSTaggedType) * maxStackSize))); 9664514f5e3Sopenharmony_ci context->SetFramePointers(context->GetFrameBase() + maxStackSize, nullptr, nullptr); 9674514f5e3Sopenharmony_ci context->SetStackLimit(GetAsmStackLimit()); 9684514f5e3Sopenharmony_ci context->SetStackStart(GetCurrentStackPosition()); 9694514f5e3Sopenharmony_ci EcmaInterpreter::InitStackFrame(context); 9704514f5e3Sopenharmony_ci } 9714514f5e3Sopenharmony_ci} 9724514f5e3Sopenharmony_ci 9734514f5e3Sopenharmony_civoid JSThread::PopContext() 9744514f5e3Sopenharmony_ci{ 9754514f5e3Sopenharmony_ci contexts_.pop_back(); 9764514f5e3Sopenharmony_ci glueData_.currentContext_ = contexts_.back(); 9774514f5e3Sopenharmony_ci} 9784514f5e3Sopenharmony_ci 9794514f5e3Sopenharmony_civoid JSThread::SwitchCurrentContext(EcmaContext *currentContext, bool isInIterate) 9804514f5e3Sopenharmony_ci{ 9814514f5e3Sopenharmony_ci ASSERT(std::count(contexts_.begin(), contexts_.end(), currentContext)); 9824514f5e3Sopenharmony_ci 9834514f5e3Sopenharmony_ci glueData_.currentContext_->SetFramePointers(const_cast<JSTaggedType *>(GetCurrentSPFrame()), 9844514f5e3Sopenharmony_ci const_cast<JSTaggedType *>(GetLastLeaveFrame()), 9854514f5e3Sopenharmony_ci const_cast<JSTaggedType *>(GetLastFp())); 9864514f5e3Sopenharmony_ci glueData_.currentContext_->SetFrameBase(glueData_.frameBase_); 9874514f5e3Sopenharmony_ci glueData_.currentContext_->SetStackLimit(GetStackLimit()); 9884514f5e3Sopenharmony_ci glueData_.currentContext_->SetStackStart(GetStackStart()); 9894514f5e3Sopenharmony_ci glueData_.currentContext_->SetGlobalEnv(GetGlueGlobalEnv()); 9904514f5e3Sopenharmony_ci // When the glueData_.currentContext_ is not fully initialized,glueData_.globalObject_ will be hole. 9914514f5e3Sopenharmony_ci // Assigning hole to JSGlobalObject could cause a mistake at builtins initalization. 9924514f5e3Sopenharmony_ci if (!glueData_.globalObject_.IsHole()) { 9934514f5e3Sopenharmony_ci glueData_.currentContext_->GetGlobalEnv()->SetJSGlobalObject(this, glueData_.globalObject_); 9944514f5e3Sopenharmony_ci } 9954514f5e3Sopenharmony_ci 9964514f5e3Sopenharmony_ci SetCurrentSPFrame(currentContext->GetCurrentFrame()); 9974514f5e3Sopenharmony_ci SetLastLeaveFrame(currentContext->GetLeaveFrame()); 9984514f5e3Sopenharmony_ci SetLastFp(currentContext->GetLastFp()); 9994514f5e3Sopenharmony_ci glueData_.frameBase_ = currentContext->GetFrameBase(); 10004514f5e3Sopenharmony_ci glueData_.stackLimit_ = currentContext->GetStackLimit(); 10014514f5e3Sopenharmony_ci glueData_.stackStart_ = currentContext->GetStackStart(); 10024514f5e3Sopenharmony_ci if (!currentContext->GlobalEnvIsHole()) { 10034514f5e3Sopenharmony_ci SetGlueGlobalEnv(*(currentContext->GetGlobalEnv())); 10044514f5e3Sopenharmony_ci /** 10054514f5e3Sopenharmony_ci * GlobalObject has two copies, one in GlueData and one in Context.GlobalEnv, when switch context, will save 10064514f5e3Sopenharmony_ci * GlobalObject in GlueData to CurrentContext.GlobalEnv(is this nessary?), and then switch to new context, 10074514f5e3Sopenharmony_ci * save the GlobalObject in NewContext.GlobalEnv to GlueData. 10084514f5e3Sopenharmony_ci * The initial value of GlobalObject in Context.GlobalEnv is Undefined, but in GlueData is Hole, 10094514f5e3Sopenharmony_ci * so if two SharedGC happened during the builtins initalization like this, maybe will cause incorrect scene: 10104514f5e3Sopenharmony_ci * 10114514f5e3Sopenharmony_ci * Default: 10124514f5e3Sopenharmony_ci * Slot for GlobalObject: Context.GlobalEnv GlueData 10134514f5e3Sopenharmony_ci * value: Undefined Hole 10144514f5e3Sopenharmony_ci * 10154514f5e3Sopenharmony_ci * First SharedGC(JSThread::SwitchCurrentContext), Set GlobalObject from Context.GlobalEnv to GlueData: 10164514f5e3Sopenharmony_ci * Slot for GlobalObject: Context.GlobalEnv GlueData 10174514f5e3Sopenharmony_ci * value: Undefined Undefined 10184514f5e3Sopenharmony_ci * 10194514f5e3Sopenharmony_ci * Builtins Initialize, Create GlobalObject and Set to Context.GlobalEnv: 10204514f5e3Sopenharmony_ci * Slot for GlobalObject: Context.GlobalEnv GlueData 10214514f5e3Sopenharmony_ci * value: Obj Undefined 10224514f5e3Sopenharmony_ci * 10234514f5e3Sopenharmony_ci * Second SharedGC(JSThread::SwitchCurrentContext), Set GlobalObject from GlueData to Context.GlobalEnv: 10244514f5e3Sopenharmony_ci * Slot for GlobalObject: Context.GlobalEnv GlueData 10254514f5e3Sopenharmony_ci * value: Undefined Undefined 10264514f5e3Sopenharmony_ci * 10274514f5e3Sopenharmony_ci * So when copy values between Context.GlobalEnv and GlueData, need to check if the value is Hole in GlueData, 10284514f5e3Sopenharmony_ci * and if is Undefined in Context.GlobalEnv, because the initial value is different. 10294514f5e3Sopenharmony_ci */ 10304514f5e3Sopenharmony_ci if (!currentContext->GetGlobalEnv()->GetGlobalObject().IsUndefined()) { 10314514f5e3Sopenharmony_ci SetGlobalObject(currentContext->GetGlobalEnv()->GetGlobalObject()); 10324514f5e3Sopenharmony_ci } 10334514f5e3Sopenharmony_ci } 10344514f5e3Sopenharmony_ci if (!isInIterate) { 10354514f5e3Sopenharmony_ci // If isInIterate is true, it means it is in GC iterate and global variables are no need to change. 10364514f5e3Sopenharmony_ci glueData_.globalConst_ = const_cast<GlobalEnvConstants *>(currentContext->GlobalConstants()); 10374514f5e3Sopenharmony_ci } 10384514f5e3Sopenharmony_ci 10394514f5e3Sopenharmony_ci glueData_.currentContext_ = currentContext; 10404514f5e3Sopenharmony_ci} 10414514f5e3Sopenharmony_ci 10424514f5e3Sopenharmony_cibool JSThread::EraseContext(EcmaContext *context) 10434514f5e3Sopenharmony_ci{ 10444514f5e3Sopenharmony_ci const_cast<Heap *>(vm_->GetHeap())->WaitAllTasksFinished(); 10454514f5e3Sopenharmony_ci bool isCurrentContext = false; 10464514f5e3Sopenharmony_ci auto iter = std::find(contexts_.begin(), contexts_.end(), context); 10474514f5e3Sopenharmony_ci if (*iter == context) { 10484514f5e3Sopenharmony_ci if (glueData_.currentContext_ == context) { 10494514f5e3Sopenharmony_ci isCurrentContext = true; 10504514f5e3Sopenharmony_ci } 10514514f5e3Sopenharmony_ci contexts_.erase(iter); 10524514f5e3Sopenharmony_ci if (isCurrentContext) { 10534514f5e3Sopenharmony_ci SwitchCurrentContext(contexts_.back()); 10544514f5e3Sopenharmony_ci } 10554514f5e3Sopenharmony_ci return true; 10564514f5e3Sopenharmony_ci } 10574514f5e3Sopenharmony_ci return false; 10584514f5e3Sopenharmony_ci} 10594514f5e3Sopenharmony_ci 10604514f5e3Sopenharmony_civoid JSThread::ClearContextCachedConstantPool() 10614514f5e3Sopenharmony_ci{ 10624514f5e3Sopenharmony_ci for (EcmaContext *context : contexts_) { 10634514f5e3Sopenharmony_ci context->ClearCachedConstantPool(); 10644514f5e3Sopenharmony_ci } 10654514f5e3Sopenharmony_ci} 10664514f5e3Sopenharmony_ci 10674514f5e3Sopenharmony_ciPropertiesCache *JSThread::GetPropertiesCache() const 10684514f5e3Sopenharmony_ci{ 10694514f5e3Sopenharmony_ci return glueData_.currentContext_->GetPropertiesCache(); 10704514f5e3Sopenharmony_ci} 10714514f5e3Sopenharmony_ci 10724514f5e3Sopenharmony_ciconst GlobalEnvConstants *JSThread::GetFirstGlobalConst() const 10734514f5e3Sopenharmony_ci{ 10744514f5e3Sopenharmony_ci return contexts_[0]->GlobalConstants(); 10754514f5e3Sopenharmony_ci} 10764514f5e3Sopenharmony_ci 10774514f5e3Sopenharmony_cibool JSThread::IsAllContextsInitialized() const 10784514f5e3Sopenharmony_ci{ 10794514f5e3Sopenharmony_ci return contexts_.back()->IsInitialized(); 10804514f5e3Sopenharmony_ci} 10814514f5e3Sopenharmony_ci 10824514f5e3Sopenharmony_cibool JSThread::IsReadyToUpdateDetector() const 10834514f5e3Sopenharmony_ci{ 10844514f5e3Sopenharmony_ci return !GetEnableLazyBuiltins() && IsAllContextsInitialized(); 10854514f5e3Sopenharmony_ci} 10864514f5e3Sopenharmony_ci 10874514f5e3Sopenharmony_ciArea *JSThread::GetOrCreateRegExpCache() 10884514f5e3Sopenharmony_ci{ 10894514f5e3Sopenharmony_ci if (regExpCache_ == nullptr) { 10904514f5e3Sopenharmony_ci regExpCache_ = nativeAreaAllocator_->AllocateArea(MAX_REGEXP_CACHE_SIZE); 10914514f5e3Sopenharmony_ci } 10924514f5e3Sopenharmony_ci return regExpCache_; 10934514f5e3Sopenharmony_ci} 10944514f5e3Sopenharmony_ci 10954514f5e3Sopenharmony_civoid JSThread::InitializeBuiltinObject(const std::string& key) 10964514f5e3Sopenharmony_ci{ 10974514f5e3Sopenharmony_ci BuiltinIndex& builtins = BuiltinIndex::GetInstance(); 10984514f5e3Sopenharmony_ci auto index = builtins.GetBuiltinIndex(key); 10994514f5e3Sopenharmony_ci ASSERT(index != BuiltinIndex::NOT_FOUND); 11004514f5e3Sopenharmony_ci /* 11014514f5e3Sopenharmony_ci If using `auto globalObject = GetEcmaVM()->GetGlobalEnv()->GetGlobalObject()` here, 11024514f5e3Sopenharmony_ci it will cause incorrect result in multi-context environment. For example: 11034514f5e3Sopenharmony_ci 11044514f5e3Sopenharmony_ci ```ts 11054514f5e3Sopenharmony_ci let obj = {}; 11064514f5e3Sopenharmony_ci print(obj instanceof Object); // instead of true, will print false 11074514f5e3Sopenharmony_ci ``` 11084514f5e3Sopenharmony_ci */ 11094514f5e3Sopenharmony_ci auto globalObject = contexts_.back()->GetGlobalEnv()->GetGlobalObject(); 11104514f5e3Sopenharmony_ci auto jsObject = JSHandle<JSObject>(this, globalObject); 11114514f5e3Sopenharmony_ci auto box = jsObject->GetGlobalPropertyBox(this, key); 11124514f5e3Sopenharmony_ci if (box == nullptr) { 11134514f5e3Sopenharmony_ci return; 11144514f5e3Sopenharmony_ci } 11154514f5e3Sopenharmony_ci auto& entry = glueData_.builtinEntries_.builtin_[index]; 11164514f5e3Sopenharmony_ci entry.box_ = JSTaggedValue::Cast(box); 11174514f5e3Sopenharmony_ci auto builtin = JSHandle<JSObject>(this, box->GetValue()); 11184514f5e3Sopenharmony_ci auto hclass = builtin->GetJSHClass(); 11194514f5e3Sopenharmony_ci entry.hClass_ = JSTaggedValue::Cast(hclass); 11204514f5e3Sopenharmony_ci} 11214514f5e3Sopenharmony_ci 11224514f5e3Sopenharmony_civoid JSThread::InitializeBuiltinObject() 11234514f5e3Sopenharmony_ci{ 11244514f5e3Sopenharmony_ci BuiltinIndex& builtins = BuiltinIndex::GetInstance(); 11254514f5e3Sopenharmony_ci for (auto key: builtins.GetBuiltinKeys()) { 11264514f5e3Sopenharmony_ci InitializeBuiltinObject(key); 11274514f5e3Sopenharmony_ci } 11284514f5e3Sopenharmony_ci} 11294514f5e3Sopenharmony_ci 11304514f5e3Sopenharmony_cibool JSThread::IsPropertyCacheCleared() const 11314514f5e3Sopenharmony_ci{ 11324514f5e3Sopenharmony_ci for (EcmaContext *context : contexts_) { 11334514f5e3Sopenharmony_ci if (!context->GetPropertiesCache()->IsCleared()) { 11344514f5e3Sopenharmony_ci return false; 11354514f5e3Sopenharmony_ci } 11364514f5e3Sopenharmony_ci } 11374514f5e3Sopenharmony_ci return true; 11384514f5e3Sopenharmony_ci} 11394514f5e3Sopenharmony_ci 11404514f5e3Sopenharmony_civoid JSThread::UpdateState(ThreadState newState) 11414514f5e3Sopenharmony_ci{ 11424514f5e3Sopenharmony_ci ThreadState oldState = GetState(); 11434514f5e3Sopenharmony_ci if (oldState == ThreadState::RUNNING && newState != ThreadState::RUNNING) { 11444514f5e3Sopenharmony_ci TransferFromRunningToSuspended(newState); 11454514f5e3Sopenharmony_ci } else if (oldState != ThreadState::RUNNING && newState == ThreadState::RUNNING) { 11464514f5e3Sopenharmony_ci TransferToRunning(); 11474514f5e3Sopenharmony_ci } else { 11484514f5e3Sopenharmony_ci // Here can be some extra checks... 11494514f5e3Sopenharmony_ci StoreState(newState); 11504514f5e3Sopenharmony_ci } 11514514f5e3Sopenharmony_ci} 11524514f5e3Sopenharmony_ci 11534514f5e3Sopenharmony_civoid JSThread::SuspendThread(bool internalSuspend, SuspendBarrier* barrier) 11544514f5e3Sopenharmony_ci{ 11554514f5e3Sopenharmony_ci LockHolder lock(suspendLock_); 11564514f5e3Sopenharmony_ci if (!internalSuspend) { 11574514f5e3Sopenharmony_ci // do smth here if we want to combine internal and external suspension 11584514f5e3Sopenharmony_ci } 11594514f5e3Sopenharmony_ci 11604514f5e3Sopenharmony_ci uint32_t old_count = suspendCount_++; 11614514f5e3Sopenharmony_ci if (old_count == 0) { 11624514f5e3Sopenharmony_ci SetFlag(ThreadFlag::SUSPEND_REQUEST); 11634514f5e3Sopenharmony_ci SetCheckSafePointStatus(); 11644514f5e3Sopenharmony_ci } 11654514f5e3Sopenharmony_ci 11664514f5e3Sopenharmony_ci if (barrier != nullptr) { 11674514f5e3Sopenharmony_ci ASSERT(suspendBarrier_ == nullptr); 11684514f5e3Sopenharmony_ci suspendBarrier_ = barrier; 11694514f5e3Sopenharmony_ci SetFlag(ThreadFlag::ACTIVE_BARRIER); 11704514f5e3Sopenharmony_ci SetCheckSafePointStatus(); 11714514f5e3Sopenharmony_ci } 11724514f5e3Sopenharmony_ci} 11734514f5e3Sopenharmony_ci 11744514f5e3Sopenharmony_civoid JSThread::ResumeThread(bool internalSuspend) 11754514f5e3Sopenharmony_ci{ 11764514f5e3Sopenharmony_ci LockHolder lock(suspendLock_); 11774514f5e3Sopenharmony_ci if (!internalSuspend) { 11784514f5e3Sopenharmony_ci // do smth here if we want to combine internal and external suspension 11794514f5e3Sopenharmony_ci } 11804514f5e3Sopenharmony_ci if (suspendCount_ > 0) { 11814514f5e3Sopenharmony_ci suspendCount_--; 11824514f5e3Sopenharmony_ci if (suspendCount_ == 0) { 11834514f5e3Sopenharmony_ci ClearFlag(ThreadFlag::SUSPEND_REQUEST); 11844514f5e3Sopenharmony_ci ResetCheckSafePointStatus(); 11854514f5e3Sopenharmony_ci } 11864514f5e3Sopenharmony_ci } 11874514f5e3Sopenharmony_ci suspendCondVar_.Signal(); 11884514f5e3Sopenharmony_ci} 11894514f5e3Sopenharmony_ci 11904514f5e3Sopenharmony_civoid JSThread::WaitSuspension() 11914514f5e3Sopenharmony_ci{ 11924514f5e3Sopenharmony_ci constexpr int TIMEOUT = 100; 11934514f5e3Sopenharmony_ci ThreadState oldState = GetState(); 11944514f5e3Sopenharmony_ci UpdateState(ThreadState::IS_SUSPENDED); 11954514f5e3Sopenharmony_ci { 11964514f5e3Sopenharmony_ci ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SuspendTime::WaitSuspension"); 11974514f5e3Sopenharmony_ci LockHolder lock(suspendLock_); 11984514f5e3Sopenharmony_ci while (suspendCount_ > 0) { 11994514f5e3Sopenharmony_ci suspendCondVar_.TimedWait(&suspendLock_, TIMEOUT); 12004514f5e3Sopenharmony_ci // we need to do smth if Runtime is terminating at this point 12014514f5e3Sopenharmony_ci } 12024514f5e3Sopenharmony_ci ASSERT(!HasSuspendRequest()); 12034514f5e3Sopenharmony_ci } 12044514f5e3Sopenharmony_ci UpdateState(oldState); 12054514f5e3Sopenharmony_ci} 12064514f5e3Sopenharmony_ci 12074514f5e3Sopenharmony_civoid JSThread::ManagedCodeBegin() 12084514f5e3Sopenharmony_ci{ 12094514f5e3Sopenharmony_ci ASSERT(!IsInManagedState()); 12104514f5e3Sopenharmony_ci UpdateState(ThreadState::RUNNING); 12114514f5e3Sopenharmony_ci} 12124514f5e3Sopenharmony_ci 12134514f5e3Sopenharmony_civoid JSThread::ManagedCodeEnd() 12144514f5e3Sopenharmony_ci{ 12154514f5e3Sopenharmony_ci ASSERT(IsInManagedState()); 12164514f5e3Sopenharmony_ci UpdateState(ThreadState::NATIVE); 12174514f5e3Sopenharmony_ci} 12184514f5e3Sopenharmony_ci 12194514f5e3Sopenharmony_civoid JSThread::TransferFromRunningToSuspended(ThreadState newState) 12204514f5e3Sopenharmony_ci{ 12214514f5e3Sopenharmony_ci ASSERT(currentThread == this); 12224514f5e3Sopenharmony_ci StoreSuspendedState(newState); 12234514f5e3Sopenharmony_ci CheckAndPassActiveBarrier(); 12244514f5e3Sopenharmony_ci} 12254514f5e3Sopenharmony_ci 12264514f5e3Sopenharmony_civoid JSThread::TransferToRunning() 12274514f5e3Sopenharmony_ci{ 12284514f5e3Sopenharmony_ci ASSERT(!IsDaemonThread()); 12294514f5e3Sopenharmony_ci ASSERT(currentThread == this); 12304514f5e3Sopenharmony_ci StoreRunningState(ThreadState::RUNNING); 12314514f5e3Sopenharmony_ci // Invoke free weak global callback when thread switch to running 12324514f5e3Sopenharmony_ci if (!weakNodeFreeGlobalCallbacks_.empty()) { 12334514f5e3Sopenharmony_ci InvokeWeakNodeFreeGlobalCallBack(); 12344514f5e3Sopenharmony_ci } 12354514f5e3Sopenharmony_ci if (fullMarkRequest_) { 12364514f5e3Sopenharmony_ci fullMarkRequest_ = const_cast<Heap*>(vm_->GetHeap())->TryTriggerFullMarkBySharedLimit(); 12374514f5e3Sopenharmony_ci } 12384514f5e3Sopenharmony_ci} 12394514f5e3Sopenharmony_ci 12404514f5e3Sopenharmony_civoid JSThread::TransferDaemonThreadToRunning() 12414514f5e3Sopenharmony_ci{ 12424514f5e3Sopenharmony_ci ASSERT(IsDaemonThread()); 12434514f5e3Sopenharmony_ci ASSERT(currentThread == this); 12444514f5e3Sopenharmony_ci StoreRunningState(ThreadState::RUNNING); 12454514f5e3Sopenharmony_ci} 12464514f5e3Sopenharmony_ci 12474514f5e3Sopenharmony_ciinline void JSThread::StoreState(ThreadState newState) 12484514f5e3Sopenharmony_ci{ 12494514f5e3Sopenharmony_ci while (true) { 12504514f5e3Sopenharmony_ci ThreadStateAndFlags oldStateAndFlags; 12514514f5e3Sopenharmony_ci oldStateAndFlags.asNonvolatileInt = glueData_.stateAndFlags_.asInt; 12524514f5e3Sopenharmony_ci 12534514f5e3Sopenharmony_ci ThreadStateAndFlags newStateAndFlags; 12544514f5e3Sopenharmony_ci newStateAndFlags.asNonvolatileStruct.flags = oldStateAndFlags.asNonvolatileStruct.flags; 12554514f5e3Sopenharmony_ci newStateAndFlags.asNonvolatileStruct.state = newState; 12564514f5e3Sopenharmony_ci 12574514f5e3Sopenharmony_ci bool done = glueData_.stateAndFlags_.asAtomicInt.compare_exchange_weak(oldStateAndFlags.asNonvolatileInt, 12584514f5e3Sopenharmony_ci newStateAndFlags.asNonvolatileInt, 12594514f5e3Sopenharmony_ci std::memory_order_release); 12604514f5e3Sopenharmony_ci if (LIKELY(done)) { 12614514f5e3Sopenharmony_ci break; 12624514f5e3Sopenharmony_ci } 12634514f5e3Sopenharmony_ci } 12644514f5e3Sopenharmony_ci} 12654514f5e3Sopenharmony_ci 12664514f5e3Sopenharmony_civoid JSThread::StoreRunningState(ThreadState newState) 12674514f5e3Sopenharmony_ci{ 12684514f5e3Sopenharmony_ci ASSERT(newState == ThreadState::RUNNING); 12694514f5e3Sopenharmony_ci while (true) { 12704514f5e3Sopenharmony_ci ThreadStateAndFlags oldStateAndFlags; 12714514f5e3Sopenharmony_ci oldStateAndFlags.asNonvolatileInt = glueData_.stateAndFlags_.asInt; 12724514f5e3Sopenharmony_ci ASSERT(oldStateAndFlags.asNonvolatileStruct.state != ThreadState::RUNNING); 12734514f5e3Sopenharmony_ci 12744514f5e3Sopenharmony_ci if (LIKELY(oldStateAndFlags.asNonvolatileStruct.flags == ThreadFlag::NO_FLAGS)) { 12754514f5e3Sopenharmony_ci ThreadStateAndFlags newStateAndFlags; 12764514f5e3Sopenharmony_ci newStateAndFlags.asNonvolatileStruct.flags = oldStateAndFlags.asNonvolatileStruct.flags; 12774514f5e3Sopenharmony_ci newStateAndFlags.asNonvolatileStruct.state = newState; 12784514f5e3Sopenharmony_ci 12794514f5e3Sopenharmony_ci if (glueData_.stateAndFlags_.asAtomicInt.compare_exchange_weak(oldStateAndFlags.asNonvolatileInt, 12804514f5e3Sopenharmony_ci newStateAndFlags.asNonvolatileInt, 12814514f5e3Sopenharmony_ci std::memory_order_release)) { 12824514f5e3Sopenharmony_ci break; 12834514f5e3Sopenharmony_ci } 12844514f5e3Sopenharmony_ci } else if ((oldStateAndFlags.asNonvolatileStruct.flags & ThreadFlag::ACTIVE_BARRIER) != 0) { 12854514f5e3Sopenharmony_ci PassSuspendBarrier(); 12864514f5e3Sopenharmony_ci } else if ((oldStateAndFlags.asNonvolatileStruct.flags & ThreadFlag::SUSPEND_REQUEST) != 0) { 12874514f5e3Sopenharmony_ci constexpr int TIMEOUT = 100; 12884514f5e3Sopenharmony_ci ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SuspendTime::StoreRunningState"); 12894514f5e3Sopenharmony_ci LockHolder lock(suspendLock_); 12904514f5e3Sopenharmony_ci while (suspendCount_ > 0) { 12914514f5e3Sopenharmony_ci suspendCondVar_.TimedWait(&suspendLock_, TIMEOUT); 12924514f5e3Sopenharmony_ci } 12934514f5e3Sopenharmony_ci ASSERT(!HasSuspendRequest()); 12944514f5e3Sopenharmony_ci } 12954514f5e3Sopenharmony_ci } 12964514f5e3Sopenharmony_ci} 12974514f5e3Sopenharmony_ci 12984514f5e3Sopenharmony_ciinline void JSThread::StoreSuspendedState(ThreadState newState) 12994514f5e3Sopenharmony_ci{ 13004514f5e3Sopenharmony_ci ASSERT(newState != ThreadState::RUNNING); 13014514f5e3Sopenharmony_ci StoreState(newState); 13024514f5e3Sopenharmony_ci} 13034514f5e3Sopenharmony_ci 13044514f5e3Sopenharmony_civoid JSThread::PostFork() 13054514f5e3Sopenharmony_ci{ 13064514f5e3Sopenharmony_ci SetThreadId(); 13074514f5e3Sopenharmony_ci if (currentThread == nullptr) { 13084514f5e3Sopenharmony_ci currentThread = this; 13094514f5e3Sopenharmony_ci ASSERT(GetState() == ThreadState::CREATED); 13104514f5e3Sopenharmony_ci UpdateState(ThreadState::NATIVE); 13114514f5e3Sopenharmony_ci } else { 13124514f5e3Sopenharmony_ci // We tried to call fork in the same thread 13134514f5e3Sopenharmony_ci ASSERT(currentThread == this); 13144514f5e3Sopenharmony_ci ASSERT(GetState() == ThreadState::NATIVE); 13154514f5e3Sopenharmony_ci } 13164514f5e3Sopenharmony_ci} 13174514f5e3Sopenharmony_ci#ifndef NDEBUG 13184514f5e3Sopenharmony_cibool JSThread::IsInManagedState() const 13194514f5e3Sopenharmony_ci{ 13204514f5e3Sopenharmony_ci ASSERT(this == JSThread::GetCurrent()); 13214514f5e3Sopenharmony_ci return GetState() == ThreadState::RUNNING; 13224514f5e3Sopenharmony_ci} 13234514f5e3Sopenharmony_ci 13244514f5e3Sopenharmony_ciMutatorLock::MutatorLockState JSThread::GetMutatorLockState() const 13254514f5e3Sopenharmony_ci{ 13264514f5e3Sopenharmony_ci return mutatorLockState_; 13274514f5e3Sopenharmony_ci} 13284514f5e3Sopenharmony_ci 13294514f5e3Sopenharmony_civoid JSThread::SetMutatorLockState(MutatorLock::MutatorLockState newState) 13304514f5e3Sopenharmony_ci{ 13314514f5e3Sopenharmony_ci mutatorLockState_ = newState; 13324514f5e3Sopenharmony_ci} 13334514f5e3Sopenharmony_ci#endif 13344514f5e3Sopenharmony_ci} // namespace panda::ecmascript 1335