• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_STRING_TABLE_H
17 #define ECMASCRIPT_STRING_TABLE_H
18 
19 #include <array>
20 #include "common_components/objects/string_table/hashtriemap.h"
21 #include "common_components/objects/string_table_internal.h"
22 #include "common_components/taskpool/task.h"
23 #include "ecmascript/ecma_string.h"
24 #include "ecmascript/js_tagged_value.h"
25 #include "ecmascript/mem/c_containers.h"
26 #include "ecmascript/mem/space.h"
27 #include "ecmascript/mem/visitor.h"
28 #include "ecmascript/platform/mutex.h"
29 #include "ecmascript/tagged_array.h"
30 #include "common_interfaces/objects/base_string_table.h"
31 #include "common_interfaces/objects/string/base_string_declare.h"
32 
33 namespace panda::ecmascript {
34 #if ENABLE_NEXT_OPTIMIZATION
35 class EcmaString;
36 class EcmaVM;
37 class JSPandaFile;
38 class JSThread;
39 
40 class EcmaStringTable;
41 class EcmaStringTableCleaner {
42 public:
43     using IteratorPtr = std::shared_ptr<std::atomic<uint32_t>>;
EcmaStringTableCleaner(EcmaStringTable * stringTable)44     EcmaStringTableCleaner(EcmaStringTable *stringTable) : stringTable_(stringTable) {}
~EcmaStringTableCleaner()45     ~EcmaStringTableCleaner()
46     {
47         stringTable_ = nullptr;
48     }
49     void PostSweepWeakRefTask(const WeakRootVisitor &visitor);
50     void JoinAndWaitSweepWeakRefTask(const WeakRootVisitor &visitor);
51 
52 private:
53     NO_COPY_SEMANTIC(EcmaStringTableCleaner);
54     NO_MOVE_SEMANTIC(EcmaStringTableCleaner);
55     static void ProcessSweepWeakRef(IteratorPtr &iter, EcmaStringTableCleaner *cleaner, const WeakRootVisitor &visitor);
56     void StartSweepWeakRefTask();
57     void WaitSweepWeakRefTask();
58     void SignalSweepWeakRefTask();
59 
GetNextIndexId(IteratorPtr & iter)60     static inline uint32_t GetNextIndexId(IteratorPtr &iter)
61     {
62         return iter->fetch_add(1U, std::memory_order_relaxed);
63     }
64 
ReduceCountAndCheckFinish(EcmaStringTableCleaner * cleaner)65     static inline bool ReduceCountAndCheckFinish(EcmaStringTableCleaner *cleaner)
66     {
67         return (cleaner->PendingTaskCount_.fetch_sub(1U, std::memory_order_relaxed) == 1U);
68     }
69 
70     class SweepWeakRefTask : public common::Task {
71     public:
SweepWeakRefTask(IteratorPtr iter,EcmaStringTableCleaner * cleaner,const WeakRootVisitor & visitor)72         SweepWeakRefTask(IteratorPtr iter, EcmaStringTableCleaner *cleaner, const WeakRootVisitor &visitor)
73             : common::Task(0), iter_(iter), cleaner_(cleaner), visitor_(visitor)
74         {
75         }
76         ~SweepWeakRefTask() = default;
77 
78         bool Run(uint32_t threadIndex) override;
79 
80         NO_COPY_SEMANTIC(SweepWeakRefTask);
81         NO_MOVE_SEMANTIC(SweepWeakRefTask);
82 
83     private:
84         IteratorPtr iter_;
85         EcmaStringTableCleaner *cleaner_;
86         const WeakRootVisitor &visitor_;
87     };
88     IteratorPtr iter_;
89     EcmaStringTable *stringTable_;
90     std::atomic<uint32_t> PendingTaskCount_ {0U};
91     Mutex sweepWeakRefMutex_;
92     bool sweepWeakRefFinished_ {true};
93     ConditionVariable sweepWeakRefCV_;
94 };
95 
96 class EcmaStringTableMutex {
97 public:
mtx_(is_init)98     explicit EcmaStringTableMutex(bool is_init = true) : mtx_(is_init)
99     {
100     }
101 
102     void LockWithThreadState(JSThread* thread);
103 
Lock()104     void Lock()
105     {
106         return mtx_.Lock();
107     }
108 
Unlock()109     void Unlock()
110     {
111         return mtx_.Unlock();
112     }
113 
114 private:
115     Mutex mtx_;
116 };
117 
118 struct EnableCMCGCTrait {
119     using StringTableInterface = common::BaseStringTableInterface<common::BaseStringTableImpl>;
120 #ifndef GC_STW_STRINGTABLE
121     using HashTrieMapImpl = common::HashTrieMap<common::BaseStringTableMutex, common::ThreadHolder,
122                                                 common::TrieMapConfig::NeedSlotBarrier>;
123 #else
124     using HashTrieMapImpl = common::HashTrieMap<common::BaseStringTableMutex, common::ThreadHolder,
125                                             common::TrieMapConfig::NoSlotBarrier>;
126 #endif
127     using ThreadType = common::ThreadHolder;
128     static constexpr bool EnableCMCGC = true;
CreateHandleEnableCMCGCTrait129     static common::ReadOnlyHandle<BaseString> CreateHandle(ThreadType* holder, BaseString* string)
130     {
131         return JSHandle<EcmaString>(holder->GetJSThread(), EcmaString::FromBaseString(string));
132     }
133 };
134 
135 struct DisableCMCGCTrait {
136     struct DummyStringTableInterface {}; // placeholder for consistent type
137     using StringTableInterface = DummyStringTableInterface;
138     using HashTrieMapImpl = common::HashTrieMap<EcmaStringTableMutex, JSThread, common::TrieMapConfig::NoSlotBarrier>;
139     using ThreadType = JSThread;
140     static constexpr bool EnableCMCGC = false;
CreateHandleDisableCMCGCTrait141     static common::ReadOnlyHandle<BaseString> CreateHandle(ThreadType* holder, BaseString* string)
142     {
143         return JSHandle<EcmaString>(holder, EcmaString::FromBaseString(string));
144     }
145 };
146 
147 template <typename Traits>
148 class EcmaStringTableImpl final {
149 public:
150     using StringTableInterface = typename Traits::StringTableInterface;
151     using HashTrieMapImpl = typename Traits::HashTrieMapImpl;
152     using ThreadType = typename Traits::ThreadType;
153     // CMC constructor
154     template <typename T = Traits, std::enable_if_t<T::EnableCMCGC, int> = 0>
EcmaStringTableImpl(StringTableInterface * itf,HashTrieMapImpl & map)155     EcmaStringTableImpl(StringTableInterface* itf, HashTrieMapImpl& map)
156         : stringTable_(map), stringTableItf_(itf) {}
157 
158     // Non-CMC constructor
159     template <typename T = Traits, std::enable_if_t<!T::EnableCMCGC, int> = 0>
EcmaStringTableImpl()160     EcmaStringTableImpl() {}
161 
162     EcmaString *GetOrInternFlattenString(EcmaVM *vm, EcmaString *string);
163     EcmaString *GetOrInternFlattenStringNoGC(EcmaVM *vm, EcmaString *string);
164     EcmaString *GetOrInternStringFromCompressedSubString(EcmaVM *vm, const JSHandle<EcmaString> &string,
165                                                          uint32_t offset, uint32_t utf8Len);
166     EcmaString *GetOrInternString(EcmaVM *vm, EcmaString *string);
167 
168     template <typename LoaderCallback, typename EqualsCallback>
169     EcmaString *GetOrInternString(EcmaVM *vm, uint32_t hashcode, LoaderCallback loaderCallback,
170                                   EqualsCallback equalsCallback);
171     EcmaString *GetOrInternString(EcmaVM *vm, const JSHandle<EcmaString> &firstString,
172                                   const JSHandle<EcmaString> &secondString);
173     EcmaString *GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress,
174                                   MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
175     EcmaString *GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, MemSpaceType type);
176     EcmaString *GetOrInternString(EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress);
177     // This is ONLY for JIT Thread, since JIT could not create JSHandle so need to allocate String with holding
178     // lock_ --- need to support JSHandle
179     EcmaString *GetOrInternStringWithoutJSHandleForJit(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len,
180                                                        MemSpaceType type);
181     EcmaString *GetOrInternStringWithoutJSHandleForJit(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
182                                                        bool canBeCompress, MemSpaceType type);
183     EcmaString *TryGetInternString(JSThread *thread, const JSHandle<EcmaString> &string);
184     void SweepWeakRef(const WeakRootVisitor &visitor, uint32_t rootID);
185 
186     bool CheckStringTableValidity(JSThread *thread);
187 
188     NO_COPY_SEMANTIC(EcmaStringTableImpl);
189     NO_MOVE_SEMANTIC(EcmaStringTableImpl);
190 
191     /**
192      *
193      * These are some "incorrect" functions, which need to fix the call chain to be removed.
194      *
195      */
196     // This should only call in Debugger Signal, and need to fix and remove
197     EcmaString *GetOrInternStringThreadUnsafe(EcmaVM *vm, const JSHandle<EcmaString> firstString,
198                                               const JSHandle<EcmaString> secondString);
199     // This should only call in Debugger Signal, and need to fix and remove
200     EcmaString* GetOrInternStringThreadUnsafe(EcmaVM* vm, const uint8_t* utf8Data, uint32_t utf8Len,
201                                               bool canBeCompress);
202 
203 private:
204     static ThreadType* GetThreadHolder(JSThread* thread);
205 
206     std::conditional_t<Traits::EnableCMCGC, HashTrieMapImpl&, HashTrieMapImpl> stringTable_;
207     StringTableInterface* stringTableItf_ = nullptr;
208 };
209 
210 
211 class EcmaStringTable final {
212 public:
enableCMCGC_(enableCMC)213     EcmaStringTable(bool enableCMC, void* itf = nullptr, void* map = nullptr): enableCMCGC_(enableCMC)
214     {
215         if (enableCMC) {
216             impl_.emplace<EcmaStringTableImpl<EnableCMCGCTrait>>(
217                 static_cast<EnableCMCGCTrait::StringTableInterface*>(itf),
218                 *static_cast<EnableCMCGCTrait::HashTrieMapImpl*>(map));
219         } else {
220             impl_.emplace<EcmaStringTableImpl<DisableCMCGCTrait>>();
221             cleaner_ = new EcmaStringTableCleaner(this);
222         }
223     }
224 
~EcmaStringTable()225     ~EcmaStringTable()
226     {
227         if (cleaner_ != nullptr) {
228             delete cleaner_;
229             cleaner_ = nullptr;
230         }
231     }
232 
233     EcmaString *GetOrInternFlattenString(EcmaVM *vm, EcmaString *string);
234     EcmaString *GetOrInternFlattenStringNoGC(EcmaVM *vm, EcmaString *string);
235     EcmaString *GetOrInternStringFromCompressedSubString(EcmaVM *vm, const JSHandle<EcmaString> &string,
236                                                          uint32_t offset, uint32_t utf8Len);
237     EcmaString *GetOrInternString(EcmaVM *vm, EcmaString *string);
238 
239     template <typename LoaderCallback, typename EqualsCallback>
240     EcmaString *GetOrInternString(EcmaVM *vm, uint32_t hashcode, LoaderCallback loaderCallback,
241                                   EqualsCallback equalsCallback);
242     EcmaString *GetOrInternString(EcmaVM *vm, const JSHandle<EcmaString> &firstString,
243                                   const JSHandle<EcmaString> &secondString);
244     EcmaString *GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress,
245                                   MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
246     EcmaString *GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, MemSpaceType type);
247     EcmaString *GetOrInternString(EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress);
248     // This is ONLY for JIT Thread, since JIT could not create JSHandle so need to allocate String with holding
249     // lock_ --- need to support JSHandle
250     EcmaString *GetOrInternStringWithoutJSHandleForJit(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len,
251                                                        MemSpaceType type);
252     EcmaString *GetOrInternStringWithoutJSHandleForJit(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
253                                                        bool canBeCompress, MemSpaceType type);
254     EcmaString *TryGetInternString(JSThread *thread, const JSHandle<EcmaString> &string);
255 
256     void SweepWeakRef(const WeakRootVisitor &visitor, uint32_t index);
257 
258     bool CheckStringTableValidity(JSThread *thread);
259 
GetCleaner()260     EcmaStringTableCleaner *GetCleaner()
261     {
262         ASSERT(!enableCMCGC_ && "EcmaStringTableCleaner should not be used when cmcgc enabled");
263         return cleaner_;
264     }
265 
266 private:
267     NO_COPY_SEMANTIC(EcmaStringTable);
268     NO_MOVE_SEMANTIC(EcmaStringTable);
269 
270     /**
271      *
272      * These are some "incorrect" functions, which need to fix the call chain to be removed.
273      *
274      */
275     // This should only call in Debugger Signal, and need to fix and remove
276     EcmaString *GetOrInternStringThreadUnsafe(EcmaVM *vm, const JSHandle<EcmaString> firstString,
277                                               const JSHandle<EcmaString> secondString);
278     // This should only call in Debugger Signal, and need to fix and remove
279     EcmaString* GetOrInternStringThreadUnsafe(EcmaVM* vm, const uint8_t* utf8Data, uint32_t utf8Len,
280                                               bool canBeCompress);
281 
282     template <typename Fn>
decltype(auto)283     decltype(auto) visitImpl(Fn&& fn)
284     {
285         return std::visit(std::forward<Fn>(fn), impl_);
286     }
287 
288     std::variant<
289         EcmaStringTableImpl<DisableCMCGCTrait>,
290         EcmaStringTableImpl<EnableCMCGCTrait>
291     > impl_;
292 
293     EcmaStringTableCleaner *cleaner_ = nullptr;
294     bool enableCMCGC_ = false;
295     friend class SnapshotProcessor;
296     friend class BaseDeserializer;
297 };
298 
299 #else
300 class EcmaString;
301 class EcmaVM;
302 class JSPandaFile;
303 class JSThread;
304 
305 class EcmaStringTable;
306 
307 class EcmaStringTableCleaner {
308 public:
309     using IteratorPtr = std::shared_ptr<std::atomic<uint32_t>>;
310     EcmaStringTableCleaner(EcmaStringTable* stringTable) : stringTable_(stringTable) {}
311     ~EcmaStringTableCleaner() { stringTable_ = nullptr; }
312 
313     void PostSweepWeakRefTask(const WeakRootVisitor &visitor);
314     void JoinAndWaitSweepWeakRefTask(const WeakRootVisitor &visitor);
315 
316 private:
317     NO_COPY_SEMANTIC(EcmaStringTableCleaner);
318     NO_MOVE_SEMANTIC(EcmaStringTableCleaner);
319 
320     static void ProcessSweepWeakRef(IteratorPtr& iter, EcmaStringTableCleaner *cleaner, const WeakRootVisitor &visitor);
321     void StartSweepWeakRefTask();
322     void WaitSweepWeakRefTask();
323     void SignalSweepWeakRefTask();
324 
325     static inline uint32_t GetNextTableId(IteratorPtr& iter)
326     {
327         return iter->fetch_add(1U, std::memory_order_relaxed);
328     }
329 
330     static inline bool ReduceCountAndCheckFinish(EcmaStringTableCleaner* cleaner)
331     {
332         return (cleaner->PendingTaskCount_.fetch_sub(1U, std::memory_order_relaxed) == 1U);
333     }
334 
335     class SweepWeakRefTask : public common::Task {
336     public:
337         SweepWeakRefTask(IteratorPtr iter, EcmaStringTableCleaner* cleaner, const WeakRootVisitor& visitor)
338             : common::Task(0), iter_(iter), cleaner_(cleaner), visitor_(visitor) {}
339         ~SweepWeakRefTask() = default;
340 
341         bool Run(uint32_t threadIndex) override;
342 
343         NO_COPY_SEMANTIC(SweepWeakRefTask);
344         NO_MOVE_SEMANTIC(SweepWeakRefTask);
345 
346     private:
347         IteratorPtr iter_;
348         EcmaStringTableCleaner* cleaner_;
349         const WeakRootVisitor& visitor_;
350     };
351 
352     IteratorPtr iter_;
353     EcmaStringTable* stringTable_;
354     std::atomic<uint32_t> PendingTaskCount_ {0U};
355     Mutex sweepWeakRefMutex_;
356     bool sweepWeakRefFinished_ {true};
357     ConditionVariable sweepWeakRefCV_;
358 };
359 
360 class EcmaStringTable {
361 public:
362     EcmaStringTable() : cleaner_(new EcmaStringTableCleaner(this))
363     {
364         stringTable_.fill(Segment());
365     }
366     virtual ~EcmaStringTable()
367     {
368         if (cleaner_ != nullptr) {
369             delete cleaner_;
370             cleaner_ = nullptr;
371         }
372         for (auto &seg : stringTable_) {
373             seg.table_.clear();
374         }
375     }
376 
377     static inline uint32_t GetTableId(uint32_t hashcode)
378     {
379         return hashcode & SEGMENT_MASK;
380     }
381     EcmaString *GetOrInternFlattenString(EcmaVM *vm, EcmaString *string);
382     EcmaString *GetOrInternFlattenStringNoGC(EcmaVM *vm, EcmaString *string);
383     EcmaString *GetOrInternStringFromCompressedSubString(EcmaVM *vm, const JSHandle<EcmaString> &string,
384         uint32_t offset, uint32_t utf8Len);
385     EcmaString *GetOrInternString(EcmaVM *vm, EcmaString *string);
386     EcmaString *GetOrInternString(EcmaVM *vm,
387                                   const JSHandle<EcmaString> &firstString, const JSHandle<EcmaString> &secondString);
388     EcmaString *GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress,
389                                   MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
390     EcmaString *GetOrInternString(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, MemSpaceType type);
391     EcmaString *GetOrInternString(EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress);
392     // This is ONLY for JIT Thread, since JIT could not create JSHandle so need to allocate String with holding
393     // lock_ --- need to support JSHandle
394     EcmaString *GetOrInternStringWithoutJSHandleForJit(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len,
395                                                        MemSpaceType type);
396     EcmaString *GetOrInternStringWithoutJSHandleForJit(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
397                                                        bool canBeCompress, MemSpaceType type);
398     EcmaString *TryGetInternString(JSThread *thread, const JSHandle<EcmaString> &string);
399     EcmaString *InsertStringToTable(EcmaVM *vm, const JSHandle<EcmaString> &strHandle);
400 
401     void SweepWeakRef(const WeakRootVisitor &visitor);
402     void SweepWeakRef(const WeakRootVisitor &visitor, uint32_t tableId);
403 
404     bool CheckStringTableValidity(JSThread *thread);
405     void RelocateConstantData(EcmaVM *vm, const JSPandaFile *jsPandaFile);
406     void IterWeakRoot(WeakVisitor &visitor);
407 
408     EcmaStringTableCleaner* GetCleaner()
409     {
410         return cleaner_;
411     }
412     static constexpr uint32_t SEGMENT_COUNT = 16U; // 16: 2^4
413     static constexpr uint32_t SEGMENT_MASK = SEGMENT_COUNT - 1U;
414 private:
415     NO_COPY_SEMANTIC(EcmaStringTable);
416     NO_MOVE_SEMANTIC(EcmaStringTable);
417 
418     EcmaString *GetStringThreadUnsafe(JSThread *thread, EcmaString *string, uint32_t hashcode) const;
419     void InternStringThreadUnsafe(EcmaString *string, uint32_t hashcode);
420     EcmaString *AtomicGetOrInternStringImpl(JSThread *thread, const JSHandle<EcmaString> string, uint32_t hashcode);
421     EcmaString *AtomicGetOrInternStringImplNoGC(JSThread *thread, EcmaString *string, uint32_t hashcode);
422 
423     EcmaString *GetStringFromCompressedSubString(JSThread *thread, const JSHandle<EcmaString> string, uint32_t offset,
424                                                  uint32_t utf8Len, uint32_t hashcode);
425     EcmaString *GetString(JSThread *thread, const JSHandle<EcmaString> string, uint32_t hashcode);
426     EcmaString *GetString(JSThread *thread, const JSHandle<EcmaString> firstString,
427                           const JSHandle<EcmaString> secondString, uint32_t hashcode);
428     // utf8Data MUST NOT on JSHeap
429     EcmaString *GetString(JSThread *thread, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress,
430                           uint32_t hashcode);
431     // utf16Data MUST NOT on JSHeap
432     EcmaString *GetString(JSThread *thread, const uint16_t *utf16Data, uint32_t utf16Len, uint32_t hashcode);
433 
434     // This used only for SnapShot.
435     void InsertStringToTableWithHashThreadUnsafe(JSThread *thread, EcmaString *string, uint32_t hashcode);
436     /**
437      *
438      * These are some "incorrect" functions, which need to fix the call chain to be removed.
439      *
440     */
441     // This should only call in Debugger Signal, and need to fix and remove
442     EcmaString *GetOrInternStringThreadUnsafe(EcmaVM *vm,
443                                               const JSHandle<EcmaString> firstString,
444                                               const JSHandle<EcmaString> secondString);
445     // This should only call in Debugger Signal, and need to fix and remove
446     EcmaString *GetOrInternStringThreadUnsafe(EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
447                                               bool canBeCompress);
448     // This should only call in Debugger Signal, and need to fix and remove
449     EcmaString *GetStringThreadUnsafe(JSThread *thread, const JSHandle<EcmaString> firstString,
450                                       const JSHandle<EcmaString> secondString, uint32_t hashcode) const;
451     // This should only call in Debugger Signal or from JIT, and need to fix and remove
452     EcmaString *GetStringThreadUnsafe(JSThread *thread, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress,
453                                       uint32_t hashcode) const;
454     // This should only call in JIT Thread, and need to fix and remove
455     EcmaString *GetStringThreadUnsafe(JSThread *thread, const uint16_t *utf16Data, uint32_t utf16Len,
456                                       uint32_t hashcode) const;
457 
458     struct Segment {
459         CUnorderedMultiMap<uint32_t, EcmaString *> table_;
460         Mutex mutex_;
461     };
462 
463     std::array<Segment, SEGMENT_COUNT> stringTable_;
464     EcmaStringTableCleaner* cleaner_;
465 
466     friend class SnapshotProcessor;
467     friend class BaseDeserializer;
468 };
469 #endif
470 
471 class SingleCharTable : public TaggedArray {
472 public:
Cast(TaggedObject * object)473     static SingleCharTable *Cast(TaggedObject *object)
474     {
475         return reinterpret_cast<SingleCharTable*>(object);
476     }
477     static JSTaggedValue CreateSingleCharTable(JSThread *thread);
GetStringFromSingleCharTable(JSThread * thread,int32_t ch)478     JSTaggedValue GetStringFromSingleCharTable(JSThread *thread, int32_t ch)
479     {
480         return Get(thread, ch);
481     }
482 private:
483     SingleCharTable() = default;
484     ~SingleCharTable() = default;
485     NO_COPY_SEMANTIC(SingleCharTable);
486     NO_MOVE_SEMANTIC(SingleCharTable);
487     static constexpr uint32_t MAX_ONEBYTE_CHARCODE = 128; // 0X00-0X7F
488 };
489 }  // namespace panda::ecmascript
490 
491 #endif  // ECMASCRIPT_STRING_TABLE_H
492