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