* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef COMMON_COMPONENTS_OBJECTS_STRING_TABLE_INTERNAL_H
#define COMMON_COMPONENTS_OBJECTS_STRING_TABLE_INTERNAL_H
#include "common_components/base/globals.h"
#include "common_components/platform/mutex.h"
#include "common_components/taskpool/task.h"
#include "thread/thread_holder.h"
#include "ecmascript/string/base_string_table.h"
#include "ecmascript/string/hashtriemap.h"
namespace panda::ecmascript {
using WeakRefFieldVisitor = std::function<bool(common::RefField<> &)>;
class BaseStringTableImpl;
class BaseStringTableMutex {
public:
explicit BaseStringTableMutex(bool isInit = true) : mtx_(isInit) {}
void LockWithThreadState(common::ThreadHolder* holder)
{
if (mtx_.TryLock()) {
return;
}
#ifndef NDEBUG
common::BaseRuntime::RequestGC(common::GC_REASON_USER, true, common::GC_TYPE_FULL);
#endif
common::ThreadStateTransitionScope<common::ThreadHolder, common::ThreadState::WAIT> ts(holder);
mtx_.Lock();
}
void Lock()
{
return mtx_.Lock();
}
void Unlock()
{
return mtx_.Unlock();
}
private:
common::Mutex mtx_;
};
template<bool ConcurrentSweep>
class BaseStringTableInternal;
class BaseStringTableCleaner {
public:
using IteratorPtr = std::shared_ptr<std::atomic<uint32_t>>;
BaseStringTableCleaner(BaseStringTableInternal<true>* stringTable) : stringTable_(stringTable) {}
~BaseStringTableCleaner()
{
stringTable_ = nullptr;
}
void PostSweepWeakRefTask(const WeakRefFieldVisitor &visitor);
void JoinAndWaitSweepWeakRefTask(const WeakRefFieldVisitor &visitor);
void CleanUp();
private:
NO_COPY_SEMANTIC_CC(BaseStringTableCleaner);
NO_MOVE_SEMANTIC_CC(BaseStringTableCleaner);
static void ProcessSweepWeakRef(IteratorPtr &iter,
BaseStringTableCleaner *cleaner,
const WeakRefFieldVisitor &visitor);
void StartSweepWeakRefTask();
void WaitSweepWeakRefTask();
void SignalSweepWeakRefTask();
static inline uint32_t GetNextIndexId(IteratorPtr &iter)
{
return iter->fetch_add(1U, std::memory_order_relaxed);
}
static inline bool ReduceCountAndCheckFinish(BaseStringTableCleaner *cleaner)
{
return (cleaner->PendingTaskCount_.fetch_sub(1U, std::memory_order_relaxed) == 1U);
}
class CMCSweepWeakRefTask : public common::Task {
public:
CMCSweepWeakRefTask(IteratorPtr iter, BaseStringTableCleaner *cleaner,
const WeakRefFieldVisitor &visitor)
: Task(0), iter_(iter), cleaner_(cleaner), visitor_(visitor) {}
~CMCSweepWeakRefTask() = default;
bool Run(uint32_t threadIndex) override;
NO_COPY_SEMANTIC_CC(CMCSweepWeakRefTask);
NO_MOVE_SEMANTIC_CC(CMCSweepWeakRefTask);
private:
IteratorPtr iter_;
BaseStringTableCleaner *cleaner_;
const WeakRefFieldVisitor &visitor_;
};
IteratorPtr iter_{};
BaseStringTableInternal<true>* stringTable_;
std::atomic<uint32_t> PendingTaskCount_{0U};
std::array<std::vector<HashTrieMapEntry*>, TrieMapConfig::ROOT_SIZE> waitFreeEntries_{};
common::Mutex sweepWeakRefMutex_{};
bool sweepWeakRefFinished_{true};
common::ConditionVariable sweepWeakRefCV_{};
};
template<bool ConcurrentSweep>
class BaseStringTableInternal {
public:
using HandleCreator = BaseStringTableInterface<BaseStringTableImpl>::HandleCreator;
using HashTrieMapType = HashTrieMap<BaseStringTableMutex>;
using HashTrieMapInUseScopeType = HashTrieMapInUseScope<BaseStringTableMutex>;
using HashTrieMapOperationType = std::conditional_t<ConcurrentSweep,
HashTrieMapOperation<BaseStringTableMutex, common::ThreadHolder, TrieMapConfig::NeedSlotBarrierCMC>,
HashTrieMapOperation<BaseStringTableMutex, common::ThreadHolder, TrieMapConfig::NoSlotBarrier>>;
template <bool B = ConcurrentSweep, std::enable_if_t<B, int> = 0>
BaseStringTableInternal(): cleaner_(new BaseStringTableCleaner(this)) {}
template <bool B = ConcurrentSweep, std::enable_if_t<!B, int> = 0>
BaseStringTableInternal() {}
~BaseStringTableInternal()
{
if constexpr (ConcurrentSweep) {
delete cleaner_;
}
}
BaseString *GetOrInternFlattenString(common::ThreadHolder *holder, const HandleCreator &handleCreator,
BaseString *string);
BaseString *GetOrInternStringFromCompressedSubString(common::ThreadHolder *holder,
const HandleCreator &handleCreator,
const common::ReadOnlyHandle<BaseString> &string,
uint32_t offset,
uint32_t utf8Len);
BaseString *GetOrInternString(common::ThreadHolder *holder, const HandleCreator &handleCreator,
const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress);
BaseString *GetOrInternString(common::ThreadHolder *holder, const HandleCreator &handleCreator,
const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress);
BaseString *TryGetInternString(const common::ReadOnlyHandle<BaseString> &string);
HashTrieMapType &GetHashTrieMap()
{
return hashTrieMap_;
}
BaseStringTableCleaner *GetCleaner()
{
return cleaner_;
}
template <bool B = ConcurrentSweep, std::enable_if_t<B, int> = 0>
void SweepWeakRef(const WeakRefFieldVisitor& visitor, uint32_t rootID,
std::vector<HashTrieMapEntry*>& waitDeleteEntries);
template <bool B = ConcurrentSweep, std::enable_if_t<B, int> = 0>
void CleanUp();
template <bool B = ConcurrentSweep, std::enable_if_t<!B, int> = 0>
void SweepWeakRef(const WeakRefFieldVisitor& visitor);
private:
HashTrieMapType hashTrieMap_{};
BaseStringTableCleaner* cleaner_ = nullptr;
static BaseString* AllocateLineStringObject(size_t size);
static constexpr size_t MAX_REGULAR_HEAP_OBJECT_SIZE = 32 * common::KB;
};
class BaseStringTableImpl : public BaseStringTableInterface<BaseStringTableImpl> {
public:
BaseString* GetOrInternFlattenString(common::ThreadHolder* holder, const HandleCreator& handleCreator,
BaseString* string);
BaseString* GetOrInternStringFromCompressedSubString(common::ThreadHolder* holder,
const HandleCreator& handleCreator,
const common::ReadOnlyHandle<BaseString>& string,
uint32_t offset,
uint32_t utf8Len);
BaseString* GetOrInternString(common::ThreadHolder* holder, const HandleCreator& handleCreator,
const uint8_t* utf8Data, uint32_t utf8Len, bool canBeCompress);
BaseString* GetOrInternString(common::ThreadHolder* holder, const HandleCreator& handleCreator,
const uint16_t* utf16Data, uint32_t utf16Len, bool canBeCompress);
BaseString* TryGetInternString(const common::ReadOnlyHandle<BaseString>& string);
auto* GetInternalTable()
{
return &stringTable_;
}
private:
#ifndef GC_STW_STRINGTABLE
BaseStringTableInternal<true> stringTable_{};
#else
BaseStringTableInternal<false> stringTable_{};
#endif
};
}
#endif