mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-24 02:30:03 +00:00
3fd11f3d9f
Merge pull request !9697 from XinweiCai/set_max_suspendall_retries
315 lines
11 KiB
C++
315 lines
11 KiB
C++
/*
|
|
* Copyright (c) 2024 Huawei Device Co., Ltd.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef ECMASCRIPT_RUNTIME_H
|
|
#define ECMASCRIPT_RUNTIME_H
|
|
|
|
#include "ecmascript/ecma_string_table.h"
|
|
#include "ecmascript/global_env_constants.h"
|
|
#include "ecmascript/js_runtime_options.h"
|
|
#include "ecmascript/js_thread.h"
|
|
#include "ecmascript/mem/heap.h"
|
|
#include "ecmascript/module/js_shared_module_manager.h"
|
|
#include "ecmascript/mutator_lock.h"
|
|
#include "ecmascript/platform/mutex.h"
|
|
#include "ecmascript/serializer/serialize_chunk.h"
|
|
|
|
#include "libpandabase/macros.h"
|
|
|
|
#include <list>
|
|
#include <memory>
|
|
|
|
namespace panda::ecmascript {
|
|
class Runtime {
|
|
public:
|
|
PUBLIC_API static Runtime *GetInstance();
|
|
|
|
static void CreateIfFirstVm(const JSRuntimeOptions &options);
|
|
static void DestroyIfLastVm();
|
|
void InitializeIfFirstVm(EcmaVM *vm);
|
|
|
|
void RegisterThread(JSThread* newThread);
|
|
void UnregisterThread(JSThread* thread);
|
|
|
|
void SuspendAll(JSThread *current);
|
|
void ResumeAll(JSThread *current);
|
|
void IterateSerializeRoot(const RootVisitor &v);
|
|
|
|
JSThread *GetMainThread() const
|
|
{
|
|
return mainThread_;
|
|
}
|
|
|
|
MutatorLock *GetMutatorLock()
|
|
{
|
|
return &mutatorLock_;
|
|
}
|
|
|
|
const MutatorLock *GetMutatorLock() const
|
|
{
|
|
return &mutatorLock_;
|
|
}
|
|
|
|
template<class Callback>
|
|
void GCIterateThreadList(const Callback &cb)
|
|
{
|
|
LockHolder lock(threadsLock_);
|
|
GCIterateThreadListWithoutLock(cb);
|
|
}
|
|
|
|
template<class Callback>
|
|
void GCIterateThreadListWithoutLock(const Callback &cb)
|
|
{
|
|
for (auto thread : threads_) {
|
|
if (thread->ReadyForGCIterating()) {
|
|
cb(thread);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Result may be inaccurate, just an approximate value.
|
|
size_t ApproximateThreadListSize()
|
|
{
|
|
return threads_.size();
|
|
}
|
|
|
|
inline const GlobalEnvConstants *GetGlobalEnvConstants()
|
|
{
|
|
return &globalConst_;
|
|
}
|
|
|
|
inline bool SharedConstInited()
|
|
{
|
|
return sharedConstInited_;
|
|
}
|
|
|
|
JSTaggedValue GetGlobalEnv() const
|
|
{
|
|
return globalEnv_;
|
|
}
|
|
|
|
inline EcmaStringTable *GetEcmaStringTable() const
|
|
{
|
|
return stringTable_.get();
|
|
}
|
|
|
|
inline SerializationChunk *GetSerializeRootMapValue([[maybe_unused]] JSThread *thread,
|
|
uint32_t dataIndex)
|
|
{
|
|
ASSERT(thread->IsInManagedState());
|
|
LockHolder lock(serializeLock_);
|
|
auto iter = serializeRootMap_.find(dataIndex);
|
|
if (iter == serializeRootMap_.end()) {
|
|
return nullptr;
|
|
}
|
|
return iter->second.get();
|
|
}
|
|
|
|
uint32_t PushSerializationRoot([[maybe_unused]] JSThread *thread, std::unique_ptr<SerializationChunk> chunk)
|
|
{
|
|
ASSERT(thread->IsInManagedState());
|
|
LockHolder lock(serializeLock_);
|
|
uint32_t index = GetSerializeDataIndex();
|
|
ASSERT(serializeRootMap_.find(index) == serializeRootMap_.end());
|
|
serializeRootMap_.emplace(index, std::move(chunk));
|
|
return index;
|
|
}
|
|
|
|
void RemoveSerializationRoot([[maybe_unused]] JSThread *thread, uint32_t index)
|
|
{
|
|
ASSERT(thread->IsInManagedState());
|
|
LockHolder lock(serializeLock_);
|
|
ASSERT(serializeRootMap_.find(index) != serializeRootMap_.end());
|
|
serializeRootMap_.erase(index);
|
|
serializeDataIndexVector_.emplace_back(index);
|
|
}
|
|
|
|
static bool SharedGCRequest()
|
|
{
|
|
LockHolder lock(*vmCreationLock_);
|
|
destroyCount_++;
|
|
if (destroyCount_ == WORKER_DESTRUCTION_COUNT || vmCount_ < MIN_GC_TRIGGER_VM_COUNT) {
|
|
destroyCount_ = 0;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool HasCachedConstpool(const JSPandaFile *jsPandaFile);
|
|
PUBLIC_API JSTaggedValue FindConstpool(const JSPandaFile *jsPandaFile, int32_t index);
|
|
JSTaggedValue FindConstpoolUnlocked(const JSPandaFile *jsPandaFile, int32_t index);
|
|
JSHandle<ConstantPool> AddOrUpdateConstpool(const JSPandaFile *jsPandaFile,
|
|
JSHandle<ConstantPool> constpool,
|
|
int32_t index = 0);
|
|
std::optional<std::reference_wrapper<CMap<int32_t, JSTaggedValue>>> FindConstpools(
|
|
const JSPandaFile *jsPandaFile);
|
|
void EraseUnusedConstpool(const JSPandaFile *jsPandaFile, int32_t index, int32_t constpoolIndex);
|
|
|
|
void ProcessNativeDeleteInSharedGC(const WeakRootVisitor &visitor);
|
|
|
|
void ProcessSharedNativeDelete(const WeakRootVisitor &visitor);
|
|
void InvokeSharedNativePointerCallbacks();
|
|
void PushToSharedNativePointerList(JSNativePointer *pointer);
|
|
|
|
inline bool CreateStringCacheTable(uint32_t size)
|
|
{
|
|
constexpr int32_t MAX_SIZE = 150;
|
|
if ((size == 0) || (size > MAX_SIZE) || (externalRegisteredStringTable_ != nullptr)) {
|
|
LOG_ECMA(WARN) << "invalid size of the string cache table or the table has been registered.";
|
|
LOG_ECMA(WARN) << "Currently, maximum size of the table is " << MAX_SIZE;
|
|
return false;
|
|
}
|
|
|
|
externalRegisteredStringTable_ = new JSTaggedValue[size];
|
|
if (externalRegisteredStringTable_ == nullptr) {
|
|
LOG_ECMA(ERROR) << "create string cache table failed";
|
|
return false;
|
|
}
|
|
registeredStringTableSize_ = size;
|
|
return true;
|
|
}
|
|
|
|
inline bool SetCachedString(JSHandle<EcmaString> str, uint32_t propertyIndex)
|
|
{
|
|
if (propertyIndex >= registeredStringTableSize_ || (externalRegisteredStringTable_ == nullptr)) {
|
|
LOG_ECMA(ERROR) << "invalid size of the string cache table or the table has never been registered.";
|
|
return false;
|
|
}
|
|
externalRegisteredStringTable_[propertyIndex] = str.GetTaggedValue();
|
|
return true;
|
|
}
|
|
|
|
inline JSHandle<EcmaString> GetCachedString(JSThread *thread, uint32_t propertyIndex)
|
|
{
|
|
if ((externalRegisteredStringTable_ == nullptr) || (propertyIndex >= registeredStringTableSize_)) {
|
|
LOG_ECMA(ERROR) << "invalid size of the string cache table or the table has never been registered.";
|
|
return JSHandle<EcmaString>(thread->GlobalConstants()->GetHandledEmptyString());
|
|
}
|
|
return JSHandle<EcmaString>(reinterpret_cast<uintptr_t>(&externalRegisteredStringTable_[propertyIndex]));
|
|
}
|
|
|
|
inline bool HasCachedString(uint32_t propertyIndex)
|
|
{
|
|
if ((externalRegisteredStringTable_ == nullptr) || propertyIndex >= registeredStringTableSize_) {
|
|
LOG_ECMA(ERROR) << "invalid size of the string cache table or the table has never been registered.";
|
|
return false;
|
|
}
|
|
|
|
if (externalRegisteredStringTable_[propertyIndex].GetRawData() != JSTaggedValue::NULL_POINTER) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void IterateCachedStringRoot(const RootRangeVisitor &v)
|
|
{
|
|
if ((externalRegisteredStringTable_ == nullptr) || (registeredStringTableSize_ <= 0)) {
|
|
return;
|
|
}
|
|
auto begin = ObjectSlot(reinterpret_cast<uintptr_t>(externalRegisteredStringTable_));
|
|
auto end = ObjectSlot(reinterpret_cast<uintptr_t>(externalRegisteredStringTable_ +
|
|
registeredStringTableSize_));
|
|
v(Root::ROOT_VM, begin, end);
|
|
}
|
|
|
|
private:
|
|
static constexpr int32_t WORKER_DESTRUCTION_COUNT = 3;
|
|
static constexpr int32_t MIN_GC_TRIGGER_VM_COUNT = 4;
|
|
static constexpr uint32_t MAX_SUSPEND_RETRIES = 5000;
|
|
Runtime() = default;
|
|
~Runtime();
|
|
void SuspendAllThreadsImpl(JSThread *current);
|
|
void ResumeAllThreadsImpl(JSThread *current);
|
|
|
|
void PreInitialization(const EcmaVM *vm);
|
|
void PostInitialization(const EcmaVM *vm);
|
|
|
|
uint32_t GetSerializeDataIndex()
|
|
{
|
|
if (!serializeDataIndexVector_.empty()) {
|
|
uint32_t index = serializeDataIndexVector_.back();
|
|
serializeDataIndexVector_.pop_back();
|
|
return index;
|
|
}
|
|
return ++serializeDataIndex_;
|
|
}
|
|
|
|
int32_t GetAndIncreaseSharedConstpoolCount()
|
|
{
|
|
if (freeSharedConstpoolIndex_.size() > 0) {
|
|
auto iter = freeSharedConstpoolIndex_.begin();
|
|
int32_t freeCount = *iter;
|
|
freeSharedConstpoolIndex_.erase(iter);
|
|
return freeCount;
|
|
}
|
|
return sharedConstpoolCount_++;
|
|
}
|
|
|
|
std::vector<std::pair<NativePointerCallback, std::pair<void *, void *>>> &GetSharedNativePointerCallbacks()
|
|
{
|
|
return sharedNativePointerCallbacks_;
|
|
}
|
|
|
|
Mutex threadsLock_;
|
|
ConditionVariable threadSuspendCondVar_;
|
|
Mutex serializeLock_;
|
|
std::list<JSThread*> threads_;
|
|
uint32_t suspendNewCount_ {0};
|
|
uint32_t serializeDataIndex_ {0};
|
|
MutatorLock mutatorLock_;
|
|
|
|
bool sharedConstInited_ {false};
|
|
GlobalEnvConstants globalConst_;
|
|
JSTaggedValue globalEnv_ {JSTaggedValue::Hole()};
|
|
JSThread *mainThread_ {nullptr};
|
|
// for shared heap.
|
|
std::unique_ptr<NativeAreaAllocator> nativeAreaAllocator_;
|
|
std::unique_ptr<HeapRegionAllocator> heapRegionAllocator_;
|
|
// for stringTable.
|
|
std::unique_ptr<EcmaStringTable> stringTable_;
|
|
std::unordered_map<uint32_t, std::unique_ptr<SerializationChunk>> serializeRootMap_;
|
|
std::vector<uint32_t> serializeDataIndexVector_;
|
|
|
|
// Shared constantpool cache
|
|
Mutex constpoolLock_;
|
|
CMap<const JSPandaFile *, CMap<int32_t, JSTaggedValue>> globalSharedConstpools_ {};
|
|
int32_t sharedConstpoolCount_ = 0; // shared constpool count.
|
|
std::set<int32_t> freeSharedConstpoolIndex_ {}; // reuse shared constpool index.
|
|
|
|
// Runtime instance and VMs creation.
|
|
static int32_t vmCount_;
|
|
static int32_t destroyCount_;
|
|
static bool firstVmCreated_;
|
|
static Mutex *vmCreationLock_;
|
|
static Runtime *instance_;
|
|
|
|
// for string cache
|
|
JSTaggedValue *externalRegisteredStringTable_ {nullptr};
|
|
uint32_t registeredStringTableSize_ = 0;
|
|
|
|
// for shared native pointer
|
|
std::vector<std::pair<NativePointerCallback, std::pair<void *, void *>>> sharedNativePointerCallbacks_ {};
|
|
|
|
friend class EcmaVM;
|
|
friend class JSThread;
|
|
friend class SharedHeap;
|
|
|
|
NO_COPY_SEMANTIC(Runtime);
|
|
NO_MOVE_SEMANTIC(Runtime);
|
|
};
|
|
} // namespace panda::ecmascript
|
|
#endif // ECMASCRIPT_RUNTIME_H
|