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