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