14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 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#ifndef ECMASCRIPT_RUNTIME_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_RUNTIME_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/ecma_string_table.h" 204514f5e3Sopenharmony_ci#include "ecmascript/global_env_constants.h" 214514f5e3Sopenharmony_ci#include "ecmascript/js_runtime_options.h" 224514f5e3Sopenharmony_ci#include "ecmascript/js_thread.h" 234514f5e3Sopenharmony_ci#include "ecmascript/mem/heap.h" 244514f5e3Sopenharmony_ci#include "ecmascript/module/js_shared_module_manager.h" 254514f5e3Sopenharmony_ci#include "ecmascript/mutator_lock.h" 264514f5e3Sopenharmony_ci#include "ecmascript/platform/mutex.h" 274514f5e3Sopenharmony_ci#include "ecmascript/serializer/serialize_chunk.h" 284514f5e3Sopenharmony_ci 294514f5e3Sopenharmony_ci#include "libpandabase/macros.h" 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_ci#include <list> 324514f5e3Sopenharmony_ci#include <memory> 334514f5e3Sopenharmony_ci 344514f5e3Sopenharmony_cinamespace panda::ecmascript { 354514f5e3Sopenharmony_ciclass Runtime { 364514f5e3Sopenharmony_cipublic: 374514f5e3Sopenharmony_ci PUBLIC_API static Runtime *GetInstance(); 384514f5e3Sopenharmony_ci 394514f5e3Sopenharmony_ci static void CreateIfFirstVm(const JSRuntimeOptions &options); 404514f5e3Sopenharmony_ci static void DestroyIfLastVm(); 414514f5e3Sopenharmony_ci void InitializeIfFirstVm(EcmaVM *vm); 424514f5e3Sopenharmony_ci 434514f5e3Sopenharmony_ci void RegisterThread(JSThread* newThread); 444514f5e3Sopenharmony_ci void UnregisterThread(JSThread* thread); 454514f5e3Sopenharmony_ci 464514f5e3Sopenharmony_ci void SuspendAll(JSThread *current); 474514f5e3Sopenharmony_ci void ResumeAll(JSThread *current); 484514f5e3Sopenharmony_ci void IterateSerializeRoot(const RootVisitor &v); 494514f5e3Sopenharmony_ci 504514f5e3Sopenharmony_ci JSThread *GetMainThread() const 514514f5e3Sopenharmony_ci { 524514f5e3Sopenharmony_ci return mainThread_; 534514f5e3Sopenharmony_ci } 544514f5e3Sopenharmony_ci 554514f5e3Sopenharmony_ci MutatorLock *GetMutatorLock() 564514f5e3Sopenharmony_ci { 574514f5e3Sopenharmony_ci return &mutatorLock_; 584514f5e3Sopenharmony_ci } 594514f5e3Sopenharmony_ci 604514f5e3Sopenharmony_ci const MutatorLock *GetMutatorLock() const 614514f5e3Sopenharmony_ci { 624514f5e3Sopenharmony_ci return &mutatorLock_; 634514f5e3Sopenharmony_ci } 644514f5e3Sopenharmony_ci 654514f5e3Sopenharmony_ci template<class Callback> 664514f5e3Sopenharmony_ci void GCIterateThreadList(const Callback &cb) 674514f5e3Sopenharmony_ci { 684514f5e3Sopenharmony_ci LockHolder lock(threadsLock_); 694514f5e3Sopenharmony_ci GCIterateThreadListWithoutLock(cb); 704514f5e3Sopenharmony_ci } 714514f5e3Sopenharmony_ci 724514f5e3Sopenharmony_ci template<class Callback> 734514f5e3Sopenharmony_ci void GCIterateThreadListWithoutLock(const Callback &cb) 744514f5e3Sopenharmony_ci { 754514f5e3Sopenharmony_ci for (auto thread : threads_) { 764514f5e3Sopenharmony_ci if (thread->ReadyForGCIterating()) { 774514f5e3Sopenharmony_ci cb(thread); 784514f5e3Sopenharmony_ci } 794514f5e3Sopenharmony_ci } 804514f5e3Sopenharmony_ci } 814514f5e3Sopenharmony_ci 824514f5e3Sopenharmony_ci // Result may be inaccurate, just an approximate value. 834514f5e3Sopenharmony_ci size_t ApproximateThreadListSize() 844514f5e3Sopenharmony_ci { 854514f5e3Sopenharmony_ci return threads_.size(); 864514f5e3Sopenharmony_ci } 874514f5e3Sopenharmony_ci 884514f5e3Sopenharmony_ci inline const GlobalEnvConstants *GetGlobalEnvConstants() 894514f5e3Sopenharmony_ci { 904514f5e3Sopenharmony_ci return &globalConst_; 914514f5e3Sopenharmony_ci } 924514f5e3Sopenharmony_ci 934514f5e3Sopenharmony_ci inline bool SharedConstInited() 944514f5e3Sopenharmony_ci { 954514f5e3Sopenharmony_ci return sharedConstInited_; 964514f5e3Sopenharmony_ci } 974514f5e3Sopenharmony_ci 984514f5e3Sopenharmony_ci JSTaggedValue GetGlobalEnv() const 994514f5e3Sopenharmony_ci { 1004514f5e3Sopenharmony_ci return globalEnv_; 1014514f5e3Sopenharmony_ci } 1024514f5e3Sopenharmony_ci 1034514f5e3Sopenharmony_ci inline EcmaStringTable *GetEcmaStringTable() const 1044514f5e3Sopenharmony_ci { 1054514f5e3Sopenharmony_ci return stringTable_.get(); 1064514f5e3Sopenharmony_ci } 1074514f5e3Sopenharmony_ci 1084514f5e3Sopenharmony_ci inline SerializationChunk *GetSerializeRootMapValue([[maybe_unused]] JSThread *thread, 1094514f5e3Sopenharmony_ci uint32_t dataIndex) 1104514f5e3Sopenharmony_ci { 1114514f5e3Sopenharmony_ci ASSERT(thread->IsInManagedState()); 1124514f5e3Sopenharmony_ci LockHolder lock(serializeLock_); 1134514f5e3Sopenharmony_ci auto iter = serializeRootMap_.find(dataIndex); 1144514f5e3Sopenharmony_ci if (iter == serializeRootMap_.end()) { 1154514f5e3Sopenharmony_ci return nullptr; 1164514f5e3Sopenharmony_ci } 1174514f5e3Sopenharmony_ci return iter->second.get(); 1184514f5e3Sopenharmony_ci } 1194514f5e3Sopenharmony_ci 1204514f5e3Sopenharmony_ci uint32_t PushSerializationRoot([[maybe_unused]] JSThread *thread, std::unique_ptr<SerializationChunk> chunk) 1214514f5e3Sopenharmony_ci { 1224514f5e3Sopenharmony_ci ASSERT(thread->IsInManagedState()); 1234514f5e3Sopenharmony_ci LockHolder lock(serializeLock_); 1244514f5e3Sopenharmony_ci uint32_t index = GetSerializeDataIndex(); 1254514f5e3Sopenharmony_ci ASSERT(serializeRootMap_.find(index) == serializeRootMap_.end()); 1264514f5e3Sopenharmony_ci serializeRootMap_.emplace(index, std::move(chunk)); 1274514f5e3Sopenharmony_ci return index; 1284514f5e3Sopenharmony_ci } 1294514f5e3Sopenharmony_ci 1304514f5e3Sopenharmony_ci void RemoveSerializationRoot([[maybe_unused]] JSThread *thread, uint32_t index) 1314514f5e3Sopenharmony_ci { 1324514f5e3Sopenharmony_ci ASSERT(thread->IsInManagedState()); 1334514f5e3Sopenharmony_ci LockHolder lock(serializeLock_); 1344514f5e3Sopenharmony_ci ASSERT(serializeRootMap_.find(index) != serializeRootMap_.end()); 1354514f5e3Sopenharmony_ci serializeRootMap_.erase(index); 1364514f5e3Sopenharmony_ci serializeDataIndexVector_.emplace_back(index); 1374514f5e3Sopenharmony_ci } 1384514f5e3Sopenharmony_ci 1394514f5e3Sopenharmony_ci static bool SharedGCRequest() 1404514f5e3Sopenharmony_ci { 1414514f5e3Sopenharmony_ci LockHolder lock(*vmCreationLock_); 1424514f5e3Sopenharmony_ci destroyCount_++; 1434514f5e3Sopenharmony_ci if (destroyCount_ == WORKER_DESTRUCTION_COUNT || vmCount_ < MIN_GC_TRIGGER_VM_COUNT) { 1444514f5e3Sopenharmony_ci destroyCount_ = 0; 1454514f5e3Sopenharmony_ci return true; 1464514f5e3Sopenharmony_ci } else { 1474514f5e3Sopenharmony_ci return false; 1484514f5e3Sopenharmony_ci } 1494514f5e3Sopenharmony_ci } 1504514f5e3Sopenharmony_ci 1514514f5e3Sopenharmony_ci bool HasCachedConstpool(const JSPandaFile *jsPandaFile); 1524514f5e3Sopenharmony_ci PUBLIC_API JSTaggedValue FindConstpool(const JSPandaFile *jsPandaFile, int32_t index); 1534514f5e3Sopenharmony_ci JSTaggedValue FindConstpoolUnlocked(const JSPandaFile *jsPandaFile, int32_t index); 1544514f5e3Sopenharmony_ci JSHandle<ConstantPool> AddOrUpdateConstpool(const JSPandaFile *jsPandaFile, 1554514f5e3Sopenharmony_ci JSHandle<ConstantPool> constpool, 1564514f5e3Sopenharmony_ci int32_t index = 0); 1574514f5e3Sopenharmony_ci std::optional<std::reference_wrapper<CMap<int32_t, JSTaggedValue>>> FindConstpools( 1584514f5e3Sopenharmony_ci const JSPandaFile *jsPandaFile); 1594514f5e3Sopenharmony_ci void EraseUnusedConstpool(const JSPandaFile *jsPandaFile, int32_t index, int32_t constpoolIndex); 1604514f5e3Sopenharmony_ci 1614514f5e3Sopenharmony_ci void ProcessNativeDeleteInSharedGC(const WeakRootVisitor &visitor); 1624514f5e3Sopenharmony_ci 1634514f5e3Sopenharmony_ci void ProcessSharedNativeDelete(const WeakRootVisitor &visitor); 1644514f5e3Sopenharmony_ci void InvokeSharedNativePointerCallbacks(); 1654514f5e3Sopenharmony_ci void PushToSharedNativePointerList(JSNativePointer *pointer); 1664514f5e3Sopenharmony_ci 1674514f5e3Sopenharmony_ci inline bool CreateStringCacheTable(uint32_t size) 1684514f5e3Sopenharmony_ci { 1694514f5e3Sopenharmony_ci constexpr int32_t MAX_SIZE = 150; 1704514f5e3Sopenharmony_ci if ((size == 0) || (size > MAX_SIZE) || (externalRegisteredStringTable_ != nullptr)) { 1714514f5e3Sopenharmony_ci LOG_ECMA(WARN) << "invalid size of the string cache table or the table has been registered."; 1724514f5e3Sopenharmony_ci LOG_ECMA(WARN) << "Currently, maximum size of the table is " << MAX_SIZE; 1734514f5e3Sopenharmony_ci return false; 1744514f5e3Sopenharmony_ci } 1754514f5e3Sopenharmony_ci 1764514f5e3Sopenharmony_ci externalRegisteredStringTable_ = new JSTaggedValue[size]; 1774514f5e3Sopenharmony_ci if (externalRegisteredStringTable_ == nullptr) { 1784514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "create string cache table failed"; 1794514f5e3Sopenharmony_ci return false; 1804514f5e3Sopenharmony_ci } 1814514f5e3Sopenharmony_ci registeredStringTableSize_ = size; 1824514f5e3Sopenharmony_ci return true; 1834514f5e3Sopenharmony_ci } 1844514f5e3Sopenharmony_ci 1854514f5e3Sopenharmony_ci inline bool SetCachedString(JSHandle<EcmaString> str, uint32_t propertyIndex) 1864514f5e3Sopenharmony_ci { 1874514f5e3Sopenharmony_ci if (propertyIndex >= registeredStringTableSize_ || (externalRegisteredStringTable_ == nullptr)) { 1884514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "invalid size of the string cache table or the table has never been registered."; 1894514f5e3Sopenharmony_ci return false; 1904514f5e3Sopenharmony_ci } 1914514f5e3Sopenharmony_ci externalRegisteredStringTable_[propertyIndex] = str.GetTaggedValue(); 1924514f5e3Sopenharmony_ci return true; 1934514f5e3Sopenharmony_ci } 1944514f5e3Sopenharmony_ci 1954514f5e3Sopenharmony_ci inline JSHandle<EcmaString> GetCachedString(JSThread *thread, uint32_t propertyIndex) 1964514f5e3Sopenharmony_ci { 1974514f5e3Sopenharmony_ci if ((externalRegisteredStringTable_ == nullptr) || (propertyIndex >= registeredStringTableSize_)) { 1984514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "invalid size of the string cache table or the table has never been registered."; 1994514f5e3Sopenharmony_ci return JSHandle<EcmaString>(thread->GlobalConstants()->GetHandledEmptyString()); 2004514f5e3Sopenharmony_ci } 2014514f5e3Sopenharmony_ci return JSHandle<EcmaString>(reinterpret_cast<uintptr_t>(&externalRegisteredStringTable_[propertyIndex])); 2024514f5e3Sopenharmony_ci } 2034514f5e3Sopenharmony_ci 2044514f5e3Sopenharmony_ci inline bool HasCachedString(uint32_t propertyIndex) 2054514f5e3Sopenharmony_ci { 2064514f5e3Sopenharmony_ci if ((externalRegisteredStringTable_ == nullptr) || propertyIndex >= registeredStringTableSize_) { 2074514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "invalid size of the string cache table or the table has never been registered."; 2084514f5e3Sopenharmony_ci return false; 2094514f5e3Sopenharmony_ci } 2104514f5e3Sopenharmony_ci 2114514f5e3Sopenharmony_ci if (externalRegisteredStringTable_[propertyIndex].GetRawData() != JSTaggedValue::NULL_POINTER) { 2124514f5e3Sopenharmony_ci return true; 2134514f5e3Sopenharmony_ci } 2144514f5e3Sopenharmony_ci return false; 2154514f5e3Sopenharmony_ci } 2164514f5e3Sopenharmony_ci 2174514f5e3Sopenharmony_ci void IterateCachedStringRoot(const RootRangeVisitor &v) 2184514f5e3Sopenharmony_ci { 2194514f5e3Sopenharmony_ci if ((externalRegisteredStringTable_ == nullptr) || (registeredStringTableSize_ <= 0)) { 2204514f5e3Sopenharmony_ci return; 2214514f5e3Sopenharmony_ci } 2224514f5e3Sopenharmony_ci auto begin = ObjectSlot(reinterpret_cast<uintptr_t>(externalRegisteredStringTable_)); 2234514f5e3Sopenharmony_ci auto end = ObjectSlot(reinterpret_cast<uintptr_t>(externalRegisteredStringTable_ + 2244514f5e3Sopenharmony_ci registeredStringTableSize_)); 2254514f5e3Sopenharmony_ci v(Root::ROOT_VM, begin, end); 2264514f5e3Sopenharmony_ci } 2274514f5e3Sopenharmony_ci 2284514f5e3Sopenharmony_ciprivate: 2294514f5e3Sopenharmony_ci static constexpr int32_t WORKER_DESTRUCTION_COUNT = 3; 2304514f5e3Sopenharmony_ci static constexpr int32_t MIN_GC_TRIGGER_VM_COUNT = 4; 2314514f5e3Sopenharmony_ci static constexpr uint32_t MAX_SUSPEND_RETRIES = 5000; 2324514f5e3Sopenharmony_ci Runtime() = default; 2334514f5e3Sopenharmony_ci ~Runtime(); 2344514f5e3Sopenharmony_ci void SuspendAllThreadsImpl(JSThread *current); 2354514f5e3Sopenharmony_ci void ResumeAllThreadsImpl(JSThread *current); 2364514f5e3Sopenharmony_ci 2374514f5e3Sopenharmony_ci void PreInitialization(const EcmaVM *vm); 2384514f5e3Sopenharmony_ci void PostInitialization(const EcmaVM *vm); 2394514f5e3Sopenharmony_ci 2404514f5e3Sopenharmony_ci uint32_t GetSerializeDataIndex() 2414514f5e3Sopenharmony_ci { 2424514f5e3Sopenharmony_ci if (!serializeDataIndexVector_.empty()) { 2434514f5e3Sopenharmony_ci uint32_t index = serializeDataIndexVector_.back(); 2444514f5e3Sopenharmony_ci serializeDataIndexVector_.pop_back(); 2454514f5e3Sopenharmony_ci return index; 2464514f5e3Sopenharmony_ci } 2474514f5e3Sopenharmony_ci return ++serializeDataIndex_; 2484514f5e3Sopenharmony_ci } 2494514f5e3Sopenharmony_ci 2504514f5e3Sopenharmony_ci int32_t GetAndIncreaseSharedConstpoolCount() 2514514f5e3Sopenharmony_ci { 2524514f5e3Sopenharmony_ci if (freeSharedConstpoolIndex_.size() > 0) { 2534514f5e3Sopenharmony_ci auto iter = freeSharedConstpoolIndex_.begin(); 2544514f5e3Sopenharmony_ci int32_t freeCount = *iter; 2554514f5e3Sopenharmony_ci freeSharedConstpoolIndex_.erase(iter); 2564514f5e3Sopenharmony_ci return freeCount; 2574514f5e3Sopenharmony_ci } 2584514f5e3Sopenharmony_ci return sharedConstpoolCount_++; 2594514f5e3Sopenharmony_ci } 2604514f5e3Sopenharmony_ci 2614514f5e3Sopenharmony_ci std::vector<std::pair<NativePointerCallback, std::pair<void *, void *>>> &GetSharedNativePointerCallbacks() 2624514f5e3Sopenharmony_ci { 2634514f5e3Sopenharmony_ci return sharedNativePointerCallbacks_; 2644514f5e3Sopenharmony_ci } 2654514f5e3Sopenharmony_ci 2664514f5e3Sopenharmony_ci Mutex threadsLock_; 2674514f5e3Sopenharmony_ci ConditionVariable threadSuspendCondVar_; 2684514f5e3Sopenharmony_ci Mutex serializeLock_; 2694514f5e3Sopenharmony_ci std::list<JSThread*> threads_; 2704514f5e3Sopenharmony_ci uint32_t suspendNewCount_ {0}; 2714514f5e3Sopenharmony_ci uint32_t serializeDataIndex_ {0}; 2724514f5e3Sopenharmony_ci MutatorLock mutatorLock_; 2734514f5e3Sopenharmony_ci 2744514f5e3Sopenharmony_ci bool sharedConstInited_ {false}; 2754514f5e3Sopenharmony_ci GlobalEnvConstants globalConst_; 2764514f5e3Sopenharmony_ci JSTaggedValue globalEnv_ {JSTaggedValue::Hole()}; 2774514f5e3Sopenharmony_ci JSThread *mainThread_ {nullptr}; 2784514f5e3Sopenharmony_ci // for shared heap. 2794514f5e3Sopenharmony_ci std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_; 2804514f5e3Sopenharmony_ci std::unique_ptr<HeapRegionAllocator> heapRegionAllocator_; 2814514f5e3Sopenharmony_ci // for stringTable. 2824514f5e3Sopenharmony_ci std::unique_ptr<EcmaStringTable> stringTable_; 2834514f5e3Sopenharmony_ci std::unordered_map<uint32_t, std::unique_ptr<SerializationChunk>> serializeRootMap_; 2844514f5e3Sopenharmony_ci std::vector<uint32_t> serializeDataIndexVector_; 2854514f5e3Sopenharmony_ci 2864514f5e3Sopenharmony_ci // Shared constantpool cache 2874514f5e3Sopenharmony_ci Mutex constpoolLock_; 2884514f5e3Sopenharmony_ci CMap<const JSPandaFile *, CMap<int32_t, JSTaggedValue>> globalSharedConstpools_ {}; 2894514f5e3Sopenharmony_ci int32_t sharedConstpoolCount_ = 0; // shared constpool count. 2904514f5e3Sopenharmony_ci std::set<int32_t> freeSharedConstpoolIndex_ {}; // reuse shared constpool index. 2914514f5e3Sopenharmony_ci 2924514f5e3Sopenharmony_ci // Runtime instance and VMs creation. 2934514f5e3Sopenharmony_ci static int32_t vmCount_; 2944514f5e3Sopenharmony_ci static int32_t destroyCount_; 2954514f5e3Sopenharmony_ci static bool firstVmCreated_; 2964514f5e3Sopenharmony_ci static Mutex *vmCreationLock_; 2974514f5e3Sopenharmony_ci static Runtime *instance_; 2984514f5e3Sopenharmony_ci 2994514f5e3Sopenharmony_ci // for string cache 3004514f5e3Sopenharmony_ci JSTaggedValue *externalRegisteredStringTable_ {nullptr}; 3014514f5e3Sopenharmony_ci uint32_t registeredStringTableSize_ = 0; 3024514f5e3Sopenharmony_ci 3034514f5e3Sopenharmony_ci // for shared native pointer 3044514f5e3Sopenharmony_ci std::vector<std::pair<NativePointerCallback, std::pair<void *, void *>>> sharedNativePointerCallbacks_ {}; 3054514f5e3Sopenharmony_ci 3064514f5e3Sopenharmony_ci friend class EcmaVM; 3074514f5e3Sopenharmony_ci friend class JSThread; 3084514f5e3Sopenharmony_ci friend class SharedHeap; 3094514f5e3Sopenharmony_ci 3104514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(Runtime); 3114514f5e3Sopenharmony_ci NO_MOVE_SEMANTIC(Runtime); 3124514f5e3Sopenharmony_ci}; 3134514f5e3Sopenharmony_ci} // namespace panda::ecmascript 3144514f5e3Sopenharmony_ci#endif // ECMASCRIPT_RUNTIME_H 315