• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_STRING_INL_H
17 #define ECMASCRIPT_STRING_INL_H
18 
19 #include "ecmascript/ecma_string.h"
20 #include "ecmascript/base/string_helper.h"
21 #include "ecmascript/ecma_vm.h"
22 #include "ecmascript/js_handle.h"
23 #include "ecmascript/js_tagged_value-inl.h"
24 #include "ecmascript/mem/space.h"
25 #include "ecmascript/object_factory-inl.h"
26 #include "ecmascript/debugger/js_debugger_manager.h"
27 
28 namespace panda::ecmascript {
29 /* static */
CreateEmptyString(const EcmaVM * vm)30 inline EcmaString *EcmaString::CreateEmptyString(const EcmaVM *vm)
31 {
32     auto string = vm->GetFactory()->AllocNonMovableLineStringObject(EcmaString::SIZE);
33     string->SetLength(0, true);
34     string->SetRawHashcode(0);
35     return string;
36 }
37 
38 /* static */
CreateFromUtf8(const EcmaVM * vm,const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress,MemSpaceType type,bool isConstantString,uint32_t idOffset)39 inline EcmaString *EcmaString::CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len,
40                                               bool canBeCompress, MemSpaceType type, bool isConstantString,
41                                               uint32_t idOffset)
42 {
43     if (utf8Len == 0) {
44         return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>();
45     }
46     EcmaString *string = nullptr;
47     if (canBeCompress) {
48         if (isConstantString) {
49             string = CreateConstantString(vm, utf8Data, utf8Len, canBeCompress, type, idOffset);
50         } else {
51             string = CreateLineStringWithSpaceType(vm, utf8Len, true, type);
52             ASSERT(string != nullptr);
53             std::copy(utf8Data, utf8Data + utf8Len, string->GetDataUtf8Writable());
54         }
55     } else {
56         auto utf16Len = base::utf_helper::Utf8ToUtf16Size(utf8Data, utf8Len);
57         string = CreateLineStringWithSpaceType(vm, utf16Len, false, type);
58         ASSERT(string != nullptr);
59 
60         [[maybe_unused]] auto len =
61             base::utf_helper::ConvertRegionUtf8ToUtf16(utf8Data, string->GetDataUtf16Writable(), utf8Len, utf16Len);
62         ASSERT(len == utf16Len);
63     }
64 
65     ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!");
66     return string;
67 }
68 
69 /* static */
CreateFromUtf8CompressedSubString(const EcmaVM * vm,const JSHandle<EcmaString> & string,uint32_t offset,uint32_t utf8Len,MemSpaceType type)70 inline EcmaString *EcmaString::CreateFromUtf8CompressedSubString(const EcmaVM *vm, const JSHandle<EcmaString> &string,
71                                                                  uint32_t offset, uint32_t utf8Len, MemSpaceType type)
72 {
73     if (UNLIKELY(utf8Len == 0)) {
74         return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>();
75     }
76     EcmaString *subString = CreateLineStringWithSpaceType(vm, utf8Len, true, type);
77     ASSERT(subString != nullptr);
78 
79     auto *utf8Data = string->GetDataUtf8() + offset;
80     std::copy(utf8Data, utf8Data + utf8Len, subString->GetDataUtf8Writable());
81     ASSERT_PRINT(CanBeCompressed(subString), "String cannot be compressed!");
82     return subString;
83 }
84 
CreateUtf16StringFromUtf8(const EcmaVM * vm,const uint8_t * utf8Data,uint32_t utf16Len,MemSpaceType type)85 inline EcmaString *EcmaString::CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len,
86     MemSpaceType type)
87 {
88     if (utf16Len == 0) {
89         return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>();
90     }
91     auto string = CreateLineStringWithSpaceType(vm, utf16Len, false, type);
92     ASSERT(string != nullptr);
93     auto len = utf::ConvertRegionMUtf8ToUtf16(
94         utf8Data, string->GetDataUtf16Writable(), utf::Mutf8Size(utf8Data), utf16Len, 0);
95     if (len < utf16Len) {
96         string->TrimLineString(vm->GetJSThread(), len);
97     }
98     ASSERT_PRINT(false == CanBeCompressed(string), "Bad input canBeCompress!");
99     return string;
100 }
101 
TrimLineString(const JSThread * thread,uint32_t newLength)102 inline void EcmaString::TrimLineString(const JSThread *thread, uint32_t newLength)
103 {
104     ASSERT(IsLineString());
105     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
106     uint32_t oldLength = GetLength();
107     ASSERT(oldLength > newLength);
108     size_t trimBytes = (oldLength - newLength) * (IsUtf8() ? sizeof(uint8_t) : sizeof(uint16_t));
109     size_t size = IsUtf8() ? LineEcmaString::ComputeSizeUtf8(newLength) : LineEcmaString::ComputeSizeUtf16(newLength);
110     factory->FillFreeObject(ToUintPtr(this) + size, trimBytes, RemoveSlots::YES, ToUintPtr(this));
111     SetLength(newLength, CanBeCompressed(this));
112 }
113 
CreateFromUtf16(const EcmaVM * vm,const uint16_t * utf16Data,uint32_t utf16Len,bool canBeCompress,MemSpaceType type)114 inline EcmaString *EcmaString::CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len,
115                                                bool canBeCompress, MemSpaceType type)
116 {
117     if (utf16Len == 0) {
118         return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>();
119     }
120     auto string = CreateLineStringWithSpaceType(vm, utf16Len, canBeCompress, type);
121     ASSERT(string != nullptr);
122 
123     if (canBeCompress) {
124         CopyChars(string->GetDataUtf8Writable(), utf16Data, utf16Len);
125     } else {
126         uint32_t len = utf16Len * (sizeof(uint16_t) / sizeof(uint8_t));
127         if (memcpy_s(string->GetDataUtf16Writable(), len, utf16Data, len) != EOK) {
128             LOG_FULL(FATAL) << "memcpy_s failed";
129             UNREACHABLE();
130         }
131     }
132 
133     ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!");
134     return string;
135 }
136 
137 /* static */
CreateLineString(const EcmaVM * vm,size_t length,bool compressed)138 inline EcmaString *EcmaString::CreateLineString(const EcmaVM *vm, size_t length, bool compressed)
139 {
140     size_t size = compressed ? LineEcmaString::ComputeSizeUtf8(length) : LineEcmaString::ComputeSizeUtf16(length);
141     auto string = vm->GetFactory()->AllocLineStringObject(size);
142     string->SetLength(length, compressed);
143     string->SetRawHashcode(0);
144     return string;
145 }
146 
147 /* static */
CreateLineStringNoGC(const EcmaVM * vm,size_t length,bool compressed)148 inline EcmaString *EcmaString::CreateLineStringNoGC(const EcmaVM *vm, size_t length, bool compressed)
149 {
150     size_t size = compressed ? LineEcmaString::ComputeSizeUtf8(length) : LineEcmaString::ComputeSizeUtf16(length);
151     size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
152     auto string = vm->GetFactory()->AllocLineStringObjectNoGC(size);
153     string->SetLength(length, compressed);
154     string->SetRawHashcode(0);
155     return string;
156 }
157 
158 /* static */
CreateLineStringWithSpaceType(const EcmaVM * vm,size_t length,bool compressed,MemSpaceType type)159 inline EcmaString *EcmaString::CreateLineStringWithSpaceType(const EcmaVM *vm, size_t length, bool compressed,
160                                                              MemSpaceType type)
161 {
162     ASSERT(IsSMemSpace(type));
163     size_t size = compressed ? LineEcmaString::ComputeSizeUtf8(length) : LineEcmaString::ComputeSizeUtf16(length);
164     EcmaString *string = nullptr;
165     switch (type) {
166         case MemSpaceType::SHARED_OLD_SPACE:
167             string = vm->GetFactory()->AllocOldSpaceLineStringObject(size);
168             break;
169         case MemSpaceType::SHARED_NON_MOVABLE:
170             string = vm->GetFactory()->AllocNonMovableLineStringObject(size);
171             break;
172         case MemSpaceType::SHARED_READ_ONLY_SPACE:
173             string = vm->GetFactory()->AllocReadOnlyLineStringObject(size);
174             break;
175         default:
176             LOG_ECMA(FATAL) << "this branch is unreachable";
177             UNREACHABLE();
178     }
179     string->SetLength(length, compressed);
180     string->SetRawHashcode(0);
181     return string;
182 }
183 
CreateSlicedString(const EcmaVM * vm,MemSpaceType type)184 inline SlicedString *EcmaString::CreateSlicedString(const EcmaVM *vm, MemSpaceType type)
185 {
186     auto slicedString = SlicedString::Cast(vm->GetFactory()->AllocSlicedStringObject(type));
187     slicedString->SetRawHashcode(0);
188     slicedString->SetParent(vm->GetJSThread(), JSTaggedValue::Undefined(), BarrierMode::SKIP_BARRIER);
189     return slicedString;
190 }
191 
CreateConstantString(const EcmaVM * vm,const uint8_t * utf8Data,size_t length,bool compressed,MemSpaceType type,uint32_t idOffset)192 inline EcmaString *EcmaString::CreateConstantString(const EcmaVM *vm, const uint8_t *utf8Data,
193     size_t length, bool compressed, MemSpaceType type, uint32_t idOffset)
194 {
195     ASSERT(IsSMemSpace(type));
196     auto string = ConstantString::Cast(vm->GetFactory()->AllocConstantStringObject(type));
197     auto thread = vm->GetJSThread();
198     string->SetLength(length, compressed);
199     string->SetRawHashcode(0);
200     string->SetConstantData(const_cast<uint8_t *>(utf8Data));
201     // The string might be serialized, the const data will be replaced by index in the panda file.
202     string->SetEntityId(idOffset);
203     string->SetRelocatedData(thread, JSTaggedValue::Undefined(), BarrierMode::SKIP_BARRIER);
204     return string;
205 }
206 
207 /*
208  * In the multi-thread optimization scenario, start the application.
209  * 1.The thread executes until CheckThread () acquires the lock.
210  * 2.At this time, the thread receives the SIGPROF signal, interrupts the current program execution,
211  * and enters the signal processing function.
212  * 3.When CreateTreeString()->GetJSThread()->CheckThread() is executed, the lock cannot be obtained
213  * and the system has to wait, causing a deadlock.
214  * Therefore, if the function is executed during signal processing, the thread ID is directly obtained and
215  * the thread detection is not performed, thereby avoiding deadlock.
216  */
217 
GetDebuggerThread(const EcmaVM * vm,JSThread ** thread)218 inline void GetDebuggerThread(const EcmaVM *vm, JSThread **thread)
219 {
220     if (vm->GetJsDebuggerManager()->GetSignalState()) {
221         *thread = vm->GetJSThreadNoCheck();
222     } else {
223         *thread = vm->GetJSThread();
224     }
225 }
226 
CreateTreeString(const EcmaVM * vm,const JSHandle<EcmaString> & left,const JSHandle<EcmaString> & right,uint32_t length,bool compressed)227 inline EcmaString *EcmaString::CreateTreeString(const EcmaVM *vm,
228     const JSHandle<EcmaString> &left, const JSHandle<EcmaString> &right, uint32_t length, bool compressed)
229 {
230     ECMA_STRING_CHECK_LENGTH_AND_TRHOW(vm, length);
231     JSThread *thread = nullptr;
232     GetDebuggerThread(vm, &thread);
233     auto string = TreeEcmaString::Cast(vm->GetFactory()->AllocTreeStringObject());
234     string->SetLength(length, compressed);
235     string->SetRawHashcode(0);
236     string->SetFirst(thread, left.GetTaggedValue());
237     string->SetSecond(thread, right.GetTaggedValue());
238     return string;
239 }
240 
241 /* static */
FastSubUtf8String(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)242 EcmaString *EcmaString::FastSubUtf8String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
243                                           uint32_t length)
244 {
245     JSHandle<EcmaString> string(vm->GetJSThread(), CreateLineString(vm, length, true));
246     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
247     FlatStringInfo srcFlat = FlattenAllString(vm, src);
248     Span<uint8_t> dst(string->GetDataUtf8Writable(), length);
249     Span<const uint8_t> source(srcFlat.GetDataUtf8() + start, length);
250     EcmaString::MemCopyChars(dst, length, source, length);
251 
252     ASSERT_PRINT(CanBeCompressed(*string), "canBeCompresse does not match the real value!");
253     return *string;
254 }
255 
256 /* static */
FastSubUtf16String(const EcmaVM * vm,const JSHandle<EcmaString> & src,uint32_t start,uint32_t length)257 EcmaString *EcmaString::FastSubUtf16String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start,
258                                            uint32_t length)
259 {
260     FlatStringInfo srcFlat = FlattenAllString(vm, src);
261     bool canBeCompressed = CanBeCompressed(srcFlat.GetDataUtf16() + start, length);
262     JSHandle<EcmaString> string(vm->GetJSThread(), CreateLineString(vm, length, canBeCompressed));
263     // maybe happen GC,so get srcFlat again
264     srcFlat = FlattenAllString(vm, src);
265     if (canBeCompressed) {
266         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
267         CopyChars(string->GetDataUtf8Writable(), srcFlat.GetDataUtf16() + start, length);
268     } else {
269         uint32_t len = length * (sizeof(uint16_t) / sizeof(uint8_t));
270         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
271         Span<uint16_t> dst(string->GetDataUtf16Writable(), length);
272         Span<const uint16_t> source(srcFlat.GetDataUtf16() + start, length);
273         EcmaString::MemCopyChars(dst, len, source, len);
274     }
275     ASSERT_PRINT(canBeCompressed == CanBeCompressed(*string), "canBeCompresse does not match the real value!");
276     return *string;
277 }
278 
GetData()279 inline uint16_t *EcmaString::GetData() const
280 {
281     ASSERT_PRINT(IsLineString(), "EcmaString: Read data from not LineString");
282     return LineEcmaString::Cast(this)->GetData();
283 }
284 
GetDataUtf8()285 inline const uint8_t *EcmaString::GetDataUtf8() const
286 {
287     ASSERT_PRINT(IsUtf8(), "EcmaString: Read data as utf8 for utf16 string");
288     if (IsLineString()) {
289         return reinterpret_cast<uint8_t *>(GetData());
290     }
291     return ConstantString::Cast(this)->GetConstantData();
292 }
293 
GetDataUtf16()294 inline const uint16_t *EcmaString::GetDataUtf16() const
295 {
296     LOG_ECMA_IF(!IsUtf16(), FATAL) << "EcmaString: Read data as utf16 for utf8 string";
297     return GetData();
298 }
299 
GetDataUtf8Writable()300 inline uint8_t *EcmaString::GetDataUtf8Writable()
301 {
302     ASSERT_PRINT(IsUtf8(), "EcmaString: Read data as utf8 for utf16 string");
303     if (IsConstantString()) {
304         return ConstantString::Cast(this)->GetConstantData();
305     }
306     return reinterpret_cast<uint8_t *>(GetData());
307 }
308 
GetDataUtf16Writable()309 inline uint16_t *EcmaString::GetDataUtf16Writable()
310 {
311     LOG_ECMA_IF(!IsUtf16(), FATAL) << "EcmaString: Read data as utf16 for utf8 string";
312     return GetData();
313 }
314 
GetUtf8Length(bool modify,bool isGetBufferSize)315 inline size_t EcmaString::GetUtf8Length(bool modify, bool isGetBufferSize) const
316 {
317     if (!IsUtf16()) {
318         return GetLength() + 1;  // add place for zero in the end
319     }
320     CVector<uint16_t> tmpBuf;
321     const uint16_t *data = GetUtf16DataFlat(this, tmpBuf);
322     return base::utf_helper::Utf16ToUtf8Size(data, GetLength(), modify, isGetBufferSize);
323 }
324 
325 template<bool verify>
At(int32_t index)326 inline uint16_t EcmaString::At(int32_t index) const
327 {
328     int32_t length = static_cast<int32_t>(GetLength());
329     if constexpr (verify) {
330         if ((index < 0) || (index >= length)) {
331             return 0;
332         }
333     }
334     switch (GetStringType()) {
335         case JSType::LINE_STRING:
336             return LineEcmaString::Cast(this)->Get<verify>(index);
337         case JSType::CONSTANT_STRING:
338             return ConstantString::Cast(this)->Get<verify>(index);
339         case JSType::SLICED_STRING:
340             return SlicedString::Cast(this)->Get<verify>(index);
341         case JSType::TREE_STRING:
342             return TreeEcmaString::Cast(this)->Get<verify>(index);
343         default:
344             LOG_ECMA(FATAL) << "this branch is unreachable";
345             UNREACHABLE();
346     }
347 }
348 
FastToUtf8Span()349 inline Span<const uint8_t> EcmaString::FastToUtf8Span() const
350 {
351     uint32_t strLen = GetLength();
352     ASSERT(IsUtf8());
353     const uint8_t *data = GetDataUtf8();
354     return Span<const uint8_t>(data, strLen);
355 }
356 
WriteData(uint32_t index,uint16_t src)357 inline void EcmaString::WriteData(uint32_t index, uint16_t src)
358 {
359     ASSERT(index < GetLength());
360     ASSERT(IsLineString());
361     LineEcmaString::Cast(this)->Set(index, src);
362 }
363 
IsFlat()364 inline bool EcmaString::IsFlat() const
365 {
366     if (!JSTaggedValue(this).IsTreeString()) {
367         return true;
368     }
369     return TreeEcmaString::Cast(this)->IsFlat();
370 }
371 
372 template <typename Char>
WriteToFlat(EcmaString * src,Char * buf,uint32_t maxLength)373 void EcmaString::WriteToFlat(EcmaString *src, Char *buf, uint32_t maxLength)
374 {
375     DISALLOW_GARBAGE_COLLECTION;
376     uint32_t length = src->GetLength();
377     if (length == 0) {
378         return;
379     }
380     while (true) {
381         ASSERT(length <= maxLength && length > 0);
382         ASSERT(length <= src->GetLength());
383         switch (src->GetStringType()) {
384             case JSType::LINE_STRING: {
385                 if (src->IsUtf8()) {
386                     CopyChars(buf, src->GetDataUtf8(), length);
387                 } else {
388                     CopyChars(buf, src->GetDataUtf16(), length);
389                 }
390                 return;
391             }
392             case JSType::CONSTANT_STRING: {
393                 ASSERT(src->IsUtf8());
394                 CopyChars(buf, src->GetDataUtf8(), length);
395                 return;
396             }
397             case JSType::TREE_STRING: {
398                 TreeEcmaString *treeSrc = TreeEcmaString::Cast(src);
399                 EcmaString *first = EcmaString::Cast(treeSrc->GetFirst());
400                 EcmaString *second = EcmaString::Cast(treeSrc->GetSecond());
401                 uint32_t firstLength = first->GetLength();
402                 uint32_t secondLength = second->GetLength();
403                 if (secondLength >= firstLength) {
404                     // second string is longer. So recurse over first.
405                     WriteToFlat(first, buf, maxLength);
406                     if (first == second) {
407                         CopyChars(buf + firstLength, buf, firstLength);
408                         return;
409                     }
410                     buf += firstLength;
411                     maxLength -= firstLength;
412                     src = second;
413                     length -= firstLength;
414                 } else {
415                     // first string is longer.  So recurse over second.
416                     // if src{first:A,second:B} is half flat to {first:A+B,second:empty} by another thread
417                     // but the other thread didn't end, and this thread get  {first:A+B,second:B}
418                     // it may cause write buffer overflower in line 424, buf + firstLength is overflower.
419                     // so use 'length > firstLength' instead of 'secondLength > 0'
420                     if (length > firstLength) {
421                         if (secondLength == 1) {
422                             buf[firstLength] = static_cast<Char>(second->At<false>(0));
423                         } else if ((second->IsLineOrConstantString()) && second->IsUtf8()) {
424                             CopyChars(buf + firstLength, second->GetDataUtf8(), secondLength);
425                         } else {
426                             WriteToFlat(second, buf + firstLength, maxLength - firstLength);
427                         }
428                         length -= secondLength;
429                     }
430                     maxLength = firstLength;
431                     src = first;
432                 }
433                 continue;
434             }
435             case JSType::SLICED_STRING: {
436                 EcmaString *parent = EcmaString::Cast(SlicedString::Cast(src)->GetParent());
437                 if (src->IsUtf8()) {
438                     CopyChars(buf, parent->GetDataUtf8() + SlicedString::Cast(src)->GetStartIndex(), length);
439                 } else {
440                     CopyChars(buf, parent->GetDataUtf16() + SlicedString::Cast(src)->GetStartIndex(), length);
441                 }
442                 return;
443             }
444             default:
445                 LOG_ECMA(FATAL) << "this branch is unreachable";
446                 UNREACHABLE();
447         }
448     }
449 }
450 
451 template <typename Char>
WriteToFlatWithPos(EcmaString * src,Char * buf,uint32_t length,uint32_t pos)452 void EcmaString::WriteToFlatWithPos(EcmaString *src, Char *buf, uint32_t length, uint32_t pos)
453 {
454     DISALLOW_GARBAGE_COLLECTION;
455     [[ maybe_unused ]] uint32_t maxLength = src->GetLength();
456     if (length == 0) {
457         return;
458     }
459     while (true) {
460         ASSERT(length + pos <= maxLength && length > 0);
461         ASSERT(length <= src->GetLength());
462         ASSERT(pos >= 0);
463         switch (src->GetStringType()) {
464             case JSType::LINE_STRING: {
465                 if (src->IsUtf8()) {
466                     CopyChars(buf, src->GetDataUtf8() + pos, length);
467                 } else {
468                     CopyChars(buf, src->GetDataUtf16() + pos, length);
469                 }
470                 return;
471             }
472             case JSType::CONSTANT_STRING: {
473                 ASSERT(src->IsUtf8());
474                 CopyChars(buf, src->GetDataUtf8() + pos, length);
475                 return;
476             }
477             case JSType::TREE_STRING: {
478                 TreeEcmaString *treeSrc = TreeEcmaString::Cast(src);
479                 EcmaString *first = EcmaString::Cast(treeSrc->GetFirst());
480                 ASSERT(first->IsLineString());
481                 src = first;
482                 continue;
483             }
484             case JSType::SLICED_STRING: {
485                 EcmaString *parent = EcmaString::Cast(SlicedString::Cast(src)->GetParent());
486                 if (src->IsUtf8()) {
487                     CopyChars(buf, parent->GetDataUtf8() + SlicedString::Cast(src)->GetStartIndex() + pos, length);
488                 } else {
489                     CopyChars(buf, parent->GetDataUtf16() + SlicedString::Cast(src)->GetStartIndex() + pos, length);
490                 }
491                 return;
492             }
493             default:
494                 LOG_ECMA(FATAL) << "this branch is unreachable";
495                 UNREACHABLE();
496         }
497     }
498 }
499 
GetDataUtf8()500 inline const uint8_t *FlatStringInfo::GetDataUtf8() const
501 {
502     return string_->GetDataUtf8() + startIndex_;
503 }
504 
GetDataUtf16()505 inline const uint16_t *FlatStringInfo::GetDataUtf16() const
506 {
507     return string_->GetDataUtf16() + startIndex_;
508 }
509 
GetDataUtf8Writable()510 inline uint8_t *FlatStringInfo::GetDataUtf8Writable() const
511 {
512     return string_->GetDataUtf8Writable() + startIndex_;
513 }
514 
GetDataUtf16Writable()515 inline uint16_t *FlatStringInfo::GetDataUtf16Writable() const
516 {
517     return string_->GetDataUtf16Writable() + startIndex_;
518 }
519 
GetDataUtf8()520 inline const uint8_t *EcmaStringAccessor::GetDataUtf8()
521 {
522     return string_->GetDataUtf8();
523 }
524 
GetDataUtf16()525 inline const uint16_t *EcmaStringAccessor::GetDataUtf16()
526 {
527     return string_->GetDataUtf16();
528 }
529 
GetUtf8Length(bool isGetBufferSize)530 inline size_t EcmaStringAccessor::GetUtf8Length(bool isGetBufferSize) const
531 {
532     return string_->GetUtf8Length(true, isGetBufferSize);
533 }
534 
ReadData(EcmaString * dst,EcmaString * src,uint32_t start,uint32_t destSize,uint32_t length)535 inline void EcmaStringAccessor::ReadData(EcmaString *dst, EcmaString *src,
536     uint32_t start, uint32_t destSize, uint32_t length)
537 {
538     dst->WriteData(src, start, destSize, length);
539 }
540 
FastToUtf8Span()541 inline Span<const uint8_t> EcmaStringAccessor::FastToUtf8Span()
542 {
543     return string_->FastToUtf8Span();
544 }
545 }  // namespace panda::ecmascript
546 #endif
547