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#ifndef ECMASCRIPT_STRING_TABLE_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_STRING_TABLE_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include <array> 204514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value.h" 214514f5e3Sopenharmony_ci#include "ecmascript/mem/c_containers.h" 224514f5e3Sopenharmony_ci#include "ecmascript/mem/space.h" 234514f5e3Sopenharmony_ci#include "ecmascript/mem/visitor.h" 244514f5e3Sopenharmony_ci#include "ecmascript/platform/mutex.h" 254514f5e3Sopenharmony_ci#include "ecmascript/tagged_array.h" 264514f5e3Sopenharmony_ci#include "ecmascript/taskpool/task.h" 274514f5e3Sopenharmony_ci 284514f5e3Sopenharmony_cinamespace panda::ecmascript { 294514f5e3Sopenharmony_ciclass EcmaString; 304514f5e3Sopenharmony_ciclass EcmaVM; 314514f5e3Sopenharmony_ciclass JSPandaFile; 324514f5e3Sopenharmony_ciclass JSThread; 334514f5e3Sopenharmony_ci 344514f5e3Sopenharmony_ciclass EcmaStringTable; 354514f5e3Sopenharmony_ci 364514f5e3Sopenharmony_ciclass EcmaStringTableCleaner { 374514f5e3Sopenharmony_cipublic: 384514f5e3Sopenharmony_ci using IteratorPtr = std::shared_ptr<std::atomic<uint32_t>>; 394514f5e3Sopenharmony_ci EcmaStringTableCleaner(EcmaStringTable* stringTable) : stringTable_(stringTable) {} 404514f5e3Sopenharmony_ci ~EcmaStringTableCleaner() { stringTable_ = nullptr; } 414514f5e3Sopenharmony_ci 424514f5e3Sopenharmony_ci void PostSweepWeakRefTask(const WeakRootVisitor &visitor); 434514f5e3Sopenharmony_ci void JoinAndWaitSweepWeakRefTask(const WeakRootVisitor &visitor); 444514f5e3Sopenharmony_ci 454514f5e3Sopenharmony_ciprivate: 464514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(EcmaStringTableCleaner); 474514f5e3Sopenharmony_ci NO_MOVE_SEMANTIC(EcmaStringTableCleaner); 484514f5e3Sopenharmony_ci 494514f5e3Sopenharmony_ci static void ProcessSweepWeakRef(IteratorPtr& iter, EcmaStringTableCleaner *cleaner, const WeakRootVisitor &visitor); 504514f5e3Sopenharmony_ci void StartSweepWeakRefTask(); 514514f5e3Sopenharmony_ci void WaitSweepWeakRefTask(); 524514f5e3Sopenharmony_ci void SignalSweepWeakRefTask(); 534514f5e3Sopenharmony_ci 544514f5e3Sopenharmony_ci static inline uint32_t GetNextTableId(IteratorPtr& iter) 554514f5e3Sopenharmony_ci { 564514f5e3Sopenharmony_ci return iter->fetch_add(1U, std::memory_order_relaxed); 574514f5e3Sopenharmony_ci } 584514f5e3Sopenharmony_ci 594514f5e3Sopenharmony_ci static inline bool ReduceCountAndCheckFinish(EcmaStringTableCleaner* cleaner) 604514f5e3Sopenharmony_ci { 614514f5e3Sopenharmony_ci return (cleaner->PendingTaskCount_.fetch_sub(1U, std::memory_order_relaxed) == 1U); 624514f5e3Sopenharmony_ci } 634514f5e3Sopenharmony_ci 644514f5e3Sopenharmony_ci class SweepWeakRefTask : public Task { 654514f5e3Sopenharmony_ci public: 664514f5e3Sopenharmony_ci SweepWeakRefTask(IteratorPtr iter, EcmaStringTableCleaner* cleaner, const WeakRootVisitor& visitor) 674514f5e3Sopenharmony_ci : Task(0), iter_(iter), cleaner_(cleaner), visitor_(visitor) {} 684514f5e3Sopenharmony_ci ~SweepWeakRefTask() = default; 694514f5e3Sopenharmony_ci 704514f5e3Sopenharmony_ci bool Run(uint32_t threadIndex) override; 714514f5e3Sopenharmony_ci 724514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(SweepWeakRefTask); 734514f5e3Sopenharmony_ci NO_MOVE_SEMANTIC(SweepWeakRefTask); 744514f5e3Sopenharmony_ci 754514f5e3Sopenharmony_ci private: 764514f5e3Sopenharmony_ci IteratorPtr iter_; 774514f5e3Sopenharmony_ci EcmaStringTableCleaner* cleaner_; 784514f5e3Sopenharmony_ci const WeakRootVisitor& visitor_; 794514f5e3Sopenharmony_ci }; 804514f5e3Sopenharmony_ci 814514f5e3Sopenharmony_ci IteratorPtr iter_; 824514f5e3Sopenharmony_ci EcmaStringTable* stringTable_; 834514f5e3Sopenharmony_ci std::atomic<uint32_t> PendingTaskCount_ {0U}; 844514f5e3Sopenharmony_ci Mutex sweepWeakRefMutex_; 854514f5e3Sopenharmony_ci bool sweepWeakRefFinished_ {true}; 864514f5e3Sopenharmony_ci ConditionVariable sweepWeakRefCV_; 874514f5e3Sopenharmony_ci}; 884514f5e3Sopenharmony_ci 894514f5e3Sopenharmony_ciclass EcmaStringTable { 904514f5e3Sopenharmony_cipublic: 914514f5e3Sopenharmony_ci EcmaStringTable() : cleaner_(new EcmaStringTableCleaner(this)) 924514f5e3Sopenharmony_ci { 934514f5e3Sopenharmony_ci stringTable_.fill(Segment()); 944514f5e3Sopenharmony_ci } 954514f5e3Sopenharmony_ci virtual ~EcmaStringTable() 964514f5e3Sopenharmony_ci { 974514f5e3Sopenharmony_ci if (cleaner_ != nullptr) { 984514f5e3Sopenharmony_ci delete cleaner_; 994514f5e3Sopenharmony_ci cleaner_ = nullptr; 1004514f5e3Sopenharmony_ci } 1014514f5e3Sopenharmony_ci for (auto &seg : stringTable_) { 1024514f5e3Sopenharmony_ci seg.table_.clear(); 1034514f5e3Sopenharmony_ci } 1044514f5e3Sopenharmony_ci } 1054514f5e3Sopenharmony_ci 1064514f5e3Sopenharmony_ci static inline uint32_t GetTableId(uint32_t hashcode) 1074514f5e3Sopenharmony_ci { 1084514f5e3Sopenharmony_ci return hashcode & SEGMENT_MASK; 1094514f5e3Sopenharmony_ci } 1104514f5e3Sopenharmony_ci void InternEmptyString(JSThread *thread, EcmaString *emptyStr); 1114514f5e3Sopenharmony_ci EcmaString *GetOrInternString(EcmaVM *vm, 1124514f5e3Sopenharmony_ci const JSHandle<EcmaString> &firstString, 1134514f5e3Sopenharmony_ci const JSHandle<EcmaString> &secondString); 1144514f5e3Sopenharmony_ci EcmaString *GetOrInternStringWithoutLock(JSThread *thread, 1154514f5e3Sopenharmony_ci const JSHandle<EcmaString> &firstString, 1164514f5e3Sopenharmony_ci const JSHandle<EcmaString> &secondString, uint32_t hashcode); 1174514f5e3Sopenharmony_ci EcmaString *GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress); 1184514f5e3Sopenharmony_ci EcmaString *GetOrInternStringWithoutLock(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, 1194514f5e3Sopenharmony_ci bool canBeCompress, uint32_t hashcode); 1204514f5e3Sopenharmony_ci EcmaString *CreateAndInternStringNonMovable(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len); 1214514f5e3Sopenharmony_ci EcmaString *CreateAndInternStringReadOnly(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, 1224514f5e3Sopenharmony_ci bool canBeCompress); 1234514f5e3Sopenharmony_ci EcmaString *GetOrInternString(EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress); 1244514f5e3Sopenharmony_ci EcmaString *GetOrInternString(EcmaVM *vm, EcmaString *string); 1254514f5e3Sopenharmony_ci EcmaString *GetOrInternCompressedSubString(EcmaVM *vm, const JSHandle<EcmaString> &string, 1264514f5e3Sopenharmony_ci uint32_t offset, uint32_t utf8Len); 1274514f5e3Sopenharmony_ci EcmaString *GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, 1284514f5e3Sopenharmony_ci bool canBeCompress, MemSpaceType type, bool isConstantString, uint32_t idOffset); 1294514f5e3Sopenharmony_ci EcmaString *GetOrInternStringWithSpaceType(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, 1304514f5e3Sopenharmony_ci MemSpaceType type); 1314514f5e3Sopenharmony_ci EcmaString *GetOrInternStringWithSpaceTypeWithoutJSHandle(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, 1324514f5e3Sopenharmony_ci MemSpaceType type); 1334514f5e3Sopenharmony_ci EcmaString *TryGetInternString(JSThread *thread, const JSHandle<EcmaString> &string); 1344514f5e3Sopenharmony_ci void InsertStringToTableWithHashThreadUnsafe(EcmaString* string, uint32_t hashcode); 1354514f5e3Sopenharmony_ci EcmaString *InsertStringToTable(EcmaVM *vm, const JSHandle<EcmaString> &strHandle); 1364514f5e3Sopenharmony_ci 1374514f5e3Sopenharmony_ci void SweepWeakRef(const WeakRootVisitor &visitor); 1384514f5e3Sopenharmony_ci void SweepWeakRef(const WeakRootVisitor &visitor, uint32_t tableId); 1394514f5e3Sopenharmony_ci 1404514f5e3Sopenharmony_ci bool CheckStringTableValidity(JSThread *thread); 1414514f5e3Sopenharmony_ci void RelocateConstantData(EcmaVM *vm, const JSPandaFile *jsPandaFile); 1424514f5e3Sopenharmony_ci 1434514f5e3Sopenharmony_ci EcmaStringTableCleaner* GetCleaner() 1444514f5e3Sopenharmony_ci { 1454514f5e3Sopenharmony_ci return cleaner_; 1464514f5e3Sopenharmony_ci } 1474514f5e3Sopenharmony_ci static constexpr uint32_t SEGMENT_COUNT = 16U; // 16: 2^4 1484514f5e3Sopenharmony_ci static constexpr uint32_t SEGMENT_MASK = SEGMENT_COUNT - 1U; 1494514f5e3Sopenharmony_ciprivate: 1504514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(EcmaStringTable); 1514514f5e3Sopenharmony_ci NO_MOVE_SEMANTIC(EcmaStringTable); 1524514f5e3Sopenharmony_ci 1534514f5e3Sopenharmony_ci std::pair<EcmaString *, uint32_t> GetStringThreadUnsafe(const JSHandle<EcmaString> &firstString, 1544514f5e3Sopenharmony_ci const JSHandle<EcmaString> &secondString, 1554514f5e3Sopenharmony_ci uint32_t hashcode) const; 1564514f5e3Sopenharmony_ci std::pair<EcmaString *, uint32_t> GetStringThreadUnsafe(const uint8_t *utf8Data, uint32_t utf8Len, 1574514f5e3Sopenharmony_ci bool canBeCompress, uint32_t hashcode) const; 1584514f5e3Sopenharmony_ci std::pair<EcmaString *, uint32_t> GetStringThreadUnsafe(const uint16_t *utf16Data, 1594514f5e3Sopenharmony_ci uint32_t utf16Len, uint32_t hashcode) const; 1604514f5e3Sopenharmony_ci EcmaString *GetStringWithHashThreadUnsafe(EcmaString *string, uint32_t hashcode) const; 1614514f5e3Sopenharmony_ci EcmaString *GetStringThreadUnsafe(EcmaString *string, uint32_t hashcode) const; 1624514f5e3Sopenharmony_ci 1634514f5e3Sopenharmony_ci void InternStringThreadUnsafe(EcmaString *string, uint32_t hashcode); 1644514f5e3Sopenharmony_ci EcmaString *GetOrInternStringThreadUnsafe(EcmaVM *vm, EcmaString *string); 1654514f5e3Sopenharmony_ci 1664514f5e3Sopenharmony_ci void InsertStringIfNotExistThreadUnsafe(EcmaString *string); 1674514f5e3Sopenharmony_ci 1684514f5e3Sopenharmony_ci struct Segment { 1694514f5e3Sopenharmony_ci CUnorderedMultiMap<uint32_t, EcmaString *> table_; 1704514f5e3Sopenharmony_ci Mutex mutex_; 1714514f5e3Sopenharmony_ci }; 1724514f5e3Sopenharmony_ci 1734514f5e3Sopenharmony_ci std::array<Segment, SEGMENT_COUNT> stringTable_; 1744514f5e3Sopenharmony_ci EcmaStringTableCleaner* cleaner_; 1754514f5e3Sopenharmony_ci 1764514f5e3Sopenharmony_ci friend class SnapshotProcessor; 1774514f5e3Sopenharmony_ci friend class BaseDeserializer; 1784514f5e3Sopenharmony_ci}; 1794514f5e3Sopenharmony_ci 1804514f5e3Sopenharmony_ciclass SingleCharTable : public TaggedArray { 1814514f5e3Sopenharmony_cipublic: 1824514f5e3Sopenharmony_ci static SingleCharTable *Cast(TaggedObject *object) 1834514f5e3Sopenharmony_ci { 1844514f5e3Sopenharmony_ci return reinterpret_cast<SingleCharTable*>(object); 1854514f5e3Sopenharmony_ci } 1864514f5e3Sopenharmony_ci static JSTaggedValue CreateSingleCharTable(JSThread *thread); 1874514f5e3Sopenharmony_ci JSTaggedValue GetStringFromSingleCharTable(int32_t ch) 1884514f5e3Sopenharmony_ci { 1894514f5e3Sopenharmony_ci return Get(ch); 1904514f5e3Sopenharmony_ci } 1914514f5e3Sopenharmony_ciprivate: 1924514f5e3Sopenharmony_ci SingleCharTable() = default; 1934514f5e3Sopenharmony_ci ~SingleCharTable() = default; 1944514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(SingleCharTable); 1954514f5e3Sopenharmony_ci NO_MOVE_SEMANTIC(SingleCharTable); 1964514f5e3Sopenharmony_ci static constexpr uint32_t MAX_ONEBYTE_CHARCODE = 128; // 0X00-0X7F 1974514f5e3Sopenharmony_ci}; 1984514f5e3Sopenharmony_ci} // namespace panda::ecmascript 1994514f5e3Sopenharmony_ci 2004514f5e3Sopenharmony_ci#endif // ECMASCRIPT_STRING_TABLE_H 201