• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_H
17 #define ECMASCRIPT_STRING_H
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <cstring>
22 
23 #include "common_components/base/utf_helper.h"
24 #include "common_interfaces/objects/base_string.h"
25 #include "common_interfaces/objects/string/line_string.h"
26 #include "common_interfaces/objects/string/sliced_string.h"
27 #include "common_interfaces/objects/string/tree_string.h"
28 #include "common_interfaces/objects/string/base_string-inl1.h"
29 #include "ecmascript/common.h"
30 #include "ecmascript/ecma_macros.h"
31 #include "ecmascript/js_hclass.h"
32 #include "ecmascript/js_tagged_value.h"
33 #include "ecmascript/mem/barriers.h"
34 #include "ecmascript/mem/space.h"
35 #include "ecmascript/mem/tagged_object.h"
36 #include "libpandabase/macros.h"
37 #include "securec.h"
38 #include "unicode/locid.h"
39 
40 namespace panda {
41 namespace test {
42     class EcmaStringEqualsTest;
43     class EcmaStringHashTest;
44 }
45 namespace ecmascript {
46 template<typename T>
47 class JSHandle;
48 class JSPandaFile;
49 class EcmaVM;
50 class LineEcmaString;
51 class TreeEcmaString;
52 class SlicedEcmaString;
53 class FlatStringInfo;
54 
55 using ::common::BaseString;
56 using ::common::LineString;
57 using ::common::SlicedString;
58 using ::common::TreeString;
59 
60 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
61 #define ECMA_STRING_CHECK_LENGTH_AND_TRHOW(vm, length)                                        \
62     if ((length) >= BaseString::MAX_STRING_LENGTH) {                                                      \
63         THROW_RANGE_ERROR_AND_RETURN((vm)->GetJSThread(), "Invalid string length", nullptr);  \
64     }
65 
66 class EcmaString : public TaggedObject {
67 private:
68     using TaggedObject::SIZE;
69 
70 public:
71     CAST_CHECK(EcmaString, IsString);
72 
ToBaseString()73     BaseString* ToBaseString()
74     {
75         return BaseString::Cast(this);
76     }
77 
ToBaseString()78     const BaseString* ToBaseString() const
79     {
80         return BaseString::ConstCast(this);
81     }
82 
FromBaseString(BaseString * str)83     static EcmaString* FromBaseString(BaseString* str)
84     {
85         return reinterpret_cast<EcmaString*>(str);
86     }
87 
88     enum TrimMode : uint8_t {
89         TRIM,
90         TRIM_START,
91         TRIM_END,
92     };
93 
SetMixHashcode(uint32_t mixHashCode)94     void SetMixHashcode(uint32_t mixHashCode)
95     {
96         ToBaseString()->SetMixHashcode(mixHashCode);
97     }
98 
99 private:
100 
101     friend class EcmaStringAccessor;
102     friend class LineEcmaString;
103     friend class TreeEcmaString;
104     friend class SlicedEcmaString;
105     friend class FlatStringInfo;
106     friend class NameDictionary;
107     friend class panda::test::EcmaStringEqualsTest;
108     friend class panda::test::EcmaStringHashTest;
109 
110     static constexpr size_t ALIGNMENT_8_BYTES = 8;
111     static EcmaString *CreateEmptyString(const EcmaVM *vm);
112     static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
113         bool canBeCompress, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
114     static EcmaString *CreateFromUtf8CompressedSubString(const EcmaVM *vm, const JSHandle<EcmaString> &string,
115         uint32_t offset, uint32_t utf8Len, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
116     static EcmaString *CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len,
117         MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
118     static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len,
119         bool canBeCompress, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
120     static SlicedEcmaString* CreateSlicedString(const EcmaVM* vm, JSHandle<EcmaString> parent,
121                                                 MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
122     static EcmaString *CreateLineString(const EcmaVM *vm, size_t length, bool compressed);
123     static EcmaString *CreateLineStringNoGC(const EcmaVM *vm, size_t length, bool compressed);
124     static EcmaString *AllocLineString(const EcmaVM* vm, size_t size, MemSpaceType type);
125     static EcmaString *CreateLineStringWithSpaceType(const EcmaVM *vm,
126                                                      size_t length, bool compressed, MemSpaceType type);
127     static EcmaString *CreateTreeString(const EcmaVM *vm,
128         const JSHandle<EcmaString> &left, const JSHandle<EcmaString> &right, uint32_t length, bool compressed);
129     static EcmaString *Concat(const EcmaVM *vm, const JSHandle<EcmaString> &left,
130         const JSHandle<EcmaString> &right, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
131     template<typename T1, typename T2>
132     static uint32_t CalculateDataConcatHashCode(const T1 *dataFirst, size_t sizeFirst,
133                                                 const T2 *dataSecond, size_t sizeSecond);
134     static uint32_t CalculateConcatHashCode(const JSThread *thread,
135                                             const JSHandle<EcmaString> &firstString,
136                                             const JSHandle<EcmaString> &secondString);
137 
138     bool HashIntegerString(uint32_t length, uint32_t *hash, uint32_t hashSeed) const;
139 
IsInteger(const JSThread * thread)140     inline bool IsInteger(const JSThread* thread)
141     {
142         auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* {
143             return Barriers::GetTaggedObject(thread, obj, offset);
144         };
145         return ToBaseString()->IsInteger(std::move(readBarrier));
146     }
147 
148     static EcmaString *CopyStringToOldSpace(const EcmaVM *vm, const JSHandle<EcmaString> &original,
149                                             uint32_t length, bool compressed);
150     static EcmaString *FastSubString(const EcmaVM *vm,
151         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
152     static bool SubStringIsUtf8(const EcmaVM *vm,
153         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
154     static EcmaString *GetSlicedString(const EcmaVM *vm,
155         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
156     static EcmaString *GetSubString(const EcmaVM *vm,
157         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
158     // require src is LineString
159     // not change src data structure
160     static inline EcmaString *FastSubUtf8String(const EcmaVM *vm,
161         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
162     // require src is LineString
163     // not change src data structure
164     static inline EcmaString *FastSubUtf16String(const EcmaVM *vm,
165         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
166     inline void TrimLineString(uint32_t newLength);
167 
IsUtf8()168     inline bool IsUtf8() const
169     {
170         return ToBaseString()->IsUtf8();
171     }
172 
IsUtf16()173     inline bool IsUtf16() const
174     {
175         return ToBaseString()->IsUtf16();
176     }
177 
178     inline const uint8_t *GetDataUtf8() const;
179     inline const uint16_t *GetDataUtf16() const;
180 
181     inline Span<const uint8_t> FastToUtf8Span() const;
182 
183     // require is LineString
184     inline uint8_t *GetDataUtf8Writable();
185     inline uint16_t *GetDataUtf16Writable();
186 
GetLength()187     inline uint32_t GetLength() const
188     {
189         return ToBaseString()->GetLength();
190     }
191 
192     inline void InitLengthAndFlags(uint32_t length, bool compressed = false, bool isIntern = false)
193     {
194         ToBaseString()->InitLengthAndFlags(length, compressed, isIntern);
195     }
196 
197     inline size_t GetUtf8Length(const JSThread *thread, bool modify = true, bool isGetBufferSize = false) const;
198 
SetIsInternString()199     inline void SetIsInternString()
200     {
201         ToBaseString()->SetIsInternString();
202     }
203 
IsInternString()204     inline bool IsInternString() const
205     {
206         return ToBaseString()->IsInternString();
207     }
208 
ClearInternStringFlag()209     inline void ClearInternStringFlag()
210     {
211         ToBaseString()->ClearInternStringFlag();
212     }
213 
TryGetHashCode(uint32_t * hash)214     inline bool TryGetHashCode(uint32_t *hash)
215     {
216         return ToBaseString()->TryGetHashCode(hash);
217     }
218 
219     // not change this data structure.
220     // if string is not flat, this func has low efficiency.
GetHashcode(const JSThread * thread)221     uint32_t PUBLIC_API GetHashcode(const JSThread *thread)
222     {
223         auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* {
224             return Barriers::GetTaggedObject(thread, obj, offset);
225         };
226         return ToBaseString()->GetHashcode(std::move(readBarrier));
227     }
228 
229     // not change this data structure.
230     // if string is not flat, this func has low efficiency.
ComputeHashcode(const JSThread * thread)231     uint32_t PUBLIC_API ComputeHashcode(const JSThread *thread) const
232     {
233         auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* {
234             return Barriers::GetTaggedObject(thread, obj, offset);
235         };
236         return ToBaseString()->ComputeHashcode(std::move(readBarrier));
237     }
238 
239     static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress);
240     static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length);
241 
242     template<bool verify = true>
243     uint16_t At(const JSThread *thread, int32_t index) const;
244 
245     // require is LineString
246     void WriteData(uint32_t index, uint16_t src);
247 
248     // can change left and right data structure
249     static int32_t Compare(const EcmaVM *vm, const JSHandle<EcmaString> &left, const JSHandle<EcmaString> &right);
250 
251     static bool IsSubStringAt(const EcmaVM *vm, const JSHandle<EcmaString>& left,
252         const JSHandle<EcmaString>& right, uint32_t offset);
253 
254     // Check that two spans are equal. Should have the same length.
255     /* static */
256     template<typename T, typename T1>
StringsAreEquals(Span<const T> & str1,Span<const T1> & str2)257     static bool StringsAreEquals(Span<const T> &str1, Span<const T1> &str2)
258     {
259         return BaseString::StringsAreEquals(str1, str2);
260     }
261 
262     // Compares string1 + string2 by bytes, It doesn't check canonical unicode equivalence.
263     bool EqualToSplicedString(const JSThread *thread, const EcmaString *str1, const EcmaString *str2);
264     // Compares strings by bytes, It doesn't check canonical unicode equivalence.
265     static PUBLIC_API bool StringsAreEqual(const EcmaVM *vm, const JSHandle<EcmaString> &str1,
266         const JSHandle<EcmaString> &str2);
267     // Compares strings by bytes, It doesn't check canonical unicode equivalence.
268     template <RBMode mode = RBMode::DEFAULT_RB>
StringsAreEqual(const JSThread * thread,EcmaString * str1,EcmaString * str2)269     static PUBLIC_API bool StringsAreEqual(const JSThread *thread, EcmaString *str1, EcmaString *str2)
270     {
271         auto readBarrier = [thread](const void *obj, size_t offset) -> TaggedObject * {
272             return Barriers::GetTaggedObject<mode>(thread, obj, offset);
273         };
274         return BaseString::StringsAreEqual(std::move(readBarrier), str1->ToBaseString(), str2->ToBaseString());
275     }
276 
277     // Two strings have the same type of utf encoding format.
278     static bool StringsAreEqualDiffUtfEncoding(const JSThread *thread, EcmaString *str1, EcmaString *str2);
279     static bool StringsAreEqualDiffUtfEncoding(const FlatStringInfo &str1, const FlatStringInfo &str2);
280     // Compares strings by bytes, It doesn't check canonical unicode equivalence.
281     // not change str1 data structure.
282     // if str1 is not flat, this func has low efficiency.
283     static bool StringIsEqualUint8Data(const JSThread *thread,
284                                        const EcmaString *str1, const uint8_t *dataAddr, uint32_t dataLen,
285                                        bool canBeCompress);
286     // Compares strings by bytes, It doesn't check canonical unicode equivalence.
287     // not change str1 data structure.
288     // if str1 is not flat, this func has low efficiency.
289     static bool StringsAreEqualUtf16(const JSThread *thread,
290                                      const EcmaString *str1, const uint16_t *utf16Data, uint32_t utf16Len);
291 
292     // can change receiver and search data structure
293     static int32_t IndexOf(const EcmaVM *vm,
294         const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0);
295 
296     // can change receiver and search data structure
297     static int32_t LastIndexOf(const EcmaVM *vm,
298         const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0);
299 
300     // It allows user to copy into buffer even if maxLength < length
301     size_t WriteUtf8(const JSThread *thread, uint8_t *buf, size_t maxLength, bool isWriteBuffer = false) const;
302 
303     // It allows user to copy into buffer even if maxLength < length
304     size_t WriteUtf16(const JSThread *thread, uint16_t *buf, uint32_t targetLength, uint32_t bufLength) const;
305 
306     size_t WriteOneByte(const JSThread *thread, uint8_t *buf, size_t maxLength) const;
307 
308     uint32_t CopyDataUtf16(const JSThread *thread, uint16_t *buf, uint32_t maxLength) const;
309 
310     std::u16string ToU16String(const JSThread *thread, uint32_t len = 0);
311 
312     Span<const uint8_t> ToUtf8Span(const JSThread *thread, CVector<uint8_t> &buf, bool modify = true,
313                                    bool cesu8 = false);
314 
315     Span<const uint8_t> DebuggerToUtf8Span(const JSThread *thread, CVector<uint8_t> &buf, bool modify = true);
316 
ToUtf16Span(const JSThread * thread,CVector<uint16_t> & buf)317     Span<const uint16_t> ToUtf16Span(const JSThread *thread, CVector<uint16_t> &buf)
318     {
319         Span<const uint16_t> str;
320         uint32_t strLen = GetLength();
321         if (UNLIKELY(IsUtf16())) {
322             const uint16_t *data = EcmaString::GetUtf16DataFlat(thread, this, buf);
323             str = Span<const uint16_t>(data, strLen);
324         } else {
325             CVector<uint8_t> tmpBuf;
326             const uint8_t *data = EcmaString::GetUtf8DataFlat(thread, this, tmpBuf);
327             buf.reserve(strLen);
328             auto utf16Len = common::utf_helper::ConvertRegionUtf8ToUtf16(data, buf.data(), strLen, strLen);
329 #if !defined(NDEBUG)
330             auto calculatedLen = common::utf_helper::Utf8ToUtf16Size(data, strLen);
331             ASSERT_PRINT(utf16Len == calculatedLen, "Bad utf8 to utf16 conversion!");
332 #endif
333             str = Span<const uint16_t>(buf.data(), utf16Len);
334         }
335         return str;
336     }
337 
338     template <RBMode mode = RBMode::DEFAULT_RB>
WriteData(const JSThread * thread,EcmaString * src,uint32_t start,uint32_t destSize,uint32_t length)339     void WriteData(const JSThread *thread, EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length)
340     {
341         auto readBarrier = [thread](const void *obj, size_t offset) -> TaggedObject * {
342             return Barriers::GetTaggedObject<mode>(thread, obj, offset);
343         };
344         ToBaseString()->WriteData(std::move(readBarrier), src->ToBaseString(), start, destSize, length);
345     }
346 
347     static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len);
348     static bool CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len);
349     static bool CanBeCompressed(const EcmaString *string);
350 
351     bool PUBLIC_API ToElementIndex(const JSThread *thread, uint32_t *index);
352 
353     bool ToInt(const JSThread *thread, int32_t *index, bool *negative);
354 
355     bool ToUInt64FromLoopStart(uint64_t *index, uint32_t loopStart, const uint8_t *data);
356 
357     bool PUBLIC_API ToTypedArrayIndex(const JSThread *thread, uint32_t *index);
358 
359     template<typename T>
360     static EcmaString *TrimBody(const JSThread *thread, const JSHandle<EcmaString> &src, Span<T> &data, TrimMode mode);
361 
362     static EcmaString *Trim(const JSThread *thread, const JSHandle<EcmaString> &src, TrimMode mode = TrimMode::TRIM);
363 
364     // memory block copy
365     template<typename T>
366     static bool MemCopyChars(Span<T> &dst, size_t dstMax, Span<const T> &src, size_t count);
367 
368     template<typename T1, typename T2>
369     static int32_t IndexOf(Span<const T1> &lhsSp, Span<const T2> &rhsSp, int32_t pos, int32_t max);
370 
371     template<typename T1, typename T2>
372     static int32_t LastIndexOf(Span<const T1> &lhsSp, Span<const T2> &rhsSp, int32_t pos);
373 
374     bool IsFlat(const JSThread *thread) const;
375 
IsLineString()376     bool IsLineString() const
377     {
378         return ToBaseString()->IsLineString();
379     }
IsSlicedString()380     bool IsSlicedString() const
381     {
382         return ToBaseString()->IsSlicedString();
383     }
IsTreeString()384     bool IsTreeString() const
385     {
386         return ToBaseString()->IsTreeString();
387     }
388 
NotTreeString()389     bool NotTreeString() const
390     {
391         return !IsTreeString();
392     }
393 
394     template <typename Char>
395     static void WriteToFlat(const JSThread *thread, EcmaString *src, Char *buf, uint32_t maxLength);
396 
397     template <typename Char>
398     static void WriteToFlatWithPos(const JSThread *thread, EcmaString *src, Char *buf, uint32_t length, uint32_t pos);
399 
400     static const uint8_t *PUBLIC_API GetUtf8DataFlat(const JSThread *thread, const EcmaString *src,
401                                                      CVector<uint8_t> &buf);
402 
403     static const uint8_t *PUBLIC_API GetNonTreeUtf8Data(const JSThread *thread, const EcmaString *src);
404 
405     static const uint16_t *PUBLIC_API GetUtf16DataFlat(const JSThread *thread, const EcmaString *src,
406                                                        CVector<uint16_t> &buf);
407 
408     static const uint16_t *PUBLIC_API GetNonTreeUtf16Data(const JSThread *thread, const EcmaString *src);
409 
410     // string must be not flat
411     static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<EcmaString> &string, MemSpaceType type);
412 
413     PUBLIC_API static EcmaString *Flatten(const EcmaVM *vm, const JSHandle<EcmaString> &string,
414                                MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
415 
416     static FlatStringInfo FlattenAllString(const EcmaVM *vm, const JSHandle<EcmaString> &string,
417                                             MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE);
418 
419     static EcmaString *FlattenNoGCForSnapshot(const EcmaVM *vm, EcmaString *string);
420 
421     static EcmaString *ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src);
422 
423     static EcmaString *ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src);
424 
425     static EcmaString *ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale);
426 
427     static EcmaString *ToLocaleUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale);
428 
429     static EcmaString *TryToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src);
430 
431     static EcmaString *TryToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src);
432 
433     static EcmaString *ConvertUtf8ToLowerOrUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src,
434                                                  bool toLower, uint32_t startIndex = 0);
435 };
436 
437 // The LineEcmaString abstract class captures sequential string values, only LineEcmaString can store chars data
438 class LineEcmaString : public EcmaString {
439 private:
440     using TaggedObject::SIZE;
441 public:
ToLineString()442     LineString* ToLineString()
443     {
444         return LineString::Cast(this);
445     }
446 
ToLineString()447     const LineString* ToLineString() const
448     {
449         return LineString::ConstCast(this);
450     }
451 
452     CAST_CHECK(LineEcmaString, IsLineString);
453 
454     DECL_VISIT_ARRAY(LineString::DATA_OFFSET, 0, GetPointerLength());
455 
Cast(EcmaString * str)456     static LineEcmaString* Cast(EcmaString* str)
457     {
458         return static_cast<LineEcmaString *>(str);
459     }
460 
Cast(const EcmaString * str)461     static LineEcmaString *Cast(const EcmaString *str)
462     {
463         return LineEcmaString::Cast(const_cast<EcmaString *>(str));
464     }
465 
ComputeSizeUtf8(uint32_t utf8Len)466     static size_t ComputeSizeUtf8(uint32_t utf8Len)
467     {
468         return LineString::ComputeSizeUtf8(utf8Len);
469     }
470 
ComputeSizeUtf16(uint32_t utf16Len)471     static size_t ComputeSizeUtf16(uint32_t utf16Len)
472     {
473         return LineString::ComputeSizeUtf16(utf16Len);
474     }
475 
ObjectSize(EcmaString * str)476     static size_t ObjectSize(EcmaString *str)
477     {
478         return LineString::ObjectSize(str->ToBaseString());
479     }
480 
DataSize(EcmaString * str)481     static size_t DataSize(EcmaString *str)
482     {
483         return LineString::DataSize(str->ToBaseString());
484     }
485 
GetPointerLength()486     size_t GetPointerLength()
487     {
488         size_t byteSize = DataSize(this);
489         return AlignUp(byteSize, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) / sizeof(JSTaggedType);
490     }
491 
492     template<bool verify = true>
Get(int32_t index)493     uint16_t Get(int32_t index) const
494     {
495         return ToLineString()->Get<verify>(index);
496     }
497 
Set(uint32_t index,uint16_t src)498     void Set(uint32_t index, uint16_t src)
499     {
500         return ToLineString()->Set(index, src);
501     }
502 };
503 // static_assert((LineString::DATA_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0);
504 
505 // The substrings of another string use SlicedString to describe.
506 class SlicedEcmaString : public EcmaString {
507 private:
508     using TaggedObject::SIZE;
509 public:
510     DECL_VISIT_OBJECT(SlicedString::PARENT_OFFSET, SlicedString::STARTINDEX_AND_FLAGS_OFFSET);
511 
512     CAST_CHECK(SlicedEcmaString, IsSlicedString);
513 
ToSlicedString()514     SlicedString* ToSlicedString()
515     {
516         return SlicedString::Cast(this);
517     }
518 
ToSlicedString()519     const SlicedString* ToSlicedString() const
520     {
521         return SlicedString::ConstCast(this);
522     }
523 
FromBaseString(SlicedString * str)524     static SlicedEcmaString* FromBaseString(SlicedString* str)
525     {
526         return reinterpret_cast<SlicedEcmaString*>(str);
527     }
528 
GetStartIndex()529     uint32_t GetStartIndex() const
530     {
531         return ToSlicedString()->GetStartIndex();
532     }
533 
SetStartIndex(uint32_t startIndex)534     void SetStartIndex(uint32_t startIndex)
535     {
536         ToSlicedString()->SetStartIndex(startIndex);
537     }
538 
GetHasBackingStore()539     bool GetHasBackingStore() const
540     {
541         return ToSlicedString()->GetHasBackingStore();
542     }
543 
SetHasBackingStore(bool hasBackingStore)544     void SetHasBackingStore(bool hasBackingStore)
545     {
546         return ToSlicedString()->SetHasBackingStore(hasBackingStore);
547     }
548 
GetParent(const JSThread * thread)549     JSTaggedValue GetParent(const JSThread* thread) const
550     {
551         auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* {
552             return Barriers::GetTaggedObject(thread, obj, offset);
553         };
554         return JSTaggedValue(ToSlicedString()->GetParent<TaggedObject*>(std::move(readBarrier)));
555     }
556 
557     template <typename T>
558     void SetParent(const JSThread* thread, JSHandle<T> value, BarrierMode mode = WRITE_BARRIER)
559     {
560         auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) {
561             if (mode == WRITE_BARRIER) {
562                 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str));
563             } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); }
564         };
565         ToSlicedString()->SetParent(std::move(writeBarrier), value.GetTaggedValue().GetTaggedObject());
566     }
567 
568     void SetParent(const JSThread* thread, JSTaggedValue value, BarrierMode mode = WRITE_BARRIER)
569     {
570         auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) {
571             if (mode == WRITE_BARRIER) {
572                 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str));
573             } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); }
574         };
575         ToSlicedString()->SetParent(std::move(writeBarrier), value.GetTaggedObject());
576     };
577 private:
578     friend class EcmaString;
Cast(EcmaString * str)579     static SlicedEcmaString *Cast(EcmaString *str)
580     {
581         return static_cast<SlicedEcmaString *>(str);
582     }
583 
Cast(const EcmaString * str)584     static SlicedEcmaString *Cast(const EcmaString *str)
585     {
586         return SlicedEcmaString::Cast(const_cast<EcmaString *>(str));
587     }
588 
ObjectSize()589     static size_t ObjectSize()
590     {
591         return SlicedString::SIZE;
592     }
593 
594     // Minimum length for a sliced string
595     template<bool verify = true>
Get(const JSThread * thread,int32_t index)596     uint16_t Get(const JSThread *thread, int32_t index) const
597     {
598         auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* {
599             return Barriers::GetTaggedObject(thread, obj, offset);
600         };
601         return ToSlicedString()->Get<verify>(std::move(readBarrier), index);
602     }
603 };
604 
605 class TreeEcmaString : public EcmaString {
606 private:
607     using TaggedObject::SIZE;
608 public:
609     DECL_VISIT_OBJECT(TreeString::FIRST_OFFSET, TreeString::SIZE);
610 
611     CAST_CHECK(TreeEcmaString, IsTreeString);
612 
Cast(EcmaString * str)613     static TreeEcmaString* Cast(EcmaString* str)
614     {
615         return static_cast<TreeEcmaString*>(str);
616     }
617 
Cast(const EcmaString * str)618     static TreeEcmaString* Cast(const EcmaString* str)
619     {
620         return TreeEcmaString::Cast(const_cast<EcmaString*>(str));
621     }
622 
ToTreeString()623     TreeString* ToTreeString()
624     {
625         return TreeString::Cast(this);
626     }
627 
ToTreeString()628     const TreeString* ToTreeString() const
629     {
630         return TreeString::ConstCast(this);
631     }
632 
FromBaseString(TreeString * str)633     static TreeEcmaString* FromBaseString(TreeString* str)
634     {
635         return reinterpret_cast<TreeEcmaString*>(str);
636     }
637 
GetFirst(const JSThread * thread)638     JSTaggedValue GetFirst(const JSThread *thread) const
639     {
640         auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* {
641             return Barriers::GetTaggedObject(thread, obj, offset);
642         };
643         return JSTaggedValue(ToTreeString()->GetFirst<TaggedObject*>(std::move(readBarrier)));
644     }
645 
646     template <typename T>
647     void SetFirst(const JSThread* thread, JSHandle<T> value, BarrierMode mode = WRITE_BARRIER)
648     {
649         auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) {
650             if (mode == WRITE_BARRIER) {
651                 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str));
652             } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); }
653         };
654         ToTreeString()->SetFirst(std::move(writeBarrier), value->GetTaggedObject());
655     }
656 
657     void SetFirst(const JSThread* thread, JSTaggedValue value, BarrierMode mode = WRITE_BARRIER)
658     {
659         auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) {
660             if (mode == WRITE_BARRIER) {
661                 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str));
662             } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); }
663         };
664         ToTreeString()->SetFirst(std::move(writeBarrier), value.GetTaggedObject());
665     };
666 
GetSecond(const JSThread * thread)667     JSTaggedValue GetSecond(const JSThread *thread) const
668     {
669         auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* {
670             return Barriers::GetTaggedObject(thread, obj, offset);
671         };
672         return JSTaggedValue(ToTreeString()->GetSecond<TaggedObject*>(std::move(readBarrier)));
673     }
674 
675     template <typename T>
676     void SetSecond(const JSThread* thread, JSHandle<T> value, BarrierMode mode = WRITE_BARRIER)
677     {
678         auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) {
679             if (mode == WRITE_BARRIER) {
680                 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str));
681             } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); }
682         };
683         ToTreeString()->SetSecond(std::move(writeBarrier), value->GetTaggedObject());
684     }
685 
686     void SetSecond(const JSThread* thread, JSTaggedValue value, BarrierMode mode = WRITE_BARRIER)
687     {
688         auto writeBarrier = [thread, mode](void* obj, size_t offset, BaseObject* str) {
689             if (mode == WRITE_BARRIER) {
690                 Barriers::SetObject<true>(thread, obj, offset, reinterpret_cast<JSTaggedType>(str));
691             } else { Barriers::SetPrimitive<JSTaggedType>(obj, offset, reinterpret_cast<JSTaggedType>(str)); }
692         };
693         ToTreeString()->SetSecond(std::move(writeBarrier), value.GetTaggedObject());
694     };
695 
IsFlat(const JSThread * thread)696     bool IsFlat(const JSThread *thread) const
697     {
698         auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* {
699             return Barriers::GetTaggedObject(thread, obj, offset);
700         };
701         return ToTreeString()->IsFlat(std::move(readBarrier));
702     }
703 
704     template<bool verify = true>
Get(const JSThread * thread,int32_t index)705     uint16_t Get(const JSThread *thread, int32_t index) const
706     {
707         auto readBarrier = [thread](const void* obj, size_t offset)-> TaggedObject* {
708             return Barriers::GetTaggedObject(thread, obj, offset);
709         };
710         return ToTreeString()->Get<verify>(std::move(readBarrier), index);
711     }
712 };
713 
714 // FlatStringInfo holds an EcmaString* instead of a JSHandle. If a GC occurs during its usage period,
715 // it may cause the pointer to become invalid, necessitating the pointer to be reset.
716 class FlatStringInfo {
717 public:
FlatStringInfo(EcmaString * string,uint32_t startIndex,uint32_t length)718     FlatStringInfo(EcmaString *string, uint32_t startIndex, uint32_t length) : string_(string),
719                                                                                startIndex_(startIndex),
720                                                                                length_(length) {}
IsUtf8()721     bool IsUtf8() const
722     {
723         return string_->IsUtf8();
724     }
725 
IsUtf16()726     bool IsUtf16() const
727     {
728         return string_->IsUtf16();
729     }
730 
GetString()731     EcmaString *GetString() const
732     {
733         return string_;
734     }
735 
SetString(EcmaString * string)736     void SetString(EcmaString *string)
737     {
738         string_ = string;
739     }
740 
GetStartIndex()741     uint32_t GetStartIndex() const
742     {
743         return startIndex_;
744     }
745 
SetStartIndex(uint32_t index)746     void SetStartIndex(uint32_t index)
747     {
748         startIndex_ = index;
749     }
750 
GetLength()751     uint32_t GetLength() const
752     {
753         return length_;
754     }
755 
756     const uint8_t *GetDataUtf8() const;
757     const uint16_t *GetDataUtf16() const;
758     uint8_t *GetDataUtf8Writable() const;
759     uint16_t *GetDataUtf16Writable() const;
760     std::u16string ToU16String(uint32_t len = 0);
761 private:
762     EcmaString *string_ {nullptr};
763     uint32_t startIndex_ {0};
764     uint32_t length_ {0};
765 };
766 
767 // if you want to use functions of EcmaString, please not use directly,
768 // and use functions of EcmaStringAccessor alternatively.
769 // eg: EcmaString *str = ***; str->GetLength() ----->  EcmaStringAccessor(str).GetLength()
770 class PUBLIC_API EcmaStringAccessor {
771 public:
EcmaStringAccessor(EcmaString * string)772     explicit inline EcmaStringAccessor(EcmaString *string)
773     {
774         ASSERT(string != nullptr);
775         string_ = string;
776     }
777 
778     explicit EcmaStringAccessor(TaggedObject *obj);
779 
780     explicit EcmaStringAccessor(JSTaggedValue value);
781 
782     explicit EcmaStringAccessor(const JSHandle<EcmaString> &strHandle);
783 
CalculateAllConcatHashCode(const JSThread * thread,const JSHandle<EcmaString> & firstString,const JSHandle<EcmaString> & secondString)784     static uint32_t CalculateAllConcatHashCode(const JSThread *thread,
785                                                const JSHandle<EcmaString> &firstString,
786                                                const JSHandle<EcmaString> &secondString)
787     {
788         return EcmaString::CalculateConcatHashCode(thread, firstString, secondString);
789     }
790 
791     static EcmaString *CreateLineString(const EcmaVM *vm, size_t length, bool compressed);
792 
CreateEmptyString(const EcmaVM * vm)793     static EcmaString *CreateEmptyString(const EcmaVM *vm)
794     {
795         return EcmaString::CreateEmptyString(vm);
796     }
797 
798     static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress,
799                                       MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE)
800     {
801         return EcmaString::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type);
802     }
803 
804     static EcmaString *CreateFromUtf8CompressedSubString(const EcmaVM *vm, const JSHandle<EcmaString> &string,
805                                                          uint32_t offset, uint32_t utf8Len,
806                                                          MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE)
807     {
808         return EcmaString::CreateFromUtf8CompressedSubString(vm, string, offset, utf8Len, type);
809     }
810 
811     static EcmaString *CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len,
812         MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE)
813     {
814         return EcmaString::CreateUtf16StringFromUtf8(vm, utf8Data, utf16Len, type);
815     }
816 
817     static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len,
818                                        bool canBeCompress, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE)
819     {
820         return EcmaString::CreateFromUtf16(vm, utf16Data, utf16Len, canBeCompress, type);
821     }
822 
823     static EcmaString *Concat(const EcmaVM *vm, const JSHandle<EcmaString> &str1Handle,
824         const JSHandle<EcmaString> &str2Handle, MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE)
825     {
826         return EcmaString::Concat(vm, str1Handle, str2Handle, type);
827     }
828 
CopyStringToOldSpace(const EcmaVM * vm,const JSHandle<EcmaString> & original,uint32_t length,bool compressed)829     static EcmaString *CopyStringToOldSpace(const EcmaVM *vm, const JSHandle<EcmaString> &original,
830         uint32_t length, bool compressed)
831     {
832         return EcmaString::CopyStringToOldSpace(vm, original, length, compressed);
833     }
834 
835     // can change src data structure
FastSubString(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)836     static EcmaString *FastSubString(const EcmaVM *vm,
837         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length)
838     {
839         return EcmaString::FastSubString(vm, src, start, length);
840     }
SubStringIsUtf8(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)841     static bool SubStringIsUtf8(const EcmaVM *vm,
842         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length)
843     {
844         return EcmaString::SubStringIsUtf8(vm, src, start, length);
845     }
846     // get
GetSubString(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)847     static EcmaString *GetSubString(const EcmaVM *vm,
848         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length)
849     {
850         return EcmaString::GetSubString(vm, src, start, length);
851     }
852 
IsUtf8()853     bool IsUtf8() const
854     {
855         return string_->IsUtf8();
856     }
857 
IsUtf16()858     bool IsUtf16() const
859     {
860         return string_->IsUtf16();
861     }
862 
GetLength()863     uint32_t GetLength() const
864     {
865         return string_->GetLength();
866     }
867 
868     // require is LineString
869     inline size_t GetUtf8Length(const JSThread *thread, bool isGetBufferSize = false) const;
870 
ObjectSize()871     size_t ObjectSize() const
872     {
873         if (string_->IsLineString()) {
874             return LineEcmaString::ObjectSize(string_);
875         } else {
876             return TreeString::SIZE;
877         }
878     }
879 
880     // For TreeString, the calculation result is size of LineString correspondingly.
GetFlatStringSize()881     size_t GetFlatStringSize() const
882     {
883         return LineEcmaString::ObjectSize(string_);
884     }
885 
IsInternString()886     bool IsInternString() const
887     {
888         return string_->IsInternString();
889     }
890 
SetInternString()891     void SetInternString()
892     {
893         string_->SetIsInternString();
894     }
895 
ClearInternString()896     void ClearInternString()
897     {
898         string_->ClearInternStringFlag();
899     }
900 
901     // require is LineString
902     // It's Utf8 format, but without 0 in the end.
903     inline const uint8_t *GetDataUtf8();
904 
905     // require is LineString
906     inline const uint16_t *GetDataUtf16();
907 
908     // not change string data structure.
909     // if string is not flat, this func has low efficiency.
910     std::u16string ToU16String(const JSThread *thread, uint32_t len = 0)
911     {
912         return string_->ToU16String(thread, len);
913     }
914 
915 
916     // not change string data structure.
917     // if string is not flat, this func has low efficiency.
ToUtf8Span(const JSThread * thread,CVector<uint8_t> & buf)918     Span<const uint8_t> ToUtf8Span(const JSThread *thread, CVector<uint8_t> &buf)
919     {
920         return string_->ToUtf8Span(thread, buf);
921     }
922 
923     // not change string data structure.
924     // if string is not flat, this func has low efficiency.
925     std::string ToStdString(const JSThread *thread, StringConvertedUsage usage = StringConvertedUsage::PRINT);
926 
927     // this function convert for Utf8
928     CString Utf8ConvertToString(const JSThread *thread);
929 
930     std::string DebuggerToStdString(const JSThread *thread, StringConvertedUsage usage = StringConvertedUsage::PRINT);
931     // not change string data structure.
932     // if string is not flat, this func has low efficiency.
933     CString ToCString(const JSThread *thread, StringConvertedUsage usage = StringConvertedUsage::LOGICOPERATION,
934                       bool cesu8 = false);
935 
936 #if ENABLE_NEXT_OPTIMIZATION
937     void AppendToCString(const JSThread *thread, CString &str);
938     void AppendToC16String(const JSThread *thread, C16String &str);
939 #endif
940 
941     // not change string data structure.
942     // if string is not flat, this func has low efficiency.
943     uint32_t WriteToFlatUtf8(const JSThread *thread, uint8_t *buf, uint32_t maxLength, bool isWriteBuffer = false)
944     {
945         return string_->WriteUtf8(thread, buf, maxLength, isWriteBuffer);
946     }
947 
WriteToUtf16(const JSThread * thread,uint16_t * buf,uint32_t bufLength)948     uint32_t WriteToUtf16(const JSThread *thread, uint16_t *buf, uint32_t bufLength)
949     {
950         return string_->WriteUtf16(thread, buf, GetLength(), bufLength);
951     }
952 
WriteToOneByte(const JSThread * thread,uint8_t * buf,uint32_t maxLength)953     uint32_t WriteToOneByte(const JSThread *thread, uint8_t *buf, uint32_t maxLength)
954     {
955         return string_->WriteOneByte(thread, buf, maxLength);
956     }
957 
958     // not change string data structure.
959     // if string is not flat, this func has low efficiency.
WriteToFlatUtf16(const JSThread * thread,uint16_t * buf,uint32_t maxLength)960     uint32_t WriteToFlatUtf16(const JSThread *thread, uint16_t *buf, uint32_t maxLength) const
961     {
962         return string_->CopyDataUtf16(thread, buf, maxLength);
963     }
964 
965     template <typename Char>
WriteToFlatWithPos(const JSThread * thread,EcmaString * src,Char * buf,uint32_t length,uint32_t pos)966     static void WriteToFlatWithPos(const JSThread *thread, EcmaString *src, Char *buf, uint32_t length, uint32_t pos)
967     {
968         src->WriteToFlatWithPos(thread, src, buf, length, pos);
969     }
970 
971     template <typename Char>
WriteToFlat(const JSThread * thread,EcmaString * src,Char * buf,uint32_t maxLength)972     static void WriteToFlat(const JSThread *thread, EcmaString *src, Char *buf, uint32_t maxLength)
973     {
974         src->WriteToFlat(thread, src, buf, maxLength);
975     }
976 
977     // require dst is LineString
978     // not change src data structure.
979     // if src is not flat, this func has low efficiency.
980     template <RBMode mode = RBMode::DEFAULT_RB>
981     inline static void ReadData(const JSThread *thread, EcmaString *dst, EcmaString *src, uint32_t start,
982                                 uint32_t destSize, uint32_t length);
983 
984     // not change src data structure.
985     // if src is not flat, this func has low efficiency.
986     template<bool verify = true>
Get(const JSThread * thread,uint32_t index)987     uint16_t Get(const JSThread *thread, uint32_t index) const
988     {
989         return string_->At<verify>(thread, index);
990     }
991 
992     // require string is LineString.
Set(uint32_t index,uint16_t src)993     void Set(uint32_t index, uint16_t src)
994     {
995         return string_->WriteData(index, src);
996     }
997 
998     // not change src data structure.
999     // if src is not flat, this func has low efficiency.
GetHashcode(const JSThread * thread)1000     uint32_t GetHashcode(const JSThread *thread)
1001     {
1002         return string_->GetHashcode(thread);
1003     }
1004 
ComputeHashcode(const JSThread * thread)1005     uint32_t ComputeHashcode(const JSThread *thread)
1006     {
1007         return string_->ComputeHashcode(thread);
1008     }
1009 
ComputeHashcodeUtf8(const uint8_t * utf8Data,size_t utf8Len,bool canBeCompress)1010     static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress)
1011     {
1012         return EcmaString::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress);
1013     }
1014 
ComputeHashcodeUtf16(const uint16_t * utf16Data,uint32_t length)1015     static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length)
1016     {
1017         return EcmaString::ComputeHashcodeUtf16(utf16Data, length);
1018     }
1019 
1020     // can change receiver and search data structure
1021     static int32_t IndexOf(const EcmaVM *vm,
1022         const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0)
1023     {
1024         return EcmaString::IndexOf(vm, receiver, search, pos);
1025     }
1026 
1027     // can change receiver and search data structure
1028     static int32_t LastIndexOf(const EcmaVM *vm,
1029         const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0)
1030     {
1031         return EcmaString::LastIndexOf(vm, receiver, search, pos);
1032     }
1033 
1034     // can change receiver and search data structure
Compare(const EcmaVM * vm,const JSHandle<EcmaString> & left,const JSHandle<EcmaString> & right)1035     static int32_t Compare(const EcmaVM *vm, const JSHandle<EcmaString>& left, const JSHandle<EcmaString>& right)
1036     {
1037         return EcmaString::Compare(vm, left, right);
1038     }
1039 
1040 
1041     // can change receiver and search data structure
1042     static bool IsSubStringAt(const EcmaVM *vm, const JSHandle<EcmaString>& left,
1043         const JSHandle<EcmaString>& right, uint32_t offset = 0)
1044     {
1045         return EcmaString::IsSubStringAt(vm, left, right, offset);
1046     }
1047 
1048     // can change str1 and str2 data structure
StringsAreEqual(const EcmaVM * vm,const JSHandle<EcmaString> & str1,const JSHandle<EcmaString> & str2)1049     static bool StringsAreEqual(const EcmaVM *vm, const JSHandle<EcmaString> &str1, const JSHandle<EcmaString> &str2)
1050     {
1051         return EcmaString::StringsAreEqual(vm, str1, str2);
1052     }
1053 
1054     // not change str1 and str2 data structure.
1055     // if str1 or str2 is not flat, this func has low efficiency.
1056     template <RBMode mode = RBMode::DEFAULT_RB>
StringsAreEqual(const JSThread * thread,EcmaString * str1,EcmaString * str2)1057     static bool StringsAreEqual(const JSThread *thread, EcmaString *str1, EcmaString *str2)
1058     {
1059         return EcmaString::StringsAreEqual<mode>(thread, str1, str2);
1060     }
1061 
1062     // not change str1 and str2 data structure.
1063     // if str1 or str2 is not flat, this func has low efficiency.
StringsAreEqualDiffUtfEncoding(const JSThread * thread,EcmaString * str1,EcmaString * str2)1064     static bool StringsAreEqualDiffUtfEncoding(const JSThread *thread, EcmaString *str1, EcmaString *str2)
1065     {
1066         return EcmaString::StringsAreEqualDiffUtfEncoding(thread, str1, str2);
1067     }
1068 
1069     // not change str1 data structure.
1070     // if str1 is not flat, this func has low efficiency.
StringIsEqualUint8Data(const JSThread * thread,const EcmaString * str1,const uint8_t * dataAddr,uint32_t dataLen,bool canBeCompress)1071     static bool StringIsEqualUint8Data(const JSThread *thread,
1072                                        const EcmaString *str1, const uint8_t *dataAddr, uint32_t dataLen,
1073                                        bool canBeCompress)
1074     {
1075         return EcmaString::StringIsEqualUint8Data(thread, str1, dataAddr, dataLen, canBeCompress);
1076     }
1077 
1078     // not change str1 data structure.
1079     // if str1 is not flat, this func has low efficiency.
StringsAreEqualUtf16(const JSThread * thread,const EcmaString * str1,const uint16_t * utf16Data,uint32_t utf16Len)1080     static bool StringsAreEqualUtf16(const JSThread *thread, const EcmaString *str1, const uint16_t *utf16Data,
1081                                      uint32_t utf16Len)
1082     {
1083         return EcmaString::StringsAreEqualUtf16(thread, str1, utf16Data, utf16Len);
1084     }
1085 
1086     // require str1 and str2 are LineString.
1087     // not change string data structure.
1088     // if string is not flat, this func has low efficiency.
EqualToSplicedString(const JSThread * thread,const EcmaString * str1,const EcmaString * str2)1089     bool EqualToSplicedString(const JSThread *thread, const EcmaString *str1, const EcmaString *str2)
1090     {
1091         return string_->EqualToSplicedString(thread, str1, str2);
1092     }
1093 
CanBeCompressed(const uint8_t * utf8Data,uint32_t utf8Len)1094     static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len)
1095     {
1096         return EcmaString::CanBeCompressed(utf8Data, utf8Len);
1097     }
1098 
CanBeCompressed(const uint16_t * utf16Data,uint32_t utf16Len)1099     static bool CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len)
1100     {
1101         return EcmaString::CanBeCompressed(utf16Data, utf16Len);
1102     }
1103 
1104     // require string is LineString
CanBeCompressed(const EcmaString * string)1105     static bool CanBeCompressed(const EcmaString *string)
1106     {
1107         return EcmaString::CanBeCompressed(string);
1108     }
1109 
1110     // not change string data structure.
1111     // if string is not flat, this func has low efficiency.
ToElementIndex(const JSThread * thread,uint32_t * index)1112     bool ToElementIndex(const JSThread *thread, uint32_t *index)
1113     {
1114         return string_->ToElementIndex(thread, index);
1115     }
1116 
1117     // not change string data structure.
1118     // if string is not flat, this func has low efficiency.
ToInt(const JSThread * thread,int32_t * index,bool * negative)1119     bool ToInt(const JSThread *thread, int32_t *index, bool *negative)
1120     {
1121         return string_->ToInt(thread, index, negative);
1122     }
1123 
1124     // not change string data structure.
1125     // if string is not flat, this func has low efficiency.
ToTypedArrayIndex(const JSThread * thread,uint32_t * index)1126     bool PUBLIC_API ToTypedArrayIndex(const JSThread *thread, uint32_t *index)
1127     {
1128         return string_->ToTypedArrayIndex(thread, index);
1129     }
1130 
ToLower(const EcmaVM * vm,const JSHandle<EcmaString> & src)1131     static EcmaString *ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src)
1132     {
1133         return EcmaString::ToLower(vm, src);
1134     }
1135 
TryToLower(const EcmaVM * vm,const JSHandle<EcmaString> & src)1136     static EcmaString *TryToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src)
1137     {
1138         return EcmaString::TryToLower(vm, src);
1139     }
1140 
TryToUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src)1141     static EcmaString *TryToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src)
1142     {
1143         return EcmaString::TryToUpper(vm, src);
1144     }
1145 
ToUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src)1146     static EcmaString *ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src)
1147     {
1148         return EcmaString::ToUpper(vm, src);
1149     }
1150 
ToLocaleLower(const EcmaVM * vm,const JSHandle<EcmaString> & src,const icu::Locale & locale)1151     static EcmaString *ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale)
1152     {
1153         return EcmaString::ToLocaleLower(vm, src, locale);
1154     }
1155 
ToLocaleUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src,const icu::Locale & locale)1156     static EcmaString *ToLocaleUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale)
1157     {
1158         return EcmaString::ToLocaleUpper(vm, src, locale);
1159     }
1160 
1161     static EcmaString *Trim(const JSThread *thread,
1162         const JSHandle<EcmaString> &src, EcmaString::TrimMode mode = EcmaString::TrimMode::TRIM)
1163     {
1164         return EcmaString::Trim(thread, src, mode);
1165     }
1166 
IsASCIICharacter(uint16_t data)1167     static bool IsASCIICharacter(uint16_t data)
1168     {
1169         if (data == 0) {
1170             return false;
1171         }
1172         // \0 is not considered ASCII in Ecma-Modified-UTF8 [only modify '\u0000']
1173         return data <= common::utf_helper::UTF8_1B_MAX;
1174     }
1175 
IsFlat(const JSThread * thread)1176     bool IsFlat(const JSThread *thread) const
1177     {
1178         return string_->IsFlat(thread);
1179     }
1180 
IsLineString()1181     bool IsLineString() const
1182     {
1183         return string_->IsLineString();
1184     }
1185 
IsSlicedString()1186     bool IsSlicedString() const
1187     {
1188         return string_->IsSlicedString();
1189     }
1190 
IsTreeString()1191     bool IsTreeString() const
1192     {
1193         return string_->IsTreeString();
1194     }
1195 
NotTreeString()1196     bool NotTreeString() const
1197     {
1198         return string_->NotTreeString();
1199     }
1200 
1201     inline Span<const uint8_t> FastToUtf8Span() const;
1202 
1203     // the returned string may be a linestring or slicestring!!
1204     PUBLIC_API static EcmaString *Flatten(const EcmaVM *vm, const JSHandle<EcmaString> &string,
1205         MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE)
1206     {
1207         return EcmaString::Flatten(vm, string, type);
1208     }
1209 
1210     static FlatStringInfo FlattenAllString(const EcmaVM *vm, const JSHandle<EcmaString> &string,
1211         MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE)
1212     {
1213         return EcmaString::FlattenAllString(vm, string, type);
1214     }
1215 
1216     static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<EcmaString> &string,
1217         MemSpaceType type = MemSpaceType::SHARED_OLD_SPACE)
1218     {
1219         return EcmaString::SlowFlatten(vm, string, type);
1220     }
1221 
FlattenNoGCForSnapshot(const EcmaVM * vm,EcmaString * string)1222     static EcmaString *FlattenNoGCForSnapshot(const EcmaVM *vm, EcmaString *string)
1223     {
1224         return EcmaString::FlattenNoGCForSnapshot(vm, string);
1225     }
1226 
GetUtf8DataFlat(const JSThread * thread,const EcmaString * src,CVector<uint8_t> & buf)1227     static const uint8_t *GetUtf8DataFlat(const JSThread *thread, const EcmaString *src, CVector<uint8_t> &buf)
1228     {
1229         return EcmaString::GetUtf8DataFlat(thread, src, buf);
1230     }
1231 
GetNonTreeUtf8Data(const JSThread * thread,const EcmaString * src)1232     static const uint8_t *GetNonTreeUtf8Data(const JSThread *thread, const EcmaString *src)
1233     {
1234         return EcmaString::GetNonTreeUtf8Data(thread, src);
1235     }
1236 
GetUtf16DataFlat(const JSThread * thread,const EcmaString * src,CVector<uint16_t> & buf)1237     static const uint16_t *GetUtf16DataFlat(const JSThread *thread, const EcmaString *src, CVector<uint16_t> &buf)
1238     {
1239         return EcmaString::GetUtf16DataFlat(thread, src, buf);
1240     }
1241 
GetNonTreeUtf16Data(const JSThread * thread,const EcmaString * src)1242     static const uint16_t *GetNonTreeUtf16Data(const JSThread *thread, const EcmaString *src)
1243     {
1244         return EcmaString::GetNonTreeUtf16Data(thread, src);
1245     }
1246 
1247     static JSTaggedValue StringToList(JSThread *thread, JSHandle<JSTaggedValue> &str);
1248 
1249 private:
1250     EcmaString *string_ {nullptr};
1251 };
1252 }  // namespace ecmascript
1253 }  // namespace panda
1254 #endif  // ECMASCRIPT_STRING_H
1255