• 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 "ecmascript/base/utf_helper.h"
24 #include "ecmascript/common.h"
25 #include "ecmascript/ecma_macros.h"
26 #include "ecmascript/js_hclass.h"
27 #include "ecmascript/js_tagged_value.h"
28 #include "ecmascript/mem/barriers.h"
29 #include "ecmascript/mem/space.h"
30 #include "ecmascript/mem/tagged_object.h"
31 
32 #include "libpandabase/macros.h"
33 #include "securec.h"
34 #include "unicode/locid.h"
35 
36 namespace panda {
37 namespace ecmascript {
38 template<typename T>
39 class JSHandle;
40 class JSPandaFile;
41 class EcmaVM;
42 class LineEcmaString;
43 class ConstantString;
44 class TreeEcmaString;
45 
46 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
47 #define ECMA_STRING_CHECK_LENGTH_AND_TRHOW(vm, length)                                        \
48     if ((length) >= MAX_STRING_LENGTH) {                                                      \
49         THROW_RANGE_ERROR_AND_RETURN((vm)->GetJSThread(), "Invalid string length", nullptr);  \
50     }
51 
52 class EcmaString : public TaggedObject {
53 public:
54     CAST_CHECK(EcmaString, IsString);
55 
56     static constexpr uint32_t STRING_COMPRESSED_BIT = 0x1;
57     static constexpr uint32_t STRING_INTERN_BIT = 0x2;
58     static constexpr size_t MAX_STRING_LENGTH = 0x40000000U; // 30 bits for string length, 2 bits for special meaning
59 
60     static constexpr size_t MIX_LENGTH_OFFSET = TaggedObjectSize();
61     // In last bit of mix_length we store if this string is compressed or not.
62     ACCESSORS_PRIMITIVE_FIELD(MixLength, uint32_t, MIX_LENGTH_OFFSET, HASHCODE_OFFSET)
63     ACCESSORS_PRIMITIVE_FIELD(RawHashcode, uint32_t, HASHCODE_OFFSET, SIZE)
64 
65     enum CompressedStatus {
66         STRING_COMPRESSED,
67         STRING_UNCOMPRESSED,
68     };
69 
70     enum TrimMode : uint8_t {
71         TRIM,
72         TRIM_START,
73         TRIM_END,
74     };
75 
76 private:
77     friend class EcmaStringAccessor;
78     friend class LineEcmaString;
79     friend class ConstantString;
80     friend class TreeEcmaString;
81     friend class NameDictionary;
82 
83     static constexpr int SMALL_STRING_SIZE = 128;
84 
85     static EcmaString *CreateEmptyString(const EcmaVM *vm);
86     static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
87         bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE, bool isConstantString = false,
88         uint32_t idOffset = 0);
89     static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len,
90         bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE);
91     static EcmaString *CreateLineString(const EcmaVM *vm, size_t length, bool compressed);
92     static EcmaString *CreateLineStringNoGC(const EcmaVM *vm, size_t length, bool compressed);
93     static EcmaString *CreateLineStringWithSpaceType(const EcmaVM *vm,
94         size_t length, bool compressed, MemSpaceType type);
95     static EcmaString *CreateTreeString(const EcmaVM *vm,
96         const JSHandle<EcmaString> &left, const JSHandle<EcmaString> &right, uint32_t length, bool compressed);
97     static EcmaString *CreateConstantString(const EcmaVM *vm, const uint8_t *utf8Data,
98         size_t length, bool compressed, MemSpaceType type = MemSpaceType::SEMI_SPACE, uint32_t idOffset = 0);
99     static EcmaString *Concat(const EcmaVM *vm, const JSHandle<EcmaString> &left,
100         const JSHandle<EcmaString> &right, MemSpaceType type = MemSpaceType::SEMI_SPACE);
101     static EcmaString *CopyStringToOldSpace(const EcmaVM *vm, const JSHandle<EcmaString> &original,
102         uint32_t length, bool compressed);
103     static EcmaString *FastSubString(const EcmaVM *vm,
104         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
105     // require src is LineString
106     // not change src data structure
107     static inline EcmaString *FastSubUtf8String(const EcmaVM *vm,
108         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
109     // require src is LineString
110     // not change src data structure
111     static inline EcmaString *FastSubUtf16String(const EcmaVM *vm,
112         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length);
113 
IsUtf8()114     bool IsUtf8() const
115     {
116         return (GetMixLength() & STRING_COMPRESSED_BIT) == STRING_COMPRESSED;
117     }
118 
IsUtf16()119     bool IsUtf16() const
120     {
121         return (GetMixLength() & STRING_COMPRESSED_BIT) == STRING_UNCOMPRESSED;
122     }
123 
124     // require is LineString
125     inline uint16_t *GetData() const;
126     inline const uint8_t *GetDataUtf8() const;
127     inline const uint16_t *GetDataUtf16() const;
128 
129     // require is LineString
130     inline uint8_t *GetDataUtf8Writable();
131     inline uint16_t *GetDataUtf16Writable();
132 
GetLength()133     uint32_t GetLength() const
134     {
135         return GetMixLength() >> 2U;
136     }
137 
138     void SetLength(uint32_t length, bool compressed = false)
139     {
140         ASSERT(length < MAX_STRING_LENGTH);
141         // Use 0u for compressed/utf8 expression
142         SetMixLength((length << 2U) | (compressed ? STRING_COMPRESSED : STRING_UNCOMPRESSED));
143     }
144 
145     inline size_t GetUtf8Length(bool modify = true) const;
146 
SetIsInternString()147     void SetIsInternString()
148     {
149         SetMixLength(GetMixLength() | STRING_INTERN_BIT);
150     }
151 
IsInternString()152     bool IsInternString() const
153     {
154         return (GetMixLength() & STRING_INTERN_BIT) != 0;
155     }
156 
ClearInternStringFlag()157     void ClearInternStringFlag()
158     {
159         SetMixLength(GetMixLength() & ~STRING_INTERN_BIT);
160     }
161 
TryGetHashCode(uint32_t * hash)162     bool TryGetHashCode(uint32_t *hash)
163     {
164         uint32_t hashcode = GetRawHashcode();
165         if (hashcode == 0 && GetLength() != 0) {
166             return false;
167         }
168         *hash = hashcode;
169         return true;
170     }
171 
172     // not change this data structure.
173     // if string is not flat, this func has low efficiency.
GetHashcode()174     uint32_t PUBLIC_API GetHashcode()
175     {
176         uint32_t hashcode = GetRawHashcode();
177         // GetLength() == 0 means it's an empty array.No need to computeHashCode again when hashseed is 0.
178         if (hashcode == 0 && GetLength() != 0) {
179             hashcode = ComputeHashcode(0);
180             SetRawHashcode(hashcode);
181         }
182         return hashcode;
183     }
184 
185     // not change this data structure.
186     // if string is not flat, this func has low efficiency.
187     uint32_t PUBLIC_API ComputeHashcode(uint32_t hashSeed) const;
188 
189     static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress);
190     static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length);
191 
192     template<bool verify = true>
193     uint16_t At(int32_t index) const;
194 
195     // require is LineString
196     void WriteData(uint32_t index, uint16_t src);
197 
198     // can change left and right data structure
199     static int32_t Compare(const EcmaVM *vm, const JSHandle<EcmaString> &left, const JSHandle<EcmaString> &right);
200 
201     // Check that two spans are equal. Should have the same length.
202     /* static */
203     template<typename T>
StringsAreEquals(Span<const T> & str1,Span<const T> & str2)204     static bool StringsAreEquals(Span<const T> &str1, Span<const T> &str2)
205     {
206         ASSERT(str1.Size() <= str2.Size());
207         size_t size = str1.Size();
208         if (size < SMALL_STRING_SIZE) {
209             for (size_t i = 0; i < size; i++) {
210                 if (str1[i] != str2[i]) {
211                     return false;
212                 }
213             }
214             return true;
215         }
216         return memcmp(str1.data(), str2.data(), size * sizeof(T)) == 0;
217     }
218 
219     // Converts utf8Data to utf16 and compare it with given utf16_data.
220     static bool IsUtf8EqualsUtf16(const uint8_t *utf8Data, size_t utf8Len, const uint16_t *utf16Data,
221                                   uint32_t utf16Len);
222     // Compares string1 + string2 by bytes, It doesn't check canonical unicode equivalence.
223     bool EqualToSplicedString(const EcmaString *str1, const EcmaString *str2);
224     // Compares strings by bytes, It doesn't check canonical unicode equivalence.
225     static bool StringsAreEqual(const EcmaVM *vm, const JSHandle<EcmaString> &str1, const JSHandle<EcmaString> &str2);
226     // Compares strings by bytes, It doesn't check canonical unicode equivalence.
227     static bool StringsAreEqual(EcmaString *str1, EcmaString *str2);
228     // Two strings have the same type of utf encoding format.
229     static bool StringsAreEqualSameUtfEncoding(EcmaString *str1, EcmaString *str2);
230     // Compares strings by bytes, It doesn't check canonical unicode equivalence.
231     // not change str1 data structure.
232     // if str1 is not flat, this func has low efficiency.
233     static bool StringsAreEqualUtf8(const EcmaString *str1, const uint8_t *utf8Data, uint32_t utf8Len,
234                                     bool canBeCompress);
235     // Compares strings by bytes, It doesn't check canonical unicode equivalence.
236     // not change str1 data structure.
237     // if str1 is not flat, this func has low efficiency.
238     static bool StringsAreEqualUtf16(const EcmaString *str1, const uint16_t *utf16Data, uint32_t utf16Len);
239 
240     // can change receiver and search data structure
241     static int32_t IndexOf(const EcmaVM *vm,
242         const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0);
243 
244     // can change receiver and search data structure
245     static int32_t LastIndexOf(const EcmaVM *vm,
246         const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0);
247 
248     inline size_t CopyDataUtf8(uint8_t *buf, size_t maxLength, bool modify = true) const
249     {
250         if (maxLength == 0) {
251             return 1; // maxLength was -1 at napi
252         }
253         size_t length = GetLength();
254         if (length > maxLength) {
255             return 0;
256         }
257         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
258         buf[maxLength - 1] = '\0';
259         // Put comparison here so that internal usage and napi can use the same CopyDataRegionUtf8
260         return CopyDataRegionUtf8(buf, 0, length, maxLength, modify) + 1;  // add place for zero in the end
261     }
262 
263     // It allows user to copy into buffer even if maxLength < length
264     inline size_t WriteUtf8(uint8_t *buf, size_t maxLength, bool isWriteBuffer = false) const
265     {
266         if (maxLength == 0) {
267             return 1; // maxLength was -1 at napi
268         }
269         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
270         buf[maxLength - 1] = '\0';
271         return CopyDataRegionUtf8(buf, 0, GetLength(), maxLength, true, isWriteBuffer) + 1;
272     }
273 
CopyDataToUtf16(uint16_t * buf,uint32_t length,uint32_t bufLength)274     size_t CopyDataToUtf16(uint16_t *buf, uint32_t length, uint32_t bufLength) const
275     {
276         if (IsUtf16()) {
277             CVector<uint16_t> tmpBuf;
278             const uint16_t *data = EcmaString::GetUtf16DataFlat(this, tmpBuf);
279             if (length > bufLength) {
280                 if (memcpy_s(buf, bufLength * sizeof(uint16_t), data, bufLength * sizeof(uint16_t)) != EOK) {
281                     LOG_FULL(FATAL) << "memcpy_s failed when length > bufLength";
282                     UNREACHABLE();
283                 }
284                 return bufLength;
285             }
286             if (memcpy_s(buf, bufLength * sizeof(uint16_t), data, length * sizeof(uint16_t)) != EOK) {
287                 LOG_FULL(FATAL) << "memcpy_s failed";
288                 UNREACHABLE();
289             }
290             return length;
291         }
292         CVector<uint8_t> tmpBuf;
293         const uint8_t *data = EcmaString::GetUtf8DataFlat(this, tmpBuf);
294         if (length > bufLength) {
295             return base::utf_helper::ConvertRegionUtf8ToUtf16(data, buf, bufLength, bufLength, 0);
296         }
297         return base::utf_helper::ConvertRegionUtf8ToUtf16(data, buf, length, bufLength, 0);
298     }
299 
300     // It allows user to copy into buffer even if maxLength < length
WriteUtf16(uint16_t * buf,uint32_t targetLength,uint32_t bufLength)301     inline size_t WriteUtf16(uint16_t *buf, uint32_t targetLength, uint32_t bufLength) const
302     {
303         if (bufLength == 0) {
304             return 0;
305         }
306         // Returns a number representing a valid backrest length.
307         return CopyDataToUtf16(buf, targetLength, bufLength);
308     }
309 
WriteOneByte(uint8_t * buf,size_t maxLength)310     size_t WriteOneByte(uint8_t *buf, size_t maxLength) const
311     {
312         if (maxLength == 0) {
313             return 0;
314         }
315         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
316         buf[maxLength - 1] = '\0';
317         uint32_t length = GetLength();
318         if (!IsUtf16()) {
319             CVector<uint8_t> tmpBuf;
320             const uint8_t *data = GetUtf8DataFlat(this, tmpBuf);
321             if (length > maxLength) {
322                 length = maxLength;
323             }
324             if (memcpy_s(buf, maxLength, data, length) != EOK) {
325                 LOG_FULL(FATAL) << "memcpy_s failed when write one byte";
326                 UNREACHABLE();
327             }
328             return length;
329         }
330 
331         CVector<uint16_t> tmpBuf;
332         const uint16_t *data = GetUtf16DataFlat(this, tmpBuf);
333         if (length > maxLength) {
334             return base::utf_helper::ConvertRegionUtf16ToLatin1(data, buf, maxLength, maxLength);
335         }
336         return base::utf_helper::ConvertRegionUtf16ToLatin1(data, buf, length, maxLength);
337     }
338 
339     size_t CopyDataRegionUtf8(uint8_t *buf, size_t start, size_t length, size_t maxLength,
340                               bool modify = true, bool isWriteBuffer = false) const
341     {
342         uint32_t len = GetLength();
343         if (start + length > len) {
344             return 0;
345         }
346         if (!IsUtf16()) {
347             if (length > std::numeric_limits<size_t>::max() / 2 - 1) {  // 2: half
348                 LOG_FULL(FATAL) << " length is higher than half of size_t::max";
349                 UNREACHABLE();
350             }
351             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
352             // Only memcpy_s maxLength number of chars into buffer if length > maxLength
353             CVector<uint8_t> tmpBuf;
354             const uint8_t *data = GetUtf8DataFlat(this, tmpBuf);
355             if (length > maxLength) {
356                 if (memcpy_s(buf, maxLength, data + start, maxLength) != EOK) {
357                     LOG_FULL(FATAL) << "memcpy_s failed when length > maxlength";
358                     UNREACHABLE();
359                 }
360                 return maxLength;
361             }
362             if (memcpy_s(buf, maxLength, data + start, length) != EOK) {
363                 LOG_FULL(FATAL) << "memcpy_s failed when length <= maxlength";
364                 UNREACHABLE();
365             }
366             return length;
367         }
368         CVector<uint16_t> tmpBuf;
369         const uint16_t *data = GetUtf16DataFlat(this, tmpBuf);
370         if (length > maxLength) {
371             return base::utf_helper::ConvertRegionUtf16ToUtf8(data, buf, maxLength, maxLength, start,
372                                                               modify, isWriteBuffer);
373         }
374         return base::utf_helper::ConvertRegionUtf16ToUtf8(data, buf, length, maxLength, start,
375                                                           modify, isWriteBuffer);
376     }
377 
CopyDataUtf16(uint16_t * buf,uint32_t maxLength)378     inline uint32_t CopyDataUtf16(uint16_t *buf, uint32_t maxLength) const
379     {
380         return CopyDataRegionUtf16(buf, 0, GetLength(), maxLength);
381     }
382 
CopyDataRegionUtf16(uint16_t * buf,uint32_t start,uint32_t length,uint32_t maxLength)383     uint32_t CopyDataRegionUtf16(uint16_t *buf, uint32_t start, uint32_t length, uint32_t maxLength) const
384     {
385         if (length > maxLength) {
386             return 0;
387         }
388         uint32_t len = GetLength();
389         if (start + length > len) {
390             return 0;
391         }
392         if (IsUtf16()) {
393             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
394             CVector<uint16_t> tmpBuf;
395             const uint16_t *data = EcmaString::GetUtf16DataFlat(this, tmpBuf);
396             if (memcpy_s(buf, maxLength * sizeof(uint16_t), data + start, length * sizeof(uint16_t)) != EOK) {
397                 LOG_FULL(FATAL) << "memcpy_s failed";
398                 UNREACHABLE();
399             }
400             return length;
401         }
402         CVector<uint8_t> tmpBuf;
403         const uint8_t *data = EcmaString::GetUtf8DataFlat(this, tmpBuf);
404         return base::utf_helper::ConvertRegionUtf8ToUtf16(data, buf, len, maxLength, start);
405     }
406 
407     std::u16string ToU16String(uint32_t len = 0);
408 
ToOneByteDataForced()409     std::unique_ptr<uint8_t[]> ToOneByteDataForced()
410     {
411         uint8_t *buf = nullptr;
412         auto length = GetLength();
413         if (IsUtf16()) {
414             auto size = length * sizeof(uint16_t);
415             buf = new uint8_t[size]();
416             CopyDataUtf16(reinterpret_cast<uint16_t *>(buf), length);
417         } else {
418             buf = new uint8_t[length + 1]();
419             CopyDataUtf8(buf, length + 1);
420         }
421         return std::unique_ptr<uint8_t[]>(buf);
422     }
423 
424     Span<const uint8_t> ToUtf8Span(CVector<uint8_t> &buf, bool modify = true)
425     {
426         Span<const uint8_t> str;
427         uint32_t strLen = GetLength();
428         if (UNLIKELY(IsUtf16())) {
429             CVector<uint16_t> tmpBuf;
430             const uint16_t *data = EcmaString::GetUtf16DataFlat(this, tmpBuf);
431             size_t len = base::utf_helper::Utf16ToUtf8Size(data, strLen, modify) - 1;
432             buf.reserve(len);
433             len = base::utf_helper::ConvertRegionUtf16ToUtf8(data, buf.data(), strLen, len, 0, modify);
434             str = Span<const uint8_t>(buf.data(), len);
435         } else {
436             const uint8_t *data = EcmaString::GetUtf8DataFlat(this, buf);
437             str = Span<const uint8_t>(data, strLen);
438         }
439         return str;
440     }
441 
442     void WriteData(EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length);
443 
444     static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len);
445     static bool CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len);
446     static bool CanBeCompressed(const EcmaString *string);
447 
448     bool ToElementIndex(uint32_t *index);
449 
450     bool ToTypedArrayIndex(uint32_t *index);
451 
452     template<bool isLower>
453     static EcmaString *ConvertCase(const EcmaVM *vm, const JSHandle<EcmaString> &src);
454 
455     template<bool isLower>
456     static EcmaString *LocaleConvertCase(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale);
457 
458     template<typename T>
459     static EcmaString *TrimBody(const JSThread *thread, const JSHandle<EcmaString> &src, Span<T> &data, TrimMode mode);
460 
461     static EcmaString *Trim(const JSThread *thread, const JSHandle<EcmaString> &src, TrimMode mode = TrimMode::TRIM);
462 
463     // single char copy for loop
464     template<typename DstType, typename SrcType>
CopyChars(DstType * dst,SrcType * src,uint32_t count)465     static void CopyChars(DstType *dst, SrcType *src, uint32_t count)
466     {
467         Span<SrcType> srcSp(src, count);
468         Span<DstType> dstSp(dst, count);
469         for (uint32_t i = 0; i < count; i++) {
470             dstSp[i] = srcSp[i];
471         }
472     }
473 
474     // memory block copy
475     template<typename T>
476     static bool MemCopyChars(Span<T> &dst, size_t dstMax, Span<const T> &src, size_t count);
477 
478     template<typename T>
ComputeHashForData(const T * data,size_t size,uint32_t hashSeed)479     static uint32_t ComputeHashForData(const T *data, size_t size, uint32_t hashSeed)
480     {
481         uint32_t hash = hashSeed;
482         Span<const T> sp(data, size);
483         for (auto c : sp) {
484             constexpr size_t SHIFT = 5;
485             hash = (hash << SHIFT) - hash + c;
486         }
487         return hash;
488     }
489 
IsASCIICharacter(uint16_t data)490     static bool IsASCIICharacter(uint16_t data)
491     {
492         // \0 is not considered ASCII in Ecma-Modified-UTF8 [only modify '\u0000']
493         return data - 1U < base::utf_helper::UTF8_1B_MAX;
494     }
495 
496     template<typename T1, typename T2>
497     static int32_t IndexOf(Span<const T1> &lhsSp, Span<const T2> &rhsSp, int32_t pos, int32_t max);
498 
499     template<typename T1, typename T2>
500     static int32_t LastIndexOf(Span<const T1> &lhsSp, Span<const T2> &rhsSp, int32_t pos);
501 
502     bool IsFlat() const;
503 
IsLineString()504     bool IsLineString() const
505     {
506         return GetClass()->IsLineString();
507     }
IsConstantString()508     bool IsConstantString() const
509     {
510         return GetClass()->IsConstantString();
511     }
IsTreeString()512     bool IsTreeString() const
513     {
514         return GetClass()->IsTreeString();
515     }
IsLineOrConstantString()516     bool IsLineOrConstantString() const
517     {
518         auto hclass = GetClass();
519         return hclass->IsLineString() || hclass->IsConstantString();
520     }
521 
GetStringType()522     JSType GetStringType() const
523     {
524         JSType type = GetClass()->GetObjectType();
525         ASSERT(type >= JSType::STRING_FIRST && type <= JSType::STRING_LAST);
526         return type;
527     }
528 
529     template <typename Char>
530     static void WriteToFlat(EcmaString *src, Char *buf, uint32_t maxLength);
531 
532     static const uint8_t *GetUtf8DataFlat(const EcmaString *src, CVector<uint8_t> &buf);
533 
534     static const uint16_t *GetUtf16DataFlat(const EcmaString *src, CVector<uint16_t> &buf);
535 
536     // string must be not flat
537     static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<TreeEcmaString> &string, MemSpaceType type);
538 
539     static EcmaString *Flatten(const EcmaVM *vm, const JSHandle<EcmaString> &string,
540                                MemSpaceType type = MemSpaceType::SEMI_SPACE);
541 
542     static EcmaString *FlattenNoGC(const EcmaVM *vm, EcmaString *string);
543 
544     static EcmaString *ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src);
545 
546     static EcmaString *ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src);
547 
548     static EcmaString *ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale);
549 
550     static EcmaString *ToLocaleUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale);
551 
552     static EcmaString *TryToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src);
553 
554     static EcmaString *ConvertUtf8ToLowerOrUpper(const EcmaVM *vm, const JSHandle<EcmaString> &srcFlat,
555                                                  bool toLower, uint32_t startIndex = 0);
556 };
557 
558 // The LineEcmaString abstract class captures sequential string values, only LineEcmaString can store chars data
559 class LineEcmaString : public EcmaString {
560 public:
561     // DATA_OFFSET: the string data stored after the string header.
562     // Data can be stored in utf8 or utf16 form according to compressed bit.
563     static constexpr size_t DATA_OFFSET = EcmaString::SIZE;  // DATA_OFFSET equal to Empty String size
564 
565     CAST_CHECK(LineEcmaString, IsLineString);
566 
Cast(EcmaString * str)567     static LineEcmaString *Cast(EcmaString *str)
568     {
569         return static_cast<LineEcmaString *>(str);
570     }
571 
Cast(const EcmaString * str)572     static LineEcmaString *Cast(const EcmaString *str)
573     {
574         return LineEcmaString::Cast(const_cast<EcmaString *>(str));
575     }
576 
ComputeSizeUtf8(uint32_t utf8Len)577     static size_t ComputeSizeUtf8(uint32_t utf8Len)
578     {
579         return DATA_OFFSET + utf8Len;
580     }
581 
ComputeSizeUtf16(uint32_t utf16Len)582     static size_t ComputeSizeUtf16(uint32_t utf16Len)
583     {
584         return DATA_OFFSET + utf16Len * sizeof(uint16_t);
585     }
586 
ObjectSize(EcmaString * str)587     static size_t ObjectSize(EcmaString *str)
588     {
589         uint32_t length = str->GetLength();
590         return str->IsUtf16() ? ComputeSizeUtf16(length) : ComputeSizeUtf8(length);
591     }
592 
GetData()593     uint16_t *GetData() const
594     {
595         return reinterpret_cast<uint16_t *>(ToUintPtr(this) + DATA_OFFSET);
596     }
597 
598     template<bool verify = true>
Get(int32_t index)599     uint16_t Get(int32_t index) const
600     {
601         int32_t length = static_cast<int32_t>(GetLength());
602         if (verify) {
603             if ((index < 0) || (index >= length)) {
604                 return 0;
605             }
606         }
607         if (!IsUtf16()) {
608             Span<const uint8_t> sp(GetDataUtf8(), length);
609             return sp[index];
610         }
611         Span<const uint16_t> sp(GetDataUtf16(), length);
612         return sp[index];
613     }
614 
Set(uint32_t index,uint16_t src)615     void Set(uint32_t index, uint16_t src)
616     {
617         ASSERT(index < GetLength());
618         if (IsUtf8()) {
619             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
620             *(reinterpret_cast<uint8_t *>(GetData()) + index) = static_cast<uint8_t>(src);
621         } else {
622             // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
623             *(GetData() + index) = src;
624         }
625     }
626 };
627 static_assert((LineEcmaString::DATA_OFFSET % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0);
628 
629 class ConstantString : public EcmaString {
630 public:
631     static constexpr size_t ENTITY_ID_OFFSET = EcmaString::SIZE;
632     // ConstantData is the pointer of const string in the pandafile.
633     // String in pandafile is encoded by the utf8 format.
634     ACCESSORS_PRIMITIVE_FIELD(EntityId, uint32_t, ENTITY_ID_OFFSET, CONSTANT_DATA_OFFSET);
635     ACCESSORS_NATIVE_FIELD(ConstantData, uint8_t, CONSTANT_DATA_OFFSET, SIZE);
636 
637     CAST_CHECK(ConstantString, IsConstantString);
638 
Cast(EcmaString * str)639     static ConstantString *Cast(EcmaString *str)
640     {
641         return static_cast<ConstantString *>(str);
642     }
643 
Cast(const EcmaString * str)644     static ConstantString *Cast(const EcmaString *str)
645     {
646         return ConstantString::Cast(const_cast<EcmaString *>(str));
647     }
648 
ObjectSize()649     static size_t ObjectSize()
650     {
651         return ConstantString::SIZE;
652     }
653 
654     template<bool verify = true>
Get(int32_t index)655     uint16_t Get(int32_t index) const
656     {
657         int32_t length = static_cast<int32_t>(GetLength());
658         if (verify) {
659             if ((index < 0) || (index >= length)) {
660                 return 0;
661             }
662         }
663         ASSERT(IsUtf8());
664         Span<const uint8_t> sp(GetConstantData(), length);
665         return sp[index];
666     }
667 };
668 
669 class TreeEcmaString : public EcmaString {
670 public:
671     // Minimum length for a tree string
672     static constexpr uint32_t MIN_TREE_ECMASTRING_LENGTH = 13;
673 
674     static constexpr size_t FIRST_OFFSET = EcmaString::SIZE;
675     ACCESSORS(First, FIRST_OFFSET, SECOND_OFFSET);
676     ACCESSORS(Second, SECOND_OFFSET, SIZE);
677 
678     DECL_VISIT_OBJECT(FIRST_OFFSET, SIZE);
679 
680     CAST_CHECK(TreeEcmaString, IsTreeString);
681 
Cast(EcmaString * str)682     static TreeEcmaString *Cast(EcmaString *str)
683     {
684         return static_cast<TreeEcmaString *>(str);
685     }
686 
Cast(const EcmaString * str)687     static TreeEcmaString *Cast(const EcmaString *str)
688     {
689         return TreeEcmaString::Cast(const_cast<EcmaString *>(str));
690     }
691 
IsFlat()692     bool IsFlat() const
693     {
694         auto strSecond = EcmaString::Cast(GetSecond());
695         return strSecond->GetLength() == 0;
696     }
697 
698     template<bool verify = true>
Get(int32_t index)699     uint16_t Get(int32_t index) const
700     {
701         int32_t length = static_cast<int32_t>(GetLength());
702         if (verify) {
703             if ((index < 0) || (index >= length)) {
704                 return 0;
705             }
706         }
707 
708         if (IsFlat()) {
709             EcmaString *first = EcmaString::Cast(GetFirst());
710             return first->At<verify>(index);
711         }
712         EcmaString *string = const_cast<TreeEcmaString *>(this);
713         while (true) {
714             if (string->IsTreeString()) {
715                 EcmaString *first = EcmaString::Cast(TreeEcmaString::Cast(string)->GetFirst());
716                 if (static_cast<int32_t>(first->GetLength()) > index) {
717                     string = first;
718                 } else {
719                     index -= static_cast<int32_t>(first->GetLength());
720                     string = EcmaString::Cast(TreeEcmaString::Cast(string)->GetSecond());
721                 }
722             } else {
723                 return string->At<verify>(index);
724             }
725         }
726         UNREACHABLE();
727         }
728 };
729 
730 // if you want to use functions of EcmaString, please not use directly,
731 // and use functions of EcmaStringAccessor alternatively.
732 // eg: EcmaString *str = ***; str->GetLength() ----->  EcmaStringAccessor(str).GetLength()
733 class PUBLIC_API EcmaStringAccessor {
734 public:
735     explicit EcmaStringAccessor(EcmaString *string);
736 
737     explicit EcmaStringAccessor(TaggedObject *obj);
738 
739     explicit EcmaStringAccessor(JSTaggedValue value);
740 
741     explicit EcmaStringAccessor(const JSHandle<EcmaString> &strHandle);
742 
CreateLineString(const EcmaVM * vm,size_t length,bool compressed)743     static EcmaString *CreateLineString(const EcmaVM *vm, size_t length, bool compressed)
744     {
745         return EcmaString::CreateLineString(vm, length, compressed);
746     }
747 
CreateEmptyString(const EcmaVM * vm)748     static EcmaString *CreateEmptyString(const EcmaVM *vm)
749     {
750         return EcmaString::CreateEmptyString(vm);
751     }
752 
753     static EcmaString *CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress,
754                                       MemSpaceType type = MemSpaceType::SEMI_SPACE, bool isConstantString = false,
755                                       uint32_t idOffset = 0)
756     {
757         return EcmaString::CreateFromUtf8(vm, utf8Data, utf8Len, canBeCompress, type, isConstantString, idOffset);
758     }
759 
760     static EcmaString *CreateConstantString(const EcmaVM *vm, const uint8_t *utf8Data, size_t length,
761         bool compressed, MemSpaceType type = MemSpaceType::SEMI_SPACE, uint32_t idOffset = 0)
762     {
763         return EcmaString::CreateConstantString(vm, utf8Data, length, compressed, type, idOffset);
764     }
765 
766     static EcmaString *CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len,
767                                        bool canBeCompress, MemSpaceType type = MemSpaceType::SEMI_SPACE)
768     {
769         return EcmaString::CreateFromUtf16(vm, utf16Data, utf16Len, canBeCompress, type);
770     }
771 
772     static EcmaString *Concat(const EcmaVM *vm, const JSHandle<EcmaString> &str1Handle,
773         const JSHandle<EcmaString> &str2Handle, MemSpaceType type = MemSpaceType::SEMI_SPACE)
774     {
775         return EcmaString::Concat(vm, str1Handle, str2Handle, type);
776     }
777 
CopyStringToOldSpace(const EcmaVM * vm,const JSHandle<EcmaString> & original,uint32_t length,bool compressed)778     static EcmaString *CopyStringToOldSpace(const EcmaVM *vm, const JSHandle<EcmaString> &original,
779         uint32_t length, bool compressed)
780     {
781         return EcmaString::CopyStringToOldSpace(vm, original, length, compressed);
782     }
783 
784     // can change src data structure
FastSubString(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)785     static EcmaString *FastSubString(const EcmaVM *vm,
786         const JSHandle<EcmaString> &src, uint32_t start, uint32_t length)
787     {
788         return EcmaString::FastSubString(vm, src, start, length);
789     }
790 
IsUtf8()791     bool IsUtf8() const
792     {
793         return string_->IsUtf8();
794     }
795 
IsUtf16()796     bool IsUtf16() const
797     {
798         return string_->IsUtf16();
799     }
800 
GetLength()801     uint32_t GetLength() const
802     {
803         return string_->GetLength();
804     }
805 
806     // require is LineString
807     inline size_t GetUtf8Length() const;
808 
ObjectSize()809     size_t ObjectSize() const
810     {
811         if (string_->IsLineString()) {
812             return LineEcmaString::ObjectSize(string_);
813         } if (string_->IsConstantString()) {
814             return ConstantString::ObjectSize();
815         } else {
816             return TreeEcmaString::SIZE;
817         }
818     }
819 
820     // For TreeString, the calculation result is size of LineString correspondingly.
GetFlatStringSize()821     size_t GetFlatStringSize() const
822     {
823         if (string_->IsConstantString()) {
824             return ConstantString::ObjectSize();
825         }
826         return LineEcmaString::ObjectSize(string_);
827     }
828 
IsInternString()829     bool IsInternString() const
830     {
831         return string_->IsInternString();
832     }
833 
SetInternString()834     void SetInternString()
835     {
836         string_->SetIsInternString();
837     }
838 
ClearInternString()839     void ClearInternString()
840     {
841         string_->ClearInternStringFlag();
842     }
843 
844     // require is LineString
845     // It's Utf8 format, but without 0 in the end.
846     inline const uint8_t *GetDataUtf8();
847 
848     // require is LineString
849     inline const uint16_t *GetDataUtf16();
850 
851     // not change string data structure.
852     // if string is not flat, this func has low efficiency.
853     std::u16string ToU16String(uint32_t len = 0)
854     {
855         return string_->ToU16String(len);
856     }
857 
858     // not change string data structure.
859     // if string is not flat, this func has low efficiency.
ToOneByteDataForced()860     std::unique_ptr<uint8_t[]> ToOneByteDataForced()
861     {
862         return string_->ToOneByteDataForced();
863     }
864 
865     // not change string data structure.
866     // if string is not flat, this func has low efficiency.
ToUtf8Span(CVector<uint8_t> & buf)867     Span<const uint8_t> ToUtf8Span(CVector<uint8_t> &buf)
868     {
869         return string_->ToUtf8Span(buf);
870     }
871 
872     // not change string data structure.
873     // if string is not flat, this func has low efficiency.
874     std::string ToStdString(StringConvertedUsage usage = StringConvertedUsage::PRINT);
875 
876     // not change string data structure.
877     // if string is not flat, this func has low efficiency.
878     CString ToCString(StringConvertedUsage usage = StringConvertedUsage::LOGICOPERATION);
879 
880     // not change string data structure.
881     // if string is not flat, this func has low efficiency.
882     uint32_t WriteToFlatUtf8(uint8_t *buf, uint32_t maxLength, bool isWriteBuffer = false)
883     {
884         return string_->WriteUtf8(buf, maxLength, isWriteBuffer);
885     }
886 
WriteToUtf16(uint16_t * buf,uint32_t bufLength)887     uint32_t WriteToUtf16(uint16_t *buf, uint32_t bufLength)
888     {
889         return string_->WriteUtf16(buf, GetLength(), bufLength);
890     }
891 
WriteToOneByte(uint8_t * buf,uint32_t maxLength)892     uint32_t WriteToOneByte(uint8_t *buf, uint32_t maxLength)
893     {
894         return string_->WriteOneByte(buf, maxLength);
895     }
896 
897     // not change string data structure.
898     // if string is not flat, this func has low efficiency.
WriteToFlatUtf16(uint16_t * buf,uint32_t maxLength)899     uint32_t WriteToFlatUtf16(uint16_t *buf, uint32_t maxLength) const
900     {
901         return string_->CopyDataUtf16(buf, maxLength);
902     }
903 
904     // require dst is LineString
905     // not change src data structure.
906     // if src is not flat, this func has low efficiency.
907     inline static void ReadData(EcmaString * dst, EcmaString *src, uint32_t start, uint32_t destSize, uint32_t length);
908 
909     // not change src data structure.
910     // if src is not flat, this func has low efficiency.
911     template<bool verify = true>
Get(uint32_t index)912     uint16_t Get(uint32_t index) const
913     {
914         return string_->At<verify>(index);
915     }
916 
917     // require string is LineString.
Set(uint32_t index,uint16_t src)918     void Set(uint32_t index, uint16_t src)
919     {
920         return string_->WriteData(index, src);
921     }
922 
923     // not change src data structure.
924     // if src is not flat, this func has low efficiency.
GetHashcode()925     uint32_t GetHashcode()
926     {
927         return string_->GetHashcode();
928     }
929 
930     // not change src data structure.
931     // if src is not flat, this func has low efficiency.
ComputeHashcode(uint32_t hashSeed)932     uint32_t ComputeHashcode(uint32_t hashSeed)
933     {
934         return string_->ComputeHashcode(hashSeed);
935     }
936 
ComputeHashcodeUtf8(const uint8_t * utf8Data,size_t utf8Len,bool canBeCompress)937     static uint32_t ComputeHashcodeUtf8(const uint8_t *utf8Data, size_t utf8Len, bool canBeCompress)
938     {
939         return EcmaString::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress);
940     }
941 
ComputeHashcodeUtf16(const uint16_t * utf16Data,uint32_t length)942     static uint32_t ComputeHashcodeUtf16(const uint16_t *utf16Data, uint32_t length)
943     {
944         return EcmaString::ComputeHashcodeUtf16(utf16Data, length);
945     }
946 
947     // can change receiver and search data structure
948     static int32_t IndexOf(const EcmaVM *vm,
949         const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0)
950     {
951         return EcmaString::IndexOf(vm, receiver, search, pos);
952     }
953 
954     // can change receiver and search data structure
955     static int32_t LastIndexOf(const EcmaVM *vm,
956         const JSHandle<EcmaString> &receiver, const JSHandle<EcmaString> &search, int pos = 0)
957     {
958         return EcmaString::LastIndexOf(vm, receiver, search, pos);
959     }
960 
961     // can change receiver and search data structure
Compare(const EcmaVM * vm,const JSHandle<EcmaString> & left,const JSHandle<EcmaString> & right)962     static int32_t Compare(const EcmaVM *vm, const JSHandle<EcmaString>& left, const JSHandle<EcmaString>& right)
963     {
964         return EcmaString::Compare(vm, left, right);
965     }
966 
967     // can change str1 and str2 data structure
StringsAreEqual(const EcmaVM * vm,const JSHandle<EcmaString> & str1,const JSHandle<EcmaString> & str2)968     static bool StringsAreEqual(const EcmaVM *vm, const JSHandle<EcmaString> &str1, const JSHandle<EcmaString> &str2)
969     {
970         return EcmaString::StringsAreEqual(vm, str1, str2);
971     }
972 
973     // not change str1 and str2 data structure.
974     // if str1 or str2 is not flat, this func has low efficiency.
StringsAreEqual(EcmaString * str1,EcmaString * str2)975     static bool StringsAreEqual(EcmaString *str1, EcmaString *str2)
976     {
977         return EcmaString::StringsAreEqual(str1, str2);
978     }
979 
980     // not change str1 and str2 data structure.
981     // if str1 or str2 is not flat, this func has low efficiency.
StringsAreEqualSameUtfEncoding(EcmaString * str1,EcmaString * str2)982     static bool StringsAreEqualSameUtfEncoding(EcmaString *str1, EcmaString *str2)
983     {
984         return EcmaString::StringsAreEqualSameUtfEncoding(str1, str2);
985     }
986 
987     // not change str1 data structure.
988     // if str1 is not flat, this func has low efficiency.
StringsAreEqualUtf8(const EcmaString * str1,const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress)989     static bool StringsAreEqualUtf8(const EcmaString *str1, const uint8_t *utf8Data, uint32_t utf8Len,
990                                     bool canBeCompress)
991     {
992         return EcmaString::StringsAreEqualUtf8(str1, utf8Data, utf8Len, canBeCompress);
993     }
994 
995     // not change str1 data structure.
996     // if str1 is not flat, this func has low efficiency.
StringsAreEqualUtf16(const EcmaString * str1,const uint16_t * utf16Data,uint32_t utf16Len)997     static bool StringsAreEqualUtf16(const EcmaString *str1, const uint16_t *utf16Data, uint32_t utf16Len)
998     {
999         return EcmaString::StringsAreEqualUtf16(str1, utf16Data, utf16Len);
1000     }
1001 
1002     // require str1 and str2 are LineString.
1003     // not change string data structure.
1004     // if string is not flat, this func has low efficiency.
EqualToSplicedString(const EcmaString * str1,const EcmaString * str2)1005     bool EqualToSplicedString(const EcmaString *str1, const EcmaString *str2)
1006     {
1007         return string_->EqualToSplicedString(str1, str2);
1008     }
1009 
CanBeCompressed(const uint8_t * utf8Data,uint32_t utf8Len)1010     static bool CanBeCompressed(const uint8_t *utf8Data, uint32_t utf8Len)
1011     {
1012         return EcmaString::CanBeCompressed(utf8Data, utf8Len);
1013     }
1014 
CanBeCompressed(const uint16_t * utf16Data,uint32_t utf16Len)1015     static bool CanBeCompressed(const uint16_t *utf16Data, uint32_t utf16Len)
1016     {
1017         return EcmaString::CanBeCompressed(utf16Data, utf16Len);
1018     }
1019 
1020     // require string is LineString
CanBeCompressed(const EcmaString * string)1021     static bool CanBeCompressed(const EcmaString *string)
1022     {
1023         return EcmaString::CanBeCompressed(string);
1024     }
1025 
1026     // not change string data structure.
1027     // if string is not flat, this func has low efficiency.
ToElementIndex(uint32_t * index)1028     bool ToElementIndex(uint32_t *index)
1029     {
1030         return string_->ToElementIndex(index);
1031     }
1032 
1033     // not change string data structure.
1034     // if string is not flat, this func has low efficiency.
ToTypedArrayIndex(uint32_t * index)1035     bool ToTypedArrayIndex(uint32_t *index)
1036     {
1037         return string_->ToTypedArrayIndex(index);
1038     }
1039 
ToLower(const EcmaVM * vm,const JSHandle<EcmaString> & src)1040     static EcmaString *ToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src)
1041     {
1042         return EcmaString::ToLower(vm, src);
1043     }
1044 
TryToLower(const EcmaVM * vm,const JSHandle<EcmaString> & src)1045     static EcmaString *TryToLower(const EcmaVM *vm, const JSHandle<EcmaString> &src)
1046     {
1047         return EcmaString::TryToLower(vm, src);
1048     }
1049 
ToUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src)1050     static EcmaString *ToUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src)
1051     {
1052         return EcmaString::ToUpper(vm, src);
1053     }
1054 
ToLocaleLower(const EcmaVM * vm,const JSHandle<EcmaString> & src,const icu::Locale & locale)1055     static EcmaString *ToLocaleLower(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale)
1056     {
1057         return EcmaString::ToLocaleLower(vm, src, locale);
1058     }
1059 
ToLocaleUpper(const EcmaVM * vm,const JSHandle<EcmaString> & src,const icu::Locale & locale)1060     static EcmaString *ToLocaleUpper(const EcmaVM *vm, const JSHandle<EcmaString> &src, const icu::Locale &locale)
1061     {
1062         return EcmaString::ToLocaleUpper(vm, src, locale);
1063     }
1064 
1065     static EcmaString *Trim(const JSThread *thread,
1066         const JSHandle<EcmaString> &src, EcmaString::TrimMode mode = EcmaString::TrimMode::TRIM)
1067     {
1068         return EcmaString::Trim(thread, src, mode);
1069     }
1070 
IsFlat()1071     bool IsFlat() const
1072     {
1073         return string_->IsFlat();
1074     }
1075 
IsLineString()1076     bool IsLineString() const
1077     {
1078         return string_->IsLineString();
1079     }
1080 
IsConstantString()1081     bool IsConstantString() const
1082     {
1083         return string_->IsConstantString();
1084     }
1085 
IsLineOrConstantString()1086     bool IsLineOrConstantString() const
1087     {
1088         return string_->IsLineOrConstantString();
1089     }
1090 
IsTreeString()1091     bool IsTreeString() const
1092     {
1093         return string_->IsTreeString();
1094     }
1095 
1096     static EcmaString *Flatten(const EcmaVM *vm, const JSHandle<EcmaString> &string,
1097         MemSpaceType type = MemSpaceType::SEMI_SPACE)
1098     {
1099         return EcmaString::Flatten(vm, string, type);
1100     }
1101 
1102     static EcmaString *SlowFlatten(const EcmaVM *vm, const JSHandle<TreeEcmaString> &string,
1103         MemSpaceType type = MemSpaceType::SEMI_SPACE)
1104     {
1105         return EcmaString::SlowFlatten(vm, string, type);
1106     }
1107 
FlattenNoGC(const EcmaVM * vm,EcmaString * string)1108     static EcmaString *FlattenNoGC(const EcmaVM *vm, EcmaString *string)
1109     {
1110         return EcmaString::FlattenNoGC(vm, string);
1111     }
1112 
GetUtf8DataFlat(const EcmaString * src,CVector<uint8_t> & buf)1113     static const uint8_t *GetUtf8DataFlat(const EcmaString *src, CVector<uint8_t> &buf)
1114     {
1115         return EcmaString::GetUtf8DataFlat(src, buf);
1116     }
1117 
GetUtf16DataFlat(const EcmaString * src,CVector<uint16_t> & buf)1118     static const uint16_t *GetUtf16DataFlat(const EcmaString *src, CVector<uint16_t> &buf)
1119     {
1120         return EcmaString::GetUtf16DataFlat(src, buf);
1121     }
1122 
1123 private:
1124     EcmaString *string_ {nullptr};
1125 };
1126 }  // namespace ecmascript
1127 }  // namespace panda
1128 #endif  // ECMASCRIPT_STRING_H