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/ecma_string_table.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/ecma_string-inl.h"
194514f5e3Sopenharmony_ci#include "ecmascript/runtime_lock.h"
204514f5e3Sopenharmony_cinamespace panda::ecmascript {
214514f5e3Sopenharmony_civoid EcmaStringTableCleaner::PostSweepWeakRefTask(const WeakRootVisitor &visitor)
224514f5e3Sopenharmony_ci{
234514f5e3Sopenharmony_ci    StartSweepWeakRefTask();
244514f5e3Sopenharmony_ci    iter_ = std::make_shared<std::atomic<uint32_t>>(0U);
254514f5e3Sopenharmony_ci    const uint32_t postTaskCount = Taskpool::GetCurrentTaskpool()->GetTotalThreadNum();
264514f5e3Sopenharmony_ci    for (uint32_t i = 0U; i < postTaskCount; ++i) {
274514f5e3Sopenharmony_ci        Taskpool::GetCurrentTaskpool()->PostTask(std::make_unique<SweepWeakRefTask>(iter_, this, visitor));
284514f5e3Sopenharmony_ci    }
294514f5e3Sopenharmony_ci}
304514f5e3Sopenharmony_ci
314514f5e3Sopenharmony_civoid EcmaStringTableCleaner::JoinAndWaitSweepWeakRefTask(const WeakRootVisitor &visitor)
324514f5e3Sopenharmony_ci{
334514f5e3Sopenharmony_ci    ProcessSweepWeakRef(iter_, this, visitor);
344514f5e3Sopenharmony_ci    WaitSweepWeakRefTask();
354514f5e3Sopenharmony_ci    iter_.reset();
364514f5e3Sopenharmony_ci}
374514f5e3Sopenharmony_ci
384514f5e3Sopenharmony_civoid EcmaStringTableCleaner::ProcessSweepWeakRef(IteratorPtr& iter, EcmaStringTableCleaner *cleaner,
394514f5e3Sopenharmony_ci                                                 const WeakRootVisitor &visitor)
404514f5e3Sopenharmony_ci{
414514f5e3Sopenharmony_ci    uint32_t tableId = 0U;
424514f5e3Sopenharmony_ci    while ((tableId = GetNextTableId(iter)) < EcmaStringTable::SEGMENT_COUNT) {
434514f5e3Sopenharmony_ci        cleaner->stringTable_->SweepWeakRef(visitor, tableId);
444514f5e3Sopenharmony_ci        if (ReduceCountAndCheckFinish(cleaner)) {
454514f5e3Sopenharmony_ci            cleaner->SignalSweepWeakRefTask();
464514f5e3Sopenharmony_ci        }
474514f5e3Sopenharmony_ci    }
484514f5e3Sopenharmony_ci}
494514f5e3Sopenharmony_ci
504514f5e3Sopenharmony_civoid EcmaStringTableCleaner::StartSweepWeakRefTask()
514514f5e3Sopenharmony_ci{
524514f5e3Sopenharmony_ci    // No need lock here, only the daemon thread will reset the state.
534514f5e3Sopenharmony_ci    sweepWeakRefFinished_ = false;
544514f5e3Sopenharmony_ci    PendingTaskCount_.store(EcmaStringTable::SEGMENT_COUNT, std::memory_order_relaxed);
554514f5e3Sopenharmony_ci}
564514f5e3Sopenharmony_ci
574514f5e3Sopenharmony_civoid EcmaStringTableCleaner::WaitSweepWeakRefTask()
584514f5e3Sopenharmony_ci{
594514f5e3Sopenharmony_ci    LockHolder holder(sweepWeakRefMutex_);
604514f5e3Sopenharmony_ci    while (!sweepWeakRefFinished_) {
614514f5e3Sopenharmony_ci        sweepWeakRefCV_.Wait(&sweepWeakRefMutex_);
624514f5e3Sopenharmony_ci    }
634514f5e3Sopenharmony_ci}
644514f5e3Sopenharmony_ci
654514f5e3Sopenharmony_civoid EcmaStringTableCleaner::SignalSweepWeakRefTask()
664514f5e3Sopenharmony_ci{
674514f5e3Sopenharmony_ci    LockHolder holder(sweepWeakRefMutex_);
684514f5e3Sopenharmony_ci    sweepWeakRefFinished_ = true;
694514f5e3Sopenharmony_ci    sweepWeakRefCV_.SignalAll();
704514f5e3Sopenharmony_ci}
714514f5e3Sopenharmony_ci
724514f5e3Sopenharmony_cibool EcmaStringTableCleaner::SweepWeakRefTask::Run([[maybe_unused]] uint32_t threadIndex)
734514f5e3Sopenharmony_ci{
744514f5e3Sopenharmony_ci    ProcessSweepWeakRef(iter_, cleaner_, visitor_);
754514f5e3Sopenharmony_ci    return true;
764514f5e3Sopenharmony_ci}
774514f5e3Sopenharmony_ci
784514f5e3Sopenharmony_cistd::pair<EcmaString *, uint32_t> EcmaStringTable::GetStringThreadUnsafe(const JSHandle<EcmaString> &firstString,
794514f5e3Sopenharmony_ci                                                                         const JSHandle<EcmaString> &secondString,
804514f5e3Sopenharmony_ci                                                                         uint32_t hashcode) const
814514f5e3Sopenharmony_ci{
824514f5e3Sopenharmony_ci    ASSERT(EcmaStringAccessor(firstString).NotTreeString());
834514f5e3Sopenharmony_ci    ASSERT(EcmaStringAccessor(secondString).NotTreeString());
844514f5e3Sopenharmony_ci    auto range = stringTable_[GetTableId(hashcode)].table_.equal_range(hashcode);
854514f5e3Sopenharmony_ci    for (auto item = range.first; item != range.second;) {
864514f5e3Sopenharmony_ci        auto foundString = (item++)->second;
874514f5e3Sopenharmony_ci        if (EcmaStringAccessor(foundString).EqualToSplicedString(*firstString, *secondString)) {
884514f5e3Sopenharmony_ci            return std::make_pair(foundString, hashcode);
894514f5e3Sopenharmony_ci        }
904514f5e3Sopenharmony_ci    }
914514f5e3Sopenharmony_ci    return std::make_pair(nullptr, hashcode);
924514f5e3Sopenharmony_ci}
934514f5e3Sopenharmony_ci
944514f5e3Sopenharmony_cistd::pair<EcmaString *, uint32_t> EcmaStringTable::GetStringThreadUnsafe(const uint8_t *utf8Data, uint32_t utf8Len,
954514f5e3Sopenharmony_ci                                                                         bool canBeCompress, uint32_t hashcode) const
964514f5e3Sopenharmony_ci{
974514f5e3Sopenharmony_ci    auto range = stringTable_[GetTableId(hashcode)].table_.equal_range(hashcode);
984514f5e3Sopenharmony_ci    for (auto item = range.first; item != range.second;) {
994514f5e3Sopenharmony_ci        auto foundString = (item++)->second;
1004514f5e3Sopenharmony_ci        if (EcmaStringAccessor::StringIsEqualUint8Data(foundString, utf8Data, utf8Len, canBeCompress)) {
1014514f5e3Sopenharmony_ci            return std::make_pair(foundString, hashcode);
1024514f5e3Sopenharmony_ci        }
1034514f5e3Sopenharmony_ci    }
1044514f5e3Sopenharmony_ci    return std::make_pair(nullptr, hashcode);
1054514f5e3Sopenharmony_ci}
1064514f5e3Sopenharmony_ci
1074514f5e3Sopenharmony_cistd::pair<EcmaString *, uint32_t> EcmaStringTable::GetStringThreadUnsafe(const uint16_t *utf16Data,
1084514f5e3Sopenharmony_ci                                                                         uint32_t utf16Len, uint32_t hashcode) const
1094514f5e3Sopenharmony_ci{
1104514f5e3Sopenharmony_ci    auto range = stringTable_[GetTableId(hashcode)].table_.equal_range(hashcode);
1114514f5e3Sopenharmony_ci    for (auto item = range.first; item != range.second;) {
1124514f5e3Sopenharmony_ci        auto foundString = (item++)->second;
1134514f5e3Sopenharmony_ci        if (EcmaStringAccessor::StringsAreEqualUtf16(foundString, utf16Data, utf16Len)) {
1144514f5e3Sopenharmony_ci            return std::make_pair(foundString, hashcode);
1154514f5e3Sopenharmony_ci        }
1164514f5e3Sopenharmony_ci    }
1174514f5e3Sopenharmony_ci    return std::make_pair(nullptr, hashcode);
1184514f5e3Sopenharmony_ci}
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetStringWithHashThreadUnsafe(EcmaString *string, uint32_t hashcode) const
1214514f5e3Sopenharmony_ci{
1224514f5e3Sopenharmony_ci    auto range = stringTable_[GetTableId(hashcode)].table_.equal_range(hashcode);
1234514f5e3Sopenharmony_ci    for (auto item = range.first; item != range.second;) {
1244514f5e3Sopenharmony_ci        auto foundString = (item++)->second;
1254514f5e3Sopenharmony_ci        if (EcmaStringAccessor::StringsAreEqual(foundString, string)) {
1264514f5e3Sopenharmony_ci            return foundString;
1274514f5e3Sopenharmony_ci        }
1284514f5e3Sopenharmony_ci    }
1294514f5e3Sopenharmony_ci    return nullptr;
1304514f5e3Sopenharmony_ci}
1314514f5e3Sopenharmony_ci
1324514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetStringThreadUnsafe(EcmaString *string, uint32_t hashcode) const
1334514f5e3Sopenharmony_ci{
1344514f5e3Sopenharmony_ci    auto range = stringTable_[GetTableId(hashcode)].table_.equal_range(hashcode);
1354514f5e3Sopenharmony_ci    for (auto item = range.first; item != range.second;) {
1364514f5e3Sopenharmony_ci        auto foundString = (item++)->second;
1374514f5e3Sopenharmony_ci        if (EcmaStringAccessor::StringsAreEqual(foundString, string)) {
1384514f5e3Sopenharmony_ci            return foundString;
1394514f5e3Sopenharmony_ci        }
1404514f5e3Sopenharmony_ci    }
1414514f5e3Sopenharmony_ci    return nullptr;
1424514f5e3Sopenharmony_ci}
1434514f5e3Sopenharmony_ci
1444514f5e3Sopenharmony_civoid EcmaStringTable::InternStringThreadUnsafe(EcmaString *string, uint32_t hashcode)
1454514f5e3Sopenharmony_ci{
1464514f5e3Sopenharmony_ci    if (EcmaStringAccessor(string).IsInternString()) {
1474514f5e3Sopenharmony_ci        return;
1484514f5e3Sopenharmony_ci    }
1494514f5e3Sopenharmony_ci    // Strings in string table should not be in the young space.
1504514f5e3Sopenharmony_ci    ASSERT(Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(string))->InSharedHeap());
1514514f5e3Sopenharmony_ci    ASSERT(EcmaStringAccessor(string).NotTreeString());
1524514f5e3Sopenharmony_ci    stringTable_[GetTableId(hashcode)].table_.emplace(hashcode, string);
1534514f5e3Sopenharmony_ci    EcmaStringAccessor(string).SetInternString();
1544514f5e3Sopenharmony_ci}
1554514f5e3Sopenharmony_ci
1564514f5e3Sopenharmony_civoid EcmaStringTable::InternEmptyString(JSThread *thread, EcmaString *emptyStr)
1574514f5e3Sopenharmony_ci{
1584514f5e3Sopenharmony_ci    auto hashcode = EcmaStringAccessor(emptyStr).GetHashcode();
1594514f5e3Sopenharmony_ci    RuntimeLockHolder locker(thread, stringTable_[GetTableId(hashcode)].mutex_);
1604514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
1614514f5e3Sopenharmony_ci    auto vm = thread->GetEcmaVM();
1624514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
1634514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
1644514f5e3Sopenharmony_ci    }
1654514f5e3Sopenharmony_ci#endif
1664514f5e3Sopenharmony_ci    InternStringThreadUnsafe(emptyStr, hashcode);
1674514f5e3Sopenharmony_ci}
1684514f5e3Sopenharmony_ci
1694514f5e3Sopenharmony_civoid EcmaStringTable::InsertStringIfNotExistThreadUnsafe(EcmaString *string)
1704514f5e3Sopenharmony_ci{
1714514f5e3Sopenharmony_ci    auto hashcode = EcmaStringAccessor(string).GetHashcode();
1724514f5e3Sopenharmony_ci    EcmaString *str = GetStringThreadUnsafe(string, hashcode);
1734514f5e3Sopenharmony_ci    if (str == nullptr) {
1744514f5e3Sopenharmony_ci        InternStringThreadUnsafe(string, hashcode);
1754514f5e3Sopenharmony_ci    }
1764514f5e3Sopenharmony_ci}
1774514f5e3Sopenharmony_ci
1784514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, const JSHandle<EcmaString> &firstString,
1794514f5e3Sopenharmony_ci                                               const JSHandle<EcmaString> &secondString)
1804514f5e3Sopenharmony_ci{
1814514f5e3Sopenharmony_ci    JSThread *thread = nullptr;
1824514f5e3Sopenharmony_ci    bool signalState = vm->GetJsDebuggerManager()->GetSignalState();
1834514f5e3Sopenharmony_ci    thread = signalState ? vm->GetJSThreadNoCheck() : vm->GetJSThread();
1844514f5e3Sopenharmony_ci    auto firstFlat = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(vm, firstString));
1854514f5e3Sopenharmony_ci    auto secondFlat = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(vm, secondString));
1864514f5e3Sopenharmony_ci    uint32_t hashcode = EcmaStringAccessor::CalculateAllConcatHashCode(firstFlat, secondFlat);
1874514f5e3Sopenharmony_ci    if (signalState) {
1884514f5e3Sopenharmony_ci        return GetOrInternStringWithoutLock(thread, firstString, secondString, hashcode);
1894514f5e3Sopenharmony_ci    }
1904514f5e3Sopenharmony_ci    RuntimeLockHolder locker(thread, stringTable_[GetTableId(hashcode)].mutex_);
1914514f5e3Sopenharmony_ci    return GetOrInternStringWithoutLock(thread, firstString, secondString, hashcode);
1924514f5e3Sopenharmony_ci}
1934514f5e3Sopenharmony_ci
1944514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternStringWithoutLock(JSThread *thread, const JSHandle<EcmaString> &firstString,
1954514f5e3Sopenharmony_ci                                                          const JSHandle<EcmaString> &secondString, uint32_t hashcode)
1964514f5e3Sopenharmony_ci{
1974514f5e3Sopenharmony_ci    EcmaVM *vm = thread->GetEcmaVM();
1984514f5e3Sopenharmony_ci    auto firstFlat = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(vm, firstString));
1994514f5e3Sopenharmony_ci    auto secondFlat = JSHandle<EcmaString>(thread, EcmaStringAccessor::Flatten(vm, secondString));
2004514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
2014514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
2024514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
2034514f5e3Sopenharmony_ci    }
2044514f5e3Sopenharmony_ci#endif
2054514f5e3Sopenharmony_ci    std::pair<EcmaString *, uint32_t> result = GetStringThreadUnsafe(firstFlat, secondFlat, hashcode);
2064514f5e3Sopenharmony_ci    if (result.first != nullptr) {
2074514f5e3Sopenharmony_ci        return result.first;
2084514f5e3Sopenharmony_ci    }
2094514f5e3Sopenharmony_ci    JSHandle<EcmaString> concatHandle(thread,
2104514f5e3Sopenharmony_ci        EcmaStringAccessor::Concat(vm, firstFlat, secondFlat, MemSpaceType::SHARED_OLD_SPACE));
2114514f5e3Sopenharmony_ci    EcmaString *concatString = EcmaStringAccessor::Flatten(vm, concatHandle, MemSpaceType::SHARED_OLD_SPACE);
2124514f5e3Sopenharmony_ci    concatString->SetMixHashcode(result.second);
2134514f5e3Sopenharmony_ci    InternStringThreadUnsafe(concatString, hashcode);
2144514f5e3Sopenharmony_ci    return concatString;
2154514f5e3Sopenharmony_ci}
2164514f5e3Sopenharmony_ci
2174514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
2184514f5e3Sopenharmony_ci                                               bool canBeCompress)
2194514f5e3Sopenharmony_ci{
2204514f5e3Sopenharmony_ci    uint32_t hashcode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress);
2214514f5e3Sopenharmony_ci    if (vm->GetJsDebuggerManager()->GetSignalState()) {
2224514f5e3Sopenharmony_ci        return GetOrInternStringWithoutLock(vm, utf8Data, utf8Len, canBeCompress, hashcode);
2234514f5e3Sopenharmony_ci    } else {
2244514f5e3Sopenharmony_ci        RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_);
2254514f5e3Sopenharmony_ci        return GetOrInternStringWithoutLock(vm, utf8Data, utf8Len, canBeCompress, hashcode);
2264514f5e3Sopenharmony_ci    }
2274514f5e3Sopenharmony_ci}
2284514f5e3Sopenharmony_ci
2294514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternStringWithoutLock(EcmaVM *vm, const uint8_t *utf8Data,
2304514f5e3Sopenharmony_ci                                                          uint32_t utf8Len, bool canBeCompress, uint32_t hashcode)
2314514f5e3Sopenharmony_ci{
2324514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
2334514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
2344514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
2354514f5e3Sopenharmony_ci    }
2364514f5e3Sopenharmony_ci#endif
2374514f5e3Sopenharmony_ci    std::pair<EcmaString *, uint32_t> result = GetStringThreadUnsafe(utf8Data, utf8Len, canBeCompress, hashcode);
2384514f5e3Sopenharmony_ci    if (result.first != nullptr) {
2394514f5e3Sopenharmony_ci        return result.first;
2404514f5e3Sopenharmony_ci    }
2414514f5e3Sopenharmony_ci
2424514f5e3Sopenharmony_ci    EcmaString *str =
2434514f5e3Sopenharmony_ci        EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE);
2444514f5e3Sopenharmony_ci    str->SetMixHashcode(result.second);
2454514f5e3Sopenharmony_ci    InternStringThreadUnsafe(str, hashcode);
2464514f5e3Sopenharmony_ci    return str;
2474514f5e3Sopenharmony_ci}
2484514f5e3Sopenharmony_ci
2494514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternCompressedSubString(EcmaVM *vm, const JSHandle<EcmaString> &string,
2504514f5e3Sopenharmony_ci    uint32_t offset, uint32_t utf8Len)
2514514f5e3Sopenharmony_ci{
2524514f5e3Sopenharmony_ci    auto *utf8Data = EcmaStringAccessor(string).GetDataUtf8() + offset;
2534514f5e3Sopenharmony_ci    uint32_t hashcode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, true);
2544514f5e3Sopenharmony_ci    RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_);
2554514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
2564514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
2574514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
2584514f5e3Sopenharmony_ci    }
2594514f5e3Sopenharmony_ci#endif
2604514f5e3Sopenharmony_ci    // utf8data may be moved after shared full gc, so reload utf8Data here.
2614514f5e3Sopenharmony_ci    utf8Data = EcmaStringAccessor(string).GetDataUtf8() + offset;
2624514f5e3Sopenharmony_ci    std::pair<EcmaString *, uint32_t> result = GetStringThreadUnsafe(utf8Data, utf8Len, true, hashcode);
2634514f5e3Sopenharmony_ci    if (result.first != nullptr) {
2644514f5e3Sopenharmony_ci        return result.first;
2654514f5e3Sopenharmony_ci    }
2664514f5e3Sopenharmony_ci
2674514f5e3Sopenharmony_ci    EcmaString *str = EcmaStringAccessor::CreateFromUtf8CompressedSubString(
2684514f5e3Sopenharmony_ci        vm, string, offset, utf8Len, MemSpaceType::SHARED_OLD_SPACE);
2694514f5e3Sopenharmony_ci    str->SetMixHashcode(result.second);
2704514f5e3Sopenharmony_ci    InternStringThreadUnsafe(str, hashcode);
2714514f5e3Sopenharmony_ci    return str;
2724514f5e3Sopenharmony_ci}
2734514f5e3Sopenharmony_ci
2744514f5e3Sopenharmony_ci/*
2754514f5e3Sopenharmony_ci    This function is used to create global constant strings from non-movable sapce only.
2764514f5e3Sopenharmony_ci    It only inserts string into string-table and provides no string-table validity check.
2774514f5e3Sopenharmony_ci*/
2784514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::CreateAndInternStringNonMovable(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len)
2794514f5e3Sopenharmony_ci{
2804514f5e3Sopenharmony_ci    uint32_t hashcode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, true);
2814514f5e3Sopenharmony_ci    RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_);
2824514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
2834514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
2844514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
2854514f5e3Sopenharmony_ci    }
2864514f5e3Sopenharmony_ci#endif
2874514f5e3Sopenharmony_ci    std::pair<EcmaString *, uint32_t> result = GetStringThreadUnsafe(utf8Data, utf8Len, true, hashcode);
2884514f5e3Sopenharmony_ci    if (result.first != nullptr) {
2894514f5e3Sopenharmony_ci        return result.first;
2904514f5e3Sopenharmony_ci    }
2914514f5e3Sopenharmony_ci    EcmaString *str = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, true, MemSpaceType::SHARED_NON_MOVABLE);
2924514f5e3Sopenharmony_ci    str->SetMixHashcode(result.second);
2934514f5e3Sopenharmony_ci    InternStringThreadUnsafe(str, hashcode);
2944514f5e3Sopenharmony_ci    return str;
2954514f5e3Sopenharmony_ci}
2964514f5e3Sopenharmony_ci
2974514f5e3Sopenharmony_ci/*
2984514f5e3Sopenharmony_ci    This function is used to create global constant strings from read-only sapce only.
2994514f5e3Sopenharmony_ci    It only inserts string into string-table and provides no string-table validity check.
3004514f5e3Sopenharmony_ci*/
3014514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::CreateAndInternStringReadOnly(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
3024514f5e3Sopenharmony_ci                                                           bool canBeCompress)
3034514f5e3Sopenharmony_ci{
3044514f5e3Sopenharmony_ci    uint32_t hashcode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress);
3054514f5e3Sopenharmony_ci    RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_);
3064514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
3074514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
3084514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
3094514f5e3Sopenharmony_ci    }
3104514f5e3Sopenharmony_ci#endif
3114514f5e3Sopenharmony_ci    std::pair<EcmaString *, uint32_t> result = GetStringThreadUnsafe(utf8Data, utf8Len, canBeCompress, hashcode);
3124514f5e3Sopenharmony_ci    if (result.first != nullptr) {
3134514f5e3Sopenharmony_ci        return result.first;
3144514f5e3Sopenharmony_ci    }
3154514f5e3Sopenharmony_ci    EcmaString *str = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress,
3164514f5e3Sopenharmony_ci                                                         MemSpaceType::SHARED_READ_ONLY_SPACE);
3174514f5e3Sopenharmony_ci    str->SetMixHashcode(result.second);
3184514f5e3Sopenharmony_ci    InternStringThreadUnsafe(str, hashcode);
3194514f5e3Sopenharmony_ci    return str;
3204514f5e3Sopenharmony_ci}
3214514f5e3Sopenharmony_ci
3224514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len,
3234514f5e3Sopenharmony_ci                                               bool canBeCompress)
3244514f5e3Sopenharmony_ci{
3254514f5e3Sopenharmony_ci    uint32_t hashcode = EcmaStringAccessor::ComputeHashcodeUtf16(const_cast<uint16_t *>(utf16Data), utf16Len);
3264514f5e3Sopenharmony_ci    RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_);
3274514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
3284514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
3294514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
3304514f5e3Sopenharmony_ci    }
3314514f5e3Sopenharmony_ci#endif
3324514f5e3Sopenharmony_ci    std::pair<EcmaString *, uint32_t> result = GetStringThreadUnsafe(utf16Data, utf16Len, hashcode);
3334514f5e3Sopenharmony_ci    if (result.first != nullptr) {
3344514f5e3Sopenharmony_ci        return result.first;
3354514f5e3Sopenharmony_ci    }
3364514f5e3Sopenharmony_ci
3374514f5e3Sopenharmony_ci    EcmaString *str =
3384514f5e3Sopenharmony_ci        EcmaStringAccessor::CreateFromUtf16(vm, utf16Data, utf16Len, canBeCompress, MemSpaceType::SHARED_OLD_SPACE);
3394514f5e3Sopenharmony_ci    str->SetMixHashcode(result.second);
3404514f5e3Sopenharmony_ci    InternStringThreadUnsafe(str, hashcode);
3414514f5e3Sopenharmony_ci    return str;
3424514f5e3Sopenharmony_ci}
3434514f5e3Sopenharmony_ci
3444514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternString(EcmaVM *vm, EcmaString *string)
3454514f5e3Sopenharmony_ci{
3464514f5e3Sopenharmony_ci    if (EcmaStringAccessor(string).IsInternString()) {
3474514f5e3Sopenharmony_ci        return string;
3484514f5e3Sopenharmony_ci    }
3494514f5e3Sopenharmony_ci    auto thread = vm->GetJSThread();
3504514f5e3Sopenharmony_ci    JSHandle<EcmaString> strHandle(thread, string);
3514514f5e3Sopenharmony_ci    // may gc
3524514f5e3Sopenharmony_ci    auto strFlat = EcmaStringAccessor::Flatten(vm, strHandle, MemSpaceType::SHARED_OLD_SPACE);
3534514f5e3Sopenharmony_ci    if (EcmaStringAccessor(strFlat).IsInternString()) {
3544514f5e3Sopenharmony_ci        return strFlat;
3554514f5e3Sopenharmony_ci    }
3564514f5e3Sopenharmony_ci    JSHandle<EcmaString> strFlatHandle(thread, strFlat);
3574514f5e3Sopenharmony_ci    // may gc
3584514f5e3Sopenharmony_ci    auto hashcode = EcmaStringAccessor(strFlat).GetHashcode();
3594514f5e3Sopenharmony_ci    RuntimeLockHolder locker(thread, stringTable_[GetTableId(hashcode)].mutex_);
3604514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
3614514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
3624514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
3634514f5e3Sopenharmony_ci    }
3644514f5e3Sopenharmony_ci#endif
3654514f5e3Sopenharmony_ci    strFlat = *strFlatHandle;
3664514f5e3Sopenharmony_ci    EcmaString *result = GetStringThreadUnsafe(strFlat, hashcode);
3674514f5e3Sopenharmony_ci    if (result != nullptr) {
3684514f5e3Sopenharmony_ci        return result;
3694514f5e3Sopenharmony_ci    }
3704514f5e3Sopenharmony_ci
3714514f5e3Sopenharmony_ci    InternStringThreadUnsafe(strFlat, hashcode);
3724514f5e3Sopenharmony_ci    return strFlat;
3734514f5e3Sopenharmony_ci}
3744514f5e3Sopenharmony_ci
3754514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternStringThreadUnsafe(EcmaVM *vm, EcmaString *string)
3764514f5e3Sopenharmony_ci{
3774514f5e3Sopenharmony_ci    if (EcmaStringAccessor(string).IsInternString()) {
3784514f5e3Sopenharmony_ci        return string;
3794514f5e3Sopenharmony_ci    }
3804514f5e3Sopenharmony_ci    JSHandle<EcmaString> strHandle(vm->GetJSThread(), string);
3814514f5e3Sopenharmony_ci    EcmaString *strFlat = EcmaStringAccessor::Flatten(vm, strHandle, MemSpaceType::SHARED_OLD_SPACE);
3824514f5e3Sopenharmony_ci    if (EcmaStringAccessor(strFlat).IsInternString()) {
3834514f5e3Sopenharmony_ci        return strFlat;
3844514f5e3Sopenharmony_ci    }
3854514f5e3Sopenharmony_ci    auto hashcode = EcmaStringAccessor(strFlat).GetHashcode();
3864514f5e3Sopenharmony_ci    EcmaString *result = GetStringThreadUnsafe(strFlat, hashcode);
3874514f5e3Sopenharmony_ci    if (result != nullptr) {
3884514f5e3Sopenharmony_ci        return result;
3894514f5e3Sopenharmony_ci    }
3904514f5e3Sopenharmony_ci
3914514f5e3Sopenharmony_ci    InternStringThreadUnsafe(strFlat, hashcode);
3924514f5e3Sopenharmony_ci    return strFlat;
3934514f5e3Sopenharmony_ci}
3944514f5e3Sopenharmony_ci
3954514f5e3Sopenharmony_civoid EcmaStringTable::InsertStringToTableWithHashThreadUnsafe(EcmaString* string, uint32_t hashcode)
3964514f5e3Sopenharmony_ci{
3974514f5e3Sopenharmony_ci    // Strings in string table should not be in the young space.
3984514f5e3Sopenharmony_ci    ASSERT(Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(string))->InSharedHeap());
3994514f5e3Sopenharmony_ci    ASSERT(EcmaStringAccessor(string).NotTreeString());
4004514f5e3Sopenharmony_ci    ASSERT(EcmaStringAccessor(string).GetHashcode() == hashcode);
4014514f5e3Sopenharmony_ci    stringTable_[GetTableId(hashcode)].table_.emplace(hashcode, string);
4024514f5e3Sopenharmony_ci    EcmaStringAccessor(string).SetInternString();
4034514f5e3Sopenharmony_ci}
4044514f5e3Sopenharmony_ci
4054514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::InsertStringToTable(EcmaVM *vm, const JSHandle<EcmaString> &strHandle)
4064514f5e3Sopenharmony_ci{
4074514f5e3Sopenharmony_ci    auto strFlat = EcmaStringAccessor::Flatten(vm, strHandle, MemSpaceType::SHARED_OLD_SPACE);
4084514f5e3Sopenharmony_ci    JSHandle<EcmaString> strFlatHandle(vm->GetJSThread(), strFlat);
4094514f5e3Sopenharmony_ci    auto hashcode = EcmaStringAccessor(strFlat).GetHashcode();
4104514f5e3Sopenharmony_ci    RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_);
4114514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
4124514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
4134514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
4144514f5e3Sopenharmony_ci    }
4154514f5e3Sopenharmony_ci#endif
4164514f5e3Sopenharmony_ci    strFlat = *strFlatHandle;
4174514f5e3Sopenharmony_ci    InternStringThreadUnsafe(strFlat, hashcode);
4184514f5e3Sopenharmony_ci    return strFlat;
4194514f5e3Sopenharmony_ci}
4204514f5e3Sopenharmony_ci
4214514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::TryGetInternString(JSThread *thread, const JSHandle<EcmaString> &string)
4224514f5e3Sopenharmony_ci{
4234514f5e3Sopenharmony_ci    auto hashcode = EcmaStringAccessor(*string).GetHashcode();
4244514f5e3Sopenharmony_ci    RuntimeLockHolder locker(thread, stringTable_[GetTableId(hashcode)].mutex_);
4254514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
4264514f5e3Sopenharmony_ci    auto vm = thread->GetEcmaVM();
4274514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
4284514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
4294514f5e3Sopenharmony_ci    }
4304514f5e3Sopenharmony_ci#endif
4314514f5e3Sopenharmony_ci    return GetStringThreadUnsafe(*string, hashcode);
4324514f5e3Sopenharmony_ci}
4334514f5e3Sopenharmony_ci
4344514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
4354514f5e3Sopenharmony_ci                                                            bool canBeCompress, MemSpaceType type,
4364514f5e3Sopenharmony_ci                                                            bool isConstantString, uint32_t idOffset)
4374514f5e3Sopenharmony_ci{
4384514f5e3Sopenharmony_ci    ASSERT(IsSMemSpace(type));
4394514f5e3Sopenharmony_ci    uint32_t hashcode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress);
4404514f5e3Sopenharmony_ci    RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_);
4414514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
4424514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
4434514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
4444514f5e3Sopenharmony_ci    }
4454514f5e3Sopenharmony_ci#endif
4464514f5e3Sopenharmony_ci    std::pair<EcmaString *, uint32_t> result = GetStringThreadUnsafe(utf8Data, utf8Len, canBeCompress, hashcode);
4474514f5e3Sopenharmony_ci    if (result.first != nullptr) {
4484514f5e3Sopenharmony_ci        return result.first;
4494514f5e3Sopenharmony_ci    }
4504514f5e3Sopenharmony_ci    type = (type == MemSpaceType::SHARED_NON_MOVABLE) ? type : MemSpaceType::SHARED_OLD_SPACE;
4514514f5e3Sopenharmony_ci    EcmaString *str = nullptr;
4524514f5e3Sopenharmony_ci    if (canBeCompress) {
4534514f5e3Sopenharmony_ci        // Constant string will be created in this branch.
4544514f5e3Sopenharmony_ci        str = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type, isConstantString,
4554514f5e3Sopenharmony_ci            idOffset);
4564514f5e3Sopenharmony_ci    } else {
4574514f5e3Sopenharmony_ci        str = EcmaStringAccessor::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type);
4584514f5e3Sopenharmony_ci    }
4594514f5e3Sopenharmony_ci    str->SetMixHashcode(result.second);
4604514f5e3Sopenharmony_ci    InternStringThreadUnsafe(str, hashcode);
4614514f5e3Sopenharmony_ci    return str;
4624514f5e3Sopenharmony_ci}
4634514f5e3Sopenharmony_ci
4644514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len,
4654514f5e3Sopenharmony_ci                                                            MemSpaceType type)
4664514f5e3Sopenharmony_ci{
4674514f5e3Sopenharmony_ci    ASSERT(IsSMemSpace(type));
4684514f5e3Sopenharmony_ci    type = (type == MemSpaceType::SHARED_NON_MOVABLE) ? type : MemSpaceType::SHARED_OLD_SPACE;
4694514f5e3Sopenharmony_ci    EcmaString *str = EcmaStringAccessor::CreateUtf16StringFromUtf8(vm, utf8Data, utf16Len, type);
4704514f5e3Sopenharmony_ci    JSHandle<EcmaString> stringHandle(vm->GetJSThread(), str);
4714514f5e3Sopenharmony_ci    auto hashcode = EcmaStringAccessor(str).GetHashcode();
4724514f5e3Sopenharmony_ci    RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_);
4734514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
4744514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
4754514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
4764514f5e3Sopenharmony_ci    }
4774514f5e3Sopenharmony_ci#endif
4784514f5e3Sopenharmony_ci    str = *stringHandle;
4794514f5e3Sopenharmony_ci    EcmaString *result = GetStringThreadUnsafe(str, hashcode);
4804514f5e3Sopenharmony_ci    if (result != nullptr) {
4814514f5e3Sopenharmony_ci        return result;
4824514f5e3Sopenharmony_ci    }
4834514f5e3Sopenharmony_ci    InternStringThreadUnsafe(str, hashcode);
4844514f5e3Sopenharmony_ci    return str;
4854514f5e3Sopenharmony_ci}
4864514f5e3Sopenharmony_ci
4874514f5e3Sopenharmony_ci// used in jit thread, which unsupport create jshandle
4884514f5e3Sopenharmony_ciEcmaString *EcmaStringTable::GetOrInternStringWithSpaceTypeWithoutJSHandle(EcmaVM *vm, const uint8_t *utf8Data,
4894514f5e3Sopenharmony_ci                                                                           uint32_t utf16Len, MemSpaceType type)
4904514f5e3Sopenharmony_ci{
4914514f5e3Sopenharmony_ci    ASSERT(IsSMemSpace(type));
4924514f5e3Sopenharmony_ci    type = (type == MemSpaceType::SHARED_NON_MOVABLE) ? type : MemSpaceType::SHARED_OLD_SPACE;
4934514f5e3Sopenharmony_ci    CVector<uint16_t> u16Buffer(utf16Len);
4944514f5e3Sopenharmony_ci    utf::ConvertRegionMUtf8ToUtf16(utf8Data, u16Buffer.data(), utf::Mutf8Size(utf8Data), utf16Len, 0);
4954514f5e3Sopenharmony_ci    auto hashcode = EcmaStringAccessor::ComputeHashcodeUtf16(u16Buffer.data(), utf16Len);
4964514f5e3Sopenharmony_ci    RuntimeLockHolder locker(vm->GetJSThread(), stringTable_[GetTableId(hashcode)].mutex_);
4974514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
4984514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
4994514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
5004514f5e3Sopenharmony_ci    }
5014514f5e3Sopenharmony_ci#endif
5024514f5e3Sopenharmony_ci    auto result = GetStringThreadUnsafe(u16Buffer.data(), utf16Len, hashcode);
5034514f5e3Sopenharmony_ci    if (result.first != nullptr) {
5044514f5e3Sopenharmony_ci        return result.first;
5054514f5e3Sopenharmony_ci    }
5064514f5e3Sopenharmony_ci    EcmaString *str = EcmaStringAccessor::CreateFromUtf16(vm, u16Buffer.data(), utf16Len, false, type);
5074514f5e3Sopenharmony_ci    str->SetMixHashcode(hashcode);
5084514f5e3Sopenharmony_ci    InternStringThreadUnsafe(str, hashcode);
5094514f5e3Sopenharmony_ci    return str;
5104514f5e3Sopenharmony_ci}
5114514f5e3Sopenharmony_ci
5124514f5e3Sopenharmony_civoid EcmaStringTable::SweepWeakRef(const WeakRootVisitor &visitor)
5134514f5e3Sopenharmony_ci{
5144514f5e3Sopenharmony_ci    // No need lock here, only shared gc will sweep string table, meanwhile other threads are suspended.
5154514f5e3Sopenharmony_ci    for (uint32_t tableId = 0; tableId < stringTable_.size(); ++tableId) {
5164514f5e3Sopenharmony_ci        SweepWeakRef(visitor, tableId);
5174514f5e3Sopenharmony_ci    }
5184514f5e3Sopenharmony_ci}
5194514f5e3Sopenharmony_ci
5204514f5e3Sopenharmony_civoid EcmaStringTable::SweepWeakRef(const WeakRootVisitor &visitor, uint32_t tableId)
5214514f5e3Sopenharmony_ci{
5224514f5e3Sopenharmony_ci    ASSERT(tableId >= 0 && tableId < stringTable_.size());
5234514f5e3Sopenharmony_ci    auto &table = stringTable_[tableId].table_;
5244514f5e3Sopenharmony_ci    for (auto it = table.begin(); it != table.end();) {
5254514f5e3Sopenharmony_ci        auto *object = it->second;
5264514f5e3Sopenharmony_ci        auto fwd = visitor(object);
5274514f5e3Sopenharmony_ci        ASSERT(Region::ObjectAddressToRange(object)->InSharedHeap());
5284514f5e3Sopenharmony_ci        if (fwd == nullptr) {
5294514f5e3Sopenharmony_ci            LOG_ECMA(VERBOSE) << "StringTable: delete string " << std::hex << object;
5304514f5e3Sopenharmony_ci            it = table.erase(it);
5314514f5e3Sopenharmony_ci        } else if (fwd != object) {
5324514f5e3Sopenharmony_ci            it->second = static_cast<EcmaString *>(fwd);
5334514f5e3Sopenharmony_ci            ++it;
5344514f5e3Sopenharmony_ci            LOG_ECMA(VERBOSE) << "StringTable: forward " << std::hex << object << " -> " << fwd;
5354514f5e3Sopenharmony_ci        } else {
5364514f5e3Sopenharmony_ci            ++it;
5374514f5e3Sopenharmony_ci        }
5384514f5e3Sopenharmony_ci    }
5394514f5e3Sopenharmony_ci}
5404514f5e3Sopenharmony_ci
5414514f5e3Sopenharmony_civoid EcmaStringTable::RelocateConstantData(EcmaVM *vm, const JSPandaFile *jsPandaFile)
5424514f5e3Sopenharmony_ci{
5434514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
5444514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
5454514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
5464514f5e3Sopenharmony_ci    }
5474514f5e3Sopenharmony_ci#endif
5484514f5e3Sopenharmony_ci    auto thread = vm->GetJSThread();
5494514f5e3Sopenharmony_ci    for (auto &[table, mutex] : stringTable_) {
5504514f5e3Sopenharmony_ci        RuntimeLockHolder locker(thread, mutex);
5514514f5e3Sopenharmony_ci        for (auto it = table.begin(); it != table.end();) {
5524514f5e3Sopenharmony_ci            auto *object = it->second;
5534514f5e3Sopenharmony_ci            if (!EcmaStringAccessor(object).IsConstantString()) {
5544514f5e3Sopenharmony_ci                ++it;
5554514f5e3Sopenharmony_ci                continue;
5564514f5e3Sopenharmony_ci            }
5574514f5e3Sopenharmony_ci            auto constantStr = ConstantString::Cast(object);
5584514f5e3Sopenharmony_ci            if (constantStr->GetEntityId() < 0 || !jsPandaFile->Contain(constantStr->GetConstantData())) {
5594514f5e3Sopenharmony_ci                // EntityId is -1, which means this str has been relocated. Or the data is not in pandafile.
5604514f5e3Sopenharmony_ci                ++it;
5614514f5e3Sopenharmony_ci                continue;
5624514f5e3Sopenharmony_ci            }
5634514f5e3Sopenharmony_ci            uint32_t id = constantStr->GetEntityIdU32();
5644514f5e3Sopenharmony_ci            panda_file::File::StringData sd = jsPandaFile->GetStringData(EntityId(id));
5654514f5e3Sopenharmony_ci            if (constantStr->GetConstantData() != sd.data) {
5664514f5e3Sopenharmony_ci                LOG_ECMA(ERROR) << "ConstantString data pointer is inconsistent with sd.data";
5674514f5e3Sopenharmony_ci                ++it;
5684514f5e3Sopenharmony_ci                continue;
5694514f5e3Sopenharmony_ci            }
5704514f5e3Sopenharmony_ci            uint32_t strLen = sd.utf16_length;
5714514f5e3Sopenharmony_ci            if (UNLIKELY(strLen == 0)) {
5724514f5e3Sopenharmony_ci                it->second = *(vm->GetFactory()->GetEmptyString());
5734514f5e3Sopenharmony_ci            }
5744514f5e3Sopenharmony_ci            size_t byteLength = sd.is_ascii ? 1 : sizeof(uint16_t);
5754514f5e3Sopenharmony_ci            JSMutableHandle<ByteArray> newData(vm->GetJSThread(), JSTaggedValue::Undefined());
5764514f5e3Sopenharmony_ci            newData.Update(vm->GetFactory()->NewByteArray(
5774514f5e3Sopenharmony_ci                strLen, byteLength, reinterpret_cast<void *>(const_cast<uint8_t *>(sd.data)),
5784514f5e3Sopenharmony_ci                MemSpaceType::SHARED_NON_MOVABLE));
5794514f5e3Sopenharmony_ci            constantStr->SetRelocatedData(thread, newData.GetTaggedValue());
5804514f5e3Sopenharmony_ci            constantStr->SetConstantData(static_cast<uint8_t *>(newData->GetData()));
5814514f5e3Sopenharmony_ci            constantStr->SetEntityId(-1);
5824514f5e3Sopenharmony_ci            ++it;
5834514f5e3Sopenharmony_ci        }
5844514f5e3Sopenharmony_ci    }
5854514f5e3Sopenharmony_ci}
5864514f5e3Sopenharmony_ci
5874514f5e3Sopenharmony_cibool EcmaStringTable::CheckStringTableValidity(JSThread *thread)
5884514f5e3Sopenharmony_ci{
5894514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_SCOPE_LOCK_STAT
5904514f5e3Sopenharmony_ci    auto vm = thread->GetEcmaVM();
5914514f5e3Sopenharmony_ci    if (vm->IsCollectingScopeLockStats()) {
5924514f5e3Sopenharmony_ci        vm->IncreaseStringTableLockCount();
5934514f5e3Sopenharmony_ci    }
5944514f5e3Sopenharmony_ci#endif
5954514f5e3Sopenharmony_ci    for (auto &[table, mutex] : stringTable_) {
5964514f5e3Sopenharmony_ci        RuntimeLockHolder locker(thread, mutex);
5974514f5e3Sopenharmony_ci        for (auto itemOuter = table.begin(); itemOuter != table.end(); ++itemOuter) {
5984514f5e3Sopenharmony_ci            auto outerString = itemOuter->second;
5994514f5e3Sopenharmony_ci            if (!EcmaStringAccessor(outerString).NotTreeString()) {
6004514f5e3Sopenharmony_ci                return false;
6014514f5e3Sopenharmony_ci            }
6024514f5e3Sopenharmony_ci            int counter = 0;
6034514f5e3Sopenharmony_ci            auto hashcode = EcmaStringAccessor(outerString).GetHashcode();
6044514f5e3Sopenharmony_ci            auto range = table.equal_range(hashcode);
6054514f5e3Sopenharmony_ci            for (auto it = range.first; it != range.second; ++it) {
6064514f5e3Sopenharmony_ci                auto foundString = it->second;
6074514f5e3Sopenharmony_ci                counter += EcmaStringAccessor::StringsAreEqual(foundString, outerString) ? 1 : 0;
6084514f5e3Sopenharmony_ci            }
6094514f5e3Sopenharmony_ci            if (counter > 1) {
6104514f5e3Sopenharmony_ci                return false;
6114514f5e3Sopenharmony_ci            }
6124514f5e3Sopenharmony_ci        }
6134514f5e3Sopenharmony_ci    }
6144514f5e3Sopenharmony_ci    return true;
6154514f5e3Sopenharmony_ci}
6164514f5e3Sopenharmony_ci
6174514f5e3Sopenharmony_ciJSTaggedValue SingleCharTable::CreateSingleCharTable(JSThread *thread)
6184514f5e3Sopenharmony_ci{
6194514f5e3Sopenharmony_ci    auto table = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(MAX_ONEBYTE_CHARCODE,
6204514f5e3Sopenharmony_ci        JSTaggedValue::Undefined(), MemSpaceType::SHARED_NON_MOVABLE);
6214514f5e3Sopenharmony_ci    ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
6224514f5e3Sopenharmony_ci    for (uint32_t i = 1; i < MAX_ONEBYTE_CHARCODE; ++i) {
6234514f5e3Sopenharmony_ci        std::string tmp(1, i + 0X00); // 1: size
6244514f5e3Sopenharmony_ci        table->Set(thread, i, factory->NewFromASCIIReadOnly(tmp).GetTaggedValue());
6254514f5e3Sopenharmony_ci    }
6264514f5e3Sopenharmony_ci    return table.GetTaggedValue();
6274514f5e3Sopenharmony_ci}
6284514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
629