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#include "ecmascript/builtins/builtins_string.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include <algorithm> 194514f5e3Sopenharmony_ci#include <vector> 204514f5e3Sopenharmony_ci#include <map> 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_ci#include "ecmascript/intl/locale_helper.h" 234514f5e3Sopenharmony_ci#include "ecmascript/builtins/builtins_number.h" 244514f5e3Sopenharmony_ci#include "ecmascript/builtins/builtins_regexp.h" 254514f5e3Sopenharmony_ci#include "ecmascript/builtins/builtins_symbol.h" 264514f5e3Sopenharmony_ci#include "ecmascript/interpreter/fast_runtime_stub-inl.h" 274514f5e3Sopenharmony_ci#include "ecmascript/js_primitive_ref.h" 284514f5e3Sopenharmony_ci#include "ecmascript/js_regexp.h" 294514f5e3Sopenharmony_ci#include "ecmascript/js_string_iterator.h" 304514f5e3Sopenharmony_ci#include "ecmascript/property_detector-inl.h" 314514f5e3Sopenharmony_ci#ifdef ARK_SUPPORT_INTL 324514f5e3Sopenharmony_ci#include "ecmascript/js_collator.h" 334514f5e3Sopenharmony_ci#include "ecmascript/js_locale.h" 344514f5e3Sopenharmony_ci#else 354514f5e3Sopenharmony_ci#ifndef ARK_NOT_SUPPORT_INTL_GLOBAL 364514f5e3Sopenharmony_ci#include "ecmascript/intl/global_intl_helper.h" 374514f5e3Sopenharmony_ci#endif 384514f5e3Sopenharmony_ci#endif 394514f5e3Sopenharmony_ci 404514f5e3Sopenharmony_ci#include "unicode/normalizer2.h" 414514f5e3Sopenharmony_ci#include "unicode/normlzr.h" 424514f5e3Sopenharmony_ci#include "unicode/unistr.h" 434514f5e3Sopenharmony_ci 444514f5e3Sopenharmony_cinamespace panda::ecmascript::builtins { 454514f5e3Sopenharmony_ciusing ObjectFactory = ecmascript::ObjectFactory; 464514f5e3Sopenharmony_ciusing JSArray = ecmascript::JSArray; 474514f5e3Sopenharmony_ciconstexpr std::uint16_t CHAR16_LETTER_NULL = u'\0'; 484514f5e3Sopenharmony_ci 494514f5e3Sopenharmony_ci// 21.1.1.1 String(value) 504514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::StringConstructor(EcmaRuntimeCallInfo *argv) 514514f5e3Sopenharmony_ci{ 524514f5e3Sopenharmony_ci ASSERT(argv); 534514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Constructor); 544514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 554514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 564514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 574514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv); 584514f5e3Sopenharmony_ci if (argv->GetArgsNumber() > 0) { 594514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> valTagNew = GetCallArg(argv, 0); 604514f5e3Sopenharmony_ci if (newTarget->IsUndefined() && valTagNew->IsSymbol()) { 614514f5e3Sopenharmony_ci return BuiltinsSymbol::SymbolDescriptiveString(thread, valTagNew.GetTaggedValue()); 624514f5e3Sopenharmony_ci } 634514f5e3Sopenharmony_ci JSHandle<EcmaString> str = JSTaggedValue::ToString(thread, valTagNew); 644514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 654514f5e3Sopenharmony_ci if (newTarget->IsUndefined()) { 664514f5e3Sopenharmony_ci return str.GetTaggedValue(); 674514f5e3Sopenharmony_ci } 684514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> strTag(str); 694514f5e3Sopenharmony_ci return JSPrimitiveRef::StringCreate(thread, strTag, newTarget).GetTaggedValue(); 704514f5e3Sopenharmony_ci } 714514f5e3Sopenharmony_ci JSHandle<EcmaString> val = factory->GetEmptyString(); 724514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> valTag(val); 734514f5e3Sopenharmony_ci if (newTarget->IsUndefined()) { 744514f5e3Sopenharmony_ci return factory->GetEmptyString().GetTaggedValue(); 754514f5e3Sopenharmony_ci } 764514f5e3Sopenharmony_ci return JSPrimitiveRef::StringCreate(thread, valTag, newTarget).GetTaggedValue(); 774514f5e3Sopenharmony_ci} 784514f5e3Sopenharmony_ci 794514f5e3Sopenharmony_ci// 21.1.2.1 804514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::FromCharCode(EcmaRuntimeCallInfo *argv) 814514f5e3Sopenharmony_ci{ 824514f5e3Sopenharmony_ci ASSERT(argv); 834514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, FromCharCode); 844514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 854514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 864514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 874514f5e3Sopenharmony_ci uint32_t argLength = argv->GetArgsNumber(); 884514f5e3Sopenharmony_ci if (argLength == 0) { 894514f5e3Sopenharmony_ci return factory->GetEmptyString().GetTaggedValue(); 904514f5e3Sopenharmony_ci } 914514f5e3Sopenharmony_ci if (argLength == 1) { 924514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> codePointTag = BuiltinsString::GetCallArg(argv, 0); 934514f5e3Sopenharmony_ci uint16_t codePointValue = JSTaggedValue::ToUint16(thread, codePointTag); 944514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 954514f5e3Sopenharmony_ci if (EcmaStringAccessor::CanBeCompressed(&codePointValue, 1)) { 964514f5e3Sopenharmony_ci JSHandle<SingleCharTable> singleCharTable(thread, thread->GetSingleCharTable()); 974514f5e3Sopenharmony_ci return singleCharTable->GetStringFromSingleCharTable(codePointValue); 984514f5e3Sopenharmony_ci } 994514f5e3Sopenharmony_ci JSHandle<EcmaString> strHandle = factory->NewFromUtf16Literal(&codePointValue, 1); 1004514f5e3Sopenharmony_ci return strHandle.GetTaggedValue(); 1014514f5e3Sopenharmony_ci } 1024514f5e3Sopenharmony_ci CVector<uint16_t> valueTable; 1034514f5e3Sopenharmony_ci valueTable.reserve(argLength); 1044514f5e3Sopenharmony_ci for (uint32_t i = 0; i < argLength; i++) { 1054514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> nextCp = BuiltinsString::GetCallArg(argv, i); 1064514f5e3Sopenharmony_ci uint16_t nextCv = JSTaggedValue::ToUint16(thread, nextCp); 1074514f5e3Sopenharmony_ci valueTable.emplace_back(nextCv); 1084514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1094514f5e3Sopenharmony_ci } 1104514f5e3Sopenharmony_ci return factory->NewFromUtf16Literal(valueTable.data(), valueTable.size()).GetTaggedValue(); 1114514f5e3Sopenharmony_ci} 1124514f5e3Sopenharmony_ci 1134514f5e3Sopenharmony_ci// 21.1.2.2 1144514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::FromCodePoint(EcmaRuntimeCallInfo *argv) 1154514f5e3Sopenharmony_ci{ 1164514f5e3Sopenharmony_ci ASSERT(argv); 1174514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, FromCodePoint); 1184514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 1194514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 1204514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1214514f5e3Sopenharmony_ci uint32_t argLength = argv->GetArgsNumber(); 1224514f5e3Sopenharmony_ci if (argLength == 0) { 1234514f5e3Sopenharmony_ci return factory->GetEmptyString().GetTaggedValue(); 1244514f5e3Sopenharmony_ci } 1254514f5e3Sopenharmony_ci std::u16string u16str; 1264514f5e3Sopenharmony_ci uint32_t u16strSize = argLength; 1274514f5e3Sopenharmony_ci for (uint32_t i = 0; i < argLength; i++) { 1284514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> nextCpTag = BuiltinsString::GetCallArg(argv, i); 1294514f5e3Sopenharmony_ci JSTaggedNumber nextCpVal = JSTaggedValue::ToNumber(thread, nextCpTag); 1304514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1314514f5e3Sopenharmony_ci if (!nextCpVal.IsInteger()) { 1324514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "is not integer", JSTaggedValue::Exception()); 1334514f5e3Sopenharmony_ci } 1344514f5e3Sopenharmony_ci int32_t cp = nextCpVal.ToInt32(); 1354514f5e3Sopenharmony_ci if (cp < 0 || cp > ENCODE_MAX_UTF16) { 1364514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "CodePoint < 0 or CodePoint > 0x10FFFF", JSTaggedValue::Exception()); 1374514f5e3Sopenharmony_ci } 1384514f5e3Sopenharmony_ci if (cp > UINT16_MAX) { 1394514f5e3Sopenharmony_ci uint16_t cu1 = 1404514f5e3Sopenharmony_ci std::floor((static_cast<uint32_t>(cp) - ENCODE_SECOND_FACTOR) / ENCODE_FIRST_FACTOR) + ENCODE_LEAD_LOW; 1414514f5e3Sopenharmony_ci uint16_t cu2 = 1424514f5e3Sopenharmony_ci ((static_cast<uint32_t>(cp) - ENCODE_SECOND_FACTOR) % ENCODE_FIRST_FACTOR) + ENCODE_TRAIL_LOW; 1434514f5e3Sopenharmony_ci std::u16string nextU16str1 = base::StringHelper::Utf16ToU16String(&cu1, 1); 1444514f5e3Sopenharmony_ci std::u16string nextU16str2 = base::StringHelper::Utf16ToU16String(&cu2, 1); 1454514f5e3Sopenharmony_ci base::StringHelper::InplaceAppend(u16str, nextU16str1); 1464514f5e3Sopenharmony_ci base::StringHelper::InplaceAppend(u16str, nextU16str2); 1474514f5e3Sopenharmony_ci u16strSize++; 1484514f5e3Sopenharmony_ci } else { 1494514f5e3Sopenharmony_ci auto u16tCp = static_cast<uint16_t>(cp); 1504514f5e3Sopenharmony_ci std::u16string nextU16str = base::StringHelper::Utf16ToU16String(&u16tCp, 1); 1514514f5e3Sopenharmony_ci base::StringHelper::InplaceAppend(u16str, nextU16str); 1524514f5e3Sopenharmony_ci } 1534514f5e3Sopenharmony_ci } 1544514f5e3Sopenharmony_ci const char16_t *constChar16tData = u16str.data(); 1554514f5e3Sopenharmony_ci auto *char16tData = const_cast<char16_t *>(constChar16tData); 1564514f5e3Sopenharmony_ci auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData); 1574514f5e3Sopenharmony_ci return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue(); 1584514f5e3Sopenharmony_ci} 1594514f5e3Sopenharmony_ci 1604514f5e3Sopenharmony_ci// 21.1.2.4 1614514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Raw(EcmaRuntimeCallInfo *argv) 1624514f5e3Sopenharmony_ci{ 1634514f5e3Sopenharmony_ci ASSERT(argv); 1644514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Raw); 1654514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 1664514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 1674514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 1684514f5e3Sopenharmony_ci // Let cooked be ToObject(template). 1694514f5e3Sopenharmony_ci JSHandle<JSObject> cooked = JSTaggedValue::ToObject(thread, BuiltinsString::GetCallArg(argv, 0)); 1704514f5e3Sopenharmony_ci // ReturnIfAbrupt(cooked). 1714514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1724514f5e3Sopenharmony_ci // Let raw be ToObject(Get(cooked, "raw")). 1734514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> rawKey(factory->NewFromASCII("raw")); 1744514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> rawTag = 1754514f5e3Sopenharmony_ci JSObject::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(cooked), rawKey).GetValue(); 1764514f5e3Sopenharmony_ci JSHandle<JSObject> rawObj = JSTaggedValue::ToObject(thread, rawTag); 1774514f5e3Sopenharmony_ci // ReturnIfAbrupt(rawObj). 1784514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1794514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString(); 1804514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> rawLen = 1814514f5e3Sopenharmony_ci JSObject::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(rawObj), lengthKey).GetValue(); 1824514f5e3Sopenharmony_ci // ReturnIfAbrupt(rawLen). 1834514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1844514f5e3Sopenharmony_ci JSTaggedNumber lengthNumber = JSTaggedValue::ToLength(thread, rawLen); 1854514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1864514f5e3Sopenharmony_ci int length = static_cast<int>(lengthNumber.ToUint32()); 1874514f5e3Sopenharmony_ci if (length <= 0) { 1884514f5e3Sopenharmony_ci return factory->GetEmptyString().GetTaggedValue(); 1894514f5e3Sopenharmony_ci } 1904514f5e3Sopenharmony_ci 1914514f5e3Sopenharmony_ci std::u16string u16str; 1924514f5e3Sopenharmony_ci uint32_t argc = argv->GetArgsNumber() - 1; 1934514f5e3Sopenharmony_ci bool canBeCompress = true; 1944514f5e3Sopenharmony_ci for (uint32_t i = 0, argsI = 1; i < static_cast<uint32_t>(length); ++i, ++argsI) { 1954514f5e3Sopenharmony_ci // Let nextSeg be ToString(Get(raw, nextKey)). 1964514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> elementString = 1974514f5e3Sopenharmony_ci JSObject::GetProperty(thread, JSHandle<JSTaggedValue>::Cast(rawObj), i).GetValue(); 1984514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 1994514f5e3Sopenharmony_ci EcmaString *nextSeg = *JSTaggedValue::ToString(thread, elementString); 2004514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2014514f5e3Sopenharmony_ci u16str += EcmaStringAccessor(nextSeg).ToU16String(); 2024514f5e3Sopenharmony_ci if (EcmaStringAccessor(nextSeg).IsUtf16()) { 2034514f5e3Sopenharmony_ci canBeCompress = false; 2044514f5e3Sopenharmony_ci } 2054514f5e3Sopenharmony_ci if (i + 1 == static_cast<uint32_t>(length)) { 2064514f5e3Sopenharmony_ci break; 2074514f5e3Sopenharmony_ci } 2084514f5e3Sopenharmony_ci if (argsI <= argc) { 2094514f5e3Sopenharmony_ci EcmaString *nextSub = *JSTaggedValue::ToString(thread, GetCallArg(argv, argsI)); 2104514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2114514f5e3Sopenharmony_ci u16str += EcmaStringAccessor(nextSub).ToU16String(); 2124514f5e3Sopenharmony_ci if (EcmaStringAccessor(nextSub).IsUtf16()) { 2134514f5e3Sopenharmony_ci canBeCompress = false; 2144514f5e3Sopenharmony_ci } 2154514f5e3Sopenharmony_ci } 2164514f5e3Sopenharmony_ci } 2174514f5e3Sopenharmony_ci // return the result string 2184514f5e3Sopenharmony_ci auto *uint16tData = reinterpret_cast<uint16_t *>(const_cast<char16_t *>(u16str.data())); 2194514f5e3Sopenharmony_ci return canBeCompress ? factory->NewFromUtf16LiteralCompress(uint16tData, u16str.size()).GetTaggedValue() : 2204514f5e3Sopenharmony_ci factory->NewFromUtf16LiteralNotCompress(uint16tData, u16str.size()).GetTaggedValue(); 2214514f5e3Sopenharmony_ci} 2224514f5e3Sopenharmony_ci 2234514f5e3Sopenharmony_ci// 21.1.3.1 2244514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::CharAt(EcmaRuntimeCallInfo *argv) 2254514f5e3Sopenharmony_ci{ 2264514f5e3Sopenharmony_ci ASSERT(argv); 2274514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, CharAt); 2284514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 2294514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 2304514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 2314514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 2324514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2334514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 2344514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2354514f5e3Sopenharmony_ci JSHandle<EcmaString> thisFlat(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), thisHandle)); 2364514f5e3Sopenharmony_ci int32_t thisLen = static_cast<int32_t>(EcmaStringAccessor(thisFlat).GetLength()); 2374514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> posTag = BuiltinsString::GetCallArg(argv, 0); 2384514f5e3Sopenharmony_ci int32_t pos = 0; 2394514f5e3Sopenharmony_ci if (posTag->IsInt()) { 2404514f5e3Sopenharmony_ci pos = posTag->GetInt(); 2414514f5e3Sopenharmony_ci } else if (posTag->IsUndefined()) { 2424514f5e3Sopenharmony_ci pos = 0; 2434514f5e3Sopenharmony_ci } else { 2444514f5e3Sopenharmony_ci JSTaggedNumber posVal = JSTaggedValue::ToInteger(thread, posTag); 2454514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2464514f5e3Sopenharmony_ci double valueNumber = posVal.GetNumber(); 2474514f5e3Sopenharmony_ci if (!std::isfinite(valueNumber)) { 2484514f5e3Sopenharmony_ci return factory->GetEmptyString().GetTaggedValue(); 2494514f5e3Sopenharmony_ci } 2504514f5e3Sopenharmony_ci pos = posVal.ToInt32(); 2514514f5e3Sopenharmony_ci } 2524514f5e3Sopenharmony_ci if (pos < 0 || pos >= thisLen) { 2534514f5e3Sopenharmony_ci return factory->GetEmptyString().GetTaggedValue(); 2544514f5e3Sopenharmony_ci } 2554514f5e3Sopenharmony_ci uint16_t res = EcmaStringAccessor(thisFlat).Get<false>(pos); 2564514f5e3Sopenharmony_ci if (EcmaStringAccessor::CanBeCompressed(&res, 1)) { 2574514f5e3Sopenharmony_ci JSHandle<SingleCharTable> singleCharTable(thread, thread->GetSingleCharTable()); 2584514f5e3Sopenharmony_ci return singleCharTable->GetStringFromSingleCharTable(res); 2594514f5e3Sopenharmony_ci } 2604514f5e3Sopenharmony_ci return factory->NewFromUtf16Literal(&res, 1).GetTaggedValue(); 2614514f5e3Sopenharmony_ci} 2624514f5e3Sopenharmony_ci 2634514f5e3Sopenharmony_ci// 21.1.3.2 2644514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::CharCodeAt(EcmaRuntimeCallInfo *argv) 2654514f5e3Sopenharmony_ci{ 2664514f5e3Sopenharmony_ci ASSERT(argv); 2674514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, CharCodeAt); 2684514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 2694514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 2704514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 2714514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2724514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 2734514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2744514f5e3Sopenharmony_ci JSHandle<EcmaString> thisFlat(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), thisHandle)); 2754514f5e3Sopenharmony_ci int32_t thisLen = static_cast<int32_t>(EcmaStringAccessor(thisFlat).GetLength()); 2764514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> posTag = BuiltinsString::GetCallArg(argv, 0); 2774514f5e3Sopenharmony_ci int32_t pos = 0; 2784514f5e3Sopenharmony_ci if (posTag->IsInt()) { 2794514f5e3Sopenharmony_ci pos = posTag->GetInt(); 2804514f5e3Sopenharmony_ci } else if (posTag->IsUndefined()) { 2814514f5e3Sopenharmony_ci pos = 0; 2824514f5e3Sopenharmony_ci } else { 2834514f5e3Sopenharmony_ci JSTaggedNumber posVal = JSTaggedValue::ToInteger(thread, posTag); 2844514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 2854514f5e3Sopenharmony_ci double valueNumber = posVal.GetNumber(); 2864514f5e3Sopenharmony_ci if (!std::isfinite(valueNumber)) { 2874514f5e3Sopenharmony_ci return GetTaggedDouble(base::NAN_VALUE); 2884514f5e3Sopenharmony_ci } 2894514f5e3Sopenharmony_ci pos = posVal.ToInt32(); 2904514f5e3Sopenharmony_ci } 2914514f5e3Sopenharmony_ci if (pos < 0 || pos >= thisLen) { 2924514f5e3Sopenharmony_ci return GetTaggedDouble(base::NAN_VALUE); 2934514f5e3Sopenharmony_ci } 2944514f5e3Sopenharmony_ci uint16_t ret = EcmaStringAccessor(thisFlat).Get<false>(pos); 2954514f5e3Sopenharmony_ci return GetTaggedInt(ret); 2964514f5e3Sopenharmony_ci} 2974514f5e3Sopenharmony_ci 2984514f5e3Sopenharmony_ci// 21.1.3.3 2994514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::CodePointAt(EcmaRuntimeCallInfo *argv) 3004514f5e3Sopenharmony_ci{ 3014514f5e3Sopenharmony_ci ASSERT(argv); 3024514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, CodePointAt); 3034514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 3044514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 3054514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 3064514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3074514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 3084514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3094514f5e3Sopenharmony_ci JSHandle<EcmaString> thisFlat(thread, EcmaStringAccessor::Flatten(thread->GetEcmaVM(), thisHandle)); 3104514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> posTag = BuiltinsString::GetCallArg(argv, 0); 3114514f5e3Sopenharmony_ci 3124514f5e3Sopenharmony_ci JSTaggedNumber posVal = JSTaggedValue::ToNumber(thread, posTag); 3134514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3144514f5e3Sopenharmony_ci int32_t pos = base::NumberHelper::DoubleInRangeInt32(posVal.GetNumber()); 3154514f5e3Sopenharmony_ci int32_t thisLen = static_cast<int32_t>(EcmaStringAccessor(thisFlat).GetLength()); 3164514f5e3Sopenharmony_ci if (pos < 0 || pos >= thisLen) { 3174514f5e3Sopenharmony_ci return JSTaggedValue::Undefined(); 3184514f5e3Sopenharmony_ci } 3194514f5e3Sopenharmony_ci uint16_t first = EcmaStringAccessor(thisFlat).Get<false>(pos); 3204514f5e3Sopenharmony_ci if (first < base::utf_helper::DECODE_LEAD_LOW || first > base::utf_helper::DECODE_LEAD_HIGH || pos + 1 == thisLen) { 3214514f5e3Sopenharmony_ci return GetTaggedInt(first); 3224514f5e3Sopenharmony_ci } 3234514f5e3Sopenharmony_ci uint16_t second = EcmaStringAccessor(thisFlat).Get<false>(pos + 1); 3244514f5e3Sopenharmony_ci if (second < base::utf_helper::DECODE_TRAIL_LOW || second > base::utf_helper::DECODE_TRAIL_HIGH) { 3254514f5e3Sopenharmony_ci return GetTaggedInt(first); 3264514f5e3Sopenharmony_ci } 3274514f5e3Sopenharmony_ci uint32_t res = base::utf_helper::UTF16Decode(first, second); 3284514f5e3Sopenharmony_ci return GetTaggedInt(res); 3294514f5e3Sopenharmony_ci} 3304514f5e3Sopenharmony_ci 3314514f5e3Sopenharmony_ci// 21.1.3.4 3324514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Concat(EcmaRuntimeCallInfo *argv) 3334514f5e3Sopenharmony_ci{ 3344514f5e3Sopenharmony_ci ASSERT(argv); 3354514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Concat); 3364514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 3374514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 3384514f5e3Sopenharmony_ci auto ecmaVm = thread->GetEcmaVM(); 3394514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 3404514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3414514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 3424514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3434514f5e3Sopenharmony_ci uint32_t argLength = argv->GetArgsNumber(); 3444514f5e3Sopenharmony_ci if (argLength == 0) { 3454514f5e3Sopenharmony_ci return thisHandle.GetTaggedValue(); 3464514f5e3Sopenharmony_ci } 3474514f5e3Sopenharmony_ci for (uint32_t i = 0; i < argLength; i++) { 3484514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> nextTag = BuiltinsString::GetCallArg(argv, i); 3494514f5e3Sopenharmony_ci JSHandle<EcmaString> nextHandle = JSTaggedValue::ToString(thread, nextTag); 3504514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3514514f5e3Sopenharmony_ci EcmaString *tempStr = EcmaStringAccessor::Concat(ecmaVm, thisHandle, nextHandle); 3524514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3534514f5e3Sopenharmony_ci thisHandle = JSHandle<EcmaString>(thread, tempStr); 3544514f5e3Sopenharmony_ci } 3554514f5e3Sopenharmony_ci return thisHandle.GetTaggedValue(); 3564514f5e3Sopenharmony_ci} 3574514f5e3Sopenharmony_ci 3584514f5e3Sopenharmony_ci// 21.1.3.5 String.prototype.constructor 3594514f5e3Sopenharmony_ci// 21.1.3.6 3604514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::EndsWith(EcmaRuntimeCallInfo *argv) 3614514f5e3Sopenharmony_ci{ 3624514f5e3Sopenharmony_ci ASSERT(argv); 3634514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, EndsWith); 3644514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 3654514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 3664514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 3674514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3684514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> searchTag = BuiltinsString::GetCallArg(argv, 0); 3694514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 3704514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3714514f5e3Sopenharmony_ci bool isRegexp = JSObject::IsRegExp(thread, searchTag); 3724514f5e3Sopenharmony_ci if (isRegexp) { 3734514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "is regexp", JSTaggedValue::Exception()); 3744514f5e3Sopenharmony_ci } 3754514f5e3Sopenharmony_ci JSHandle<EcmaString> searchHandle = JSTaggedValue::ToString(thread, searchTag); 3764514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3774514f5e3Sopenharmony_ci uint32_t thisLen = EcmaStringAccessor(thisHandle).GetLength(); 3784514f5e3Sopenharmony_ci uint32_t searchLen = EcmaStringAccessor(searchHandle).GetLength(); 3794514f5e3Sopenharmony_ci int32_t pos = 0; 3804514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> posTag = BuiltinsString::GetCallArg(argv, 1); 3814514f5e3Sopenharmony_ci if (posTag->IsUndefined()) { 3824514f5e3Sopenharmony_ci pos = static_cast<int32_t>(thisLen); 3834514f5e3Sopenharmony_ci } else { 3844514f5e3Sopenharmony_ci JSTaggedNumber posVal = JSTaggedValue::ToInteger(thread, posTag); 3854514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 3864514f5e3Sopenharmony_ci if (posVal.GetNumber() == BuiltinsNumber::POSITIVE_INFINITY) { 3874514f5e3Sopenharmony_ci pos = static_cast<int32_t>(thisLen); 3884514f5e3Sopenharmony_ci } else { 3894514f5e3Sopenharmony_ci pos = base::NumberHelper::DoubleInRangeInt32(posVal.GetNumber()); 3904514f5e3Sopenharmony_ci } 3914514f5e3Sopenharmony_ci } 3924514f5e3Sopenharmony_ci pos = std::min(std::max(pos, 0), static_cast<int32_t>(thisLen)); 3934514f5e3Sopenharmony_ci int32_t start = pos - static_cast<int32_t>(searchLen); 3944514f5e3Sopenharmony_ci if (start < 0) { 3954514f5e3Sopenharmony_ci return BuiltinsString::GetTaggedBoolean(false); 3964514f5e3Sopenharmony_ci } 3974514f5e3Sopenharmony_ci 3984514f5e3Sopenharmony_ci int32_t idx = EcmaStringAccessor::IndexOf(thread->GetEcmaVM(), thisHandle, searchHandle, start); 3994514f5e3Sopenharmony_ci if (idx == start) { 4004514f5e3Sopenharmony_ci return BuiltinsString::GetTaggedBoolean(true); 4014514f5e3Sopenharmony_ci } 4024514f5e3Sopenharmony_ci return BuiltinsString::GetTaggedBoolean(false); 4034514f5e3Sopenharmony_ci} 4044514f5e3Sopenharmony_ci 4054514f5e3Sopenharmony_ci// 21.1.3.7 4064514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Includes(EcmaRuntimeCallInfo *argv) 4074514f5e3Sopenharmony_ci{ 4084514f5e3Sopenharmony_ci ASSERT(argv); 4094514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Includes); 4104514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 4114514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 4124514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> searchTag = BuiltinsString::GetCallArg(argv, 0); 4134514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 4144514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4154514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 4164514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4174514f5e3Sopenharmony_ci bool isRegexp = JSObject::IsRegExp(thread, searchTag); 4184514f5e3Sopenharmony_ci if (isRegexp) { 4194514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "is regexp", JSTaggedValue::Exception()); 4204514f5e3Sopenharmony_ci } 4214514f5e3Sopenharmony_ci JSHandle<EcmaString> searchHandle = JSTaggedValue::ToString(thread, searchTag); 4224514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4234514f5e3Sopenharmony_ci uint32_t thisLen = EcmaStringAccessor(thisHandle).GetLength(); 4244514f5e3Sopenharmony_ci int32_t pos = 0; 4254514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> posTag = BuiltinsBase::GetCallArg(argv, 1); 4264514f5e3Sopenharmony_ci if (argv->GetArgsNumber() == 1) { 4274514f5e3Sopenharmony_ci pos = 0; 4284514f5e3Sopenharmony_ci } else { 4294514f5e3Sopenharmony_ci JSTaggedNumber posVal = JSTaggedValue::ToNumber(thread, posTag); 4304514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4314514f5e3Sopenharmony_ci pos = base::NumberHelper::DoubleInRangeInt32(posVal.GetNumber()); 4324514f5e3Sopenharmony_ci } 4334514f5e3Sopenharmony_ci int32_t start = std::min(std::max(pos, 0), static_cast<int32_t>(thisLen)); 4344514f5e3Sopenharmony_ci int32_t idx = EcmaStringAccessor::IndexOf(thread->GetEcmaVM(), thisHandle, searchHandle, start); 4354514f5e3Sopenharmony_ci if (idx < 0 || idx > static_cast<int32_t>(thisLen)) { 4364514f5e3Sopenharmony_ci return BuiltinsString::GetTaggedBoolean(false); 4374514f5e3Sopenharmony_ci } 4384514f5e3Sopenharmony_ci return BuiltinsString::GetTaggedBoolean(true); 4394514f5e3Sopenharmony_ci} 4404514f5e3Sopenharmony_ci 4414514f5e3Sopenharmony_ci// 21.1.3.8 4424514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::IndexOf(EcmaRuntimeCallInfo *argv) 4434514f5e3Sopenharmony_ci{ 4444514f5e3Sopenharmony_ci ASSERT(argv); 4454514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, IndexOf); 4464514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 4474514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 4484514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> searchTag = BuiltinsString::GetCallArg(argv, 0); 4494514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 4504514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4514514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 4524514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4534514f5e3Sopenharmony_ci uint32_t thisLen = EcmaStringAccessor(thisHandle).GetLength(); 4544514f5e3Sopenharmony_ci JSHandle<EcmaString> searchHandle = JSTaggedValue::ToString(thread, searchTag); 4554514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4564514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> posTag = BuiltinsString::GetCallArg(argv, 1); 4574514f5e3Sopenharmony_ci int32_t pos = 0; 4584514f5e3Sopenharmony_ci if (posTag->IsInt()) { 4594514f5e3Sopenharmony_ci pos = posTag->GetInt(); 4604514f5e3Sopenharmony_ci } else if (posTag->IsUndefined()) { 4614514f5e3Sopenharmony_ci pos = 0; 4624514f5e3Sopenharmony_ci } else { 4634514f5e3Sopenharmony_ci JSTaggedNumber posVal = JSTaggedValue::ToInteger(thread, posTag); 4644514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4654514f5e3Sopenharmony_ci pos = posVal.ToInt32(); 4664514f5e3Sopenharmony_ci } 4674514f5e3Sopenharmony_ci pos = std::min(std::max(pos, 0), static_cast<int32_t>(thisLen)); 4684514f5e3Sopenharmony_ci // If searching for an null string. 4694514f5e3Sopenharmony_ci if (EcmaStringAccessor(searchHandle).GetLength() == 0) { 4704514f5e3Sopenharmony_ci return GetTaggedInt(pos); 4714514f5e3Sopenharmony_ci } 4724514f5e3Sopenharmony_ci int32_t res = EcmaStringAccessor::IndexOf(thread->GetEcmaVM(), thisHandle, searchHandle, pos); 4734514f5e3Sopenharmony_ci if (res >= 0 && res < static_cast<int32_t>(thisLen)) { 4744514f5e3Sopenharmony_ci return GetTaggedInt(res); 4754514f5e3Sopenharmony_ci } 4764514f5e3Sopenharmony_ci return GetTaggedInt(-1); 4774514f5e3Sopenharmony_ci} 4784514f5e3Sopenharmony_ci 4794514f5e3Sopenharmony_ci// 21.1.3.9 4804514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::LastIndexOf(EcmaRuntimeCallInfo *argv) 4814514f5e3Sopenharmony_ci{ 4824514f5e3Sopenharmony_ci ASSERT(argv); 4834514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, LastIndexOf); 4844514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 4854514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 4864514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> searchTag = BuiltinsString::GetCallArg(argv, 0); 4874514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 4884514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4894514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 4904514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4914514f5e3Sopenharmony_ci int32_t thisLen = static_cast<int32_t>(EcmaStringAccessor(thisHandle).GetLength()); 4924514f5e3Sopenharmony_ci JSHandle<EcmaString> searchHandle = JSTaggedValue::ToString(thread, searchTag); 4934514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 4944514f5e3Sopenharmony_ci int32_t pos = 0; 4954514f5e3Sopenharmony_ci if (argv->GetArgsNumber() == 1) { 4964514f5e3Sopenharmony_ci pos = thisLen; 4974514f5e3Sopenharmony_ci } else { 4984514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> posTag = BuiltinsString::GetCallArg(argv, 1); 4994514f5e3Sopenharmony_ci JSTaggedNumber posVal = JSTaggedValue::ToInteger(thread, posTag); 5004514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 5014514f5e3Sopenharmony_ci if (std::isnan(JSTaggedValue::ToNumber(thread, posTag).GetNumber())) { 5024514f5e3Sopenharmony_ci pos = thisLen; 5034514f5e3Sopenharmony_ci } else { 5044514f5e3Sopenharmony_ci pos = posVal.ToInt32(); 5054514f5e3Sopenharmony_ci } 5064514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 5074514f5e3Sopenharmony_ci } 5084514f5e3Sopenharmony_ci pos = std::min(std::max(pos, 0), thisLen); 5094514f5e3Sopenharmony_ci int32_t res = EcmaStringAccessor::LastIndexOf(thread->GetEcmaVM(), thisHandle, searchHandle, pos); 5104514f5e3Sopenharmony_ci if (res >= 0 && res < thisLen) { 5114514f5e3Sopenharmony_ci return GetTaggedInt(res); 5124514f5e3Sopenharmony_ci } 5134514f5e3Sopenharmony_ci res = -1; 5144514f5e3Sopenharmony_ci return GetTaggedInt(static_cast<int32_t>(res)); 5154514f5e3Sopenharmony_ci} 5164514f5e3Sopenharmony_ci 5174514f5e3Sopenharmony_ci// 21.1.3.10 5184514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::LocaleCompare(EcmaRuntimeCallInfo *argv) 5194514f5e3Sopenharmony_ci{ 5204514f5e3Sopenharmony_ci ASSERT(argv); 5214514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, LocaleCompare); 5224514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 5234514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 5244514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thatTag = BuiltinsString::GetCallArg(argv, 0); 5254514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 5264514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 5274514f5e3Sopenharmony_ci [[maybe_unused]] JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 5284514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 5294514f5e3Sopenharmony_ci [[maybe_unused]] JSHandle<EcmaString> thatHandle = JSTaggedValue::ToString(thread, thatTag); 5304514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 5314514f5e3Sopenharmony_ci 5324514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> locales = GetCallArg(argv, 1); 5334514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> options = GetCallArg(argv, 2); // 2: the second argument 5344514f5e3Sopenharmony_ci return DoLocaleCompare(thread, thisHandle, thatHandle, locales, options); 5354514f5e3Sopenharmony_ci} 5364514f5e3Sopenharmony_ci 5374514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::DoLocaleCompare(JSThread *thread, 5384514f5e3Sopenharmony_ci const JSHandle<EcmaString> &thisHandle, 5394514f5e3Sopenharmony_ci const JSHandle<EcmaString> &thatHandle, 5404514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &locales, 5414514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &options) 5424514f5e3Sopenharmony_ci{ 5434514f5e3Sopenharmony_ci [[maybe_unused]] bool cacheable = (locales->IsUndefined() || locales->IsString()) && options->IsUndefined(); 5444514f5e3Sopenharmony_ci const CompareStringsOption csOption = JSCollator::CompareStringsOptionFor(thread, locales, options); 5454514f5e3Sopenharmony_ci#ifdef ARK_SUPPORT_INTL 5464514f5e3Sopenharmony_ci if (cacheable) { 5474514f5e3Sopenharmony_ci auto collator = JSCollator::GetCachedIcuCollator(thread, locales); 5484514f5e3Sopenharmony_ci if (collator != nullptr) { 5494514f5e3Sopenharmony_ci JSTaggedValue result = JSCollator::CompareStrings(thread, collator, thisHandle, thatHandle, csOption); 5504514f5e3Sopenharmony_ci return result; 5514514f5e3Sopenharmony_ci } 5524514f5e3Sopenharmony_ci } 5534514f5e3Sopenharmony_ci return LocaleCompareGC(thread, thisHandle, thatHandle, locales, options, csOption, cacheable); 5544514f5e3Sopenharmony_ci#else 5554514f5e3Sopenharmony_ci#ifdef ARK_NOT_SUPPORT_INTL_GLOBAL 5564514f5e3Sopenharmony_ci ARK_SUPPORT_INTL_RETURN_JSVALUE(thread, "LocaleCompare"); 5574514f5e3Sopenharmony_ci#else 5584514f5e3Sopenharmony_ci intl::GlobalIntlHelper gh(thread, intl::GlobalFormatterType::Collator); 5594514f5e3Sopenharmony_ci auto collator = gh.GetGlobalObject<intl::GlobalCollator>(thread, 5604514f5e3Sopenharmony_ci locales, options, intl::GlobalFormatterType::Collator, cacheable); 5614514f5e3Sopenharmony_ci if (collator == nullptr) { 5624514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "BuiltinsString::LocaleCompare:collator is nullptr"; 5634514f5e3Sopenharmony_ci } 5644514f5e3Sopenharmony_ci ASSERT(collator != nullptr); 5654514f5e3Sopenharmony_ci auto result = collator->Compare(EcmaStringAccessor(thisHandle).ToStdString(), 5664514f5e3Sopenharmony_ci EcmaStringAccessor(thatHandle).ToStdString()); 5674514f5e3Sopenharmony_ci return JSTaggedValue(result); 5684514f5e3Sopenharmony_ci#endif 5694514f5e3Sopenharmony_ci#endif 5704514f5e3Sopenharmony_ci} 5714514f5e3Sopenharmony_ci 5724514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::LocaleCompareGC(JSThread *thread, 5734514f5e3Sopenharmony_ci const JSHandle<EcmaString> &thisHandle, 5744514f5e3Sopenharmony_ci const JSHandle<EcmaString> &thatHandle, 5754514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &locales, 5764514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &options, 5774514f5e3Sopenharmony_ci CompareStringsOption csOption, 5784514f5e3Sopenharmony_ci bool cacheable) 5794514f5e3Sopenharmony_ci{ 5804514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 5814514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 5824514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> ctor = ecmaVm->GetGlobalEnv()->GetCollatorFunction(); 5834514f5e3Sopenharmony_ci JSHandle<JSCollator> collator = 5844514f5e3Sopenharmony_ci JSHandle<JSCollator>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor))); 5854514f5e3Sopenharmony_ci JSHandle<JSCollator> initCollator = 5864514f5e3Sopenharmony_ci JSCollator::InitializeCollator(thread, collator, locales, options, cacheable); 5874514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 5884514f5e3Sopenharmony_ci icu::Collator *icuCollator = nullptr; 5894514f5e3Sopenharmony_ci if (cacheable) { 5904514f5e3Sopenharmony_ci icuCollator = JSCollator::GetCachedIcuCollator(thread, locales); 5914514f5e3Sopenharmony_ci ASSERT(icuCollator != nullptr); 5924514f5e3Sopenharmony_ci } else { 5934514f5e3Sopenharmony_ci icuCollator = initCollator->GetIcuCollator(); 5944514f5e3Sopenharmony_ci } 5954514f5e3Sopenharmony_ci JSTaggedValue result = JSCollator::CompareStrings(thread, icuCollator, thisHandle, thatHandle, csOption); 5964514f5e3Sopenharmony_ci return result; 5974514f5e3Sopenharmony_ci} 5984514f5e3Sopenharmony_ci 5994514f5e3Sopenharmony_ci 6004514f5e3Sopenharmony_ci// 21.1.3.11 6014514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Match(EcmaRuntimeCallInfo *argv) 6024514f5e3Sopenharmony_ci{ 6034514f5e3Sopenharmony_ci ASSERT(argv); 6044514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Match); 6054514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 6064514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 6074514f5e3Sopenharmony_ci const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 6084514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 6094514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6104514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> regexp = BuiltinsString::GetCallArg(argv, 0); 6114514f5e3Sopenharmony_ci if (thisTag->IsString() && regexp->IsECMAObject()) { 6124514f5e3Sopenharmony_ci if (BuiltinsRegExp::IsFastRegExp(thread, regexp, BuiltinsRegExp::RegExpSymbol::MATCH)) { 6134514f5e3Sopenharmony_ci return BuiltinsRegExp::RegExpMatch(thread, regexp, thisTag, true); 6144514f5e3Sopenharmony_ci } 6154514f5e3Sopenharmony_ci } 6164514f5e3Sopenharmony_ci 6174514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> matchTag = thread->GetEcmaVM()->GetGlobalEnv()->GetMatchSymbol(); 6184514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 6194514f5e3Sopenharmony_ci if (!regexp->IsUndefined() && !regexp->IsNull()) { 6204514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> matcher = JSObject::GetMethod(thread, regexp, matchTag); 6214514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6224514f5e3Sopenharmony_ci if (!matcher->IsUndefined()) { 6234514f5e3Sopenharmony_ci ASSERT(matcher->IsJSFunctionBase()); 6244514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 6254514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, matcher, regexp, undefined, 1); 6264514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6274514f5e3Sopenharmony_ci info->SetCallArg(thisTag.GetTaggedValue()); 6284514f5e3Sopenharmony_ci return JSFunction::Call(info); 6294514f5e3Sopenharmony_ci } 6304514f5e3Sopenharmony_ci } 6314514f5e3Sopenharmony_ci JSHandle<EcmaString> thisVal = JSTaggedValue::ToString(thread, thisTag); 6324514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6334514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undifinedHandle = globalConst->GetHandledUndefined(); 6344514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> rx(thread, BuiltinsRegExp::RegExpCreate(thread, regexp, undifinedHandle)); 6354514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6364514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, rx, undefined, 1); 6374514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6384514f5e3Sopenharmony_ci info->SetCallArg(thisVal.GetTaggedValue()); 6394514f5e3Sopenharmony_ci return JSFunction::Invoke(info, matchTag); 6404514f5e3Sopenharmony_ci} 6414514f5e3Sopenharmony_ci 6424514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::MatchAll(EcmaRuntimeCallInfo *argv) 6434514f5e3Sopenharmony_ci{ 6444514f5e3Sopenharmony_ci ASSERT(argv); 6454514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, MatchAll); 6464514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 6474514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 6484514f5e3Sopenharmony_ci const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 6494514f5e3Sopenharmony_ci // 1. Let O be ? RequireObjectCoercible(this value). 6504514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 6514514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6524514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> regexp = BuiltinsString::GetCallArg(argv, 0); 6534514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 6544514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 6554514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> matchAllTag = env->GetMatchAllSymbol(); 6564514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 6574514f5e3Sopenharmony_ci 6584514f5e3Sopenharmony_ci // 2. If regexp is neither undefined nor null, then 6594514f5e3Sopenharmony_ci if (!regexp->IsUndefined() && !regexp->IsNull()) { 6604514f5e3Sopenharmony_ci // a. Let isRegExp be ? IsRegExp(searchValue). 6614514f5e3Sopenharmony_ci if (regexp->IsECMAObject() && 6624514f5e3Sopenharmony_ci BuiltinsRegExp::IsFastRegExp(thread, regexp, BuiltinsRegExp::RegExpSymbol::MATCH)) { 6634514f5e3Sopenharmony_ci bool isGlobal = BuiltinsRegExp::GetOriginalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL); 6644514f5e3Sopenharmony_ci if (!isGlobal) { 6654514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, 6664514f5e3Sopenharmony_ci "matchAll called with a non-global RegExp argument", 6674514f5e3Sopenharmony_ci JSTaggedValue::Exception()); 6684514f5e3Sopenharmony_ci } 6694514f5e3Sopenharmony_ci } else if (JSObject::IsRegExp(thread, regexp)) { 6704514f5e3Sopenharmony_ci // i. Let flags be ? Get(searchValue, "flags"). 6714514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> flagsString(globalConst->GetHandledFlagsString()); 6724514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> flags = JSObject::GetProperty(thread, regexp, flagsString).GetValue(); 6734514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6744514f5e3Sopenharmony_ci // ii. Perform ? RequireObjectCoercible(flags). 6754514f5e3Sopenharmony_ci JSTaggedValue::RequireObjectCoercible(thread, flags); 6764514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6774514f5e3Sopenharmony_ci // iii. If ? ToString(flags) does not contain "g", throw a TypeError exception. 6784514f5e3Sopenharmony_ci JSHandle<EcmaString> flagString = JSTaggedValue::ToString(thread, flags); 6794514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6804514f5e3Sopenharmony_ci int32_t pos = EcmaStringAccessor::IndexOf(ecmaVm, 6814514f5e3Sopenharmony_ci flagString, ecmaVm->GetFactory()->NewFromASCII("g")); 6824514f5e3Sopenharmony_ci if (pos == -1) { 6834514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, 6844514f5e3Sopenharmony_ci "matchAll called with a non-global RegExp argument", 6854514f5e3Sopenharmony_ci JSTaggedValue::Exception()); 6864514f5e3Sopenharmony_ci } 6874514f5e3Sopenharmony_ci } 6884514f5e3Sopenharmony_ci 6894514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 6904514f5e3Sopenharmony_ci if (thisTag->IsString() && regexp->IsECMAObject()) { 6914514f5e3Sopenharmony_ci if (PropertyDetector::IsRegExpSpeciesDetectorValid(env) && 6924514f5e3Sopenharmony_ci BuiltinsRegExp::IsFastRegExp(thread, regexp, BuiltinsRegExp::RegExpSymbol::MATCHALL)) { 6934514f5e3Sopenharmony_ci JSHandle<EcmaString> string = JSHandle<EcmaString>::Cast(thisTag); 6944514f5e3Sopenharmony_ci return BuiltinsRegExp::RegExpMatchAll(thread, regexp, string, true); 6954514f5e3Sopenharmony_ci } 6964514f5e3Sopenharmony_ci } 6974514f5e3Sopenharmony_ci // c. Let matcher be ? GetMethod(regexp, @@matchAll). 6984514f5e3Sopenharmony_ci // d. If matcher is not undefined, then 6994514f5e3Sopenharmony_ci bool canSkip = (PropertyDetector::IsNumberStringNotRegexpLikeDetectorValid(env) && 7004514f5e3Sopenharmony_ci (regexp->IsString() || regexp->IsNumber())); 7014514f5e3Sopenharmony_ci if (!canSkip) { 7024514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> matcher = JSObject::GetMethod(thread, regexp, matchAllTag); 7034514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 7044514f5e3Sopenharmony_ci if (!matcher->IsUndefined()) { 7054514f5e3Sopenharmony_ci // i. Return ? Call(matcher, regexp, « O »). 7064514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 7074514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, matcher, regexp, undefined, 1); 7084514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 7094514f5e3Sopenharmony_ci info->SetCallArg(thisTag.GetTaggedValue()); 7104514f5e3Sopenharmony_ci return JSFunction::Call(info); 7114514f5e3Sopenharmony_ci } 7124514f5e3Sopenharmony_ci } 7134514f5e3Sopenharmony_ci } 7144514f5e3Sopenharmony_ci // 3. Let S be ? ToString(O). 7154514f5e3Sopenharmony_ci JSHandle<EcmaString> thisVal = JSTaggedValue::ToString(thread, thisTag); 7164514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 7174514f5e3Sopenharmony_ci // 4. Let rx be ? RegExpCreate(regexp, "g"). 7184514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> rx(thread, BuiltinsRegExp::RegExpCreate( 7194514f5e3Sopenharmony_ci thread, regexp, JSHandle<JSTaggedValue>(ecmaVm->GetFactory()->NewFromASCII("g")))); 7204514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 7214514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, rx, undefined, 1); 7224514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 7234514f5e3Sopenharmony_ci info->SetCallArg(thisVal.GetTaggedValue()); 7244514f5e3Sopenharmony_ci return JSFunction::Invoke(info, matchAllTag); 7254514f5e3Sopenharmony_ci} 7264514f5e3Sopenharmony_ci 7274514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::IsWellFormed(EcmaRuntimeCallInfo *argv) 7284514f5e3Sopenharmony_ci{ 7294514f5e3Sopenharmony_ci ASSERT(argv); 7304514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, IsWellFormed); 7314514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 7324514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 7334514f5e3Sopenharmony_ci 7344514f5e3Sopenharmony_ci // 1. Let O be ? RequireObjectCoercible(this value). 7354514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> obj(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 7364514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 7374514f5e3Sopenharmony_ci 7384514f5e3Sopenharmony_ci // 2. Let S be ? ToString(O). 7394514f5e3Sopenharmony_ci JSHandle<EcmaString> string = JSTaggedValue::ToString(thread, obj); 7404514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 7414514f5e3Sopenharmony_ci 7424514f5e3Sopenharmony_ci // 3. Return IsStringWellFormedUnicode(S). 7434514f5e3Sopenharmony_ci uint32_t size = EcmaStringAccessor(string).GetLength(); 7444514f5e3Sopenharmony_ci uint32_t position = 0; 7454514f5e3Sopenharmony_ci while (position < size) { 7464514f5e3Sopenharmony_ci // i.Let first be the code unit at index position within string. 7474514f5e3Sopenharmony_ci uint16_t first = EcmaStringAccessor(string).Get(position); 7484514f5e3Sopenharmony_ci uint32_t cp = first - CHAR16_LETTER_NULL; 7494514f5e3Sopenharmony_ci uint8_t codeUnitCount = 0; 7504514f5e3Sopenharmony_ci bool isUnpairedSurrogate = false; 7514514f5e3Sopenharmony_ci // ii. If first is neither a leading surrogate nor a trailing surrogate, then 7524514f5e3Sopenharmony_ci // a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }. 7534514f5e3Sopenharmony_ci if (!IsUTF16HighSurrogate(first) && !IsUTF16LowSurrogate(first)) { 7544514f5e3Sopenharmony_ci codeUnitCount = 1; // 1 means: code unit count 7554514f5e3Sopenharmony_ci isUnpairedSurrogate = false; 7564514f5e3Sopenharmony_ci } else if (IsUTF16HighSurrogate(first) && position + 1 == size) { 7574514f5e3Sopenharmony_ci // iii. If first is a trailing surrogate or position + 1 = size, then 7584514f5e3Sopenharmony_ci // a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }. 7594514f5e3Sopenharmony_ci codeUnitCount = 1; 7604514f5e3Sopenharmony_ci isUnpairedSurrogate = true; 7614514f5e3Sopenharmony_ci } else { 7624514f5e3Sopenharmony_ci // iv. Let second be the code unit at index position + 1 within string. 7634514f5e3Sopenharmony_ci uint16_t second = EcmaStringAccessor(string).Get(position + 1); 7644514f5e3Sopenharmony_ci // v. If second is not a trailing surrogate, then 7654514f5e3Sopenharmony_ci // a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }. 7664514f5e3Sopenharmony_ci if (!IsUTF16LowSurrogate(second)) { 7674514f5e3Sopenharmony_ci codeUnitCount = 1; // 1 means: code unit count 7684514f5e3Sopenharmony_ci isUnpairedSurrogate = true; 7694514f5e3Sopenharmony_ci } else { 7704514f5e3Sopenharmony_ci // vi. Set cp to UTF16SurrogatePairToCodePoint(first, second). 7714514f5e3Sopenharmony_ci // vii. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }. 7724514f5e3Sopenharmony_ci cp = UTF16SurrogatePairToCodePoint(first, second); 7734514f5e3Sopenharmony_ci codeUnitCount = 2; // 2 means: code unit count 7744514f5e3Sopenharmony_ci isUnpairedSurrogate = false; 7754514f5e3Sopenharmony_ci } 7764514f5e3Sopenharmony_ci } 7774514f5e3Sopenharmony_ci if (isUnpairedSurrogate) { 7784514f5e3Sopenharmony_ci return JSTaggedValue::False(); 7794514f5e3Sopenharmony_ci } else { 7804514f5e3Sopenharmony_ci position = position + codeUnitCount; 7814514f5e3Sopenharmony_ci } 7824514f5e3Sopenharmony_ci thread->CheckSafepointIfSuspended(); 7834514f5e3Sopenharmony_ci } 7844514f5e3Sopenharmony_ci return JSTaggedValue::True(); 7854514f5e3Sopenharmony_ci} 7864514f5e3Sopenharmony_ci 7874514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::ToWellFormed(EcmaRuntimeCallInfo *argv) 7884514f5e3Sopenharmony_ci{ 7894514f5e3Sopenharmony_ci ASSERT(argv); 7904514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, ToWellFormed); 7914514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 7924514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 7934514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 7944514f5e3Sopenharmony_ci 7954514f5e3Sopenharmony_ci // 1. Let O be ? RequireObjectCoercible(this value). 7964514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> obj(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 7974514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 7984514f5e3Sopenharmony_ci 7994514f5e3Sopenharmony_ci // 2. Let S be ? ToString(O). 8004514f5e3Sopenharmony_ci JSHandle<EcmaString> string = JSTaggedValue::ToString(thread, obj); 8014514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 8024514f5e3Sopenharmony_ci 8034514f5e3Sopenharmony_ci // 3. Let strLen be the length of S. 8044514f5e3Sopenharmony_ci // 4. Let k be 0. 8054514f5e3Sopenharmony_ci uint32_t size = EcmaStringAccessor(string).GetLength(); 8064514f5e3Sopenharmony_ci uint32_t position = 0; 8074514f5e3Sopenharmony_ci 8084514f5e3Sopenharmony_ci // 5. Let result be the empty String. 8094514f5e3Sopenharmony_ci std::u16string r; 8104514f5e3Sopenharmony_ci 8114514f5e3Sopenharmony_ci // Repeat, while k < strLen, 8124514f5e3Sopenharmony_ci // a. Let cp be CodePointAt(S, k). 8134514f5e3Sopenharmony_ci // b. If cp.[[IsUnpairedSurrogate]] is true, then 8144514f5e3Sopenharmony_ci // i. Set result to the string-concatenation of result and 0xFFFD (REPLACEMENT CHARACTER). 8154514f5e3Sopenharmony_ci // c. Else, 8164514f5e3Sopenharmony_ci // i. Set result to the string-concatenation of result and UTF16EncodeCodePoint(cp.[[CodePoint]]). 8174514f5e3Sopenharmony_ci // d. Set k to k + cp.[[CodeUnitCount]]. 8184514f5e3Sopenharmony_ci while (position < size) { 8194514f5e3Sopenharmony_ci // i.Let first be the code unit at index position within string. 8204514f5e3Sopenharmony_ci uint16_t first = EcmaStringAccessor(string).Get(position); 8214514f5e3Sopenharmony_ci uint32_t cp = first - CHAR16_LETTER_NULL; 8224514f5e3Sopenharmony_ci uint8_t codeUnitCount = 0; 8234514f5e3Sopenharmony_ci bool isUnpairedSurrogate = false; 8244514f5e3Sopenharmony_ci // ii. If first is neither a leading surrogate nor a trailing surrogate, then 8254514f5e3Sopenharmony_ci // a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }. 8264514f5e3Sopenharmony_ci if (!IsUTF16HighSurrogate(first) && !IsUTF16LowSurrogate(first)) { 8274514f5e3Sopenharmony_ci codeUnitCount = 1; // 1 means: code unit count 8284514f5e3Sopenharmony_ci isUnpairedSurrogate = false; 8294514f5e3Sopenharmony_ci } else if (IsUTF16HighSurrogate(first) && position + 1 == size) { 8304514f5e3Sopenharmony_ci // iii. If first is a trailing surrogate or position + 1 = size, then 8314514f5e3Sopenharmony_ci // a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }. 8324514f5e3Sopenharmony_ci codeUnitCount = 1; 8334514f5e3Sopenharmony_ci isUnpairedSurrogate = true; 8344514f5e3Sopenharmony_ci } else { 8354514f5e3Sopenharmony_ci // iv. Let second be the code unit at index position + 1 within string. 8364514f5e3Sopenharmony_ci uint16_t second = EcmaStringAccessor(string).Get(position + 1); 8374514f5e3Sopenharmony_ci // v. If second is not a trailing surrogate, then 8384514f5e3Sopenharmony_ci // a. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }. 8394514f5e3Sopenharmony_ci if (!IsUTF16LowSurrogate(second)) { 8404514f5e3Sopenharmony_ci codeUnitCount = 1; // 1 means: code unit count 8414514f5e3Sopenharmony_ci isUnpairedSurrogate = true; 8424514f5e3Sopenharmony_ci } else { 8434514f5e3Sopenharmony_ci // vi. Set cp to UTF16SurrogatePairToCodePoint(first, second). 8444514f5e3Sopenharmony_ci // vii. Return the Record { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }. 8454514f5e3Sopenharmony_ci cp = UTF16SurrogatePairToCodePoint(first, second); 8464514f5e3Sopenharmony_ci codeUnitCount = 2; // 2 means: code unit count 8474514f5e3Sopenharmony_ci isUnpairedSurrogate = false; 8484514f5e3Sopenharmony_ci } 8494514f5e3Sopenharmony_ci } 8504514f5e3Sopenharmony_ci if (isUnpairedSurrogate) { 8514514f5e3Sopenharmony_ci r.push_back(0xFFFD); 8524514f5e3Sopenharmony_ci } else { 8534514f5e3Sopenharmony_ci if (cp < 0 || cp > ENCODE_MAX_UTF16) { 8544514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "CodePoint < 0 or CodePoint > 0x10FFFF", 8554514f5e3Sopenharmony_ci JSTaggedValue::Exception()); 8564514f5e3Sopenharmony_ci } 8574514f5e3Sopenharmony_ci if (cp > UINT16_MAX) { 8584514f5e3Sopenharmony_ci uint16_t cu1 = std::floor((static_cast<uint32_t>(cp) - ENCODE_SECOND_FACTOR) / 8594514f5e3Sopenharmony_ci ENCODE_FIRST_FACTOR) + ENCODE_LEAD_LOW; 8604514f5e3Sopenharmony_ci uint16_t cu2 = ((static_cast<uint32_t>(cp) - ENCODE_SECOND_FACTOR) % 8614514f5e3Sopenharmony_ci ENCODE_FIRST_FACTOR) + ENCODE_TRAIL_LOW; 8624514f5e3Sopenharmony_ci std::u16string nextU16str1 = base::StringHelper::Utf16ToU16String(&cu1, 1); 8634514f5e3Sopenharmony_ci std::u16string nextU16str2 = base::StringHelper::Utf16ToU16String(&cu2, 1); 8644514f5e3Sopenharmony_ci base::StringHelper::InplaceAppend(r, nextU16str1); 8654514f5e3Sopenharmony_ci base::StringHelper::InplaceAppend(r, nextU16str2); 8664514f5e3Sopenharmony_ci } else { 8674514f5e3Sopenharmony_ci auto u16tCp = static_cast<uint16_t>(cp); 8684514f5e3Sopenharmony_ci std::u16string nextU16str = base::StringHelper::Utf16ToU16String(&u16tCp, 1); 8694514f5e3Sopenharmony_ci base::StringHelper::InplaceAppend(r, nextU16str); 8704514f5e3Sopenharmony_ci } 8714514f5e3Sopenharmony_ci } 8724514f5e3Sopenharmony_ci position = position + codeUnitCount; 8734514f5e3Sopenharmony_ci thread->CheckSafepointIfSuspended(); 8744514f5e3Sopenharmony_ci } 8754514f5e3Sopenharmony_ci const char16_t *constChar16tData = r.data(); 8764514f5e3Sopenharmony_ci auto *char16tData = const_cast<char16_t *>(constChar16tData); 8774514f5e3Sopenharmony_ci auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData); 8784514f5e3Sopenharmony_ci uint32_t u16strSize = r.size(); 8794514f5e3Sopenharmony_ci return factory->NewFromUtf16Literal(uint16tData, u16strSize).GetTaggedValue(); 8804514f5e3Sopenharmony_ci} 8814514f5e3Sopenharmony_ci 8824514f5e3Sopenharmony_ci// Static Semantics: UTF16SurrogatePairToCodePoint ( lead, trail ) 8834514f5e3Sopenharmony_ciuint32_t BuiltinsString::UTF16SurrogatePairToCodePoint(uint16_t lead, uint16_t trail) 8844514f5e3Sopenharmony_ci{ 8854514f5e3Sopenharmony_ci // 1. Assert: lead is a leading surrogate and trail is a trailing surrogate. 8864514f5e3Sopenharmony_ci ASSERT(IsUTF16HighSurrogate(lead) && IsUTF16LowSurrogate(trail)); 8874514f5e3Sopenharmony_ci // 2. Let cp be (lead - 0xD800) × 0x400 + (trail - 0xDC00) + 0x10000. 8884514f5e3Sopenharmony_ci uint32_t cp = ((lead - 0xD800) << 10UL) + (trail - 0xDC00) + 0x10000; 8894514f5e3Sopenharmony_ci // 3. Return the code point cp. 8904514f5e3Sopenharmony_ci return cp; 8914514f5e3Sopenharmony_ci} 8924514f5e3Sopenharmony_ci 8934514f5e3Sopenharmony_ci// 21.1.3.12 8944514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Normalize(EcmaRuntimeCallInfo *argv) 8954514f5e3Sopenharmony_ci{ 8964514f5e3Sopenharmony_ci ASSERT(argv); 8974514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Normalize); 8984514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 8994514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 9004514f5e3Sopenharmony_ci auto vm = thread->GetEcmaVM(); 9014514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 9024514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 9034514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 9044514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); 9054514f5e3Sopenharmony_ci JSHandle<EcmaString> formValue; 9064514f5e3Sopenharmony_ci if (argv->GetArgsNumber() == 0) { 9074514f5e3Sopenharmony_ci formValue = JSHandle<EcmaString>::Cast(thread->GlobalConstants()->GetHandledNfcString()); 9084514f5e3Sopenharmony_ci } else { 9094514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> formTag = BuiltinsString::GetCallArg(argv, 0); 9104514f5e3Sopenharmony_ci if (formTag->IsUndefined()) { 9114514f5e3Sopenharmony_ci formValue = JSHandle<EcmaString>::Cast(thread->GlobalConstants()->GetHandledNfcString()); 9124514f5e3Sopenharmony_ci } else { 9134514f5e3Sopenharmony_ci formValue = JSTaggedValue::ToString(thread, formTag); 9144514f5e3Sopenharmony_ci RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); 9154514f5e3Sopenharmony_ci } 9164514f5e3Sopenharmony_ci } 9174514f5e3Sopenharmony_ci UNormalizationMode uForm; 9184514f5e3Sopenharmony_ci if (JSHandle<EcmaString> nfc = 9194514f5e3Sopenharmony_ci JSHandle<EcmaString>::Cast(thread->GlobalConstants()->GetHandledNfcString()); 9204514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(vm, formValue, nfc)) { 9214514f5e3Sopenharmony_ci uForm = UNORM_NFC; 9224514f5e3Sopenharmony_ci } else if (JSHandle<EcmaString> nfd = 9234514f5e3Sopenharmony_ci JSHandle<EcmaString>::Cast(thread->GlobalConstants()->GetHandledNfdString()); 9244514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(vm, formValue, nfd)) { 9254514f5e3Sopenharmony_ci uForm = UNORM_NFD; 9264514f5e3Sopenharmony_ci } else if (JSHandle<EcmaString> nfkc = 9274514f5e3Sopenharmony_ci JSHandle<EcmaString>::Cast(thread->GlobalConstants()->GetHandledNfkcString()); 9284514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(vm, formValue, nfkc)) { 9294514f5e3Sopenharmony_ci uForm = UNORM_NFKC; 9304514f5e3Sopenharmony_ci } else if (JSHandle<EcmaString> nfkd = 9314514f5e3Sopenharmony_ci JSHandle<EcmaString>::Cast(thread->GlobalConstants()->GetHandledNfkdString()); 9324514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(vm, formValue, nfkd)) { 9334514f5e3Sopenharmony_ci uForm = UNORM_NFKD; 9344514f5e3Sopenharmony_ci } else { 9354514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "compare not equal", JSTaggedValue::Exception()); 9364514f5e3Sopenharmony_ci } 9374514f5e3Sopenharmony_ci 9384514f5e3Sopenharmony_ci std::u16string u16strThis = EcmaStringAccessor(thisHandle).ToU16String(); 9394514f5e3Sopenharmony_ci const char16_t *constChar16tData = u16strThis.data(); 9404514f5e3Sopenharmony_ci icu::UnicodeString src(constChar16tData, u16strThis.size()); 9414514f5e3Sopenharmony_ci icu::UnicodeString res; 9424514f5e3Sopenharmony_ci UErrorCode errorCode = U_ZERO_ERROR; 9434514f5e3Sopenharmony_ci int32_t option = 0; 9444514f5e3Sopenharmony_ci 9454514f5e3Sopenharmony_ci icu::Normalizer::normalize(src, uForm, option, res, errorCode); 9464514f5e3Sopenharmony_ci JSHandle<EcmaString> str = intl::LocaleHelper::UStringToString(thread, res); 9474514f5e3Sopenharmony_ci return JSTaggedValue(*str); 9484514f5e3Sopenharmony_ci} 9494514f5e3Sopenharmony_ci 9504514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::PadStart(EcmaRuntimeCallInfo *argv) 9514514f5e3Sopenharmony_ci{ 9524514f5e3Sopenharmony_ci ASSERT(argv); 9534514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, PadStart); 9544514f5e3Sopenharmony_ci return BuiltinsString::Pad(argv, true); 9554514f5e3Sopenharmony_ci} 9564514f5e3Sopenharmony_ci 9574514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::PadEnd(EcmaRuntimeCallInfo *argv) 9584514f5e3Sopenharmony_ci{ 9594514f5e3Sopenharmony_ci ASSERT(argv); 9604514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, PadEnd); 9614514f5e3Sopenharmony_ci return BuiltinsString::Pad(argv, false); 9624514f5e3Sopenharmony_ci} 9634514f5e3Sopenharmony_ci 9644514f5e3Sopenharmony_ci// 21.1.3.13 9654514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Repeat(EcmaRuntimeCallInfo *argv) 9664514f5e3Sopenharmony_ci{ 9674514f5e3Sopenharmony_ci ASSERT(argv); 9684514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Repeat); 9694514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 9704514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 9714514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 9724514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 9734514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 9744514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 9754514f5e3Sopenharmony_ci uint32_t thisLen = EcmaStringAccessor(thisHandle).GetLength(); 9764514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> countTag = BuiltinsString::GetCallArg(argv, 0); 9774514f5e3Sopenharmony_ci int32_t count = 0; 9784514f5e3Sopenharmony_ci if (countTag->IsInt()) { 9794514f5e3Sopenharmony_ci count = countTag->GetInt(); 9804514f5e3Sopenharmony_ci } else { 9814514f5e3Sopenharmony_ci JSTaggedNumber num = JSTaggedValue::ToInteger(thread, countTag); 9824514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 9834514f5e3Sopenharmony_ci double d = num.GetNumber(); 9844514f5e3Sopenharmony_ci if (d == base::POSITIVE_INFINITY) { 9854514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "is infinity", JSTaggedValue::Exception()); 9864514f5e3Sopenharmony_ci } 9874514f5e3Sopenharmony_ci count = base::NumberHelper::DoubleInRangeInt32(d); 9884514f5e3Sopenharmony_ci } 9894514f5e3Sopenharmony_ci if (count < 0) { 9904514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "less than 0", JSTaggedValue::Exception()); 9914514f5e3Sopenharmony_ci } 9924514f5e3Sopenharmony_ci if (count == 0) { 9934514f5e3Sopenharmony_ci auto emptyStr = thread->GetEcmaVM()->GetFactory()->GetEmptyString(); 9944514f5e3Sopenharmony_ci return emptyStr.GetTaggedValue(); 9954514f5e3Sopenharmony_ci } 9964514f5e3Sopenharmony_ci if (thisLen == 0) { 9974514f5e3Sopenharmony_ci return thisHandle.GetTaggedValue(); 9984514f5e3Sopenharmony_ci } 9994514f5e3Sopenharmony_ci if (static_cast<uint32_t>(count) >= static_cast<uint32_t>(EcmaString::MAX_STRING_LENGTH) / thisLen) { 10004514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); 10014514f5e3Sopenharmony_ci } 10024514f5e3Sopenharmony_ci bool isUtf8 = EcmaStringAccessor(thisHandle).IsUtf8(); 10034514f5e3Sopenharmony_ci EcmaString *result = EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), thisLen * count, isUtf8); 10044514f5e3Sopenharmony_ci for (uint32_t index = 0; index < static_cast<uint32_t>(count); ++index) { 10054514f5e3Sopenharmony_ci EcmaStringAccessor::ReadData(result, *thisHandle, index * thisLen, (count - index) * thisLen, thisLen); 10064514f5e3Sopenharmony_ci } 10074514f5e3Sopenharmony_ci return JSTaggedValue(result); 10084514f5e3Sopenharmony_ci} 10094514f5e3Sopenharmony_ci 10104514f5e3Sopenharmony_ci// 21.1.3.14 10114514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Replace(EcmaRuntimeCallInfo *argv) 10124514f5e3Sopenharmony_ci{ 10134514f5e3Sopenharmony_ci ASSERT(argv); 10144514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Replace); 10154514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 10164514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 10174514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, BuiltinsString::GetThis(argv)); 10184514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 10194514f5e3Sopenharmony_ci 10204514f5e3Sopenharmony_ci auto ecmaVm = thread->GetEcmaVM(); 10214514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 10224514f5e3Sopenharmony_ci const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 10234514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> searchTag = BuiltinsString::GetCallArg(argv, 0); 10244514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> replaceTag = BuiltinsString::GetCallArg(argv, 1); 10254514f5e3Sopenharmony_ci 10264514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 10274514f5e3Sopenharmony_ci 10284514f5e3Sopenharmony_ci if (searchTag->IsJSRegExp() && replaceTag->IsString()) { 10294514f5e3Sopenharmony_ci JSHandle<RegExpExecResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); 10304514f5e3Sopenharmony_ci JSHandle<JSRegExp> re(searchTag); 10314514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> pattern(thread, re->GetOriginalSource()); 10324514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> flags(thread, re->GetOriginalFlags()); 10334514f5e3Sopenharmony_ci bool isFastPath = BuiltinsRegExp::IsFastRegExp(thread, searchTag); 10344514f5e3Sopenharmony_ci if (isFastPath) { 10354514f5e3Sopenharmony_ci uint32_t lastIndex = static_cast<uint32_t>(BuiltinsRegExp::GetLastIndex(thread, searchTag, true)); 10364514f5e3Sopenharmony_ci JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, thisTag, 10374514f5e3Sopenharmony_ci RegExpExecResultCache::REPLACE_TYPE, searchTag, JSTaggedValue(lastIndex), 10384514f5e3Sopenharmony_ci replaceTag); 10394514f5e3Sopenharmony_ci if (!cacheResult.IsUndefined()) { 10404514f5e3Sopenharmony_ci return cacheResult; 10414514f5e3Sopenharmony_ci } 10424514f5e3Sopenharmony_ci } 10434514f5e3Sopenharmony_ci } 10444514f5e3Sopenharmony_ci 10454514f5e3Sopenharmony_ci if (searchTag->IsJSRegExp() && PropertyDetector::IsRegExpReplaceDetectorValid(env)) { 10464514f5e3Sopenharmony_ci JSTaggedValue proto = JSObject::GetPrototype(JSHandle<JSObject>(searchTag)); 10474514f5e3Sopenharmony_ci if (proto == env->GetTaggedRegExpPrototype()) { 10484514f5e3Sopenharmony_ci return BuiltinsRegExp::ReplaceInternal(thread, searchTag, thisTag, replaceTag); 10494514f5e3Sopenharmony_ci } 10504514f5e3Sopenharmony_ci } 10514514f5e3Sopenharmony_ci 10524514f5e3Sopenharmony_ci // If searchValue is neither undefined nor null, then 10534514f5e3Sopenharmony_ci if (!searchTag->IsUndefined() && !searchTag->IsNull()) { 10544514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> replaceKey = env->GetReplaceSymbol(); 10554514f5e3Sopenharmony_ci // Let replacer be GetMethod(searchValue, @@replace). 10564514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> replaceMethod = JSObject::GetMethod(thread, searchTag, replaceKey); 10574514f5e3Sopenharmony_ci // ReturnIfAbrupt(replacer). 10584514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 10594514f5e3Sopenharmony_ci // If replacer is not undefined, then 10604514f5e3Sopenharmony_ci if (!replaceMethod->IsUndefined()) { 10614514f5e3Sopenharmony_ci // Return Call(replacer, searchValue, «O, replaceValue»). 10624514f5e3Sopenharmony_ci const uint32_t argsLength = 2; 10634514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 10644514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 10654514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, replaceMethod, searchTag, undefined, argsLength); 10664514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 10674514f5e3Sopenharmony_ci info->SetCallArg(thisTag.GetTaggedValue(), replaceTag.GetTaggedValue()); 10684514f5e3Sopenharmony_ci return JSFunction::Call(info); 10694514f5e3Sopenharmony_ci } 10704514f5e3Sopenharmony_ci } 10714514f5e3Sopenharmony_ci 10724514f5e3Sopenharmony_ci // Let string be ToString(O). 10734514f5e3Sopenharmony_ci JSHandle<EcmaString> thisString = JSTaggedValue::ToString(thread, thisTag); 10744514f5e3Sopenharmony_ci // ReturnIfAbrupt(string). 10754514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 10764514f5e3Sopenharmony_ci // Let searchString be ToString(searchValue). 10774514f5e3Sopenharmony_ci JSHandle<EcmaString> searchString = JSTaggedValue::ToString(thread, searchTag); 10784514f5e3Sopenharmony_ci // ReturnIfAbrupt(searchString). 10794514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 10804514f5e3Sopenharmony_ci // Let functionalReplace be IsCallable(replaceValue). 10814514f5e3Sopenharmony_ci if (!replaceTag->IsCallable()) { 10824514f5e3Sopenharmony_ci // If functionalReplace is false, then 10834514f5e3Sopenharmony_ci // Let replaceValue be ToString(replaceValue). 10844514f5e3Sopenharmony_ci // ReturnIfAbrupt(replaceValue) 10854514f5e3Sopenharmony_ci replaceTag = JSHandle<JSTaggedValue>(JSTaggedValue::ToString(thread, replaceTag)); 10864514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 10874514f5e3Sopenharmony_ci } 10884514f5e3Sopenharmony_ci // Search string for the first occurrence of searchString and let pos be the index within string of the first code 10894514f5e3Sopenharmony_ci // unit of the matched substring and let matched be searchString. If no occurrences of searchString were found, 10904514f5e3Sopenharmony_ci // return string. 10914514f5e3Sopenharmony_ci int32_t pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, searchString); 10924514f5e3Sopenharmony_ci if (pos == -1) { 10934514f5e3Sopenharmony_ci return thisString.GetTaggedValue(); 10944514f5e3Sopenharmony_ci } 10954514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 10964514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> replHandle(thread, factory->GetEmptyString().GetTaggedValue()); 10974514f5e3Sopenharmony_ci // If functionalReplace is true, then 10984514f5e3Sopenharmony_ci if (replaceTag->IsCallable()) { 10994514f5e3Sopenharmony_ci // Let replValue be Call(replaceValue, undefined,«matched, pos, and string»). 11004514f5e3Sopenharmony_ci const uint32_t argsLength = 3; // 3: «matched, pos, and string» 11014514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 11024514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, replaceTag, undefined, undefined, argsLength); 11034514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11044514f5e3Sopenharmony_ci info->SetCallArg(searchString.GetTaggedValue(), JSTaggedValue(pos), thisString.GetTaggedValue()); 11054514f5e3Sopenharmony_ci JSTaggedValue replStrDeocodeValue = JSFunction::Call(info); 11064514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11074514f5e3Sopenharmony_ci replHandle.Update(replStrDeocodeValue); 11084514f5e3Sopenharmony_ci } else { 11094514f5e3Sopenharmony_ci // Let captures be an empty List. 11104514f5e3Sopenharmony_ci JSHandle<TaggedArray> capturesList = factory->EmptyArray(); 11114514f5e3Sopenharmony_ci ASSERT_PRINT(replaceTag->IsString(), "replace must be string"); 11124514f5e3Sopenharmony_ci JSHandle<EcmaString> replacement(thread, replaceTag->GetTaggedObject()); 11134514f5e3Sopenharmony_ci // Let replStr be GetSubstitution(matched, string, pos, captures, replaceValue) 11144514f5e3Sopenharmony_ci replHandle.Update(GetSubstitution(thread, searchString, thisString, pos, capturesList, undefined, replacement)); 11154514f5e3Sopenharmony_ci } 11164514f5e3Sopenharmony_ci JSHandle<EcmaString> realReplaceStr = JSTaggedValue::ToString(thread, replHandle); 11174514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11184514f5e3Sopenharmony_ci // Let tailPos be pos + the number of code units in matched. 11194514f5e3Sopenharmony_ci int32_t tailPos = pos + static_cast<int32_t>(EcmaStringAccessor(searchString).GetLength()); 11204514f5e3Sopenharmony_ci // Let newString be the String formed by concatenating the first pos code units of string, 11214514f5e3Sopenharmony_ci // replStr, and the trailing 11224514f5e3Sopenharmony_ci // substring of string starting at index tailPos. If pos is 0, 11234514f5e3Sopenharmony_ci // the first element of the concatenation will be the 11244514f5e3Sopenharmony_ci // empty String. 11254514f5e3Sopenharmony_ci // Return newString. 11264514f5e3Sopenharmony_ci JSHandle<EcmaString> prefixString(thread, EcmaStringAccessor::FastSubString(ecmaVm, thisString, 0, pos)); 11274514f5e3Sopenharmony_ci auto thisLen = EcmaStringAccessor(thisString).GetLength(); 11284514f5e3Sopenharmony_ci JSHandle<EcmaString> suffixString(thread, 11294514f5e3Sopenharmony_ci EcmaStringAccessor::FastSubString(ecmaVm, thisString, tailPos, thisLen - tailPos)); 11304514f5e3Sopenharmony_ci EcmaString *tempStr = EcmaStringAccessor::Concat(ecmaVm, prefixString, realReplaceStr); 11314514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11324514f5e3Sopenharmony_ci JSHandle<EcmaString> tempString(thread, tempStr); 11334514f5e3Sopenharmony_ci EcmaString *resultStr = EcmaStringAccessor::Concat(ecmaVm, tempString, suffixString); 11344514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11354514f5e3Sopenharmony_ci return JSTaggedValue(resultStr); 11364514f5e3Sopenharmony_ci} 11374514f5e3Sopenharmony_ci 11384514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::ReplaceAll(EcmaRuntimeCallInfo *argv) 11394514f5e3Sopenharmony_ci{ 11404514f5e3Sopenharmony_ci ASSERT(argv); 11414514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 11424514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, String, ReplaceAll); 11434514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 11444514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, BuiltinsString::GetThis(argv)); 11454514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11464514f5e3Sopenharmony_ci 11474514f5e3Sopenharmony_ci auto ecmaVm = thread->GetEcmaVM(); 11484514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 11494514f5e3Sopenharmony_ci const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 11504514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> searchTag = BuiltinsString::GetCallArg(argv, 0); 11514514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> replaceTag = BuiltinsString::GetCallArg(argv, 1); 11524514f5e3Sopenharmony_ci 11534514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 11544514f5e3Sopenharmony_ci 11554514f5e3Sopenharmony_ci if (!searchTag->IsUndefined() && !searchTag->IsNull()) { 11564514f5e3Sopenharmony_ci // a. Let isRegExp be ? IsRegExp(searchValue). 11574514f5e3Sopenharmony_ci bool isJSRegExp = JSObject::IsRegExp(thread, searchTag); 11584514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11594514f5e3Sopenharmony_ci // b. If isRegExp is true, then 11604514f5e3Sopenharmony_ci if (isJSRegExp) { 11614514f5e3Sopenharmony_ci // i. Let flags be ? Get(searchValue, "flags"). 11624514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> flagsString(globalConst->GetHandledFlagsString()); 11634514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> flags = JSObject::GetProperty(thread, searchTag, flagsString).GetValue(); 11644514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11654514f5e3Sopenharmony_ci // ii. Perform ? RequireObjectCoercible(flags). 11664514f5e3Sopenharmony_ci JSTaggedValue::RequireObjectCoercible(thread, flags); 11674514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11684514f5e3Sopenharmony_ci // iii. If ? ToString(flags) does not contain "g", throw a TypeError exception. 11694514f5e3Sopenharmony_ci JSHandle<EcmaString> flagString = JSTaggedValue::ToString(thread, flags); 11704514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11714514f5e3Sopenharmony_ci JSHandle<EcmaString> gString(globalConst->GetHandledGString()); 11724514f5e3Sopenharmony_ci int32_t pos = EcmaStringAccessor::IndexOf(ecmaVm, flagString, gString); 11734514f5e3Sopenharmony_ci if (pos == -1) { 11744514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, 11754514f5e3Sopenharmony_ci "string.prototype.replaceAll called with a non-global RegExp argument", 11764514f5e3Sopenharmony_ci JSTaggedValue::Exception()); 11774514f5e3Sopenharmony_ci } 11784514f5e3Sopenharmony_ci } 11794514f5e3Sopenharmony_ci // c. Let replacer be ? GetMethod(searchValue, @@replace). 11804514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> replaceKey = env->GetReplaceSymbol(); 11814514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> replaceMethod = JSObject::GetMethod(thread, searchTag, replaceKey); 11824514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11834514f5e3Sopenharmony_ci // d. If replacer is not undefined, then 11844514f5e3Sopenharmony_ci if (!replaceMethod->IsUndefined()) { 11854514f5e3Sopenharmony_ci // i. Return ? Call(replacer, searchValue, «O, replaceValue»). 11864514f5e3Sopenharmony_ci const size_t argsLength = 2; 11874514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 11884514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 11894514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, replaceMethod, searchTag, undefined, argsLength); 11904514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11914514f5e3Sopenharmony_ci info->SetCallArg(thisTag.GetTaggedValue(), replaceTag.GetTaggedValue()); 11924514f5e3Sopenharmony_ci return JSFunction::Call(info); 11934514f5e3Sopenharmony_ci } 11944514f5e3Sopenharmony_ci } 11954514f5e3Sopenharmony_ci 11964514f5e3Sopenharmony_ci // 3. Let string be ? ToString(O). 11974514f5e3Sopenharmony_ci JSHandle<EcmaString> thisString = JSTaggedValue::ToString(thread, thisTag); 11984514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 11994514f5e3Sopenharmony_ci // 4. Let searchString be ? ToString(searchValue). 12004514f5e3Sopenharmony_ci JSHandle<EcmaString> searchString = JSTaggedValue::ToString(thread, searchTag); 12014514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 12024514f5e3Sopenharmony_ci // 5. Let functionalReplace be IsCallable(replaceValue). 12034514f5e3Sopenharmony_ci // 6. If functionalReplace is false, then 12044514f5e3Sopenharmony_ci if (!replaceTag->IsCallable()) { 12054514f5e3Sopenharmony_ci // a. Set replaceValue to ? ToString(replaceValue). 12064514f5e3Sopenharmony_ci replaceTag = JSHandle<JSTaggedValue>(JSTaggedValue::ToString(thread, replaceTag)); 12074514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 12084514f5e3Sopenharmony_ci } 12094514f5e3Sopenharmony_ci 12104514f5e3Sopenharmony_ci // 7. Let searchLength be the length of searchString. 12114514f5e3Sopenharmony_ci // 8. Let advanceBy be max(1, searchLength). 12124514f5e3Sopenharmony_ci int32_t searchLength = static_cast<int32_t>(EcmaStringAccessor(searchString).GetLength()); 12134514f5e3Sopenharmony_ci int32_t advanceBy = std::max(1, searchLength); 12144514f5e3Sopenharmony_ci // 9. Let matchPositions be a new empty List. 12154514f5e3Sopenharmony_ci JSMutableHandle<EcmaString> accumulatedResult(thread, factory->GetEmptyString()); 12164514f5e3Sopenharmony_ci // 10. Let position be ! StringIndexOf(string, searchString, 0). 12174514f5e3Sopenharmony_ci int32_t pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, searchString); 12184514f5e3Sopenharmony_ci int32_t endOfLastMatch = 0; 12194514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 12204514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> replHandle(thread, factory->GetEmptyString().GetTaggedValue()); 12214514f5e3Sopenharmony_ci while (pos != -1) { 12224514f5e3Sopenharmony_ci // If functionalReplace is true, then 12234514f5e3Sopenharmony_ci if (replaceTag->IsCallable()) { 12244514f5e3Sopenharmony_ci // Let replValue be Call(replaceValue, undefined,«matched, pos, and string»). 12254514f5e3Sopenharmony_ci const uint32_t argsLength = 3; // 3: «matched, pos, and string» 12264514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 12274514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, replaceTag, undefined, undefined, argsLength); 12284514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 12294514f5e3Sopenharmony_ci info->SetCallArg(searchString.GetTaggedValue(), JSTaggedValue(pos), thisString.GetTaggedValue()); 12304514f5e3Sopenharmony_ci JSTaggedValue replStrDeocodeValue = JSFunction::Call(info); 12314514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 12324514f5e3Sopenharmony_ci replHandle.Update(replStrDeocodeValue); 12334514f5e3Sopenharmony_ci } else { 12344514f5e3Sopenharmony_ci // Let captures be an empty List. 12354514f5e3Sopenharmony_ci JSHandle<TaggedArray> capturesList = factory->NewTaggedArray(0); 12364514f5e3Sopenharmony_ci ASSERT_PRINT(replaceTag->IsString(), "replace must be string"); 12374514f5e3Sopenharmony_ci JSHandle<EcmaString> replacement(thread, replaceTag->GetTaggedObject()); 12384514f5e3Sopenharmony_ci // Let replStr be GetSubstitution(matched, string, pos, captures, replaceValue) 12394514f5e3Sopenharmony_ci replHandle.Update(GetSubstitution(thread, searchString, thisString, pos, 12404514f5e3Sopenharmony_ci capturesList, undefined, replacement)); 12414514f5e3Sopenharmony_ci } 12424514f5e3Sopenharmony_ci JSHandle<EcmaString> realReplaceStr = JSTaggedValue::ToString(thread, replHandle); 12434514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 12444514f5e3Sopenharmony_ci // Let tailPos be pos + the number of code units in matched. 12454514f5e3Sopenharmony_ci // Let newString be the String formed by concatenating the first pos code units of string, 12464514f5e3Sopenharmony_ci // replStr, and the trailing substring of string starting at index tailPos. 12474514f5e3Sopenharmony_ci // If pos is 0, the first element of the concatenation will be the 12484514f5e3Sopenharmony_ci // empty String. 12494514f5e3Sopenharmony_ci // Return newString. 12504514f5e3Sopenharmony_ci JSHandle<EcmaString> prefixString(thread, 12514514f5e3Sopenharmony_ci EcmaStringAccessor::FastSubString(ecmaVm, thisString, endOfLastMatch, 12524514f5e3Sopenharmony_ci pos - endOfLastMatch)); 12534514f5e3Sopenharmony_ci accumulatedResult.Update(JSTaggedValue(EcmaStringAccessor::Concat(ecmaVm, accumulatedResult, prefixString))); 12544514f5e3Sopenharmony_ci accumulatedResult.Update(JSTaggedValue(EcmaStringAccessor::Concat(ecmaVm, accumulatedResult, realReplaceStr))); 12554514f5e3Sopenharmony_ci endOfLastMatch = pos + searchLength; 12564514f5e3Sopenharmony_ci pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, searchString, pos + advanceBy); 12574514f5e3Sopenharmony_ci thread->CheckSafepointIfSuspended(); 12584514f5e3Sopenharmony_ci } 12594514f5e3Sopenharmony_ci 12604514f5e3Sopenharmony_ci if (endOfLastMatch < static_cast<int32_t>(EcmaStringAccessor(thisString).GetLength())) { 12614514f5e3Sopenharmony_ci auto thisLen = EcmaStringAccessor(thisString).GetLength(); 12624514f5e3Sopenharmony_ci JSHandle<EcmaString> suffixString(thread, 12634514f5e3Sopenharmony_ci EcmaStringAccessor::FastSubString(ecmaVm, thisString, endOfLastMatch, thisLen - endOfLastMatch)); 12644514f5e3Sopenharmony_ci accumulatedResult.Update(JSTaggedValue(EcmaStringAccessor::Concat(ecmaVm, accumulatedResult, suffixString))); 12654514f5e3Sopenharmony_ci } 12664514f5e3Sopenharmony_ci 12674514f5e3Sopenharmony_ci return accumulatedResult.GetTaggedValue(); 12684514f5e3Sopenharmony_ci} 12694514f5e3Sopenharmony_ci 12704514f5e3Sopenharmony_ci// Handle $& - match case 12714514f5e3Sopenharmony_civoid ProcessDollarAmpersand(std::u16string &stringBuilder, const JSHandle<EcmaString> &matched, bool &canBeCompress) 12724514f5e3Sopenharmony_ci{ 12734514f5e3Sopenharmony_ci stringBuilder += EcmaStringAccessor(matched).ToU16String(); 12744514f5e3Sopenharmony_ci if (EcmaStringAccessor(matched).IsUtf16()) { 12754514f5e3Sopenharmony_ci canBeCompress = false; 12764514f5e3Sopenharmony_ci } 12774514f5e3Sopenharmony_ci} 12784514f5e3Sopenharmony_ci 12794514f5e3Sopenharmony_ci// Handle $` - prefix case 12804514f5e3Sopenharmony_civoid ProcessDollarBacktick(EcmaVM *ecmaVm, std::u16string &stringBuilder, const JSHandle<EcmaString> &srcString, 12814514f5e3Sopenharmony_ci int position, bool &canBeCompress) 12824514f5e3Sopenharmony_ci{ 12834514f5e3Sopenharmony_ci if (position > 0) { 12844514f5e3Sopenharmony_ci EcmaString *prefix = EcmaStringAccessor::FastSubString(ecmaVm, srcString, 0, position); 12854514f5e3Sopenharmony_ci stringBuilder += EcmaStringAccessor(prefix).ToU16String(); 12864514f5e3Sopenharmony_ci if (EcmaStringAccessor(prefix).IsUtf16()) { 12874514f5e3Sopenharmony_ci canBeCompress = false; 12884514f5e3Sopenharmony_ci } 12894514f5e3Sopenharmony_ci } 12904514f5e3Sopenharmony_ci} 12914514f5e3Sopenharmony_ci 12924514f5e3Sopenharmony_ci// Handle $' - suffix case 12934514f5e3Sopenharmony_civoid ProcessDollarSingleQuote(EcmaVM *ecmaVm, std::u16string &stringBuilder, const JSHandle<EcmaString> &srcString, 12944514f5e3Sopenharmony_ci int tailPos, bool &canBeCompress) 12954514f5e3Sopenharmony_ci{ 12964514f5e3Sopenharmony_ci int32_t srcLength = static_cast<int32_t>(EcmaStringAccessor(srcString).GetLength()); 12974514f5e3Sopenharmony_ci if (tailPos < srcLength) { 12984514f5e3Sopenharmony_ci EcmaString *suffix = EcmaStringAccessor::FastSubString(ecmaVm, srcString, tailPos, srcLength - tailPos); 12994514f5e3Sopenharmony_ci stringBuilder += EcmaStringAccessor(suffix).ToU16String(); 13004514f5e3Sopenharmony_ci if (EcmaStringAccessor(suffix).IsUtf16()) { 13014514f5e3Sopenharmony_ci canBeCompress = false; 13024514f5e3Sopenharmony_ci } 13034514f5e3Sopenharmony_ci } 13044514f5e3Sopenharmony_ci} 13054514f5e3Sopenharmony_ci 13064514f5e3Sopenharmony_cistd::pair<int32_t, bool> ProcessDigitCapture(const JSHandle<EcmaString> &replacementFlat, uint32_t peekIndex, 13074514f5e3Sopenharmony_ci uint32_t replaceLength, const JSHandle<TaggedArray> &captureList, 13084514f5e3Sopenharmony_ci std::u16string &stringBuilder) 13094514f5e3Sopenharmony_ci{ 13104514f5e3Sopenharmony_ci uint32_t capturesLength = captureList->GetLength(); 13114514f5e3Sopenharmony_ci uint16_t peek = EcmaStringAccessor(replacementFlat).Get(peekIndex); 13124514f5e3Sopenharmony_ci uint32_t scaledIndex = peek - '0'; 13134514f5e3Sopenharmony_ci int32_t advance = 1; 13144514f5e3Sopenharmony_ci bool canBeCompress = true; 13154514f5e3Sopenharmony_ci 13164514f5e3Sopenharmony_ci if (peekIndex + 1 < replaceLength) { 13174514f5e3Sopenharmony_ci uint16_t nextPeek = EcmaStringAccessor(replacementFlat).Get(peekIndex + 1); 13184514f5e3Sopenharmony_ci if (nextPeek >= '0' && nextPeek <= '9') { 13194514f5e3Sopenharmony_ci constexpr uint32_t TEN_BASE = 10; 13204514f5e3Sopenharmony_ci uint32_t newScaledIndex = scaledIndex * TEN_BASE + (nextPeek - '0'); 13214514f5e3Sopenharmony_ci if (newScaledIndex <= capturesLength) { 13224514f5e3Sopenharmony_ci scaledIndex = newScaledIndex; 13234514f5e3Sopenharmony_ci advance = 2; // 2: 2 means from index needs to add two. 13244514f5e3Sopenharmony_ci } 13254514f5e3Sopenharmony_ci } 13264514f5e3Sopenharmony_ci } 13274514f5e3Sopenharmony_ci 13284514f5e3Sopenharmony_ci if (scaledIndex == 0 || scaledIndex > capturesLength) { 13294514f5e3Sopenharmony_ci stringBuilder += '$'; 13304514f5e3Sopenharmony_ci return {peekIndex, canBeCompress}; // No change in compressibility, just return the next index. 13314514f5e3Sopenharmony_ci } 13324514f5e3Sopenharmony_ci 13334514f5e3Sopenharmony_ci JSTaggedValue capturesVal(captureList->Get(scaledIndex - 1)); 13344514f5e3Sopenharmony_ci if (!capturesVal.IsUndefined()) { 13354514f5e3Sopenharmony_ci EcmaString *captureString = EcmaString::Cast(capturesVal.GetTaggedObject()); 13364514f5e3Sopenharmony_ci stringBuilder += EcmaStringAccessor(captureString).ToU16String(); 13374514f5e3Sopenharmony_ci if (EcmaStringAccessor(captureString).IsUtf16()) { 13384514f5e3Sopenharmony_ci canBeCompress = false; 13394514f5e3Sopenharmony_ci } 13404514f5e3Sopenharmony_ci } 13414514f5e3Sopenharmony_ci return {static_cast<int32_t>(peekIndex) + advance, canBeCompress}; 13424514f5e3Sopenharmony_ci} 13434514f5e3Sopenharmony_ci 13444514f5e3Sopenharmony_ci// Handle $< case 13454514f5e3Sopenharmony_cistd::pair<int32_t, bool> ProcessNamedCaptures(JSThread *thread, const JSHandle<EcmaString> &replacementFlat, 13464514f5e3Sopenharmony_ci int32_t peekIndex, const JSHandle<JSTaggedValue> &namedCaptures, 13474514f5e3Sopenharmony_ci std::u16string &stringBuilder) 13484514f5e3Sopenharmony_ci{ 13494514f5e3Sopenharmony_ci bool canBeCompress = true; 13504514f5e3Sopenharmony_ci if (namedCaptures->IsUndefined()) { 13514514f5e3Sopenharmony_ci stringBuilder += '$'; 13524514f5e3Sopenharmony_ci return {peekIndex, canBeCompress}; 13534514f5e3Sopenharmony_ci } 13544514f5e3Sopenharmony_ci auto ecmaVm = thread->GetEcmaVM(); 13554514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 13564514f5e3Sopenharmony_ci JSHandle<EcmaString> greaterSymString = factory->NewFromASCII(">"); 13574514f5e3Sopenharmony_ci int32_t pos = EcmaStringAccessor::IndexOf(ecmaVm, replacementFlat, greaterSymString, peekIndex); 13584514f5e3Sopenharmony_ci if (pos == -1) { 13594514f5e3Sopenharmony_ci stringBuilder += '$'; 13604514f5e3Sopenharmony_ci return {peekIndex, canBeCompress}; 13614514f5e3Sopenharmony_ci } 13624514f5e3Sopenharmony_ci JSHandle<EcmaString> groupName = JSHandle<EcmaString>( 13634514f5e3Sopenharmony_ci thread, EcmaStringAccessor::FastSubString(ecmaVm, replacementFlat, peekIndex + 1, pos - peekIndex - 1)); 13644514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> names(groupName); 13654514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> capture = JSObject::GetProperty(thread, namedCaptures, names).GetValue(); 13664514f5e3Sopenharmony_ci if (capture->IsUndefined()) { 13674514f5e3Sopenharmony_ci return {pos + 1, canBeCompress}; 13684514f5e3Sopenharmony_ci } 13694514f5e3Sopenharmony_ci JSHandle<EcmaString> captureName = JSTaggedValue::ToString(thread, capture); 13704514f5e3Sopenharmony_ci stringBuilder += EcmaStringAccessor(captureName).ToU16String(); 13714514f5e3Sopenharmony_ci if (EcmaStringAccessor(captureName).IsUtf16()) { 13724514f5e3Sopenharmony_ci canBeCompress = false; 13734514f5e3Sopenharmony_ci } 13744514f5e3Sopenharmony_ci return {pos + 1, canBeCompress}; 13754514f5e3Sopenharmony_ci} 13764514f5e3Sopenharmony_ci 13774514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::GetSubstitution(JSThread *thread, const JSHandle<EcmaString> &matched, 13784514f5e3Sopenharmony_ci const JSHandle<EcmaString> &srcString, int position, 13794514f5e3Sopenharmony_ci const JSHandle<TaggedArray> &captureList, 13804514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &namedCaptures, 13814514f5e3Sopenharmony_ci const JSHandle<EcmaString> &replacement) 13824514f5e3Sopenharmony_ci{ 13834514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, String, GetSubstitution); 13844514f5e3Sopenharmony_ci auto ecmaVm = thread->GetEcmaVM(); 13854514f5e3Sopenharmony_ci ObjectFactory *factory = ecmaVm->GetFactory(); 13864514f5e3Sopenharmony_ci JSHandle<EcmaString> dollarString = JSHandle<EcmaString>::Cast(thread->GlobalConstants()->GetHandledDollarString()); 13874514f5e3Sopenharmony_ci JSHandle<EcmaString> replacementFlat(thread, EcmaStringAccessor::Flatten(ecmaVm, replacement)); 13884514f5e3Sopenharmony_ci int32_t replaceLength = static_cast<int32_t>(EcmaStringAccessor(replacementFlat).GetLength()); 13894514f5e3Sopenharmony_ci int32_t tailPos = position + static_cast<int32_t>(EcmaStringAccessor(matched).GetLength()); 13904514f5e3Sopenharmony_ci 13914514f5e3Sopenharmony_ci int32_t nextDollarIndex = EcmaStringAccessor::IndexOf(ecmaVm, replacementFlat, dollarString); 13924514f5e3Sopenharmony_ci if (nextDollarIndex < 0) { 13934514f5e3Sopenharmony_ci return replacementFlat.GetTaggedValue(); 13944514f5e3Sopenharmony_ci } 13954514f5e3Sopenharmony_ci std::u16string stringBuilder; 13964514f5e3Sopenharmony_ci bool canBeCompress = true; 13974514f5e3Sopenharmony_ci if (nextDollarIndex > 0) { 13984514f5e3Sopenharmony_ci stringBuilder = EcmaStringAccessor(replacementFlat).ToU16String(nextDollarIndex); 13994514f5e3Sopenharmony_ci if (EcmaStringAccessor(replacementFlat).IsUtf16()) { 14004514f5e3Sopenharmony_ci canBeCompress = false; 14014514f5e3Sopenharmony_ci } 14024514f5e3Sopenharmony_ci } 14034514f5e3Sopenharmony_ci 14044514f5e3Sopenharmony_ci while (true) { 14054514f5e3Sopenharmony_ci int peekIndex = nextDollarIndex + 1; 14064514f5e3Sopenharmony_ci if (peekIndex >= replaceLength) { 14074514f5e3Sopenharmony_ci stringBuilder += '$'; 14084514f5e3Sopenharmony_ci auto *char16tData = const_cast<char16_t *>(stringBuilder.c_str()); 14094514f5e3Sopenharmony_ci auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData); 14104514f5e3Sopenharmony_ci return canBeCompress ? 14114514f5e3Sopenharmony_ci factory->NewFromUtf16LiteralCompress(uint16tData, stringBuilder.length()).GetTaggedValue() : 14124514f5e3Sopenharmony_ci factory->NewFromUtf16LiteralNotCompress(uint16tData, stringBuilder.length()).GetTaggedValue(); 14134514f5e3Sopenharmony_ci } 14144514f5e3Sopenharmony_ci int continueFromIndex = -1; 14154514f5e3Sopenharmony_ci uint16_t peek = EcmaStringAccessor(replacementFlat).Get(peekIndex); 14164514f5e3Sopenharmony_ci switch (peek) { 14174514f5e3Sopenharmony_ci case '$': // $$ 14184514f5e3Sopenharmony_ci stringBuilder += '$'; 14194514f5e3Sopenharmony_ci continueFromIndex = peekIndex + 1; 14204514f5e3Sopenharmony_ci break; 14214514f5e3Sopenharmony_ci case '&': // $& - match 14224514f5e3Sopenharmony_ci ProcessDollarAmpersand(stringBuilder, matched, canBeCompress); 14234514f5e3Sopenharmony_ci continueFromIndex = peekIndex + 1; 14244514f5e3Sopenharmony_ci break; 14254514f5e3Sopenharmony_ci case '`': // $` - prefix 14264514f5e3Sopenharmony_ci ProcessDollarBacktick(ecmaVm, stringBuilder, srcString, position, canBeCompress); 14274514f5e3Sopenharmony_ci continueFromIndex = peekIndex + 1; 14284514f5e3Sopenharmony_ci break; 14294514f5e3Sopenharmony_ci case '\'': { // $' - suffix 14304514f5e3Sopenharmony_ci ProcessDollarSingleQuote(ecmaVm, stringBuilder, srcString, tailPos, canBeCompress); 14314514f5e3Sopenharmony_ci continueFromIndex = peekIndex + 1; 14324514f5e3Sopenharmony_ci break; 14334514f5e3Sopenharmony_ci } 14344514f5e3Sopenharmony_ci case '0': 14354514f5e3Sopenharmony_ci case '1': 14364514f5e3Sopenharmony_ci case '2': 14374514f5e3Sopenharmony_ci case '3': 14384514f5e3Sopenharmony_ci case '4': 14394514f5e3Sopenharmony_ci case '5': 14404514f5e3Sopenharmony_ci case '6': 14414514f5e3Sopenharmony_ci case '7': 14424514f5e3Sopenharmony_ci case '8': 14434514f5e3Sopenharmony_ci case '9': { 14444514f5e3Sopenharmony_ci auto result = 14454514f5e3Sopenharmony_ci ProcessDigitCapture(replacementFlat, peekIndex, replaceLength, captureList, stringBuilder); 14464514f5e3Sopenharmony_ci continueFromIndex = result.first; 14474514f5e3Sopenharmony_ci canBeCompress = result.second && canBeCompress; // 保留canBeCompress的值,只在需要时更新为false 14484514f5e3Sopenharmony_ci break; 14494514f5e3Sopenharmony_ci } 14504514f5e3Sopenharmony_ci case '<': { 14514514f5e3Sopenharmony_ci auto result = ProcessNamedCaptures(thread, replacementFlat, peekIndex, namedCaptures, stringBuilder); 14524514f5e3Sopenharmony_ci continueFromIndex = result.first; 14534514f5e3Sopenharmony_ci canBeCompress = result.second && canBeCompress; // 保留canBeCompress的值,只在需要时更新为false 14544514f5e3Sopenharmony_ci break; 14554514f5e3Sopenharmony_ci } 14564514f5e3Sopenharmony_ci default: 14574514f5e3Sopenharmony_ci stringBuilder += '$'; 14584514f5e3Sopenharmony_ci continueFromIndex = peekIndex; 14594514f5e3Sopenharmony_ci break; 14604514f5e3Sopenharmony_ci } 14614514f5e3Sopenharmony_ci // Go the the next $ in the replacement. 14624514f5e3Sopenharmony_ci nextDollarIndex = EcmaStringAccessor::IndexOf(ecmaVm, replacementFlat, dollarString, continueFromIndex); 14634514f5e3Sopenharmony_ci if (nextDollarIndex < 0) { 14644514f5e3Sopenharmony_ci if (continueFromIndex < replaceLength) { 14654514f5e3Sopenharmony_ci EcmaString *nextAppend = EcmaStringAccessor::FastSubString(ecmaVm, replacementFlat, continueFromIndex, 14664514f5e3Sopenharmony_ci replaceLength - continueFromIndex); 14674514f5e3Sopenharmony_ci stringBuilder += EcmaStringAccessor(nextAppend).ToU16String(); 14684514f5e3Sopenharmony_ci if (EcmaStringAccessor(nextAppend).IsUtf16()) { 14694514f5e3Sopenharmony_ci canBeCompress = false; 14704514f5e3Sopenharmony_ci } 14714514f5e3Sopenharmony_ci } 14724514f5e3Sopenharmony_ci auto *char16tData = const_cast<char16_t *>(stringBuilder.c_str()); 14734514f5e3Sopenharmony_ci auto *uint16tData = reinterpret_cast<uint16_t *>(char16tData); 14744514f5e3Sopenharmony_ci return canBeCompress ? 14754514f5e3Sopenharmony_ci factory->NewFromUtf16LiteralCompress(uint16tData, stringBuilder.length()).GetTaggedValue() : 14764514f5e3Sopenharmony_ci factory->NewFromUtf16LiteralNotCompress(uint16tData, stringBuilder.length()).GetTaggedValue(); 14774514f5e3Sopenharmony_ci } 14784514f5e3Sopenharmony_ci // Append substring between the previous and the next $ character. 14794514f5e3Sopenharmony_ci if (nextDollarIndex > continueFromIndex) { 14804514f5e3Sopenharmony_ci EcmaString *nextAppend = EcmaStringAccessor::FastSubString( 14814514f5e3Sopenharmony_ci ecmaVm, replacementFlat, continueFromIndex, nextDollarIndex - continueFromIndex); 14824514f5e3Sopenharmony_ci stringBuilder += EcmaStringAccessor(nextAppend).ToU16String(); 14834514f5e3Sopenharmony_ci if (EcmaStringAccessor(nextAppend).IsUtf16()) { 14844514f5e3Sopenharmony_ci canBeCompress = false; 14854514f5e3Sopenharmony_ci } 14864514f5e3Sopenharmony_ci } 14874514f5e3Sopenharmony_ci thread->CheckSafepointIfSuspended(); 14884514f5e3Sopenharmony_ci } 14894514f5e3Sopenharmony_ci LOG_ECMA(FATAL) << "this branch is unreachable"; 14904514f5e3Sopenharmony_ci UNREACHABLE(); 14914514f5e3Sopenharmony_ci} 14924514f5e3Sopenharmony_ci 14934514f5e3Sopenharmony_ci// 21.1.3.15 14944514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Search(EcmaRuntimeCallInfo *argv) 14954514f5e3Sopenharmony_ci{ 14964514f5e3Sopenharmony_ci ASSERT(argv); 14974514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Search); 14984514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 14994514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 15004514f5e3Sopenharmony_ci const GlobalEnvConstants *globalConst = thread->GlobalConstants(); 15014514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 15024514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15034514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> regexp = BuiltinsString::GetCallArg(argv, 0); 15044514f5e3Sopenharmony_ci if (thisTag->IsString() && regexp->IsECMAObject()) { 15054514f5e3Sopenharmony_ci if (BuiltinsRegExp::IsFastRegExp(thread, regexp, BuiltinsRegExp::RegExpSymbol::SEARCH)) { 15064514f5e3Sopenharmony_ci return BuiltinsRegExp::RegExpSearchFast(thread, regexp, thisTag); 15074514f5e3Sopenharmony_ci } 15084514f5e3Sopenharmony_ci } 15094514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> searchTag = thread->GetEcmaVM()->GetGlobalEnv()->GetSearchSymbol(); 15104514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined(); 15114514f5e3Sopenharmony_ci if (!regexp->IsUndefined() && !regexp->IsNull()) { 15124514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> searcher = JSObject::GetMethod(thread, regexp, searchTag); 15134514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15144514f5e3Sopenharmony_ci if (!searcher->IsUndefined()) { 15154514f5e3Sopenharmony_ci ASSERT(searcher->IsJSFunctionBase()); 15164514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 15174514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, searcher, regexp, undefined, 1); 15184514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15194514f5e3Sopenharmony_ci info->SetCallArg(thisTag.GetTaggedValue()); 15204514f5e3Sopenharmony_ci return JSFunction::Call(info); 15214514f5e3Sopenharmony_ci } 15224514f5e3Sopenharmony_ci } 15234514f5e3Sopenharmony_ci JSHandle<EcmaString> thisVal = JSTaggedValue::ToString(thread, thisTag); 15244514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15254514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> rx(thread, BuiltinsRegExp::RegExpCreate(thread, regexp, undefined)); 15264514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15274514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 15284514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, rx, undefined, 1); 15294514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15304514f5e3Sopenharmony_ci info->SetCallArg(thisVal.GetTaggedValue()); 15314514f5e3Sopenharmony_ci return JSFunction::Invoke(info, searchTag); 15324514f5e3Sopenharmony_ci} 15334514f5e3Sopenharmony_ci 15344514f5e3Sopenharmony_ci// 21.1.3.16 15354514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Slice(EcmaRuntimeCallInfo *argv) 15364514f5e3Sopenharmony_ci{ 15374514f5e3Sopenharmony_ci ASSERT(argv); 15384514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Slice); 15394514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 15404514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 15414514f5e3Sopenharmony_ci 15424514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 15434514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15444514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 15454514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15464514f5e3Sopenharmony_ci int32_t thisLen = static_cast<int32_t>(EcmaStringAccessor(thisHandle).GetLength()); 15474514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> startTag = BuiltinsString::GetCallArg(argv, 0); 15484514f5e3Sopenharmony_ci JSTaggedNumber startVal = JSTaggedValue::ToInteger(thread, startTag); 15494514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15504514f5e3Sopenharmony_ci int32_t start = ConvertDoubleToInt(startVal.GetNumber()); 15514514f5e3Sopenharmony_ci int32_t end = 0; 15524514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> endTag = BuiltinsString::GetCallArg(argv, 1); 15534514f5e3Sopenharmony_ci if (endTag->IsUndefined()) { 15544514f5e3Sopenharmony_ci end = thisLen; 15554514f5e3Sopenharmony_ci } else { 15564514f5e3Sopenharmony_ci JSTaggedNumber endVal = JSTaggedValue::ToInteger(thread, endTag); 15574514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15584514f5e3Sopenharmony_ci end = ConvertDoubleToInt(endVal.GetNumber()); 15594514f5e3Sopenharmony_ci } 15604514f5e3Sopenharmony_ci int32_t from = 0; 15614514f5e3Sopenharmony_ci int32_t to = 0; 15624514f5e3Sopenharmony_ci if (start < 0) { 15634514f5e3Sopenharmony_ci from = std::max(start + thisLen, 0); 15644514f5e3Sopenharmony_ci } else { 15654514f5e3Sopenharmony_ci from = std::min(start, thisLen); 15664514f5e3Sopenharmony_ci } 15674514f5e3Sopenharmony_ci if (end < 0) { 15684514f5e3Sopenharmony_ci to = std::max(end + thisLen, 0); 15694514f5e3Sopenharmony_ci } else { 15704514f5e3Sopenharmony_ci to = std::min(end, thisLen); 15714514f5e3Sopenharmony_ci } 15724514f5e3Sopenharmony_ci int32_t len = std::max(to - from, 0); 15734514f5e3Sopenharmony_ci return JSTaggedValue(EcmaStringAccessor::FastSubString(thread->GetEcmaVM(), thisHandle, from, len)); 15744514f5e3Sopenharmony_ci} 15754514f5e3Sopenharmony_ci 15764514f5e3Sopenharmony_ci// 21.1.3.17 15774514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv) 15784514f5e3Sopenharmony_ci{ 15794514f5e3Sopenharmony_ci ASSERT(argv); 15804514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Split); 15814514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 15824514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 15834514f5e3Sopenharmony_ci auto ecmaVm = thread->GetEcmaVM(); 15844514f5e3Sopenharmony_ci JSHandle<GlobalEnv> env = ecmaVm->GetGlobalEnv(); 15854514f5e3Sopenharmony_ci 15864514f5e3Sopenharmony_ci // Let O be RequireObjectCoercible(this value). 15874514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)); 15884514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15894514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> seperatorTag = BuiltinsString::GetCallArg(argv, 0); 15904514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> limitTag = BuiltinsString::GetCallArg(argv, 1); 15914514f5e3Sopenharmony_ci 15924514f5e3Sopenharmony_ci if (thisTag->IsString() && seperatorTag->IsECMAObject()) { 15934514f5e3Sopenharmony_ci // this condition need change, all regexp should use RegExpSplit 15944514f5e3Sopenharmony_ci if (BuiltinsRegExp::IsFastRegExp(thread, seperatorTag)) { 15954514f5e3Sopenharmony_ci return BuiltinsRegExp::RegExpSplit(thread, seperatorTag, thisTag, limitTag, true); 15964514f5e3Sopenharmony_ci } 15974514f5e3Sopenharmony_ci } 15984514f5e3Sopenharmony_ci if (thisTag->IsString() && seperatorTag->IsString()) { 15994514f5e3Sopenharmony_ci JSHandle<EcmaString> thisString(thisTag); 16004514f5e3Sopenharmony_ci JSHandle<EcmaString> seperatorString(seperatorTag); 16014514f5e3Sopenharmony_ci auto thisLength = EcmaStringAccessor(thisString).GetLength(); 16024514f5e3Sopenharmony_ci auto seperatorLength = EcmaStringAccessor(seperatorString).GetLength(); 16034514f5e3Sopenharmony_ci if (limitTag->IsUndefined() && thisLength != 0 && seperatorLength != 0) { 16044514f5e3Sopenharmony_ci return CreateArrayThisStringAndSeperatorStringAreNotEmpty( 16054514f5e3Sopenharmony_ci thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength); 16064514f5e3Sopenharmony_ci } 16074514f5e3Sopenharmony_ci uint32_t lim = UINT32_MAX - 1; 16084514f5e3Sopenharmony_ci if (!limitTag->IsUndefined()) { 16094514f5e3Sopenharmony_ci JSTaggedNumber limitIntValue = JSTaggedValue::ToInteger(thread, limitTag); 16104514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16114514f5e3Sopenharmony_ci lim = limitIntValue.ToUint32(); 16124514f5e3Sopenharmony_ci } 16134514f5e3Sopenharmony_ci // ReturnIfAbrupt(lim). 16144514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16154514f5e3Sopenharmony_ci if (lim == 0) { 16164514f5e3Sopenharmony_ci JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); 16174514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16184514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 16194514f5e3Sopenharmony_ci } 16204514f5e3Sopenharmony_ci return CreateArrayBySplitString(thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength, lim); 16214514f5e3Sopenharmony_ci } 16224514f5e3Sopenharmony_ci 16234514f5e3Sopenharmony_ci // If separator is neither undefined nor null, then 16244514f5e3Sopenharmony_ci if (!seperatorTag->IsUndefined() && !seperatorTag->IsNull()) { 16254514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> splitKey = env->GetSplitSymbol(); 16264514f5e3Sopenharmony_ci // Let splitter be GetMethod(separator, @@split). 16274514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> splitter = JSObject::GetMethod(thread, seperatorTag, splitKey); 16284514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16294514f5e3Sopenharmony_ci if (!splitter->IsUndefined()) { 16304514f5e3Sopenharmony_ci // Return Call(splitter, separator, «O, limit»). 16314514f5e3Sopenharmony_ci const uint32_t argsLength = 2; 16324514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined(); 16334514f5e3Sopenharmony_ci EcmaRuntimeCallInfo *info = 16344514f5e3Sopenharmony_ci EcmaInterpreter::NewRuntimeCallInfo(thread, splitter, seperatorTag, undefined, argsLength); 16354514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16364514f5e3Sopenharmony_ci info->SetCallArg(thisTag.GetTaggedValue(), limitTag.GetTaggedValue()); 16374514f5e3Sopenharmony_ci return JSFunction::Call(info); 16384514f5e3Sopenharmony_ci } 16394514f5e3Sopenharmony_ci } 16404514f5e3Sopenharmony_ci // Let S be ToString(O). 16414514f5e3Sopenharmony_ci JSHandle<EcmaString> thisString = JSTaggedValue::ToString(thread, thisTag); 16424514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16434514f5e3Sopenharmony_ci 16444514f5e3Sopenharmony_ci // If limit is undefined, let lim = 2^53–1; else let lim = ToLength(limit). 16454514f5e3Sopenharmony_ci uint32_t lim = UINT32_MAX - 1; 16464514f5e3Sopenharmony_ci if (!limitTag->IsUndefined()) { 16474514f5e3Sopenharmony_ci JSTaggedNumber limitIntValue = JSTaggedValue::ToInteger(thread, limitTag); 16484514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16494514f5e3Sopenharmony_ci lim = limitIntValue.ToUint32(); 16504514f5e3Sopenharmony_ci } 16514514f5e3Sopenharmony_ci // ReturnIfAbrupt(lim). 16524514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16534514f5e3Sopenharmony_ci // Let s be the number of elements in S. 16544514f5e3Sopenharmony_ci auto thisLength = EcmaStringAccessor(thisString).GetLength(); 16554514f5e3Sopenharmony_ci JSHandle<EcmaString> seperatorString = JSTaggedValue::ToString(thread, seperatorTag); 16564514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16574514f5e3Sopenharmony_ci // If lim = 0, return A. 16584514f5e3Sopenharmony_ci if (lim == 0) { 16594514f5e3Sopenharmony_ci JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); 16604514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16614514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 16624514f5e3Sopenharmony_ci } 16634514f5e3Sopenharmony_ci auto seperatorLength = EcmaStringAccessor(seperatorString).GetLength(); 16644514f5e3Sopenharmony_ci // If S is undefined or (this.length = 0 and S.length != 0), return array of size is 1 containing this string 16654514f5e3Sopenharmony_ci if (seperatorTag->IsUndefined()) { 16664514f5e3Sopenharmony_ci JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(1))); 16674514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 16684514f5e3Sopenharmony_ci // Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path 16694514f5e3Sopenharmony_ci JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle<JSTaggedValue>(thisString)); 16704514f5e3Sopenharmony_ci ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception"); 16714514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 16724514f5e3Sopenharmony_ci } 16734514f5e3Sopenharmony_ci return CreateArrayBySplitString(thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength, lim); 16744514f5e3Sopenharmony_ci} 16754514f5e3Sopenharmony_ci 16764514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::CreateArrayFromString(JSThread *thread, EcmaVM *ecmaVm, 16774514f5e3Sopenharmony_ci const JSHandle<EcmaString> &thisString, uint32_t thisLength, uint32_t lim) 16784514f5e3Sopenharmony_ci{ 16794514f5e3Sopenharmony_ci bool isUtf8 = EcmaStringAccessor(thisString).IsUtf8(); 16804514f5e3Sopenharmony_ci bool canBeCompressed = false; 16814514f5e3Sopenharmony_ci if (EcmaStringAccessor(thisString).IsLineOrConstantString()) { 16824514f5e3Sopenharmony_ci canBeCompressed = EcmaStringAccessor::CanBeCompressed(*thisString); 16834514f5e3Sopenharmony_ci } 16844514f5e3Sopenharmony_ci bool isOneByte = isUtf8 & canBeCompressed; 16854514f5e3Sopenharmony_ci JSHandle<EcmaString> seperatorString = thread->GetEcmaVM()->GetFactory()->GetEmptyString(); 16864514f5e3Sopenharmony_ci if (lim == UINT32_MAX - 1) { 16874514f5e3Sopenharmony_ci JSHandle<StringSplitResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetStringSplitResultCache()); 16884514f5e3Sopenharmony_ci JSTaggedValue cacheResult = StringSplitResultCache::FindCachedResult(thread, cacheTable, thisString, 16894514f5e3Sopenharmony_ci seperatorString, isOneByte); 16904514f5e3Sopenharmony_ci if (cacheResult != JSTaggedValue::Undefined()) { 16914514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> resultArray(JSArray::CreateArrayFromList(thread, 16924514f5e3Sopenharmony_ci JSHandle<TaggedArray>(thread, cacheResult))); 16934514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 16944514f5e3Sopenharmony_ci } 16954514f5e3Sopenharmony_ci } 16964514f5e3Sopenharmony_ci uint32_t actualLength = std::min(thisLength, lim); 16974514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 16984514f5e3Sopenharmony_ci JSHandle<TaggedArray> array = factory->NewTaggedArray(actualLength); 16994514f5e3Sopenharmony_ci for (uint32_t i = 0; i < actualLength; ++i) { 17004514f5e3Sopenharmony_ci EcmaString *elementString = EcmaStringAccessor::GetSubString(ecmaVm, thisString, i, 1); 17014514f5e3Sopenharmony_ci // Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path 17024514f5e3Sopenharmony_ci if (isOneByte) { 17034514f5e3Sopenharmony_ci array->Set<false>(thread, i, JSTaggedValue(elementString)); 17044514f5e3Sopenharmony_ci } else { 17054514f5e3Sopenharmony_ci array->Set(thread, i, JSTaggedValue(elementString)); 17064514f5e3Sopenharmony_ci } 17074514f5e3Sopenharmony_ci ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception"); 17084514f5e3Sopenharmony_ci } 17094514f5e3Sopenharmony_ci JSHandle<JSArray> resultArray = JSArray::CreateArrayFromList(thread, array); 17104514f5e3Sopenharmony_ci if (lim == UINT32_MAX - 1) { 17114514f5e3Sopenharmony_ci JSHandle<StringSplitResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetStringSplitResultCache()); 17124514f5e3Sopenharmony_ci StringSplitResultCache::SetCachedResult(thread, cacheTable, thisString, seperatorString, array); 17134514f5e3Sopenharmony_ci } 17144514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 17154514f5e3Sopenharmony_ci} 17164514f5e3Sopenharmony_ci 17174514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::CreateArrayBySplitString(JSThread *thread, EcmaVM *ecmaVm, 17184514f5e3Sopenharmony_ci const JSHandle<EcmaString> &thisString, const JSHandle<EcmaString> &seperatorString, 17194514f5e3Sopenharmony_ci uint32_t thisLength, uint32_t seperatorLength, uint32_t lim) 17204514f5e3Sopenharmony_ci{ 17214514f5e3Sopenharmony_ci if (thisLength != 0) { 17224514f5e3Sopenharmony_ci if (seperatorLength != 0) { 17234514f5e3Sopenharmony_ci return CreateArrayThisStringAndSeperatorStringAreNotEmpty( 17244514f5e3Sopenharmony_ci thread, ecmaVm, thisString, seperatorString, thisLength, seperatorLength, lim); 17254514f5e3Sopenharmony_ci } 17264514f5e3Sopenharmony_ci return CreateArrayFromString(thread, ecmaVm, thisString, thisLength, lim); 17274514f5e3Sopenharmony_ci } else { 17284514f5e3Sopenharmony_ci if (seperatorLength != 0) { 17294514f5e3Sopenharmony_ci JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(1))); 17304514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 17314514f5e3Sopenharmony_ci // Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path 17324514f5e3Sopenharmony_ci JSObject::CreateDataProperty(thread, resultArray, 0, JSHandle<JSTaggedValue>(thisString)); 17334514f5e3Sopenharmony_ci ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty(A, \"0\", S) can't throw exception"); 17344514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 17354514f5e3Sopenharmony_ci } 17364514f5e3Sopenharmony_ci JSHandle<JSObject> resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); 17374514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 17384514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 17394514f5e3Sopenharmony_ci } 17404514f5e3Sopenharmony_ci} 17414514f5e3Sopenharmony_ci 17424514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::CreateArrayThisStringAndSeperatorStringAreNotEmpty(JSThread *thread, 17434514f5e3Sopenharmony_ci EcmaVM *ecmaVm, const JSHandle<EcmaString> &thisString, const JSHandle<EcmaString> &seperatorString, 17444514f5e3Sopenharmony_ci uint32_t thisLength, uint32_t seperatorLength, uint32_t lim) 17454514f5e3Sopenharmony_ci{ 17464514f5e3Sopenharmony_ci if (lim == UINT32_MAX - 1) { 17474514f5e3Sopenharmony_ci JSHandle<StringSplitResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetStringSplitResultCache()); 17484514f5e3Sopenharmony_ci JSTaggedValue cacheResult = StringSplitResultCache::FindCachedResult(thread, cacheTable, thisString, 17494514f5e3Sopenharmony_ci seperatorString); 17504514f5e3Sopenharmony_ci if (cacheResult != JSTaggedValue::Undefined()) { 17514514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> resultArray(JSArray::CreateArrayFromList(thread, 17524514f5e3Sopenharmony_ci JSHandle<TaggedArray>(thread, cacheResult))); 17534514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 17544514f5e3Sopenharmony_ci } 17554514f5e3Sopenharmony_ci } 17564514f5e3Sopenharmony_ci uint32_t arrayLength = 0; 17574514f5e3Sopenharmony_ci std::vector<int32_t> posArray; 17584514f5e3Sopenharmony_ci int32_t index = 0; 17594514f5e3Sopenharmony_ci int32_t pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, seperatorString); 17604514f5e3Sopenharmony_ci while (pos != -1) { 17614514f5e3Sopenharmony_ci posArray.emplace_back(pos); 17624514f5e3Sopenharmony_ci ++arrayLength; 17634514f5e3Sopenharmony_ci if (arrayLength == lim) { 17644514f5e3Sopenharmony_ci break; 17654514f5e3Sopenharmony_ci } 17664514f5e3Sopenharmony_ci index = pos + static_cast<int32_t>(seperatorLength); 17674514f5e3Sopenharmony_ci pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, seperatorString, index); 17684514f5e3Sopenharmony_ci thread->CheckSafepointIfSuspended(); 17694514f5e3Sopenharmony_ci } 17704514f5e3Sopenharmony_ci uint32_t posArrLength = posArray.size(); 17714514f5e3Sopenharmony_ci arrayLength = lim > posArrLength ? posArrLength + 1 : posArrLength; 17724514f5e3Sopenharmony_ci return JSArray::ArrayCreateWithInit(thread, arrayLength, 17734514f5e3Sopenharmony_ci [thread, ecmaVm, &thisString, &seperatorString, &posArray, thisLength, seperatorLength, lim, posArrLength] 17744514f5e3Sopenharmony_ci (const JSHandle<TaggedArray> &newElements, [[maybe_unused]] uint32_t length) { 17754514f5e3Sopenharmony_ci int32_t index = 0; 17764514f5e3Sopenharmony_ci int32_t pos = 0; 17774514f5e3Sopenharmony_ci JSMutableHandle<JSTaggedValue> elementTag(thread, JSTaggedValue::Undefined()); 17784514f5e3Sopenharmony_ci for (uint32_t i = 0; i < posArrLength; i++) { 17794514f5e3Sopenharmony_ci pos = posArray[i]; 17804514f5e3Sopenharmony_ci EcmaString *elementString = EcmaStringAccessor::GetSubString(ecmaVm, thisString, index, pos - index); 17814514f5e3Sopenharmony_ci elementTag.Update(JSTaggedValue(elementString)); 17824514f5e3Sopenharmony_ci newElements->Set(thread, i, elementTag); 17834514f5e3Sopenharmony_ci index = pos + static_cast<int32_t>(seperatorLength); 17844514f5e3Sopenharmony_ci } 17854514f5e3Sopenharmony_ci if (lim > posArrLength) { 17864514f5e3Sopenharmony_ci EcmaString *elementString = 17874514f5e3Sopenharmony_ci EcmaStringAccessor::GetSubString(ecmaVm, thisString, index, thisLength - index); 17884514f5e3Sopenharmony_ci elementTag.Update(JSTaggedValue(elementString)); 17894514f5e3Sopenharmony_ci newElements->Set(thread, posArrLength, elementTag); 17904514f5e3Sopenharmony_ci } 17914514f5e3Sopenharmony_ci if (lim == UINT32_MAX - 1) { 17924514f5e3Sopenharmony_ci JSHandle<StringSplitResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetStringSplitResultCache()); 17934514f5e3Sopenharmony_ci StringSplitResultCache::SetCachedResult(thread, cacheTable, thisString, seperatorString, newElements); 17944514f5e3Sopenharmony_ci } 17954514f5e3Sopenharmony_ci }); 17964514f5e3Sopenharmony_ci} 17974514f5e3Sopenharmony_ci 17984514f5e3Sopenharmony_ci// 21.1.3.18 17994514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::StartsWith(EcmaRuntimeCallInfo *argv) 18004514f5e3Sopenharmony_ci{ 18014514f5e3Sopenharmony_ci ASSERT(argv); 18024514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, StartsWith); 18034514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 18044514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 18054514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> searchTag = BuiltinsString::GetCallArg(argv, 0); 18064514f5e3Sopenharmony_ci 18074514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 18084514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18094514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 18104514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18114514f5e3Sopenharmony_ci bool isRegexp = JSObject::IsRegExp(thread, searchTag); 18124514f5e3Sopenharmony_ci if (isRegexp) { 18134514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "is regexp", JSTaggedValue::Exception()); 18144514f5e3Sopenharmony_ci } 18154514f5e3Sopenharmony_ci 18164514f5e3Sopenharmony_ci JSHandle<EcmaString> searchHandle = JSTaggedValue::ToString(thread, searchTag); 18174514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18184514f5e3Sopenharmony_ci uint32_t thisLen = EcmaStringAccessor(thisHandle).GetLength(); 18194514f5e3Sopenharmony_ci uint32_t searchLen = EcmaStringAccessor(searchHandle).GetLength(); 18204514f5e3Sopenharmony_ci int32_t pos = 0; 18214514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> posTag = BuiltinsString::GetCallArg(argv, 1); 18224514f5e3Sopenharmony_ci if (posTag->IsUndefined()) { 18234514f5e3Sopenharmony_ci pos = 0; 18244514f5e3Sopenharmony_ci } else if (posTag->IsInt()) { 18254514f5e3Sopenharmony_ci pos = posTag->GetInt(); 18264514f5e3Sopenharmony_ci } else { 18274514f5e3Sopenharmony_ci JSTaggedNumber posVal = JSTaggedValue::ToInteger(thread, posTag); 18284514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18294514f5e3Sopenharmony_ci if (posVal.GetNumber() == BuiltinsNumber::POSITIVE_INFINITY) { 18304514f5e3Sopenharmony_ci pos = thisLen; 18314514f5e3Sopenharmony_ci } else { 18324514f5e3Sopenharmony_ci pos = posVal.ToInt32(); 18334514f5e3Sopenharmony_ci } 18344514f5e3Sopenharmony_ci } 18354514f5e3Sopenharmony_ci pos = std::min(std::max(pos, 0), static_cast<int32_t>(thisLen)); 18364514f5e3Sopenharmony_ci if (static_cast<uint32_t>(pos) + searchLen > thisLen) { 18374514f5e3Sopenharmony_ci return BuiltinsString::GetTaggedBoolean(false); 18384514f5e3Sopenharmony_ci } 18394514f5e3Sopenharmony_ci 18404514f5e3Sopenharmony_ci bool result = EcmaStringAccessor::IsSubStringAt(thread->GetEcmaVM(), thisHandle, searchHandle, pos); 18414514f5e3Sopenharmony_ci 18424514f5e3Sopenharmony_ci return BuiltinsString::GetTaggedBoolean(result); 18434514f5e3Sopenharmony_ci} 18444514f5e3Sopenharmony_ci 18454514f5e3Sopenharmony_ci// 21.1.3.19 18464514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Substring(EcmaRuntimeCallInfo *argv) 18474514f5e3Sopenharmony_ci{ 18484514f5e3Sopenharmony_ci ASSERT(argv); 18494514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Substring); 18504514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 18514514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 18524514f5e3Sopenharmony_ci 18534514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 18544514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18554514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 18564514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18574514f5e3Sopenharmony_ci int32_t thisLen = static_cast<int32_t>(EcmaStringAccessor(thisHandle).GetLength()); 18584514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> startTag = BuiltinsString::GetCallArg(argv, 0); 18594514f5e3Sopenharmony_ci JSTaggedNumber startVal = JSTaggedValue::ToInteger(thread, startTag); 18604514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18614514f5e3Sopenharmony_ci int32_t start = ConvertDoubleToInt(startVal.GetNumber()); 18624514f5e3Sopenharmony_ci int32_t end = 0; 18634514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> endTag = BuiltinsString::GetCallArg(argv, 1); 18644514f5e3Sopenharmony_ci if (endTag->IsUndefined()) { 18654514f5e3Sopenharmony_ci end = thisLen; 18664514f5e3Sopenharmony_ci } else { 18674514f5e3Sopenharmony_ci JSTaggedNumber endVal = JSTaggedValue::ToInteger(thread, endTag); 18684514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18694514f5e3Sopenharmony_ci end = ConvertDoubleToInt(endVal.GetNumber()); 18704514f5e3Sopenharmony_ci } 18714514f5e3Sopenharmony_ci start = std::min(std::max(start, 0), thisLen); 18724514f5e3Sopenharmony_ci end = std::min(std::max(end, 0), thisLen); 18734514f5e3Sopenharmony_ci int32_t from = std::min(start, end); 18744514f5e3Sopenharmony_ci int32_t to = std::max(start, end); 18754514f5e3Sopenharmony_ci int32_t len = to - from; 18764514f5e3Sopenharmony_ci return JSTaggedValue(EcmaStringAccessor::GetSubString(thread->GetEcmaVM(), thisHandle, from, len)); 18774514f5e3Sopenharmony_ci} 18784514f5e3Sopenharmony_ci 18794514f5e3Sopenharmony_ci// 21.1.3.20 18804514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::ToLocaleLowerCase(EcmaRuntimeCallInfo *argv) 18814514f5e3Sopenharmony_ci{ 18824514f5e3Sopenharmony_ci ASSERT(argv); 18834514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, ToLocaleLowerCase); 18844514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 18854514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 18864514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 18874514f5e3Sopenharmony_ci 18884514f5e3Sopenharmony_ci // Let O be RequireObjectCoercible(this value). 18894514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> obj(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 18904514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18914514f5e3Sopenharmony_ci // Let S be ? ToString(O). 18924514f5e3Sopenharmony_ci JSHandle<EcmaString> string = JSTaggedValue::ToString(thread, obj); 18934514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 18944514f5e3Sopenharmony_ci 18954514f5e3Sopenharmony_ci // Let requestedLocales be ? CanonicalizeLocaleList(locales). 18964514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 18974514f5e3Sopenharmony_ci // Fast path 18984514f5e3Sopenharmony_ci if (locales->IsUndefined() && EcmaStringAccessor(string).IsUtf8()) { 18994514f5e3Sopenharmony_ci EcmaString *result = EcmaStringAccessor::TryToLower(ecmaVm, string); 19004514f5e3Sopenharmony_ci return JSTaggedValue(result); 19014514f5e3Sopenharmony_ci } 19024514f5e3Sopenharmony_ci JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales); 19034514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19044514f5e3Sopenharmony_ci 19054514f5e3Sopenharmony_ci // If requestedLocales is not an empty List, then Let requestedLocale be requestedLocales[0]. 19064514f5e3Sopenharmony_ci // Else, Let requestedLocale be DefaultLocale(). 19074514f5e3Sopenharmony_ci JSHandle<EcmaString> requestedLocale = intl::LocaleHelper::DefaultLocale(thread); 19084514f5e3Sopenharmony_ci if (requestedLocales->GetLength() != 0) { 19094514f5e3Sopenharmony_ci requestedLocale = JSHandle<EcmaString>(thread, requestedLocales->Get(0)); 19104514f5e3Sopenharmony_ci } 19114514f5e3Sopenharmony_ci 19124514f5e3Sopenharmony_ci // Let noExtensionsLocale be the String value that is requestedLocale with all Unicode locale extension sequences 19134514f5e3Sopenharmony_ci // removed. 19144514f5e3Sopenharmony_ci intl::LocaleHelper::ParsedLocale noExtensionsLocale = intl::LocaleHelper::HandleLocale(requestedLocale); 19154514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19164514f5e3Sopenharmony_ci 19174514f5e3Sopenharmony_ci // Let availableLocales be a List with language tags that includes the languages for which the Unicode Character 19184514f5e3Sopenharmony_ci // Database contains language sensitive case mappings. Implementations may add additional language tags 19194514f5e3Sopenharmony_ci // if they support case mapping for additional locales. 19204514f5e3Sopenharmony_ci std::vector<std::string> availableLocales = intl::LocaleHelper::GetAvailableLocales(thread, nullptr, nullptr); 19214514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19224514f5e3Sopenharmony_ci 19234514f5e3Sopenharmony_ci // Let locale be BestAvailableLocale(availableLocales, noExtensionsLocale). 19244514f5e3Sopenharmony_ci std::string locale = intl::LocaleHelper::BestAvailableLocale(availableLocales, noExtensionsLocale.base); 19254514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19264514f5e3Sopenharmony_ci 19274514f5e3Sopenharmony_ci // If locale is undefined, let locale be "und". 19284514f5e3Sopenharmony_ci if (locale.empty()) { 19294514f5e3Sopenharmony_ci locale = "und"; 19304514f5e3Sopenharmony_ci } 19314514f5e3Sopenharmony_ci 19324514f5e3Sopenharmony_ci // Let uString be a List containing in order the code points of S as defined in ES2020, 6.1.4, 19334514f5e3Sopenharmony_ci // starting at the first element of S. 19344514f5e3Sopenharmony_ci // Transform those elements in uString to the to the Unicode Default Case Conversion algorithm 19354514f5e3Sopenharmony_ci icu::Locale icuLocale = icu::Locale::createFromName(locale.c_str()); 19364514f5e3Sopenharmony_ci EcmaString *result = EcmaStringAccessor::ToLocaleLower(ecmaVm, string, icuLocale); 19374514f5e3Sopenharmony_ci return JSTaggedValue(result); 19384514f5e3Sopenharmony_ci} 19394514f5e3Sopenharmony_ci 19404514f5e3Sopenharmony_ci// 21.1.3.21 19414514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::ToLocaleUpperCase(EcmaRuntimeCallInfo *argv) 19424514f5e3Sopenharmony_ci{ 19434514f5e3Sopenharmony_ci ASSERT(argv); 19444514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, ToLocaleLowerCase); 19454514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 19464514f5e3Sopenharmony_ci EcmaVM *ecmaVm = thread->GetEcmaVM(); 19474514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 19484514f5e3Sopenharmony_ci 19494514f5e3Sopenharmony_ci // Let O be RequireObjectCoercible(this value). 19504514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> obj(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 19514514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19524514f5e3Sopenharmony_ci // Let S be ? ToString(O). 19534514f5e3Sopenharmony_ci JSHandle<EcmaString> string = JSTaggedValue::ToString(thread, obj); 19544514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19554514f5e3Sopenharmony_ci 19564514f5e3Sopenharmony_ci // Let requestedLocales be ? CanonicalizeLocaleList(locales). 19574514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> locales = GetCallArg(argv, 0); 19584514f5e3Sopenharmony_ci // Fast path 19594514f5e3Sopenharmony_ci if (locales->IsUndefined() && EcmaStringAccessor(string).IsUtf8()) { 19604514f5e3Sopenharmony_ci EcmaString *result = EcmaStringAccessor::TryToUpper(ecmaVm, string); 19614514f5e3Sopenharmony_ci return JSTaggedValue(result); 19624514f5e3Sopenharmony_ci } 19634514f5e3Sopenharmony_ci JSHandle<TaggedArray> requestedLocales = intl::LocaleHelper::CanonicalizeLocaleList(thread, locales); 19644514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19654514f5e3Sopenharmony_ci 19664514f5e3Sopenharmony_ci // If requestedLocales is not an empty List, then Let requestedLocale be requestedLocales[0]. 19674514f5e3Sopenharmony_ci // Else, Let requestedLocale be DefaultLocale(). 19684514f5e3Sopenharmony_ci JSHandle<EcmaString> requestedLocale = intl::LocaleHelper::DefaultLocale(thread); 19694514f5e3Sopenharmony_ci if (requestedLocales->GetLength() != 0) { 19704514f5e3Sopenharmony_ci requestedLocale = JSHandle<EcmaString>(thread, requestedLocales->Get(0)); 19714514f5e3Sopenharmony_ci } 19724514f5e3Sopenharmony_ci 19734514f5e3Sopenharmony_ci // Let noExtensionsLocale be the String value that is requestedLocale with all Unicode locale extension sequences 19744514f5e3Sopenharmony_ci // removed. 19754514f5e3Sopenharmony_ci intl::LocaleHelper::ParsedLocale noExtensionsLocale = intl::LocaleHelper::HandleLocale(requestedLocale); 19764514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19774514f5e3Sopenharmony_ci 19784514f5e3Sopenharmony_ci // Let availableLocales be a List with language tags that includes the languages for which the Unicode Character 19794514f5e3Sopenharmony_ci // Database contains language sensitive case mappings. Implementations may add additional language tags 19804514f5e3Sopenharmony_ci // if they support case mapping for additional locales. 19814514f5e3Sopenharmony_ci std::vector<std::string> availableLocales = intl::LocaleHelper::GetAvailableLocales(thread, nullptr, nullptr); 19824514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19834514f5e3Sopenharmony_ci 19844514f5e3Sopenharmony_ci // Let locale be BestAvailableLocale(availableLocales, noExtensionsLocale). 19854514f5e3Sopenharmony_ci std::string locale = intl::LocaleHelper::BestAvailableLocale(availableLocales, noExtensionsLocale.base); 19864514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 19874514f5e3Sopenharmony_ci 19884514f5e3Sopenharmony_ci // If locale is undefined, let locale be "und". 19894514f5e3Sopenharmony_ci if (locale.empty()) { 19904514f5e3Sopenharmony_ci locale = "und"; 19914514f5e3Sopenharmony_ci } 19924514f5e3Sopenharmony_ci 19934514f5e3Sopenharmony_ci // Let uString be a List containing in order the code points of S as defined in ES2020, 6.1.4, 19944514f5e3Sopenharmony_ci // starting at the first element of S. 19954514f5e3Sopenharmony_ci // Transform those elements in uString to the to the Unicode Default Case Conversion algorithm 19964514f5e3Sopenharmony_ci icu::Locale icuLocale = icu::Locale::createFromName(locale.c_str()); 19974514f5e3Sopenharmony_ci EcmaString *result = EcmaStringAccessor::ToLocaleUpper(ecmaVm, string, icuLocale); 19984514f5e3Sopenharmony_ci return JSTaggedValue(result); 19994514f5e3Sopenharmony_ci} 20004514f5e3Sopenharmony_ci 20014514f5e3Sopenharmony_ci// 21.1.3.22 20024514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::ToLowerCase(EcmaRuntimeCallInfo *argv) 20034514f5e3Sopenharmony_ci{ 20044514f5e3Sopenharmony_ci ASSERT(argv); 20054514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, ToLowerCase); 20064514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 20074514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 20084514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 20094514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20104514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 20114514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20124514f5e3Sopenharmony_ci EcmaString *result = EcmaStringAccessor::ToLower(thread->GetEcmaVM(), thisHandle); 20134514f5e3Sopenharmony_ci return JSTaggedValue(result); 20144514f5e3Sopenharmony_ci} 20154514f5e3Sopenharmony_ci 20164514f5e3Sopenharmony_ci// 21.1.3.23 20174514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::ToString(EcmaRuntimeCallInfo *argv) 20184514f5e3Sopenharmony_ci{ 20194514f5e3Sopenharmony_ci ASSERT(argv); 20204514f5e3Sopenharmony_ci return ThisStringValue(argv->GetThread(), GetThis(argv).GetTaggedValue()); 20214514f5e3Sopenharmony_ci} 20224514f5e3Sopenharmony_ci 20234514f5e3Sopenharmony_ci// 21.1.3.24 20244514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::ToUpperCase(EcmaRuntimeCallInfo *argv) 20254514f5e3Sopenharmony_ci{ 20264514f5e3Sopenharmony_ci ASSERT(argv); 20274514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, ToUpperCase); 20284514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 20294514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 20304514f5e3Sopenharmony_ci 20314514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 20324514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20334514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 20344514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20354514f5e3Sopenharmony_ci EcmaString *result = EcmaStringAccessor::ToUpper(thread->GetEcmaVM(), thisHandle); 20364514f5e3Sopenharmony_ci return JSTaggedValue(result); 20374514f5e3Sopenharmony_ci} 20384514f5e3Sopenharmony_ci 20394514f5e3Sopenharmony_ci// 21.1.3.25 20404514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Trim(EcmaRuntimeCallInfo *argv) 20414514f5e3Sopenharmony_ci{ 20424514f5e3Sopenharmony_ci ASSERT(argv); 20434514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, Trim); 20444514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 20454514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 20464514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 20474514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20484514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 20494514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20504514f5e3Sopenharmony_ci EcmaString *res = EcmaStringAccessor::Trim(thread, thisHandle, EcmaString::TrimMode::TRIM); 20514514f5e3Sopenharmony_ci return JSTaggedValue(res); 20524514f5e3Sopenharmony_ci} 20534514f5e3Sopenharmony_ci 20544514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::TrimStart(EcmaRuntimeCallInfo *argv) 20554514f5e3Sopenharmony_ci{ 20564514f5e3Sopenharmony_ci ASSERT(argv); 20574514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, TrimStart); 20584514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 20594514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 20604514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)); 20614514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20624514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 20634514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20644514f5e3Sopenharmony_ci EcmaString *res = EcmaStringAccessor::Trim(thread, thisHandle, EcmaString::TrimMode::TRIM_START); 20654514f5e3Sopenharmony_ci return JSTaggedValue(res); 20664514f5e3Sopenharmony_ci} 20674514f5e3Sopenharmony_ci 20684514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::TrimEnd(EcmaRuntimeCallInfo *argv) 20694514f5e3Sopenharmony_ci{ 20704514f5e3Sopenharmony_ci ASSERT(argv); 20714514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, TrimEnd); 20724514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 20734514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 20744514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)); 20754514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20764514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 20774514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20784514f5e3Sopenharmony_ci EcmaString *res = EcmaStringAccessor::Trim(thread, thisHandle, EcmaString::TrimMode::TRIM_END); 20794514f5e3Sopenharmony_ci return JSTaggedValue(res); 20804514f5e3Sopenharmony_ci} 20814514f5e3Sopenharmony_ci 20824514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::TrimLeft(EcmaRuntimeCallInfo *argv) 20834514f5e3Sopenharmony_ci{ 20844514f5e3Sopenharmony_ci ASSERT(argv); 20854514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, TrimLeft); 20864514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 20874514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 20884514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)); 20894514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20904514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 20914514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 20924514f5e3Sopenharmony_ci EcmaString *res = EcmaStringAccessor::Trim(thread, thisHandle, EcmaString::TrimMode::TRIM_START); 20934514f5e3Sopenharmony_ci return JSTaggedValue(res); 20944514f5e3Sopenharmony_ci} 20954514f5e3Sopenharmony_ci 20964514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::TrimRight(EcmaRuntimeCallInfo *argv) 20974514f5e3Sopenharmony_ci{ 20984514f5e3Sopenharmony_ci ASSERT(argv); 20994514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, TrimRight); 21004514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 21014514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 21024514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv)); 21034514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 21044514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 21054514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 21064514f5e3Sopenharmony_ci EcmaString *res = EcmaStringAccessor::Trim(thread, thisHandle, EcmaString::TrimMode::TRIM_END); 21074514f5e3Sopenharmony_ci return JSTaggedValue(res); 21084514f5e3Sopenharmony_ci} 21094514f5e3Sopenharmony_ci 21104514f5e3Sopenharmony_ci// 21.1.3.26 21114514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::ValueOf(EcmaRuntimeCallInfo *argv) 21124514f5e3Sopenharmony_ci{ 21134514f5e3Sopenharmony_ci ASSERT(argv); 21144514f5e3Sopenharmony_ci return ThisStringValue(argv->GetThread(), GetThis(argv).GetTaggedValue()); 21154514f5e3Sopenharmony_ci} 21164514f5e3Sopenharmony_ci 21174514f5e3Sopenharmony_ci// 21.1.3.27 21184514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::GetStringIterator(EcmaRuntimeCallInfo *argv) 21194514f5e3Sopenharmony_ci{ 21204514f5e3Sopenharmony_ci ASSERT(argv); 21214514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, GetStringIterator); 21224514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 21234514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 21244514f5e3Sopenharmony_ci // 1. Let O be RequireObjectCoercible(this value). 21254514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> current(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 21264514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 21274514f5e3Sopenharmony_ci // Let S be ToString(O). 21284514f5e3Sopenharmony_ci 21294514f5e3Sopenharmony_ci JSHandle<EcmaString> string = JSTaggedValue::ToString(thread, current); 21304514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread()); 21314514f5e3Sopenharmony_ci // Return CreateStringIterator(S). 21324514f5e3Sopenharmony_ci return JSStringIterator::CreateStringIterator(thread, string).GetTaggedValue(); 21334514f5e3Sopenharmony_ci} 21344514f5e3Sopenharmony_ci 21354514f5e3Sopenharmony_ci// B.2.3.1 21364514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::SubStr(EcmaRuntimeCallInfo *argv) 21374514f5e3Sopenharmony_ci{ 21384514f5e3Sopenharmony_ci ASSERT(argv); 21394514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, SubStr); 21404514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 21414514f5e3Sopenharmony_ci 21424514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 21434514f5e3Sopenharmony_ci 21444514f5e3Sopenharmony_ci // 1. Let O be RequireObjectCoercible(this value). 21454514f5e3Sopenharmony_ci // 2. Let S be ToString(O). 21464514f5e3Sopenharmony_ci 21474514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 21484514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 21494514f5e3Sopenharmony_ci JSHandle<EcmaString> thisString = JSTaggedValue::ToString(thread, thisTag); 21504514f5e3Sopenharmony_ci 21514514f5e3Sopenharmony_ci // 3. ReturnIfAbrupt(S). 21524514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 21534514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> intStart = GetCallArg(argv, 0); 21544514f5e3Sopenharmony_ci // 4. Let intStart be ToInteger(start). 21554514f5e3Sopenharmony_ci JSTaggedNumber numStart = JSTaggedValue::ToInteger(thread, intStart); 21564514f5e3Sopenharmony_ci // 5. ReturnIfAbrupt(intStart). 21574514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 21584514f5e3Sopenharmony_ci int32_t start = base::NumberHelper::DoubleInRangeInt32(numStart.GetNumber()); 21594514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> lengthTag = GetCallArg(argv, 1); 21604514f5e3Sopenharmony_ci // 6. If length is undefined, let end be +; otherwise let end be ToInteger(length). 21614514f5e3Sopenharmony_ci int32_t end = 0; 21624514f5e3Sopenharmony_ci if (lengthTag->IsUndefined()) { 21634514f5e3Sopenharmony_ci end = INT_MAX; 21644514f5e3Sopenharmony_ci } else { 21654514f5e3Sopenharmony_ci JSTaggedNumber lengthNumber = JSTaggedValue::ToInteger(thread, lengthTag); 21664514f5e3Sopenharmony_ci // 7. ReturnIfAbrupt(end). 21674514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 21684514f5e3Sopenharmony_ci end = base::NumberHelper::DoubleInRangeInt32(lengthNumber.GetNumber()); 21694514f5e3Sopenharmony_ci } 21704514f5e3Sopenharmony_ci // 8. Let size be the number of code units in S. 21714514f5e3Sopenharmony_ci int32_t size = static_cast<int32_t>(EcmaStringAccessor(thisString).GetLength()); 21724514f5e3Sopenharmony_ci // 9. If intStart < 0, let intStart be max(size + intStart,0). 21734514f5e3Sopenharmony_ci if (start < 0) { 21744514f5e3Sopenharmony_ci start = std::max(size + start, 0); 21754514f5e3Sopenharmony_ci } 21764514f5e3Sopenharmony_ci // 10. Let resultLength be min(max(end,0), size – intStart). 21774514f5e3Sopenharmony_ci int32_t resultLength = std::min(std::max(end, 0), size - start); 21784514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 21794514f5e3Sopenharmony_ci // 11. If resultLength 0, return the empty String "". 21804514f5e3Sopenharmony_ci if (resultLength <= 0) { 21814514f5e3Sopenharmony_ci return factory->GetEmptyString().GetTaggedValue(); 21824514f5e3Sopenharmony_ci } 21834514f5e3Sopenharmony_ci return JSTaggedValue(EcmaStringAccessor::FastSubString(thread->GetEcmaVM(), thisString, start, resultLength)); 21844514f5e3Sopenharmony_ci} 21854514f5e3Sopenharmony_ci 21864514f5e3Sopenharmony_ci// 22.1.3.1 21874514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::At(EcmaRuntimeCallInfo *argv) 21884514f5e3Sopenharmony_ci{ 21894514f5e3Sopenharmony_ci ASSERT(argv); 21904514f5e3Sopenharmony_ci BUILTINS_API_TRACE(argv->GetThread(), String, At); 21914514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 21924514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 21934514f5e3Sopenharmony_ci 21944514f5e3Sopenharmony_ci // 1. Let O be RequireObjectCoercible(this value). 21954514f5e3Sopenharmony_ci // 2. Let S be ToString(O). 21964514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); 21974514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 21984514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 21994514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 22004514f5e3Sopenharmony_ci 22014514f5e3Sopenharmony_ci // 3. Let len be the length of S. 22024514f5e3Sopenharmony_ci int32_t thisLen = static_cast<int32_t>(EcmaStringAccessor(thisHandle).GetLength()); 22034514f5e3Sopenharmony_ci 22044514f5e3Sopenharmony_ci // 4. Let relativeIndex be ? ToIntegerOrInfinity(index). 22054514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> indexTag = BuiltinsString::GetCallArg(argv, 0); 22064514f5e3Sopenharmony_ci JSTaggedNumber indexVal = JSTaggedValue::ToInteger(thread, indexTag); 22074514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 22084514f5e3Sopenharmony_ci int32_t relativeIndex = base::NumberHelper::DoubleInRangeInt32(indexVal.GetNumber()); 22094514f5e3Sopenharmony_ci 22104514f5e3Sopenharmony_ci // 5. If relativeIndex ≥ 0, then Let k be relativeIndex. 6. Else, Let k be len + relativeIndex. 22114514f5e3Sopenharmony_ci int32_t k = 0; 22124514f5e3Sopenharmony_ci if (relativeIndex >= 0) { 22134514f5e3Sopenharmony_ci k = relativeIndex; 22144514f5e3Sopenharmony_ci } else { 22154514f5e3Sopenharmony_ci k = thisLen + relativeIndex; 22164514f5e3Sopenharmony_ci } 22174514f5e3Sopenharmony_ci // 7. If k < 0 or k ≥ len, return undefined. 22184514f5e3Sopenharmony_ci if (k < 0 || k >= thisLen) { 22194514f5e3Sopenharmony_ci return JSTaggedValue::Undefined(); 22204514f5e3Sopenharmony_ci } 22214514f5e3Sopenharmony_ci // 8. Return the substring of S from k to k + 1. 22224514f5e3Sopenharmony_ci return JSTaggedValue(EcmaStringAccessor::FastSubString(thread->GetEcmaVM(), thisHandle, k, 1)); 22234514f5e3Sopenharmony_ci} 22244514f5e3Sopenharmony_ci 22254514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::GetLength(EcmaRuntimeCallInfo *argv) 22264514f5e3Sopenharmony_ci{ 22274514f5e3Sopenharmony_ci ASSERT(argv); 22284514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 22294514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, String, GetLength); 22304514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 22314514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisHandle = GetThis(argv); 22324514f5e3Sopenharmony_ci 22334514f5e3Sopenharmony_ci JSHandle<EcmaString> thisString = JSTaggedValue::ToString(thread, thisHandle); 22344514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 22354514f5e3Sopenharmony_ci return GetTaggedInt(EcmaStringAccessor(thisString).GetLength()); 22364514f5e3Sopenharmony_ci} 22374514f5e3Sopenharmony_ci 22384514f5e3Sopenharmony_ci// 21.1.3 22394514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::ThisStringValue(JSThread *thread, JSTaggedValue value) 22404514f5e3Sopenharmony_ci{ 22414514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, String, ThisStringValue); 22424514f5e3Sopenharmony_ci if (value.IsString()) { 22434514f5e3Sopenharmony_ci return value; 22444514f5e3Sopenharmony_ci } 22454514f5e3Sopenharmony_ci if (value.IsECMAObject()) { 22464514f5e3Sopenharmony_ci auto jshclass = value.GetTaggedObject()->GetClass(); 22474514f5e3Sopenharmony_ci if (jshclass->GetObjectType() == JSType::JS_PRIMITIVE_REF) { 22484514f5e3Sopenharmony_ci JSTaggedValue primitive = JSPrimitiveRef::Cast(value.GetTaggedObject())->GetValue(); 22494514f5e3Sopenharmony_ci if (primitive.IsString()) { 22504514f5e3Sopenharmony_ci return primitive; 22514514f5e3Sopenharmony_ci } 22524514f5e3Sopenharmony_ci } 22534514f5e3Sopenharmony_ci } 22544514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "can not convert to String", JSTaggedValue::Exception()); 22554514f5e3Sopenharmony_ci} 22564514f5e3Sopenharmony_ci 22574514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::Pad(EcmaRuntimeCallInfo *argv, bool isStart) 22584514f5e3Sopenharmony_ci{ 22594514f5e3Sopenharmony_ci JSThread *thread = argv->GetThread(); 22604514f5e3Sopenharmony_ci BUILTINS_API_TRACE(thread, String, Pad); 22614514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope handleScope(thread); 22624514f5e3Sopenharmony_ci 22634514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> thisTag = JSTaggedValue::RequireObjectCoercible(thread, BuiltinsString::GetThis(argv)); 22644514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 22654514f5e3Sopenharmony_ci JSHandle<EcmaString> thisHandle = JSTaggedValue::ToString(thread, thisTag); 22664514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 22674514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> lengthTag = GetCallArg(argv, 0); 22684514f5e3Sopenharmony_ci JSTaggedNumber number = JSTaggedValue::ToNumber(thread, lengthTag); 22694514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 22704514f5e3Sopenharmony_ci int64_t intMaxLength = base::NumberHelper::DoubleToInt64(number.GetNumber()); 22714514f5e3Sopenharmony_ci int32_t stringLength = static_cast<int32_t>(EcmaStringAccessor(thisHandle).GetLength()); 22724514f5e3Sopenharmony_ci if (intMaxLength <= stringLength) { 22734514f5e3Sopenharmony_ci return thisHandle.GetTaggedValue(); 22744514f5e3Sopenharmony_ci } 22754514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> fillString = GetCallArg(argv, 1); 22764514f5e3Sopenharmony_ci std::u16string stringBuilder; 22774514f5e3Sopenharmony_ci if (fillString->IsUndefined()) { 22784514f5e3Sopenharmony_ci stringBuilder = u" "; 22794514f5e3Sopenharmony_ci } else { 22804514f5e3Sopenharmony_ci JSHandle<EcmaString> filler = JSTaggedValue::ToString(thread, fillString); 22814514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 22824514f5e3Sopenharmony_ci stringBuilder = EcmaStringAccessor(filler).ToU16String(); 22834514f5e3Sopenharmony_ci } 22844514f5e3Sopenharmony_ci if (stringBuilder.size() == 0) { 22854514f5e3Sopenharmony_ci return thisHandle.GetTaggedValue(); 22864514f5e3Sopenharmony_ci } 22874514f5e3Sopenharmony_ci std::u16string u16strSearch = EcmaStringAccessor(thisHandle).ToU16String(); 22884514f5e3Sopenharmony_ci int64_t fillLen = intMaxLength - stringLength; 22894514f5e3Sopenharmony_ci int64_t len = static_cast<int64_t>(stringBuilder.length()); 22904514f5e3Sopenharmony_ci if (static_cast<size_t>(intMaxLength) >= EcmaString::MAX_STRING_LENGTH) { 22914514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Invalid string length", JSTaggedValue::Exception()); 22924514f5e3Sopenharmony_ci } 22934514f5e3Sopenharmony_ci std::u16string fiString; 22944514f5e3Sopenharmony_ci for (int32_t i = 0; i < fillLen; ++i) { 22954514f5e3Sopenharmony_ci fiString += stringBuilder[i % len]; 22964514f5e3Sopenharmony_ci } 22974514f5e3Sopenharmony_ci std::u16string resultString; 22984514f5e3Sopenharmony_ci if (isStart) { 22994514f5e3Sopenharmony_ci resultString = fiString + u16strSearch; 23004514f5e3Sopenharmony_ci } else { 23014514f5e3Sopenharmony_ci resultString = u16strSearch + fiString; 23024514f5e3Sopenharmony_ci } 23034514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 23044514f5e3Sopenharmony_ci return factory->NewFromUtf16Literal(reinterpret_cast<const uint16_t *>(resultString.c_str()), 23054514f5e3Sopenharmony_ci resultString.size()).GetTaggedValue(); 23064514f5e3Sopenharmony_ci} 23074514f5e3Sopenharmony_ci 23084514f5e3Sopenharmony_ciint32_t BuiltinsString::ConvertDoubleToInt(double d) 23094514f5e3Sopenharmony_ci{ 23104514f5e3Sopenharmony_ci if (std::isnan(d) || d == -base::POSITIVE_INFINITY) { 23114514f5e3Sopenharmony_ci return 0; 23124514f5e3Sopenharmony_ci } 23134514f5e3Sopenharmony_ci if (d >= static_cast<double>(INT_MAX)) { 23144514f5e3Sopenharmony_ci return INT_MAX; 23154514f5e3Sopenharmony_ci } 23164514f5e3Sopenharmony_ci if (d <= static_cast<double>(INT_MIN)) { 23174514f5e3Sopenharmony_ci return INT_MIN; 23184514f5e3Sopenharmony_ci } 23194514f5e3Sopenharmony_ci return base::NumberHelper::DoubleToInt(d, base::INT32_BITS); 23204514f5e3Sopenharmony_ci} 23214514f5e3Sopenharmony_ci 23224514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::StringToList(JSThread *thread, JSHandle<EcmaString> &str) 23234514f5e3Sopenharmony_ci{ 23244514f5e3Sopenharmony_ci JSHandle<StringToListResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetStringToListResultCache()); 23254514f5e3Sopenharmony_ci JSTaggedValue cacheResult = StringToListResultCache::FindCachedResult(thread, cacheTable, str); 23264514f5e3Sopenharmony_ci if (cacheResult != JSTaggedValue::Undefined()) { 23274514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> resultArray(JSArray::CreateArrayFromList(thread, 23284514f5e3Sopenharmony_ci JSHandle<TaggedArray>(thread, cacheResult))); 23294514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 23304514f5e3Sopenharmony_ci } 23314514f5e3Sopenharmony_ci 23324514f5e3Sopenharmony_ci JSTaggedValue newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue(); 23334514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 23344514f5e3Sopenharmony_ci JSHandle<JSObject> newArrayHandle(thread, newArray); 23354514f5e3Sopenharmony_ci JSHandle<EcmaString> iteratedString(str); 23364514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 23374514f5e3Sopenharmony_ci JSHandle<TaggedArray> oldElements(thread, newArrayHandle->GetElements()); 23384514f5e3Sopenharmony_ci uint32_t totalElements = EcmaStringAccessor(iteratedString).GetLength(); 23394514f5e3Sopenharmony_ci JSHandle<TaggedArray> elements = (oldElements->GetLength() < totalElements) ? 23404514f5e3Sopenharmony_ci factory->ExtendArray(oldElements, totalElements) : oldElements; 23414514f5e3Sopenharmony_ci uint32_t index = 0; 23424514f5e3Sopenharmony_ci newArrayHandle->SetElements(thread, elements); 23434514f5e3Sopenharmony_ci while (index < totalElements) { 23444514f5e3Sopenharmony_ci uint16_t c = EcmaStringAccessor(iteratedString).Get(index); 23454514f5e3Sopenharmony_ci JSHandle<EcmaString> newStr = factory->NewFromUtf16Literal(&c, 1); 23464514f5e3Sopenharmony_ci ElementAccessor::Set(thread, newArrayHandle, index, newStr, true); 23474514f5e3Sopenharmony_ci index++; 23484514f5e3Sopenharmony_ci thread->CheckSafepointIfSuspended(); 23494514f5e3Sopenharmony_ci } 23504514f5e3Sopenharmony_ci JSHandle<JSArray>(newArrayHandle)->SetArrayLength(thread, totalElements); 23514514f5e3Sopenharmony_ci 23524514f5e3Sopenharmony_ci StringToListResultCache::SetCachedResult(thread, cacheTable, str, elements); 23534514f5e3Sopenharmony_ci 23544514f5e3Sopenharmony_ci return newArrayHandle.GetTaggedValue(); 23554514f5e3Sopenharmony_ci} 23564514f5e3Sopenharmony_ci 23574514f5e3Sopenharmony_ciJSTaggedValue BuiltinsString::StringToSList(JSThread *thread, JSHandle<EcmaString> &str) 23584514f5e3Sopenharmony_ci{ 23594514f5e3Sopenharmony_ci JSHandle<StringToListResultCache> cacheTable(thread->GetCurrentEcmaContext()->GetStringToListResultCache()); 23604514f5e3Sopenharmony_ci JSTaggedValue cacheResult = StringToListResultCache::FindCachedResult(thread, cacheTable, str); 23614514f5e3Sopenharmony_ci if (cacheResult != JSTaggedValue::Undefined()) { 23624514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> resultArray( 23634514f5e3Sopenharmony_ci JSSharedArray::CreateArrayFromList(thread, JSHandle<TaggedArray>(thread, cacheResult))); 23644514f5e3Sopenharmony_ci return resultArray.GetTaggedValue(); 23654514f5e3Sopenharmony_ci } 23664514f5e3Sopenharmony_ci 23674514f5e3Sopenharmony_ci JSTaggedValue newSharedArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue(); 23684514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 23694514f5e3Sopenharmony_ci JSHandle<JSObject> newSharedArrayHandle(thread, newSharedArray); 23704514f5e3Sopenharmony_ci JSHandle<EcmaString> iteratedString(str); 23714514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 23724514f5e3Sopenharmony_ci JSHandle<TaggedArray> oldElements(thread, newSharedArrayHandle->GetElements()); 23734514f5e3Sopenharmony_ci uint32_t totalElements = EcmaStringAccessor(iteratedString).GetLength(); 23744514f5e3Sopenharmony_ci JSHandle<TaggedArray> elements = 23754514f5e3Sopenharmony_ci (oldElements->GetLength() < totalElements) 23764514f5e3Sopenharmony_ci ? factory->ExtendArray(oldElements, totalElements, JSTaggedValue::Hole(), MemSpaceType::SHARED_OLD_SPACE) 23774514f5e3Sopenharmony_ci : oldElements; 23784514f5e3Sopenharmony_ci uint32_t index = 0; 23794514f5e3Sopenharmony_ci newSharedArrayHandle->SetElements(thread, elements); 23804514f5e3Sopenharmony_ci while (index < totalElements) { 23814514f5e3Sopenharmony_ci uint16_t c = EcmaStringAccessor(iteratedString).Get(index); 23824514f5e3Sopenharmony_ci JSHandle<EcmaString> newStr = factory->NewFromUtf16Literal(&c, 1); 23834514f5e3Sopenharmony_ci ElementAccessor::Set(thread, newSharedArrayHandle, index, newStr, true); 23844514f5e3Sopenharmony_ci index++; 23854514f5e3Sopenharmony_ci thread->CheckSafepointIfSuspended(); 23864514f5e3Sopenharmony_ci } 23874514f5e3Sopenharmony_ci JSHandle<JSSharedArray>(newSharedArrayHandle)->SetArrayLength(thread, totalElements); 23884514f5e3Sopenharmony_ci 23894514f5e3Sopenharmony_ci StringToListResultCache::SetCachedResult(thread, cacheTable, str, elements); 23904514f5e3Sopenharmony_ci newSharedArrayHandle->GetJSHClass()->SetExtensible(false); 23914514f5e3Sopenharmony_ci return newSharedArrayHandle.GetTaggedValue(); 23924514f5e3Sopenharmony_ci} 23934514f5e3Sopenharmony_ci 23944514f5e3Sopenharmony_ciJSTaggedValue StringSplitResultCache::CreateCacheTable(const JSThread *thread) 23954514f5e3Sopenharmony_ci{ 23964514f5e3Sopenharmony_ci int length = CACHE_SIZE * ENTRY_SIZE; 23974514f5e3Sopenharmony_ci auto table = static_cast<StringSplitResultCache*>( 23984514f5e3Sopenharmony_ci *thread->GetEcmaVM()->GetFactory()->NewTaggedArray(length, JSTaggedValue::Undefined())); 23994514f5e3Sopenharmony_ci return JSTaggedValue(table); 24004514f5e3Sopenharmony_ci} 24014514f5e3Sopenharmony_ci 24024514f5e3Sopenharmony_ciJSTaggedValue StringSplitResultCache::FindCachedResult(const JSThread *thread, 24034514f5e3Sopenharmony_ci const JSHandle<StringSplitResultCache> &cache, const JSHandle<EcmaString> &thisString, 24044514f5e3Sopenharmony_ci const JSHandle<EcmaString> &pattern, bool isOneByte) 24054514f5e3Sopenharmony_ci{ 24064514f5e3Sopenharmony_ci uint32_t hash = EcmaStringAccessor(thisString).GetHashcode(); 24074514f5e3Sopenharmony_ci uint32_t entry = hash & (CACHE_SIZE - 1); 24084514f5e3Sopenharmony_ci uint32_t index = entry * ENTRY_SIZE; 24094514f5e3Sopenharmony_ci JSTaggedValue cacheThis = cache->Get(index + STRING_INDEX); 24104514f5e3Sopenharmony_ci JSTaggedValue cachePattern = cache->Get(index + PATTERN_INDEX); 24114514f5e3Sopenharmony_ci if (!cacheThis.IsString() || !cachePattern.IsString()) { 24124514f5e3Sopenharmony_ci return JSTaggedValue::Undefined(); 24134514f5e3Sopenharmony_ci } 24144514f5e3Sopenharmony_ci JSHandle<EcmaString> cacheStringHandle(thread, cacheThis); 24154514f5e3Sopenharmony_ci JSHandle<EcmaString> cachePatternHandle(thread, cachePattern); 24164514f5e3Sopenharmony_ci 24174514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), thisString, cacheStringHandle) && 24184514f5e3Sopenharmony_ci EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), pattern, cachePatternHandle)) { 24194514f5e3Sopenharmony_ci JSHandle<TaggedArray> cacheArray(thread, cache->Get(index + ARRAY_INDEX)); 24204514f5e3Sopenharmony_ci uint32_t arrayLength = cacheArray->GetLength(); 24214514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 24224514f5e3Sopenharmony_ci JSHandle<TaggedArray> copyArray; 24234514f5e3Sopenharmony_ci if (isOneByte) { 24244514f5e3Sopenharmony_ci copyArray = factory->NewAndCopyTaggedArraySkipBarrier(cacheArray, arrayLength, arrayLength); 24254514f5e3Sopenharmony_ci } else { 24264514f5e3Sopenharmony_ci copyArray = factory->NewAndCopyTaggedArray(cacheArray, arrayLength, arrayLength); 24274514f5e3Sopenharmony_ci } 24284514f5e3Sopenharmony_ci return copyArray.GetTaggedValue(); 24294514f5e3Sopenharmony_ci } 24304514f5e3Sopenharmony_ci return JSTaggedValue::Undefined(); 24314514f5e3Sopenharmony_ci} 24324514f5e3Sopenharmony_ci 24334514f5e3Sopenharmony_civoid StringSplitResultCache::SetCachedResult(const JSThread *thread, const JSHandle<StringSplitResultCache> &cache, 24344514f5e3Sopenharmony_ci const JSHandle<EcmaString> &thisString, const JSHandle<EcmaString> &pattern, 24354514f5e3Sopenharmony_ci const JSHandle<TaggedArray> &resultArray) 24364514f5e3Sopenharmony_ci{ 24374514f5e3Sopenharmony_ci // clone to cache array 24384514f5e3Sopenharmony_ci uint32_t arrayLength = resultArray->GetLength(); 24394514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 24404514f5e3Sopenharmony_ci JSHandle<TaggedArray> newElements(factory->NewTaggedArray(arrayLength)); 24414514f5e3Sopenharmony_ci for (uint32_t i = 0; i < arrayLength; i++) { 24424514f5e3Sopenharmony_ci newElements->Set(thread, i, resultArray->Get(i)); 24434514f5e3Sopenharmony_ci } 24444514f5e3Sopenharmony_ci uint32_t hash = EcmaStringAccessor(thisString).GetHashcode(); 24454514f5e3Sopenharmony_ci uint32_t entry = hash & (CACHE_SIZE - 1); 24464514f5e3Sopenharmony_ci uint32_t index = entry * ENTRY_SIZE; 24474514f5e3Sopenharmony_ci 24484514f5e3Sopenharmony_ci cache->Set(thread, index + STRING_INDEX, thisString); 24494514f5e3Sopenharmony_ci cache->Set(thread, index + PATTERN_INDEX, pattern); 24504514f5e3Sopenharmony_ci cache->Set(thread, index + ARRAY_INDEX, newElements); 24514514f5e3Sopenharmony_ci} 24524514f5e3Sopenharmony_ci 24534514f5e3Sopenharmony_ciJSTaggedValue StringToListResultCache::CreateCacheTable(const JSThread *thread) 24544514f5e3Sopenharmony_ci{ 24554514f5e3Sopenharmony_ci int length = CACHE_SIZE * ENTRY_SIZE; 24564514f5e3Sopenharmony_ci auto table = static_cast<StringToListResultCache*>( 24574514f5e3Sopenharmony_ci *thread->GetEcmaVM()->GetFactory()->NewTaggedArray(length, JSTaggedValue::Undefined())); 24584514f5e3Sopenharmony_ci return JSTaggedValue(table); 24594514f5e3Sopenharmony_ci} 24604514f5e3Sopenharmony_ci 24614514f5e3Sopenharmony_ciJSTaggedValue StringToListResultCache::FindCachedResult(const JSThread *thread, 24624514f5e3Sopenharmony_ci const JSHandle<StringToListResultCache> &cache, const JSHandle<EcmaString> &thisString) 24634514f5e3Sopenharmony_ci{ 24644514f5e3Sopenharmony_ci if (EcmaStringAccessor(thisString).GetLength() > MAX_STRING_LENGTH) { 24654514f5e3Sopenharmony_ci return JSTaggedValue::Undefined(); 24664514f5e3Sopenharmony_ci } 24674514f5e3Sopenharmony_ci uint32_t hash = EcmaStringAccessor(thisString).GetHashcode(); 24684514f5e3Sopenharmony_ci uint32_t entry = hash & (CACHE_SIZE - 1); 24694514f5e3Sopenharmony_ci uint32_t index = entry * ENTRY_SIZE; 24704514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> cacheThis(thread, cache->Get(index + STRING_INDEX)); 24714514f5e3Sopenharmony_ci if (!cacheThis->IsString()) { 24724514f5e3Sopenharmony_ci return JSTaggedValue::Undefined(); 24734514f5e3Sopenharmony_ci } 24744514f5e3Sopenharmony_ci JSHandle<EcmaString> cacheStr(cacheThis); 24754514f5e3Sopenharmony_ci if (EcmaStringAccessor::StringsAreEqual(thread->GetEcmaVM(), thisString, cacheStr)) { 24764514f5e3Sopenharmony_ci return cache->Get(index + ARRAY_INDEX); 24774514f5e3Sopenharmony_ci } 24784514f5e3Sopenharmony_ci return JSTaggedValue::Undefined(); 24794514f5e3Sopenharmony_ci} 24804514f5e3Sopenharmony_ci 24814514f5e3Sopenharmony_civoid StringToListResultCache::SetCachedResult(const JSThread *thread, const JSHandle<StringToListResultCache> &cache, 24824514f5e3Sopenharmony_ci const JSHandle<EcmaString> &thisString, const JSHandle<TaggedArray> &resultArray) 24834514f5e3Sopenharmony_ci{ 24844514f5e3Sopenharmony_ci if (EcmaStringAccessor(thisString).GetLength() > MAX_STRING_LENGTH || 24854514f5e3Sopenharmony_ci EcmaStringAccessor(thisString).GetLength() == 0) { 24864514f5e3Sopenharmony_ci return; 24874514f5e3Sopenharmony_ci } 24884514f5e3Sopenharmony_ci if (!EcmaStringAccessor(thisString).IsInternString()) { 24894514f5e3Sopenharmony_ci return; 24904514f5e3Sopenharmony_ci } 24914514f5e3Sopenharmony_ci // clone to cache array 24924514f5e3Sopenharmony_ci uint32_t arrayLength = resultArray->GetLength(); 24934514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 24944514f5e3Sopenharmony_ci JSHandle<TaggedArray> newElements; 24954514f5e3Sopenharmony_ci if (resultArray.GetTaggedValue().IsInSharedHeap()) { 24964514f5e3Sopenharmony_ci newElements = JSHandle<TaggedArray>(factory->NewSCOWTaggedArray(arrayLength)); 24974514f5e3Sopenharmony_ci } else { 24984514f5e3Sopenharmony_ci newElements = JSHandle<TaggedArray>(factory->NewCOWTaggedArray(arrayLength)); 24994514f5e3Sopenharmony_ci } 25004514f5e3Sopenharmony_ci for (uint32_t i = 0; i < arrayLength; i++) { 25014514f5e3Sopenharmony_ci newElements->Set(thread, i, resultArray->Get(i)); 25024514f5e3Sopenharmony_ci } 25034514f5e3Sopenharmony_ci uint32_t hash = EcmaStringAccessor(thisString).GetHashcode(); 25044514f5e3Sopenharmony_ci uint32_t entry = hash & (CACHE_SIZE - 1); 25054514f5e3Sopenharmony_ci uint32_t index = entry * ENTRY_SIZE; 25064514f5e3Sopenharmony_ci cache->Set(thread, index + STRING_INDEX, thisString); 25074514f5e3Sopenharmony_ci cache->Set(thread, index + ARRAY_INDEX, newElements); 25084514f5e3Sopenharmony_ci} 25094514f5e3Sopenharmony_ci} // namespace panda::ecmascript::builtins 2510