14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_STRING_INL_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_STRING_INL_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/ecma_string.h" 204514f5e3Sopenharmony_ci#include "ecmascript/base/string_helper.h" 214514f5e3Sopenharmony_ci#include "ecmascript/ecma_vm.h" 224514f5e3Sopenharmony_ci#include "ecmascript/js_handle.h" 234514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value-inl.h" 244514f5e3Sopenharmony_ci#include "ecmascript/mem/space.h" 254514f5e3Sopenharmony_ci#include "ecmascript/object_factory-inl.h" 264514f5e3Sopenharmony_ci#include "ecmascript/debugger/js_debugger_manager.h" 274514f5e3Sopenharmony_ci 284514f5e3Sopenharmony_cinamespace panda::ecmascript { 294514f5e3Sopenharmony_ci/* static */ 304514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateEmptyString(const EcmaVM *vm) 314514f5e3Sopenharmony_ci{ 324514f5e3Sopenharmony_ci auto string = vm->GetFactory()->AllocNonMovableLineStringObject(EcmaString::SIZE); 334514f5e3Sopenharmony_ci string->SetLength(0, true); 344514f5e3Sopenharmony_ci string->SetRawHashcode(0); 354514f5e3Sopenharmony_ci return string; 364514f5e3Sopenharmony_ci} 374514f5e3Sopenharmony_ci 384514f5e3Sopenharmony_ci/* static */ 394514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf8Len, 404514f5e3Sopenharmony_ci bool canBeCompress, MemSpaceType type, bool isConstantString, 414514f5e3Sopenharmony_ci uint32_t idOffset) 424514f5e3Sopenharmony_ci{ 434514f5e3Sopenharmony_ci if (utf8Len == 0) { 444514f5e3Sopenharmony_ci return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>(); 454514f5e3Sopenharmony_ci } 464514f5e3Sopenharmony_ci EcmaString *string = nullptr; 474514f5e3Sopenharmony_ci if (canBeCompress) { 484514f5e3Sopenharmony_ci if (isConstantString) { 494514f5e3Sopenharmony_ci string = CreateConstantString(vm, utf8Data, utf8Len, canBeCompress, type, idOffset); 504514f5e3Sopenharmony_ci } else { 514514f5e3Sopenharmony_ci string = CreateLineStringWithSpaceType(vm, utf8Len, true, type); 524514f5e3Sopenharmony_ci ASSERT(string != nullptr); 534514f5e3Sopenharmony_ci std::copy(utf8Data, utf8Data + utf8Len, string->GetDataUtf8Writable()); 544514f5e3Sopenharmony_ci } 554514f5e3Sopenharmony_ci } else { 564514f5e3Sopenharmony_ci auto utf16Len = base::utf_helper::Utf8ToUtf16Size(utf8Data, utf8Len); 574514f5e3Sopenharmony_ci string = CreateLineStringWithSpaceType(vm, utf16Len, false, type); 584514f5e3Sopenharmony_ci ASSERT(string != nullptr); 594514f5e3Sopenharmony_ci 604514f5e3Sopenharmony_ci [[maybe_unused]] auto len = 614514f5e3Sopenharmony_ci base::utf_helper::ConvertRegionUtf8ToUtf16(utf8Data, string->GetDataUtf16Writable(), utf8Len, utf16Len); 624514f5e3Sopenharmony_ci ASSERT(len == utf16Len); 634514f5e3Sopenharmony_ci } 644514f5e3Sopenharmony_ci 654514f5e3Sopenharmony_ci ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!"); 664514f5e3Sopenharmony_ci return string; 674514f5e3Sopenharmony_ci} 684514f5e3Sopenharmony_ci 694514f5e3Sopenharmony_ci/* static */ 704514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateFromUtf8CompressedSubString(const EcmaVM *vm, const JSHandle<EcmaString> &string, 714514f5e3Sopenharmony_ci uint32_t offset, uint32_t utf8Len, MemSpaceType type) 724514f5e3Sopenharmony_ci{ 734514f5e3Sopenharmony_ci if (UNLIKELY(utf8Len == 0)) { 744514f5e3Sopenharmony_ci return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>(); 754514f5e3Sopenharmony_ci } 764514f5e3Sopenharmony_ci EcmaString *subString = CreateLineStringWithSpaceType(vm, utf8Len, true, type); 774514f5e3Sopenharmony_ci ASSERT(subString != nullptr); 784514f5e3Sopenharmony_ci 794514f5e3Sopenharmony_ci auto *utf8Data = string->GetDataUtf8() + offset; 804514f5e3Sopenharmony_ci std::copy(utf8Data, utf8Data + utf8Len, subString->GetDataUtf8Writable()); 814514f5e3Sopenharmony_ci ASSERT_PRINT(CanBeCompressed(subString), "String cannot be compressed!"); 824514f5e3Sopenharmony_ci return subString; 834514f5e3Sopenharmony_ci} 844514f5e3Sopenharmony_ci 854514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateUtf16StringFromUtf8(const EcmaVM *vm, const uint8_t *utf8Data, uint32_t utf16Len, 864514f5e3Sopenharmony_ci MemSpaceType type) 874514f5e3Sopenharmony_ci{ 884514f5e3Sopenharmony_ci if (utf16Len == 0) { 894514f5e3Sopenharmony_ci return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>(); 904514f5e3Sopenharmony_ci } 914514f5e3Sopenharmony_ci auto string = CreateLineStringWithSpaceType(vm, utf16Len, false, type); 924514f5e3Sopenharmony_ci ASSERT(string != nullptr); 934514f5e3Sopenharmony_ci auto len = utf::ConvertRegionMUtf8ToUtf16( 944514f5e3Sopenharmony_ci utf8Data, string->GetDataUtf16Writable(), utf::Mutf8Size(utf8Data), utf16Len, 0); 954514f5e3Sopenharmony_ci if (len < utf16Len) { 964514f5e3Sopenharmony_ci string->TrimLineString(vm->GetJSThread(), len); 974514f5e3Sopenharmony_ci } 984514f5e3Sopenharmony_ci ASSERT_PRINT(false == CanBeCompressed(string), "Bad input canBeCompress!"); 994514f5e3Sopenharmony_ci return string; 1004514f5e3Sopenharmony_ci} 1014514f5e3Sopenharmony_ci 1024514f5e3Sopenharmony_ciinline void EcmaString::TrimLineString(const JSThread *thread, uint32_t newLength) 1034514f5e3Sopenharmony_ci{ 1044514f5e3Sopenharmony_ci ASSERT(IsLineString()); 1054514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1064514f5e3Sopenharmony_ci uint32_t oldLength = GetLength(); 1074514f5e3Sopenharmony_ci ASSERT(oldLength > newLength); 1084514f5e3Sopenharmony_ci size_t trimBytes = (oldLength - newLength) * (IsUtf8() ? sizeof(uint8_t) : sizeof(uint16_t)); 1094514f5e3Sopenharmony_ci size_t size = IsUtf8() ? LineEcmaString::ComputeSizeUtf8(newLength) : LineEcmaString::ComputeSizeUtf16(newLength); 1104514f5e3Sopenharmony_ci factory->FillFreeObject(ToUintPtr(this) + size, trimBytes, RemoveSlots::YES, ToUintPtr(this)); 1114514f5e3Sopenharmony_ci SetLength(newLength, CanBeCompressed(this)); 1124514f5e3Sopenharmony_ci} 1134514f5e3Sopenharmony_ci 1144514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateFromUtf16(const EcmaVM *vm, const uint16_t *utf16Data, uint32_t utf16Len, 1154514f5e3Sopenharmony_ci bool canBeCompress, MemSpaceType type) 1164514f5e3Sopenharmony_ci{ 1174514f5e3Sopenharmony_ci if (utf16Len == 0) { 1184514f5e3Sopenharmony_ci return vm->GetFactory()->GetEmptyString().GetObject<EcmaString>(); 1194514f5e3Sopenharmony_ci } 1204514f5e3Sopenharmony_ci auto string = CreateLineStringWithSpaceType(vm, utf16Len, canBeCompress, type); 1214514f5e3Sopenharmony_ci ASSERT(string != nullptr); 1224514f5e3Sopenharmony_ci 1234514f5e3Sopenharmony_ci if (canBeCompress) { 1244514f5e3Sopenharmony_ci CopyChars(string->GetDataUtf8Writable(), utf16Data, utf16Len); 1254514f5e3Sopenharmony_ci } else { 1264514f5e3Sopenharmony_ci uint32_t len = utf16Len * (sizeof(uint16_t) / sizeof(uint8_t)); 1274514f5e3Sopenharmony_ci if (memcpy_s(string->GetDataUtf16Writable(), len, utf16Data, len) != EOK) { 1284514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "memcpy_s failed"; 1294514f5e3Sopenharmony_ci UNREACHABLE(); 1304514f5e3Sopenharmony_ci } 1314514f5e3Sopenharmony_ci } 1324514f5e3Sopenharmony_ci 1334514f5e3Sopenharmony_ci ASSERT_PRINT(canBeCompress == CanBeCompressed(string), "Bad input canBeCompress!"); 1344514f5e3Sopenharmony_ci return string; 1354514f5e3Sopenharmony_ci} 1364514f5e3Sopenharmony_ci 1374514f5e3Sopenharmony_ci/* static */ 1384514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateLineString(const EcmaVM *vm, size_t length, bool compressed) 1394514f5e3Sopenharmony_ci{ 1404514f5e3Sopenharmony_ci size_t size = compressed ? LineEcmaString::ComputeSizeUtf8(length) : LineEcmaString::ComputeSizeUtf16(length); 1414514f5e3Sopenharmony_ci auto string = vm->GetFactory()->AllocLineStringObject(size); 1424514f5e3Sopenharmony_ci string->SetLength(length, compressed); 1434514f5e3Sopenharmony_ci string->SetRawHashcode(0); 1444514f5e3Sopenharmony_ci return string; 1454514f5e3Sopenharmony_ci} 1464514f5e3Sopenharmony_ci 1474514f5e3Sopenharmony_ci/* static */ 1484514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateLineStringNoGC(const EcmaVM *vm, size_t length, bool compressed) 1494514f5e3Sopenharmony_ci{ 1504514f5e3Sopenharmony_ci size_t size = compressed ? LineEcmaString::ComputeSizeUtf8(length) : LineEcmaString::ComputeSizeUtf16(length); 1514514f5e3Sopenharmony_ci size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)); 1524514f5e3Sopenharmony_ci auto string = vm->GetFactory()->AllocLineStringObjectNoGC(size); 1534514f5e3Sopenharmony_ci string->SetLength(length, compressed); 1544514f5e3Sopenharmony_ci string->SetRawHashcode(0); 1554514f5e3Sopenharmony_ci return string; 1564514f5e3Sopenharmony_ci} 1574514f5e3Sopenharmony_ci 1584514f5e3Sopenharmony_ci/* static */ 1594514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateLineStringWithSpaceType(const EcmaVM *vm, size_t length, bool compressed, 1604514f5e3Sopenharmony_ci MemSpaceType type) 1614514f5e3Sopenharmony_ci{ 1624514f5e3Sopenharmony_ci ASSERT(IsSMemSpace(type)); 1634514f5e3Sopenharmony_ci size_t size = compressed ? LineEcmaString::ComputeSizeUtf8(length) : LineEcmaString::ComputeSizeUtf16(length); 1644514f5e3Sopenharmony_ci EcmaString *string = nullptr; 1654514f5e3Sopenharmony_ci switch (type) { 1664514f5e3Sopenharmony_ci case MemSpaceType::SHARED_OLD_SPACE: 1674514f5e3Sopenharmony_ci string = vm->GetFactory()->AllocOldSpaceLineStringObject(size); 1684514f5e3Sopenharmony_ci break; 1694514f5e3Sopenharmony_ci case MemSpaceType::SHARED_NON_MOVABLE: 1704514f5e3Sopenharmony_ci string = vm->GetFactory()->AllocNonMovableLineStringObject(size); 1714514f5e3Sopenharmony_ci break; 1724514f5e3Sopenharmony_ci case MemSpaceType::SHARED_READ_ONLY_SPACE: 1734514f5e3Sopenharmony_ci string = vm->GetFactory()->AllocReadOnlyLineStringObject(size); 1744514f5e3Sopenharmony_ci break; 1754514f5e3Sopenharmony_ci default: 1764514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 1774514f5e3Sopenharmony_ci UNREACHABLE(); 1784514f5e3Sopenharmony_ci } 1794514f5e3Sopenharmony_ci string->SetLength(length, compressed); 1804514f5e3Sopenharmony_ci string->SetRawHashcode(0); 1814514f5e3Sopenharmony_ci return string; 1824514f5e3Sopenharmony_ci} 1834514f5e3Sopenharmony_ci 1844514f5e3Sopenharmony_ciinline SlicedString *EcmaString::CreateSlicedString(const EcmaVM *vm, MemSpaceType type) 1854514f5e3Sopenharmony_ci{ 1864514f5e3Sopenharmony_ci auto slicedString = SlicedString::Cast(vm->GetFactory()->AllocSlicedStringObject(type)); 1874514f5e3Sopenharmony_ci slicedString->SetRawHashcode(0); 1884514f5e3Sopenharmony_ci slicedString->SetParent(vm->GetJSThread(), JSTaggedValue::Undefined(), BarrierMode::SKIP_BARRIER); 1894514f5e3Sopenharmony_ci return slicedString; 1904514f5e3Sopenharmony_ci} 1914514f5e3Sopenharmony_ci 1924514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateConstantString(const EcmaVM *vm, const uint8_t *utf8Data, 1934514f5e3Sopenharmony_ci size_t length, bool compressed, MemSpaceType type, uint32_t idOffset) 1944514f5e3Sopenharmony_ci{ 1954514f5e3Sopenharmony_ci ASSERT(IsSMemSpace(type)); 1964514f5e3Sopenharmony_ci auto string = ConstantString::Cast(vm->GetFactory()->AllocConstantStringObject(type)); 1974514f5e3Sopenharmony_ci auto thread = vm->GetJSThread(); 1984514f5e3Sopenharmony_ci string->SetLength(length, compressed); 1994514f5e3Sopenharmony_ci string->SetRawHashcode(0); 2004514f5e3Sopenharmony_ci string->SetConstantData(const_cast<uint8_t *>(utf8Data)); 2014514f5e3Sopenharmony_ci // The string might be serialized, the const data will be replaced by index in the panda file. 2024514f5e3Sopenharmony_ci string->SetEntityId(idOffset); 2034514f5e3Sopenharmony_ci string->SetRelocatedData(thread, JSTaggedValue::Undefined(), BarrierMode::SKIP_BARRIER); 2044514f5e3Sopenharmony_ci return string; 2054514f5e3Sopenharmony_ci} 2064514f5e3Sopenharmony_ci 2074514f5e3Sopenharmony_ci/* 2084514f5e3Sopenharmony_ci * In the multi-thread optimization scenario, start the application. 2094514f5e3Sopenharmony_ci * 1.The thread executes until CheckThread () acquires the lock. 2104514f5e3Sopenharmony_ci * 2.At this time, the thread receives the SIGPROF signal, interrupts the current program execution, 2114514f5e3Sopenharmony_ci * and enters the signal processing function. 2124514f5e3Sopenharmony_ci * 3.When CreateTreeString()->GetJSThread()->CheckThread() is executed, the lock cannot be obtained 2134514f5e3Sopenharmony_ci * and the system has to wait, causing a deadlock. 2144514f5e3Sopenharmony_ci * Therefore, if the function is executed during signal processing, the thread ID is directly obtained and 2154514f5e3Sopenharmony_ci * the thread detection is not performed, thereby avoiding deadlock. 2164514f5e3Sopenharmony_ci */ 2174514f5e3Sopenharmony_ci 2184514f5e3Sopenharmony_ciinline void GetDebuggerThread(const EcmaVM *vm, JSThread **thread) 2194514f5e3Sopenharmony_ci{ 2204514f5e3Sopenharmony_ci if (vm->GetJsDebuggerManager()->GetSignalState()) { 2214514f5e3Sopenharmony_ci *thread = vm->GetJSThreadNoCheck(); 2224514f5e3Sopenharmony_ci } else { 2234514f5e3Sopenharmony_ci *thread = vm->GetJSThread(); 2244514f5e3Sopenharmony_ci } 2254514f5e3Sopenharmony_ci} 2264514f5e3Sopenharmony_ci 2274514f5e3Sopenharmony_ciinline EcmaString *EcmaString::CreateTreeString(const EcmaVM *vm, 2284514f5e3Sopenharmony_ci const JSHandle<EcmaString> &left, const JSHandle<EcmaString> &right, uint32_t length, bool compressed) 2294514f5e3Sopenharmony_ci{ 2304514f5e3Sopenharmony_ci ECMA_STRING_CHECK_LENGTH_AND_TRHOW(vm, length); 2314514f5e3Sopenharmony_ci JSThread *thread = nullptr; 2324514f5e3Sopenharmony_ci GetDebuggerThread(vm, &thread); 2334514f5e3Sopenharmony_ci auto string = TreeEcmaString::Cast(vm->GetFactory()->AllocTreeStringObject()); 2344514f5e3Sopenharmony_ci string->SetLength(length, compressed); 2354514f5e3Sopenharmony_ci string->SetRawHashcode(0); 2364514f5e3Sopenharmony_ci string->SetFirst(thread, left.GetTaggedValue()); 2374514f5e3Sopenharmony_ci string->SetSecond(thread, right.GetTaggedValue()); 2384514f5e3Sopenharmony_ci return string; 2394514f5e3Sopenharmony_ci} 2404514f5e3Sopenharmony_ci 2414514f5e3Sopenharmony_ci/* static */ 2424514f5e3Sopenharmony_ciEcmaString *EcmaString::FastSubUtf8String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start, 2434514f5e3Sopenharmony_ci uint32_t length) 2444514f5e3Sopenharmony_ci{ 2454514f5e3Sopenharmony_ci JSHandle<EcmaString> string(vm->GetJSThread(), CreateLineString(vm, length, true)); 2464514f5e3Sopenharmony_ci // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 2474514f5e3Sopenharmony_ci FlatStringInfo srcFlat = FlattenAllString(vm, src); 2484514f5e3Sopenharmony_ci Span<uint8_t> dst(string->GetDataUtf8Writable(), length); 2494514f5e3Sopenharmony_ci Span<const uint8_t> source(srcFlat.GetDataUtf8() + start, length); 2504514f5e3Sopenharmony_ci EcmaString::MemCopyChars(dst, length, source, length); 2514514f5e3Sopenharmony_ci 2524514f5e3Sopenharmony_ci ASSERT_PRINT(CanBeCompressed(*string), "canBeCompresse does not match the real value!"); 2534514f5e3Sopenharmony_ci return *string; 2544514f5e3Sopenharmony_ci} 2554514f5e3Sopenharmony_ci 2564514f5e3Sopenharmony_ci/* static */ 2574514f5e3Sopenharmony_ciEcmaString *EcmaString::FastSubUtf16String(const EcmaVM *vm, const JSHandle<EcmaString> &src, uint32_t start, 2584514f5e3Sopenharmony_ci uint32_t length) 2594514f5e3Sopenharmony_ci{ 2604514f5e3Sopenharmony_ci FlatStringInfo srcFlat = FlattenAllString(vm, src); 2614514f5e3Sopenharmony_ci bool canBeCompressed = CanBeCompressed(srcFlat.GetDataUtf16() + start, length); 2624514f5e3Sopenharmony_ci JSHandle<EcmaString> string(vm->GetJSThread(), CreateLineString(vm, length, canBeCompressed)); 2634514f5e3Sopenharmony_ci // maybe happen GC,so get srcFlat again 2644514f5e3Sopenharmony_ci srcFlat = FlattenAllString(vm, src); 2654514f5e3Sopenharmony_ci if (canBeCompressed) { 2664514f5e3Sopenharmony_ci // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 2674514f5e3Sopenharmony_ci CopyChars(string->GetDataUtf8Writable(), srcFlat.GetDataUtf16() + start, length); 2684514f5e3Sopenharmony_ci } else { 2694514f5e3Sopenharmony_ci uint32_t len = length * (sizeof(uint16_t) / sizeof(uint8_t)); 2704514f5e3Sopenharmony_ci // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 2714514f5e3Sopenharmony_ci Span<uint16_t> dst(string->GetDataUtf16Writable(), length); 2724514f5e3Sopenharmony_ci Span<const uint16_t> source(srcFlat.GetDataUtf16() + start, length); 2734514f5e3Sopenharmony_ci EcmaString::MemCopyChars(dst, len, source, len); 2744514f5e3Sopenharmony_ci } 2754514f5e3Sopenharmony_ci ASSERT_PRINT(canBeCompressed == CanBeCompressed(*string), "canBeCompresse does not match the real value!"); 2764514f5e3Sopenharmony_ci return *string; 2774514f5e3Sopenharmony_ci} 2784514f5e3Sopenharmony_ci 2794514f5e3Sopenharmony_ciinline uint16_t *EcmaString::GetData() const 2804514f5e3Sopenharmony_ci{ 2814514f5e3Sopenharmony_ci ASSERT_PRINT(IsLineString(), "EcmaString: Read data from not LineString"); 2824514f5e3Sopenharmony_ci return LineEcmaString::Cast(this)->GetData(); 2834514f5e3Sopenharmony_ci} 2844514f5e3Sopenharmony_ci 2854514f5e3Sopenharmony_ciinline const uint8_t *EcmaString::GetDataUtf8() const 2864514f5e3Sopenharmony_ci{ 2874514f5e3Sopenharmony_ci ASSERT_PRINT(IsUtf8(), "EcmaString: Read data as utf8 for utf16 string"); 2884514f5e3Sopenharmony_ci if (IsLineString()) { 2894514f5e3Sopenharmony_ci return reinterpret_cast<uint8_t *>(GetData()); 2904514f5e3Sopenharmony_ci } 2914514f5e3Sopenharmony_ci return ConstantString::Cast(this)->GetConstantData(); 2924514f5e3Sopenharmony_ci} 2934514f5e3Sopenharmony_ci 2944514f5e3Sopenharmony_ciinline const uint16_t *EcmaString::GetDataUtf16() const 2954514f5e3Sopenharmony_ci{ 2964514f5e3Sopenharmony_ci LOG_ECMA_IF(!IsUtf16(), FATAL) << "EcmaString: Read data as utf16 for utf8 string"; 2974514f5e3Sopenharmony_ci return GetData(); 2984514f5e3Sopenharmony_ci} 2994514f5e3Sopenharmony_ci 3004514f5e3Sopenharmony_ciinline uint8_t *EcmaString::GetDataUtf8Writable() 3014514f5e3Sopenharmony_ci{ 3024514f5e3Sopenharmony_ci ASSERT_PRINT(IsUtf8(), "EcmaString: Read data as utf8 for utf16 string"); 3034514f5e3Sopenharmony_ci if (IsConstantString()) { 3044514f5e3Sopenharmony_ci return ConstantString::Cast(this)->GetConstantData(); 3054514f5e3Sopenharmony_ci } 3064514f5e3Sopenharmony_ci return reinterpret_cast<uint8_t *>(GetData()); 3074514f5e3Sopenharmony_ci} 3084514f5e3Sopenharmony_ci 3094514f5e3Sopenharmony_ciinline uint16_t *EcmaString::GetDataUtf16Writable() 3104514f5e3Sopenharmony_ci{ 3114514f5e3Sopenharmony_ci LOG_ECMA_IF(!IsUtf16(), FATAL) << "EcmaString: Read data as utf16 for utf8 string"; 3124514f5e3Sopenharmony_ci return GetData(); 3134514f5e3Sopenharmony_ci} 3144514f5e3Sopenharmony_ci 3154514f5e3Sopenharmony_ciinline size_t EcmaString::GetUtf8Length(bool modify, bool isGetBufferSize) const 3164514f5e3Sopenharmony_ci{ 3174514f5e3Sopenharmony_ci if (!IsUtf16()) { 3184514f5e3Sopenharmony_ci return GetLength() + 1; // add place for zero in the end 3194514f5e3Sopenharmony_ci } 3204514f5e3Sopenharmony_ci CVector<uint16_t> tmpBuf; 3214514f5e3Sopenharmony_ci const uint16_t *data = GetUtf16DataFlat(this, tmpBuf); 3224514f5e3Sopenharmony_ci return base::utf_helper::Utf16ToUtf8Size(data, GetLength(), modify, isGetBufferSize); 3234514f5e3Sopenharmony_ci} 3244514f5e3Sopenharmony_ci 3254514f5e3Sopenharmony_citemplate<bool verify> 3264514f5e3Sopenharmony_ciinline uint16_t EcmaString::At(int32_t index) const 3274514f5e3Sopenharmony_ci{ 3284514f5e3Sopenharmony_ci int32_t length = static_cast<int32_t>(GetLength()); 3294514f5e3Sopenharmony_ci if constexpr (verify) { 3304514f5e3Sopenharmony_ci if ((index < 0) || (index >= length)) { 3314514f5e3Sopenharmony_ci return 0; 3324514f5e3Sopenharmony_ci } 3334514f5e3Sopenharmony_ci } 3344514f5e3Sopenharmony_ci switch (GetStringType()) { 3354514f5e3Sopenharmony_ci case JSType::LINE_STRING: 3364514f5e3Sopenharmony_ci return LineEcmaString::Cast(this)->Get<verify>(index); 3374514f5e3Sopenharmony_ci case JSType::CONSTANT_STRING: 3384514f5e3Sopenharmony_ci return ConstantString::Cast(this)->Get<verify>(index); 3394514f5e3Sopenharmony_ci case JSType::SLICED_STRING: 3404514f5e3Sopenharmony_ci return SlicedString::Cast(this)->Get<verify>(index); 3414514f5e3Sopenharmony_ci case JSType::TREE_STRING: 3424514f5e3Sopenharmony_ci return TreeEcmaString::Cast(this)->Get<verify>(index); 3434514f5e3Sopenharmony_ci default: 3444514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 3454514f5e3Sopenharmony_ci UNREACHABLE(); 3464514f5e3Sopenharmony_ci } 3474514f5e3Sopenharmony_ci} 3484514f5e3Sopenharmony_ci 3494514f5e3Sopenharmony_ciinline Span<const uint8_t> EcmaString::FastToUtf8Span() const 3504514f5e3Sopenharmony_ci{ 3514514f5e3Sopenharmony_ci uint32_t strLen = GetLength(); 3524514f5e3Sopenharmony_ci ASSERT(IsUtf8()); 3534514f5e3Sopenharmony_ci const uint8_t *data = GetDataUtf8(); 3544514f5e3Sopenharmony_ci return Span<const uint8_t>(data, strLen); 3554514f5e3Sopenharmony_ci} 3564514f5e3Sopenharmony_ci 3574514f5e3Sopenharmony_ciinline void EcmaString::WriteData(uint32_t index, uint16_t src) 3584514f5e3Sopenharmony_ci{ 3594514f5e3Sopenharmony_ci ASSERT(index < GetLength()); 3604514f5e3Sopenharmony_ci ASSERT(IsLineString()); 3614514f5e3Sopenharmony_ci LineEcmaString::Cast(this)->Set(index, src); 3624514f5e3Sopenharmony_ci} 3634514f5e3Sopenharmony_ci 3644514f5e3Sopenharmony_ciinline bool EcmaString::IsFlat() const 3654514f5e3Sopenharmony_ci{ 3664514f5e3Sopenharmony_ci if (!JSTaggedValue(this).IsTreeString()) { 3674514f5e3Sopenharmony_ci return true; 3684514f5e3Sopenharmony_ci } 3694514f5e3Sopenharmony_ci return TreeEcmaString::Cast(this)->IsFlat(); 3704514f5e3Sopenharmony_ci} 3714514f5e3Sopenharmony_ci 3724514f5e3Sopenharmony_citemplate <typename Char> 3734514f5e3Sopenharmony_civoid EcmaString::WriteToFlat(EcmaString *src, Char *buf, uint32_t maxLength) 3744514f5e3Sopenharmony_ci{ 3754514f5e3Sopenharmony_ci DISALLOW_GARBAGE_COLLECTION; 3764514f5e3Sopenharmony_ci uint32_t length = src->GetLength(); 3774514f5e3Sopenharmony_ci if (length == 0) { 3784514f5e3Sopenharmony_ci return; 3794514f5e3Sopenharmony_ci } 3804514f5e3Sopenharmony_ci while (true) { 3814514f5e3Sopenharmony_ci ASSERT(length <= maxLength && length > 0); 3824514f5e3Sopenharmony_ci ASSERT(length <= src->GetLength()); 3834514f5e3Sopenharmony_ci switch (src->GetStringType()) { 3844514f5e3Sopenharmony_ci case JSType::LINE_STRING: { 3854514f5e3Sopenharmony_ci if (src->IsUtf8()) { 3864514f5e3Sopenharmony_ci CopyChars(buf, src->GetDataUtf8(), length); 3874514f5e3Sopenharmony_ci } else { 3884514f5e3Sopenharmony_ci CopyChars(buf, src->GetDataUtf16(), length); 3894514f5e3Sopenharmony_ci } 3904514f5e3Sopenharmony_ci return; 3914514f5e3Sopenharmony_ci } 3924514f5e3Sopenharmony_ci case JSType::CONSTANT_STRING: { 3934514f5e3Sopenharmony_ci ASSERT(src->IsUtf8()); 3944514f5e3Sopenharmony_ci CopyChars(buf, src->GetDataUtf8(), length); 3954514f5e3Sopenharmony_ci return; 3964514f5e3Sopenharmony_ci } 3974514f5e3Sopenharmony_ci case JSType::TREE_STRING: { 3984514f5e3Sopenharmony_ci TreeEcmaString *treeSrc = TreeEcmaString::Cast(src); 3994514f5e3Sopenharmony_ci EcmaString *first = EcmaString::Cast(treeSrc->GetFirst()); 4004514f5e3Sopenharmony_ci EcmaString *second = EcmaString::Cast(treeSrc->GetSecond()); 4014514f5e3Sopenharmony_ci uint32_t firstLength = first->GetLength(); 4024514f5e3Sopenharmony_ci uint32_t secondLength = second->GetLength(); 4034514f5e3Sopenharmony_ci if (secondLength >= firstLength) { 4044514f5e3Sopenharmony_ci // second string is longer. So recurse over first. 4054514f5e3Sopenharmony_ci WriteToFlat(first, buf, maxLength); 4064514f5e3Sopenharmony_ci if (first == second) { 4074514f5e3Sopenharmony_ci CopyChars(buf + firstLength, buf, firstLength); 4084514f5e3Sopenharmony_ci return; 4094514f5e3Sopenharmony_ci } 4104514f5e3Sopenharmony_ci buf += firstLength; 4114514f5e3Sopenharmony_ci maxLength -= firstLength; 4124514f5e3Sopenharmony_ci src = second; 4134514f5e3Sopenharmony_ci length -= firstLength; 4144514f5e3Sopenharmony_ci } else { 4154514f5e3Sopenharmony_ci // first string is longer. So recurse over second. 4164514f5e3Sopenharmony_ci if (secondLength > 0) { 4174514f5e3Sopenharmony_ci if (secondLength == 1) { 4184514f5e3Sopenharmony_ci buf[firstLength] = static_cast<Char>(second->At<false>(0)); 4194514f5e3Sopenharmony_ci } else if ((second->IsLineOrConstantString()) && second->IsUtf8()) { 4204514f5e3Sopenharmony_ci CopyChars(buf + firstLength, second->GetDataUtf8(), secondLength); 4214514f5e3Sopenharmony_ci } else { 4224514f5e3Sopenharmony_ci WriteToFlat(second, buf + firstLength, maxLength - firstLength); 4234514f5e3Sopenharmony_ci } 4244514f5e3Sopenharmony_ci } 4254514f5e3Sopenharmony_ci maxLength = firstLength; 4264514f5e3Sopenharmony_ci src = first; 4274514f5e3Sopenharmony_ci length -= secondLength; 4284514f5e3Sopenharmony_ci } 4294514f5e3Sopenharmony_ci continue; 4304514f5e3Sopenharmony_ci } 4314514f5e3Sopenharmony_ci case JSType::SLICED_STRING: { 4324514f5e3Sopenharmony_ci EcmaString *parent = EcmaString::Cast(SlicedString::Cast(src)->GetParent()); 4334514f5e3Sopenharmony_ci if (src->IsUtf8()) { 4344514f5e3Sopenharmony_ci CopyChars(buf, parent->GetDataUtf8() + SlicedString::Cast(src)->GetStartIndex(), length); 4354514f5e3Sopenharmony_ci } else { 4364514f5e3Sopenharmony_ci CopyChars(buf, parent->GetDataUtf16() + SlicedString::Cast(src)->GetStartIndex(), length); 4374514f5e3Sopenharmony_ci } 4384514f5e3Sopenharmony_ci return; 4394514f5e3Sopenharmony_ci } 4404514f5e3Sopenharmony_ci default: 4414514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 4424514f5e3Sopenharmony_ci UNREACHABLE(); 4434514f5e3Sopenharmony_ci } 4444514f5e3Sopenharmony_ci } 4454514f5e3Sopenharmony_ci} 4464514f5e3Sopenharmony_ci 4474514f5e3Sopenharmony_citemplate <typename Char> 4484514f5e3Sopenharmony_civoid EcmaString::WriteToFlatWithPos(EcmaString *src, Char *buf, uint32_t length, uint32_t pos) 4494514f5e3Sopenharmony_ci{ 4504514f5e3Sopenharmony_ci DISALLOW_GARBAGE_COLLECTION; 4514514f5e3Sopenharmony_ci [[ maybe_unused ]] uint32_t maxLength = src->GetLength(); 4524514f5e3Sopenharmony_ci if (length == 0) { 4534514f5e3Sopenharmony_ci return; 4544514f5e3Sopenharmony_ci } 4554514f5e3Sopenharmony_ci while (true) { 4564514f5e3Sopenharmony_ci ASSERT(length + pos <= maxLength && length > 0); 4574514f5e3Sopenharmony_ci ASSERT(length <= src->GetLength()); 4584514f5e3Sopenharmony_ci ASSERT(pos >= 0); 4594514f5e3Sopenharmony_ci switch (src->GetStringType()) { 4604514f5e3Sopenharmony_ci case JSType::LINE_STRING: { 4614514f5e3Sopenharmony_ci if (src->IsUtf8()) { 4624514f5e3Sopenharmony_ci CopyChars(buf, src->GetDataUtf8() + pos, length); 4634514f5e3Sopenharmony_ci } else { 4644514f5e3Sopenharmony_ci CopyChars(buf, src->GetDataUtf16() + pos, length); 4654514f5e3Sopenharmony_ci } 4664514f5e3Sopenharmony_ci return; 4674514f5e3Sopenharmony_ci } 4684514f5e3Sopenharmony_ci case JSType::CONSTANT_STRING: { 4694514f5e3Sopenharmony_ci ASSERT(src->IsUtf8()); 4704514f5e3Sopenharmony_ci CopyChars(buf, src->GetDataUtf8() + pos, length); 4714514f5e3Sopenharmony_ci return; 4724514f5e3Sopenharmony_ci } 4734514f5e3Sopenharmony_ci case JSType::TREE_STRING: { 4744514f5e3Sopenharmony_ci TreeEcmaString *treeSrc = TreeEcmaString::Cast(src); 4754514f5e3Sopenharmony_ci EcmaString *first = EcmaString::Cast(treeSrc->GetFirst()); 4764514f5e3Sopenharmony_ci ASSERT(first->IsLineString()); 4774514f5e3Sopenharmony_ci src = first; 4784514f5e3Sopenharmony_ci continue; 4794514f5e3Sopenharmony_ci } 4804514f5e3Sopenharmony_ci case JSType::SLICED_STRING: { 4814514f5e3Sopenharmony_ci EcmaString *parent = EcmaString::Cast(SlicedString::Cast(src)->GetParent()); 4824514f5e3Sopenharmony_ci if (src->IsUtf8()) { 4834514f5e3Sopenharmony_ci CopyChars(buf, parent->GetDataUtf8() + SlicedString::Cast(src)->GetStartIndex() + pos, length); 4844514f5e3Sopenharmony_ci } else { 4854514f5e3Sopenharmony_ci CopyChars(buf, parent->GetDataUtf16() + SlicedString::Cast(src)->GetStartIndex() + pos, length); 4864514f5e3Sopenharmony_ci } 4874514f5e3Sopenharmony_ci return; 4884514f5e3Sopenharmony_ci } 4894514f5e3Sopenharmony_ci default: 4904514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 4914514f5e3Sopenharmony_ci UNREACHABLE(); 4924514f5e3Sopenharmony_ci } 4934514f5e3Sopenharmony_ci } 4944514f5e3Sopenharmony_ci} 4954514f5e3Sopenharmony_ci 4964514f5e3Sopenharmony_ciinline const uint8_t *FlatStringInfo::GetDataUtf8() const 4974514f5e3Sopenharmony_ci{ 4984514f5e3Sopenharmony_ci return string_->GetDataUtf8() + startIndex_; 4994514f5e3Sopenharmony_ci} 5004514f5e3Sopenharmony_ci 5014514f5e3Sopenharmony_ciinline const uint16_t *FlatStringInfo::GetDataUtf16() const 5024514f5e3Sopenharmony_ci{ 5034514f5e3Sopenharmony_ci return string_->GetDataUtf16() + startIndex_; 5044514f5e3Sopenharmony_ci} 5054514f5e3Sopenharmony_ci 5064514f5e3Sopenharmony_ciinline uint8_t *FlatStringInfo::GetDataUtf8Writable() const 5074514f5e3Sopenharmony_ci{ 5084514f5e3Sopenharmony_ci return string_->GetDataUtf8Writable() + startIndex_; 5094514f5e3Sopenharmony_ci} 5104514f5e3Sopenharmony_ci 5114514f5e3Sopenharmony_ciinline uint16_t *FlatStringInfo::GetDataUtf16Writable() const 5124514f5e3Sopenharmony_ci{ 5134514f5e3Sopenharmony_ci return string_->GetDataUtf16Writable() + startIndex_; 5144514f5e3Sopenharmony_ci} 5154514f5e3Sopenharmony_ci 5164514f5e3Sopenharmony_ciinline const uint8_t *EcmaStringAccessor::GetDataUtf8() 5174514f5e3Sopenharmony_ci{ 5184514f5e3Sopenharmony_ci return string_->GetDataUtf8(); 5194514f5e3Sopenharmony_ci} 5204514f5e3Sopenharmony_ci 5214514f5e3Sopenharmony_ciinline const uint16_t *EcmaStringAccessor::GetDataUtf16() 5224514f5e3Sopenharmony_ci{ 5234514f5e3Sopenharmony_ci return string_->GetDataUtf16(); 5244514f5e3Sopenharmony_ci} 5254514f5e3Sopenharmony_ci 5264514f5e3Sopenharmony_ciinline size_t EcmaStringAccessor::GetUtf8Length(bool isGetBufferSize) const 5274514f5e3Sopenharmony_ci{ 5284514f5e3Sopenharmony_ci return string_->GetUtf8Length(true, isGetBufferSize); 5294514f5e3Sopenharmony_ci} 5304514f5e3Sopenharmony_ci 5314514f5e3Sopenharmony_ciinline void EcmaStringAccessor::ReadData(EcmaString *dst, EcmaString *src, 5324514f5e3Sopenharmony_ci uint32_t start, uint32_t destSize, uint32_t length) 5334514f5e3Sopenharmony_ci{ 5344514f5e3Sopenharmony_ci dst->WriteData(src, start, destSize, length); 5354514f5e3Sopenharmony_ci} 5364514f5e3Sopenharmony_ci 5374514f5e3Sopenharmony_ciinline Span<const uint8_t> EcmaStringAccessor::FastToUtf8Span() 5384514f5e3Sopenharmony_ci{ 5394514f5e3Sopenharmony_ci return string_->FastToUtf8Span(); 5404514f5e3Sopenharmony_ci} 5414514f5e3Sopenharmony_ci} // namespace panda::ecmascript 5424514f5e3Sopenharmony_ci#endif 543