1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/compiler/builtins/builtins_string_stub_builder.h"
17
18#include "ecmascript/builtins/builtins_number.h"
19#include "ecmascript/compiler/builtins/builtins_stubs.h"
20#include "ecmascript/compiler/new_object_stub_builder.h"
21#include "ecmascript/js_iterator.h"
22#include "ecmascript/js_string_iterator.h"
23
24namespace panda::ecmascript::kungfu {
25void BuiltinsStringStubBuilder::FromCharCode(GateRef glue, [[maybe_unused]] GateRef thisValue,
26    GateRef numArgs, Variable* res, Label *exit, Label *slowPath)
27{
28    auto env = GetEnvironment();
29    DEFVARIABLE(value, VariableType::INT16(), Int16(0));
30    Label lengthIsZero(env);
31    Label lengthNotZero(env);
32    Label lengthIsOne(env);
33    Label canBeCompress(env);
34    Label isInt(env);
35    Label notInt(env);
36    Label newObj(env);
37    Label canNotBeCompress(env);
38    Label isPendingException(env);
39    Label noPendingException(env);
40    BRANCH(Int64Equal(IntPtr(0), numArgs), &lengthIsZero, &lengthNotZero);
41    Bind(&lengthIsZero);
42    res->WriteVariable(GetGlobalConstantValue(
43        VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX));
44    Jump(exit);
45    Bind(&lengthNotZero);
46    {
47        BRANCH(Int64Equal(IntPtr(1), numArgs), &lengthIsOne, slowPath);
48        Bind(&lengthIsOne);
49        {
50            GateRef codePointTag = GetCallArg0(numArgs);
51            GateRef codePointValue = ToNumber(glue, codePointTag);
52            BRANCH(HasPendingException(glue), &isPendingException, &noPendingException);
53            Bind(&isPendingException);
54            {
55                res->WriteVariable(Exception());
56                Jump(exit);
57            }
58            Bind(&noPendingException);
59            {
60                BRANCH(TaggedIsInt(codePointValue), &isInt, &notInt);
61                Bind(&isInt);
62                {
63                    value = TruncInt32ToInt16(GetInt32OfTInt(codePointValue));
64                    Jump(&newObj);
65                }
66                Bind(&notInt);
67                {
68                    value = TruncInt32ToInt16(DoubleToInt(glue, GetDoubleOfTDouble(codePointValue), base::INT16_BITS));
69                    Jump(&newObj);
70                }
71                Bind(&newObj);
72                BRANCH(IsASCIICharacter(ZExtInt16ToInt32(*value)), &canBeCompress, &canNotBeCompress);
73                NewObjectStubBuilder newBuilder(this);
74                newBuilder.SetParameters(glue, 0);
75                Bind(&canBeCompress);
76                {
77                    GateRef singleCharTable = GetSingleCharTable(glue);
78                    res->WriteVariable(GetValueFromTaggedArray(singleCharTable, ZExtInt16ToInt32(*value)));
79                    Jump(exit);
80                }
81                Bind(&canNotBeCompress);
82                {
83                    Label afterNew1(env);
84                    newBuilder.AllocLineStringObject(res, &afterNew1, Int32(1), false);
85                    Bind(&afterNew1);
86                    {
87                        GateRef dst = ChangeStringTaggedPointerToInt64(
88                            PtrAdd(res->ReadVariable(), IntPtr(LineEcmaString::DATA_OFFSET)));
89                        Store(VariableType::INT16(), glue, dst, IntPtr(0), *value);
90                        Jump(exit);
91                    }
92                }
93            }
94        }
95    }
96}
97
98void BuiltinsStringStubBuilder::CharAt(GateRef glue, GateRef thisValue, GateRef numArgs,
99    Variable* res, Label *exit, Label *slowPath)
100{
101    auto env = GetEnvironment();
102    DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
103    DEFVARIABLE(doubleValue, VariableType::FLOAT64(), Double(0));
104    Label objNotUndefinedAndNull(env);
105    Label isString(env);
106    Label next(env);
107    Label posTagNotUndefined(env);
108    Label posTagIsInt(env);
109    Label posTagNotInt(env);
110    Label isINF(env);
111    Label isNotINF(env);
112    Label posNotGreaterLen(env);
113    Label posGreaterLen(env);
114    Label posNotLessZero(env);
115    Label posTagIsDouble(env);
116    Label thisIsHeapobject(env);
117    Label flattenFastPath(env);
118
119    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
120    Bind(&objNotUndefinedAndNull);
121    {
122        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
123        Bind(&thisIsHeapobject);
124        BRANCH(IsString(thisValue), &isString, slowPath);
125        Bind(&isString);
126        {
127            FlatStringStubBuilder thisFlat(this);
128            thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
129            Bind(&flattenFastPath);
130            GateRef thisLen = GetLengthFromString(thisValue);
131            BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &posTagNotUndefined);
132            Bind(&posTagNotUndefined);
133            {
134                GateRef posTag = GetCallArg0(numArgs);
135                BRANCH(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
136                Bind(&posTagIsInt);
137                pos = GetInt32OfTInt(posTag);
138                Jump(&next);
139                Bind(&posTagNotInt);
140                BRANCH(TaggedIsDouble(posTag), &posTagIsDouble, slowPath);
141                Bind(&posTagIsDouble);
142                doubleValue = GetDoubleOfTDouble(posTag);
143                BRANCH(DoubleIsINF(*doubleValue), &posGreaterLen, &isNotINF);
144                Bind(&isNotINF);
145                pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
146                Jump(&next);
147            }
148            Bind(&next);
149            {
150                BRANCH(Int32GreaterThanOrEqual(*pos, thisLen), &posGreaterLen, &posNotGreaterLen);
151                Bind(&posNotGreaterLen);
152                {
153                    BRANCH(Int32LessThan(*pos, Int32(0)), &posGreaterLen, &posNotLessZero);
154                    Bind(&posNotLessZero);
155                    {
156                        StringInfoGateRef stringInfoGate(&thisFlat);
157                        res->WriteVariable(CreateFromEcmaString(glue, *pos, stringInfoGate));
158                        Jump(exit);
159                    }
160                }
161                Bind(&posGreaterLen);
162                {
163                    res->WriteVariable(GetGlobalConstantValue(
164                        VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX));
165                    Jump(exit);
166                }
167            }
168        }
169    }
170}
171
172void BuiltinsStringStubBuilder::CharCodeAt(GateRef glue, GateRef thisValue, GateRef numArgs,
173    Variable* res, Label *exit, Label *slowPath)
174{
175    auto env = GetEnvironment();
176    DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
177    Label posIsValid(env);
178    Label flattenFastPath(env);
179    Label returnFirst(env);
180    Label getNextChar(env);
181    CheckParamsAndGetPosition(glue, thisValue, numArgs, &pos, exit, slowPath, &posIsValid);
182    Bind(&posIsValid);
183    {
184        res->WriteVariable(FastStringCharCodeAt(glue, thisValue, *pos));
185        Jump(exit);
186    }
187}
188
189GateRef BuiltinsStringStubBuilder::FastStringCharCodeAt(GateRef glue, GateRef thisValue, GateRef pos)
190{
191    auto env = GetEnvironment();
192    Label entry(env);
193    env->SubCfgEntry(&entry);
194    DEFVARIABLE(index, VariableType::INT32(), pos);
195    DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
196
197    Label exit(env);
198    Label readyStringAt(env);
199    FlatStringStubBuilder thisFlat(this);
200    thisFlat.FlattenStringWithIndex(glue, thisValue, &index, &readyStringAt);
201    Bind(&readyStringAt);
202    {
203        StringInfoGateRef stringInfoGate(&thisFlat);
204        Label isConstantString(env);
205        Label notConstantString(env);
206        Label getCharByIndex(env);
207        GateRef stringData = Circuit::NullGate();
208        BRANCH(IsConstantString(stringInfoGate.GetString()), &isConstantString, &notConstantString);
209        Bind(&isConstantString);
210        {
211            GateRef address = PtrAdd(stringInfoGate.GetString(), IntPtr(ConstantString::CONSTANT_DATA_OFFSET));
212            stringData = Load(VariableType::JS_ANY(), address, IntPtr(0));
213            Jump(&getCharByIndex);
214        }
215        Bind(&notConstantString);
216        {
217            stringData = PtrAdd(stringInfoGate.GetString(), IntPtr(LineEcmaString::DATA_OFFSET));
218            Jump(&getCharByIndex);
219        }
220        Label isUtf16(env);
221        Label isUtf8(env);
222        Bind(&getCharByIndex);
223        GateRef charPosition = Circuit::NullGate();
224        BRANCH(IsUtf16String(stringInfoGate.GetString()), &isUtf16, &isUtf8);
225        Bind(&isUtf16);
226        {
227            charPosition = PtrMul(ZExtInt32ToPtr(*index), IntPtr(sizeof(uint16_t)));
228            result = Int64ToTaggedIntPtr((ZExtInt16ToInt64(
229                Load(VariableType::INT16(), PtrAdd(stringData, charPosition)))));
230            Jump(&exit);
231        }
232        Bind(&isUtf8);
233        {
234            charPosition = PtrMul(ZExtInt32ToPtr(*index), IntPtr(sizeof(uint8_t)));
235            result = Int64ToTaggedIntPtr((ZExtInt8ToInt64(
236                Load(VariableType::INT8(), PtrAdd(stringData, charPosition)))));
237            Jump(&exit);
238        }
239    }
240    Bind(&exit);
241    auto res = *result;
242    env->SubCfgExit();
243    return res;
244}
245
246void BuiltinsStringStubBuilder::CodePointAt(GateRef glue, GateRef thisValue, GateRef numArgs,
247    Variable* res, Label *exit, Label *slowPath)
248{
249    auto env = GetEnvironment();
250    DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
251    Label posIsValid(env);
252    Label flattenFastPath(env);
253    Label returnFirst(env);
254    Label getNextChar(env);
255    CheckParamsAndGetPosition(glue, thisValue, numArgs, &pos, exit, slowPath, &posIsValid);
256    Bind(&posIsValid);
257    {
258        FlatStringStubBuilder thisFlat(this);
259        thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
260        Bind(&flattenFastPath);
261        StringInfoGateRef stringInfoGate(&thisFlat);
262        GateRef first = StringAt(stringInfoGate, *pos);
263        GateRef posVal = *pos;
264        GateRef firstIsValid = LogicOrBuilder(env)
265            .Or(Int32UnsignedLessThan(first, Int32(base::utf_helper::DECODE_LEAD_LOW)))
266            .Or(Int32UnsignedGreaterThan(first, Int32(base::utf_helper::DECODE_LEAD_HIGH)))
267            .Or(Int32Equal(Int32Add(posVal, Int32(1)), GetLengthFromString(thisValue)))
268            .Done();
269        BRANCH(firstIsValid, &returnFirst, &getNextChar);
270        Bind(&getNextChar);
271        GateRef second = StringAt(stringInfoGate, Int32Add(*pos, Int32(1)));
272        GateRef secondIsValid = BitOr(Int32UnsignedLessThan(second, Int32(base::utf_helper::DECODE_TRAIL_LOW)),
273            Int32UnsignedGreaterThan(second, Int32(base::utf_helper::DECODE_TRAIL_HIGH)));
274        BRANCH(secondIsValid, &returnFirst, slowPath);
275        Bind(&returnFirst);
276        res->WriteVariable(IntToTaggedPtr(first));
277        Jump(exit);
278    }
279}
280
281void BuiltinsStringStubBuilder::CheckParamsAndGetPosition(GateRef glue, GateRef thisValue, GateRef numArgs,
282    Variable* pos, Label *exit, Label *slowPath, Label *posIsValid)
283{
284    auto env = GetEnvironment();
285    DEFVARIABLE(doubleValue, VariableType::FLOAT64(), Double(0));
286    Label objNotUndefinedAndNull(env);
287    Label isString(env);
288    Label next(env);
289    Label posTagNotUndefined(env);
290    Label isINF(env);
291    Label isNotINF(env);
292    Label posTagIsInt(env);
293    Label posTagNotInt(env);
294    Label posNotGreaterLen(env);
295    Label posNotLessZero(env);
296    Label posTagIsDouble(env);
297    Label thisIsHeapobject(env);
298
299    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
300    Bind(&objNotUndefinedAndNull);
301    {
302        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
303        Bind(&thisIsHeapobject);
304        BRANCH(IsString(thisValue), &isString, slowPath);
305        Bind(&isString);
306        {
307            GateRef thisLen = GetLengthFromString(thisValue);
308            BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &posTagNotUndefined);
309            Bind(&posTagNotUndefined);
310            {
311                GateRef posTag = GetCallArg0(numArgs);
312                BRANCH(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
313                Bind(&posTagIsInt);
314                {
315                    pos->WriteVariable(GetInt32OfTInt(posTag));
316                    Jump(&next);
317                }
318                Bind(&posTagNotInt);
319                {
320                    BRANCH(TaggedIsDouble(posTag), &posTagIsDouble, slowPath);
321                    Bind(&posTagIsDouble);
322                    doubleValue = GetDoubleOfTDouble(posTag);
323                    BRANCH(DoubleIsINF(*doubleValue), exit, &isNotINF);
324                    Bind(&isNotINF);
325                    pos->WriteVariable(DoubleToInt(glue, GetDoubleOfTDouble(posTag)));
326                    Jump(&next);
327                }
328            }
329            Bind(&next);
330            {
331                BRANCH(Int32UnsignedLessThan(pos->ReadVariable(), thisLen), posIsValid, exit);
332            }
333        }
334    }
335}
336
337void BuiltinsStringStubBuilder::IndexOf(GateRef glue, GateRef thisValue, GateRef numArgs,
338    Variable* res, Label *exit, Label *slowPath)
339{
340    auto env = GetEnvironment();
341    DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
342
343    Label objNotUndefinedAndNull(env);
344    Label isString(env);
345    Label isSearchString(env);
346    Label next(env);
347    Label resPosGreaterZero(env);
348    Label searchTagIsHeapObject(env);
349    Label posTagNotUndefined(env);
350    Label posTagIsInt(env);
351    Label posTagNotInt(env);
352    Label posTagIsDouble(env);
353    Label nextCount(env);
354    Label posNotLessThanLen(env);
355    Label thisIsHeapobject(env);
356    Label flattenFastPath(env);
357    Label flattenFastPath1(env);
358
359    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
360    Bind(&objNotUndefinedAndNull);
361    {
362        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
363        Bind(&thisIsHeapobject);
364        BRANCH(IsString(thisValue), &isString, slowPath);
365        Bind(&isString);
366        {
367            GateRef searchTag = GetCallArg0(numArgs);
368            BRANCH(TaggedIsHeapObject(searchTag), &searchTagIsHeapObject, slowPath);
369            Bind(&searchTagIsHeapObject);
370            BRANCH(IsString(searchTag), &isSearchString, slowPath);
371            Bind(&isSearchString);
372            {
373                GateRef thisLen = GetLengthFromString(thisValue);
374                BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &next, &posTagNotUndefined);
375                Bind(&posTagNotUndefined);
376                {
377                    GateRef posTag = GetCallArg1(numArgs);
378                    BRANCH(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
379                    Bind(&posTagIsInt);
380                    pos = GetInt32OfTInt(posTag);
381                    Jump(&next);
382                    Bind(&posTagNotInt);
383                    BRANCH(TaggedIsDouble(posTag), &posTagIsDouble, slowPath);
384                    Bind(&posTagIsDouble);
385                    pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
386                    Jump(&next);
387                }
388                Bind(&next);
389                {
390                    Label posGreaterThanZero(env);
391                    Label posNotGreaterThanZero(env);
392                    BRANCH(Int32GreaterThan(*pos, Int32(0)), &posGreaterThanZero, &posNotGreaterThanZero);
393                    Bind(&posNotGreaterThanZero);
394                    {
395                        pos = Int32(0);
396                        Jump(&nextCount);
397                    }
398                    Bind(&posGreaterThanZero);
399                    {
400                        BRANCH(Int32LessThanOrEqual(*pos, thisLen), &nextCount, &posNotLessThanLen);
401                        Bind(&posNotLessThanLen);
402                        {
403                            pos = thisLen;
404                            Jump(&nextCount);
405                        }
406                    }
407                    Bind(&nextCount);
408                    {
409                        FlatStringStubBuilder thisFlat(this);
410                        thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
411                        Bind(&flattenFastPath);
412                        FlatStringStubBuilder searchFlat(this);
413                        searchFlat.FlattenString(glue, searchTag, &flattenFastPath1);
414                        Bind(&flattenFastPath1);
415                        StringInfoGateRef thisStringInfoGate(&thisFlat);
416                        StringInfoGateRef searchStringInfoGate(&searchFlat);
417                        GateRef resPos = StringIndexOf(thisStringInfoGate, searchStringInfoGate, *pos);
418                        BRANCH(Int32GreaterThanOrEqual(resPos, Int32(0)), &resPosGreaterZero, exit);
419                        Bind(&resPosGreaterZero);
420                        {
421                            Label resPosLessZero(env);
422                            BRANCH(Int32LessThanOrEqual(resPos, thisLen), &resPosLessZero, exit);
423                            Bind(&resPosLessZero);
424                            {
425                                res->WriteVariable(IntToTaggedPtr(resPos));
426                                Jump(exit);
427                            }
428                        }
429                    }
430                }
431            }
432        }
433    }
434}
435
436void BuiltinsStringStubBuilder::Substring(GateRef glue, GateRef thisValue, GateRef numArgs,
437    Variable* res, Label *exit, Label *slowPath)
438{
439    auto env = GetEnvironment();
440    DEFVARIABLE(start, VariableType::INT32(), Int32(0));
441    DEFVARIABLE(end, VariableType::INT32(), Int32(0));
442    DEFVARIABLE(from, VariableType::INT32(), Int32(0));
443    DEFVARIABLE(to, VariableType::INT32(), Int32(0));
444
445    Label objNotUndefinedAndNull(env);
446    Label isString(env);
447    Label isSearchString(env);
448    Label countStart(env);
449    Label endTagIsUndefined(env);
450    Label startNotGreatZero(env);
451    Label countEnd(env);
452    Label endNotGreatZero(env);
453    Label countFrom(env);
454    Label countRes(env);
455    Label startTagNotUndefined(env);
456    Label startTagIsNumber(env);
457    Label startTagIsInt(env);
458    Label endTagNotUndefined(env);
459    Label endTagIsNumber(env);
460    Label endTagIsInt(env);
461    Label endGreatZero(env);
462    Label endGreatLen(env);
463    Label startGreatZero(env);
464    Label startGreatEnd(env);
465    Label startNotGreatEnd(env);
466    Label thisIsHeapobject(env);
467
468    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
469    Bind(&objNotUndefinedAndNull);
470    {
471        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
472        Bind(&thisIsHeapobject);
473        BRANCH(IsString(thisValue), &isString, slowPath);
474        Bind(&isString);
475        {
476            Label next(env);
477            GateRef thisLen = GetLengthFromString(thisValue);
478            BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &startTagNotUndefined);
479            Bind(&startTagNotUndefined);
480            {
481                GateRef startTag = GetCallArg0(numArgs);
482                BRANCH(TaggedIsNumber(startTag), &startTagIsNumber, slowPath);
483                Bind(&startTagIsNumber);
484                BRANCH(TaggedIsInt(startTag), &startTagIsInt, slowPath);
485                Bind(&startTagIsInt);
486                {
487                    start = GetInt32OfTInt(startTag);
488                    Jump(&next);
489                }
490            }
491            Bind(&next);
492            {
493                BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &endTagIsUndefined, &endTagNotUndefined);
494                Bind(&endTagIsUndefined);
495                {
496                    end = thisLen;
497                    Jump(&countStart);
498                }
499                Bind(&endTagNotUndefined);
500                {
501                    GateRef endTag = GetCallArg1(numArgs);
502                    BRANCH(TaggedIsNumber(endTag), &endTagIsNumber, slowPath);
503                    Bind(&endTagIsNumber);
504                    BRANCH(TaggedIsInt(endTag), &endTagIsInt, slowPath);
505                    Bind(&endTagIsInt);
506                    {
507                        end = GetInt32OfTInt(endTag);
508                        Jump(&countStart);
509                    }
510                }
511            }
512            Bind(&countStart);
513            {
514                Label startGreatLen(env);
515                BRANCH(Int32GreaterThan(*start, Int32(0)), &startGreatZero, &startNotGreatZero);
516                Bind(&startNotGreatZero);
517                {
518                    start = Int32(0);
519                    Jump(&countEnd);
520                }
521                Bind(&startGreatZero);
522                {
523                    BRANCH(Int32GreaterThan(*start, thisLen), &startGreatLen, &countEnd);
524                    Bind(&startGreatLen);
525                    {
526                        start = thisLen;
527                        Jump(&countEnd);
528                    }
529                }
530            }
531            Bind(&countEnd);
532            {
533                BRANCH(Int32GreaterThan(*end, Int32(0)), &endGreatZero, &endNotGreatZero);
534                Bind(&endNotGreatZero);
535                {
536                    end = Int32(0);
537                    Jump(&countFrom);
538                }
539                Bind(&endGreatZero);
540                {
541                    BRANCH(Int32GreaterThan(*end, thisLen), &endGreatLen, &countFrom);
542                    Bind(&endGreatLen);
543                    {
544                        end = thisLen;
545                        Jump(&countFrom);
546                    }
547                }
548            }
549            Bind(&countFrom);
550            {
551                BRANCH(Int32GreaterThan(*start, *end), &startGreatEnd, &startNotGreatEnd);
552                Bind(&startGreatEnd);
553                {
554                    from = *end;
555                    to = *start;
556                    Jump(&countRes);
557                }
558                Bind(&startNotGreatEnd);
559                {
560                    from = *start;
561                    to = *end;
562                    Jump(&countRes);
563                }
564            }
565            Bind(&countRes);
566            {
567                GateRef len = Int32Sub(*to, *from);
568                res->WriteVariable(GetSubString(glue, thisValue, *from, len));
569                Jump(exit);
570            }
571        }
572    }
573}
574
575void BuiltinsStringStubBuilder::SubStr(GateRef glue, GateRef thisValue, GateRef numArgs,
576    Variable* res, Label *exit, Label *slowPath)
577{
578    auto env = GetEnvironment();
579    DEFVARIABLE(start, VariableType::INT32(), Int32(0));
580    DEFVARIABLE(end, VariableType::INT32(), Int32(0));
581    DEFVARIABLE(tempLength, VariableType::INT32(), Int32(0));
582    DEFVARIABLE(resultLength, VariableType::INT32(), Int32(0));
583
584    Label objNotUndefinedAndNull(env);
585    Label isString(env);
586    Label countStart(env);
587    Label lengthTagIsUndefined(env);
588    Label lengthTagNotUndefined(env);
589    Label countResultLength(env);
590    Label countResultLength1(env);
591    Label countRes(env);
592    Label intStartNotUndefined(env);
593    Label intStartIsNumber(env);
594    Label intStartIsInt(env);
595    Label lengthTagIsNumber(env);
596    Label lengthTagIsInt(env);
597    Label thisIsHeapobject(env);
598    Label endGreatZero(env);
599
600    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
601    Bind(&objNotUndefinedAndNull);
602    {
603        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
604        Bind(&thisIsHeapobject);
605        BRANCH(IsString(thisValue), &isString, slowPath);
606        Bind(&isString);
607        {
608            Label next(env);
609            GateRef thisLen = GetLengthFromString(thisValue);
610            BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &intStartNotUndefined);
611            Bind(&intStartNotUndefined);
612            {
613                GateRef intStart = GetCallArg0(numArgs);
614                BRANCH(TaggedIsNumber(intStart), &intStartIsNumber, slowPath);
615                Bind(&intStartIsNumber);
616                BRANCH(TaggedIsInt(intStart), &intStartIsInt, slowPath);
617                Bind(&intStartIsInt);
618                {
619                    start = GetInt32OfTInt(intStart);
620                    Jump(&next);
621                }
622            }
623            Bind(&next);
624            {
625                BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &lengthTagIsUndefined, &lengthTagNotUndefined);
626                Bind(&lengthTagIsUndefined);
627                {
628                    end = Int32(INT_MAX);
629                    Jump(&countStart);
630                }
631                Bind(&lengthTagNotUndefined);
632                {
633                    GateRef lengthTag = GetCallArg1(numArgs);
634                    BRANCH(TaggedIsNumber(lengthTag), &lengthTagIsNumber, slowPath);
635                    Bind(&lengthTagIsNumber);
636                    BRANCH(TaggedIsInt(lengthTag), &lengthTagIsInt, slowPath);
637                    Bind(&lengthTagIsInt);
638                    {
639                        end = GetInt32OfTInt(lengthTag);
640                        Jump(&countStart);
641                    }
642                }
643            }
644            Bind(&countStart);
645            {
646                Label startLessZero(env);
647                Label newStartGreaterThanZero(env);
648                Label newStartNotGreaterThanZero(env);
649                BRANCH(Int32LessThan(*start, Int32(0)), &startLessZero, &countResultLength);
650                Bind(&startLessZero);
651                {
652                    GateRef newStart = Int32Add(*start, thisLen);
653                    BRANCH(Int32GreaterThan(newStart, Int32(0)), &newStartGreaterThanZero, &newStartNotGreaterThanZero);
654                    Bind(&newStartGreaterThanZero);
655                    {
656                        start = newStart;
657                        Jump(&countResultLength);
658                    }
659                    Bind(&newStartNotGreaterThanZero);
660                    {
661                        start = Int32(0);
662                        Jump(&countResultLength);
663                    }
664                }
665            }
666            Bind(&countResultLength);
667            {
668                BRANCH(Int32GreaterThan(*end, Int32(0)), &endGreatZero, &countResultLength1);
669                Bind(&endGreatZero);
670                {
671                    tempLength = *end;
672                    Jump(&countResultLength1);
673                }
674            }
675            Bind(&countResultLength1);
676            {
677                Label tempLenLessLength(env);
678                Label tempLenNotLessLength(env);
679                GateRef length = Int32Sub(thisLen, *start);
680                BRANCH(Int32LessThan(*tempLength, length), &tempLenLessLength, &tempLenNotLessLength);
681                Bind(&tempLenLessLength);
682                {
683                    resultLength = *tempLength;
684                    Jump(&countRes);
685                }
686                Bind(&tempLenNotLessLength);
687                {
688                    resultLength = length;
689                    Jump(&countRes);
690                }
691            }
692            Bind(&countRes);
693            {
694                Label emptyString(env);
695                Label fastSubString(env);
696
697                BRANCH(Int32LessThanOrEqual(*resultLength, Int32(0)), &emptyString, &fastSubString);
698                Bind(&emptyString);
699                {
700                    res->WriteVariable(GetGlobalConstantValue(
701                        VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX));
702                    Jump(exit);
703                }
704                Bind(&fastSubString);
705                {
706                    Label thisFlattenFastPath(env);
707                    FlatStringStubBuilder thisFlat(this);
708                    thisFlat.FlattenString(glue, thisValue, &thisFlattenFastPath);
709                    Bind(&thisFlattenFastPath);
710                    StringInfoGateRef stringInfoGate(&thisFlat);
711                    GateRef result = FastSubString(glue, thisValue, *start, *resultLength, stringInfoGate);
712                    res->WriteVariable(result);
713                    Jump(exit);
714                }
715            }
716        }
717    }
718}
719
720GateRef BuiltinsStringStubBuilder::GetSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
721{
722    auto env = GetEnvironment();
723    Label entry(env);
724    env->SubCfgEntry(&entry);
725    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
726
727    Label exit(env);
728    Label flattenFastPath(env);
729    Label sliceString(env);
730    Label mayGetSliceString(env);
731    Label fastSubstring(env);
732    Label isUtf16(env);
733    Label isUtf8(env);
734    Label afterNew(env);
735    Label isSingleChar(env);
736    Label notSingleChar(env);
737    Label getStringFromSingleCharTable(env);
738    FlatStringStubBuilder thisFlat(this);
739    thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
740    Bind(&flattenFastPath);
741    {
742        BRANCH(Int32Equal(len, Int32(1)), &isSingleChar, &notSingleChar);
743        Bind(&isSingleChar);
744        {
745            StringInfoGateRef stringInfoGate1(&thisFlat);
746            GateRef charCode = StringAt(stringInfoGate1, from);
747            GateRef canStoreAsUtf8 = IsASCIICharacter(charCode);
748            BRANCH(canStoreAsUtf8, &getStringFromSingleCharTable, &fastSubstring);
749            Bind(&getStringFromSingleCharTable);
750            {
751                GateRef singleCharTable = GetSingleCharTable(glue);
752                result = GetValueFromTaggedArray(singleCharTable, ZExtInt16ToInt32(charCode));
753                Jump(&exit);
754            }
755        }
756        Bind(&notSingleChar);
757        BRANCH(Int32GreaterThanOrEqual(len, Int32(SlicedString::MIN_SLICED_ECMASTRING_LENGTH)),
758            &mayGetSliceString, &fastSubstring);
759        Bind(&mayGetSliceString);
760        {
761            BRANCH(IsUtf16String(thisValue), &isUtf16, &sliceString);
762            Bind(&isUtf16);
763            {
764                StringInfoGateRef stringInfoGate(&thisFlat);
765                GateRef fromOffset = PtrMul(ZExtInt32ToPtr(from), IntPtr(sizeof(uint16_t) / sizeof(uint8_t)));
766                GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
767                GateRef canBeCompressed = CanBeCompressed(source, len, true);
768                BRANCH(canBeCompressed, &isUtf8, &sliceString);
769                Bind(&isUtf8);
770                {
771                    NewObjectStubBuilder newBuilder(this);
772                    newBuilder.SetParameters(glue, 0);
773                    newBuilder.AllocLineStringObject(&result, &afterNew, len, true);
774                    Bind(&afterNew);
775                    {
776                        GateRef source1 = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
777                        GateRef dst =
778                            ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
779                        CopyUtf16AsUtf8(glue, dst, source1, len);
780                        Jump(&exit);
781                    }
782                }
783            }
784            Bind(&sliceString);
785            {
786                NewObjectStubBuilder newBuilder(this);
787                newBuilder.SetParameters(glue, 0);
788                newBuilder.AllocSlicedStringObject(&result, &exit, from, len, &thisFlat);
789            }
790        }
791        Bind(&fastSubstring);
792        StringInfoGateRef stringInfoGate(&thisFlat);
793        result = FastSubString(glue, thisValue, from, len, stringInfoGate);
794        Jump(&exit);
795    }
796    Bind(&exit);
797    auto ret = *result;
798    env->SubCfgExit();
799    return ret;
800}
801
802GateRef BuiltinsStringStubBuilder::GetFastSubString(GateRef glue, GateRef thisValue, GateRef start, GateRef len)
803{
804    auto env = GetEnvironment();
805    Label entry(env);
806    env->SubCfgEntry(&entry);
807    Label thisFlattenFastPath(env);
808    FlatStringStubBuilder thisFlat(this);
809    thisFlat.FlattenString(glue, thisValue, &thisFlattenFastPath);
810    Bind(&thisFlattenFastPath);
811    StringInfoGateRef stringInfoGate(&thisFlat);
812    GateRef result = FastSubString(glue, thisValue, start, len, stringInfoGate);
813    env->SubCfgExit();
814    return result;
815}
816
817void BuiltinsStringStubBuilder::Replace(GateRef glue, GateRef thisValue, GateRef numArgs,
818    Variable *res, Label *exit, Label *slowPath)
819{
820    auto env = GetEnvironment();
821
822    Label objNotUndefinedAndNull(env);
823
824    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
825    Bind(&objNotUndefinedAndNull);
826    {
827        Label thisIsHeapObj(env);
828        Label tagsDefined(env);
829        Label searchIsHeapObj(env);
830        Label replaceIsHeapObj(env);
831
832        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
833        Bind(&thisIsHeapObj);
834        BRANCH(Int64Equal(IntPtr(2), numArgs), &tagsDefined, slowPath); // 2: number of parameters. search & replace Tag
835        Bind(&tagsDefined);
836        {
837            Label next(env);
838
839            GateRef searchTag = GetCallArg0(numArgs);
840            BRANCH(TaggedIsHeapObject(searchTag), &searchIsHeapObj, slowPath);
841            Bind(&searchIsHeapObj);
842            GateRef replaceTag = GetCallArg1(numArgs);
843            BRANCH(TaggedIsHeapObject(replaceTag), &replaceIsHeapObj, slowPath);
844            Bind(&replaceIsHeapObj);
845            BRANCH(LogicOrBuilder(env).Or(IsJSRegExp(searchTag)).Or(IsEcmaObject(searchTag)).Done(), slowPath, &next);
846            Bind(&next);
847            {
848                Label allAreStrings(env);
849                GateRef allIsString = LogicAndBuilder(env).And(IsString(thisValue)).And(IsString(searchTag))
850                    .And(IsString(replaceTag)).Done();
851                BRANCH(allIsString, &allAreStrings, slowPath);
852                Bind(&allAreStrings);
853                {
854                    Label replaceTagNotCallable(env);
855
856                    GateRef replaceTagIsCallable = IsCallable(replaceTag);
857
858                    BRANCH(replaceTagIsCallable, slowPath, &replaceTagNotCallable);
859                    Bind(&replaceTagNotCallable);
860                    {
861                        Label thisFlattenFastPath(env);
862                        Label searchFlattenFastPath(env);
863                        Label noReplace(env);
864                        Label nextProcess(env);
865
866                        FlatStringStubBuilder thisFlat(this);
867                        thisFlat.FlattenString(glue, thisValue, &thisFlattenFastPath);
868                        Bind(&thisFlattenFastPath);
869                        StringInfoGateRef thisStringInfoGate(&thisFlat);
870                        FlatStringStubBuilder searchFlat(this);
871                        searchFlat.FlattenString(glue, searchTag, &searchFlattenFastPath);
872                        Bind(&searchFlattenFastPath);
873                        StringInfoGateRef searchStringInfoGate(&searchFlat);
874                        GateRef pos = StringIndexOf(thisStringInfoGate, searchStringInfoGate, Int32(-1));
875                        BRANCH(Int32Equal(pos, Int32(-1)), &noReplace, &nextProcess);
876                        Bind(&noReplace);
877                        {
878                            res->WriteVariable(thisValue);
879                            Jump(exit);
880                        }
881                        Bind(&nextProcess);
882                        {
883                            Label functionalReplaceFalse(env);
884
885                            BRANCH(replaceTagIsCallable, slowPath, &functionalReplaceFalse);
886                            Bind(&functionalReplaceFalse);
887                            {
888                                Label replHandleIsString(env);
889
890                                GateRef replHandle = GetSubstitution(glue, searchTag, thisValue, pos, replaceTag);
891                                BRANCH(IsString(replHandle), &replHandleIsString, slowPath);
892                                Bind(&replHandleIsString);
893                                {
894                                    GateRef tailPos = Int32Add(pos, searchStringInfoGate.GetLength());
895                                    GateRef prefixString = FastSubString(glue, thisValue, Int32(0),
896                                        pos, thisStringInfoGate);
897                                    GateRef thisLen = thisStringInfoGate.GetLength();
898                                    GateRef suffixString = FastSubString(glue, thisValue, tailPos,
899                                        Int32Sub(thisLen, tailPos), thisStringInfoGate);
900                                    GateRef tempStr = StringConcat(glue, prefixString, replHandle);
901                                    GateRef resultStr = StringConcat(glue, tempStr, suffixString);
902                                    res->WriteVariable(resultStr);
903                                    Jump(exit);
904                                }
905                            }
906                        }
907                    }
908                }
909            }
910        }
911    }
912}
913
914GateRef BuiltinsStringStubBuilder::ConvertAndClampRelativeIndex(GateRef index, GateRef length)
915{
916    auto env = GetEnvironment();
917
918    Label entry(env);
919    env->SubCfgEntry(&entry);
920
921    DEFVARIABLE(relativeIndex, VariableType::INT32(), Int32(-1));
922
923    Label indexGreaterThanOrEqualZero(env);
924    Label indexLessThanZero(env);
925    Label next(env);
926
927    BRANCH(Int32GreaterThanOrEqual(index, Int32(0)), &indexGreaterThanOrEqualZero, &indexLessThanZero);
928    Bind(&indexGreaterThanOrEqualZero);
929    {
930        relativeIndex = index;
931        Jump(&next);
932    }
933    Bind(&indexLessThanZero);
934    {
935        relativeIndex = Int32Add(index, length);
936        Jump(&next);
937    }
938    Bind(&next);
939    {
940        Label relativeIndexLessThanZero(env);
941        Label elseCheck(env);
942        Label exit(env);
943
944        BRANCH(Int32LessThan(*relativeIndex, Int32(0)), &relativeIndexLessThanZero, &elseCheck);
945        Bind(&relativeIndexLessThanZero);
946        {
947            relativeIndex = Int32(0);
948            Jump(&exit);
949        }
950        Bind(&elseCheck);
951        {
952            Label relativeIndexGreaterThanLength(env);
953
954            BRANCH(Int32GreaterThan(*relativeIndex, length), &relativeIndexGreaterThanLength, &exit);
955            Bind(&relativeIndexGreaterThanLength);
956            {
957                relativeIndex = length;
958                Jump(&exit);
959            }
960        }
961        Bind(&exit);
962        auto ret = *relativeIndex;
963        env->SubCfgExit();
964        return ret;
965    }
966}
967
968void BuiltinsStringStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef numArgs,
969    Variable *res, Label *exit, Label *slowPath)
970{
971    auto env = GetEnvironment();
972
973    DEFVARIABLE(start, VariableType::INT32(), Int32(-1));
974    DEFVARIABLE(end, VariableType::INT32(), Int32(-1));
975    DEFVARIABLE(sliceLen, VariableType::INT32(), Int32(-1));
976    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
977
978    Label objNotUndefinedAndNull(env);
979
980    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
981    Bind(&objNotUndefinedAndNull);
982    {
983        Label thisIsHeapObj(env);
984        Label isString(env);
985
986        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
987        Bind(&thisIsHeapObj);
988        BRANCH(IsString(thisValue), &isString, slowPath);
989        Bind(&isString);
990        {
991            Label startTagDefined(env);
992
993            BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), slowPath, &startTagDefined);
994            Bind(&startTagDefined);
995            {
996                Label startTagIsInt(env);
997                Label endTagUndefined(env);
998                Label endTagDefined(env);
999                Label endTagIsInt(env);
1000                Label next(env);
1001
1002                GateRef startTag = GetCallArg0(numArgs);
1003                BRANCH(TaggedIsInt(startTag), &startTagIsInt, slowPath);
1004                Bind(&startTagIsInt);
1005                GateRef thisLen = GetLengthFromString(thisValue);
1006                start = ConvertAndClampRelativeIndex(GetInt32OfTInt(startTag), thisLen);
1007                BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &endTagUndefined, &endTagDefined);
1008                Bind(&endTagUndefined);
1009                {
1010                    end = thisLen;
1011                    Jump(&next);
1012                }
1013                Bind(&endTagDefined);
1014                {
1015                    GateRef endTag = GetCallArg1(numArgs);
1016                    BRANCH(TaggedIsInt(endTag), &endTagIsInt, slowPath);
1017                    Bind(&endTagIsInt);
1018                    end = ConvertAndClampRelativeIndex(GetInt32OfTInt(endTag), thisLen);
1019                    Jump(&next);
1020                }
1021                Bind(&next);
1022                {
1023                    Label emptyString(env);
1024                    Label fastSubString(env);
1025                    Label finish(env);
1026
1027                    sliceLen = Int32Sub(*end, *start);
1028                    BRANCH(Int32LessThanOrEqual(*sliceLen, Int32(0)), &emptyString, &fastSubString);
1029                    Bind(&emptyString);
1030                    {
1031                        result = GetGlobalConstantValue(
1032                            VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
1033                        Jump(&finish);
1034                    }
1035                    Bind(&fastSubString);
1036                    {
1037                        Label thisFlattenFastPath(env);
1038                        FlatStringStubBuilder thisFlat(this);
1039                        thisFlat.FlattenString(glue, thisValue, &thisFlattenFastPath);
1040                        Bind(&thisFlattenFastPath);
1041                        StringInfoGateRef stringInfoGate(&thisFlat);
1042                        result = FastSubString(glue, thisValue, *start, *sliceLen, stringInfoGate);
1043                        Jump(&finish);
1044                    }
1045                    Bind(&finish);
1046                    res->WriteVariable(*result);
1047                    Jump(exit);
1048                }
1049            }
1050        }
1051    }
1052}
1053
1054void BuiltinsStringStubBuilder::Trim(GateRef glue, GateRef thisValue, GateRef numArgs [[maybe_unused]],
1055    Variable *res, Label *exit, Label *slowPath)
1056{
1057    auto env = GetEnvironment();
1058    DEFVARIABLE(start, VariableType::INT32(), Int32(-1));
1059    DEFVARIABLE(end, VariableType::INT32(), Int32(-1));
1060    DEFVARIABLE(sliceLen, VariableType::INT32(), Int32(-1));
1061
1062    Label objNotUndefinedAndNull(env);
1063
1064    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
1065    Bind(&objNotUndefinedAndNull);
1066    {
1067        Label thisIsHeapObj(env);
1068        Label thisIsString(env);
1069
1070        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
1071        Bind(&thisIsHeapObj);
1072        BRANCH(IsString(thisValue), &thisIsString, slowPath);
1073        Bind(&thisIsString);
1074        GateRef result = EcmaStringTrim(glue, thisValue, Int32(0)); // 0: mode = TrimMode::TRIM
1075        res->WriteVariable(result);
1076        Jump(exit);
1077    }
1078}
1079
1080GateRef BuiltinsStringStubBuilder::StringAt(const StringInfoGateRef &stringInfoGate, GateRef index)
1081{
1082    auto env = GetEnvironment();
1083    Label entry(env);
1084    env->SubCfgEntry(&entry);
1085    DEFVARIABLE(result, VariableType::INT32(), Int32(0));
1086
1087    Label exit(env);
1088    Label isUtf16(env);
1089    Label isUtf8(env);
1090    Label doIntOp(env);
1091    Label leftIsNumber(env);
1092    Label rightIsNumber(env);
1093    GateRef dataUtf16 = GetNormalStringData(stringInfoGate);
1094    BRANCH(IsUtf16String(stringInfoGate.GetString()), &isUtf16, &isUtf8);
1095    Bind(&isUtf16);
1096    {
1097        result = ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(dataUtf16,
1098            PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))))));
1099        Jump(&exit);
1100    }
1101    Bind(&isUtf8);
1102    {
1103        result = ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(dataUtf16,
1104            PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
1105        Jump(&exit);
1106    }
1107    Bind(&exit);
1108    auto ret = *result;
1109    env->SubCfgExit();
1110    return ret;
1111}
1112
1113GateRef BuiltinsStringStubBuilder::GetSingleCharCodeByIndex(GateRef str, GateRef index)
1114{
1115    // Note: This method cannot handle treestring.
1116    auto env = GetEnvironment();
1117    Label entry(env);
1118    env->SubCfgEntry(&entry);
1119    DEFVARIABLE(result, VariableType::INT32(), Int32(0));
1120
1121    Label isConstantString(env);
1122    Label lineStringCheck(env);
1123    Label isLineString(env);
1124    Label slicedStringCheck(env);
1125    Label isSlicedString(env);
1126    Label exit(env);
1127
1128    BRANCH(IsConstantString(str), &isConstantString, &lineStringCheck);
1129    Bind(&isConstantString);
1130    {
1131        result = GetSingleCharCodeFromConstantString(str, index);
1132        Jump(&exit);
1133    }
1134    Bind(&lineStringCheck);
1135    BRANCH(IsLineString(str), &isLineString, &slicedStringCheck);
1136    Bind(&isLineString);
1137    {
1138        result = GetSingleCharCodeFromLineString(str, index);
1139        Jump(&exit);
1140    }
1141    Bind(&slicedStringCheck);
1142    BRANCH(IsSlicedString(str), &isSlicedString, &exit);
1143    Bind(&isSlicedString);
1144    {
1145        result = GetSingleCharCodeFromSlicedString(str, index);
1146        Jump(&exit);
1147    }
1148
1149    Bind(&exit);
1150    auto ret = *result;
1151    env->SubCfgExit();
1152    return ret;
1153}
1154
1155GateRef BuiltinsStringStubBuilder::GetSingleCharCodeFromConstantString(GateRef str, GateRef index)
1156{
1157    auto env = GetEnvironment();
1158    Label entry(env);
1159    env->SubCfgEntry(&entry);
1160    GateRef offset = ChangeStringTaggedPointerToInt64(PtrAdd(str, IntPtr(ConstantString::CONSTANT_DATA_OFFSET)));
1161    GateRef dataAddr = Load(VariableType::NATIVE_POINTER(), offset, IntPtr(0));
1162    GateRef result = ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(dataAddr,
1163        PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
1164    env->SubCfgExit();
1165    return result;
1166}
1167
1168GateRef BuiltinsStringStubBuilder::GetSingleCharCodeFromLineString(GateRef str, GateRef index)
1169{
1170    auto env = GetEnvironment();
1171    Label entry(env);
1172    env->SubCfgEntry(&entry);
1173    DEFVARIABLE(result, VariableType::INT32(), Int32(0));
1174    GateRef dataAddr = ChangeStringTaggedPointerToInt64(PtrAdd(str, IntPtr(LineEcmaString::DATA_OFFSET)));
1175    Label isUtf16(env);
1176    Label isUtf8(env);
1177    Label exit(env);
1178    BRANCH(IsUtf16String(str), &isUtf16, &isUtf8);
1179    Bind(&isUtf16);
1180    {
1181        result = ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(dataAddr,
1182            PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))))));
1183        Jump(&exit);
1184    }
1185    Bind(&isUtf8);
1186    {
1187        result = ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(dataAddr,
1188            PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
1189        Jump(&exit);
1190    }
1191    Bind(&exit);
1192    auto ret = *result;
1193    env->SubCfgExit();
1194    return ret;
1195}
1196
1197GateRef BuiltinsStringStubBuilder::GetSingleCharCodeFromSlicedString(GateRef str, GateRef index)
1198{
1199    auto env = GetEnvironment();
1200    Label entry(env);
1201    env->SubCfgEntry(&entry);
1202    DEFVARIABLE(result, VariableType::INT32(), Int32(0));
1203    Label isLineString(env);
1204    Label notLineString(env);
1205    Label exit(env);
1206
1207    GateRef parent = Load(VariableType::JS_POINTER(), str, IntPtr(SlicedString::PARENT_OFFSET));
1208    GateRef startIndex = Load(VariableType::INT32(), str, IntPtr(SlicedString::STARTINDEX_OFFSET));
1209    BRANCH(IsLineString(parent), &isLineString, &notLineString);
1210    Bind(&isLineString);
1211    {
1212        result = GetSingleCharCodeFromLineString(parent, Int32Add(startIndex, index));
1213        Jump(&exit);
1214    }
1215    Bind(&notLineString);
1216    {
1217        result = GetSingleCharCodeFromConstantString(parent, Int32Add(startIndex, index));
1218        Jump(&exit);
1219    }
1220    Bind(&exit);
1221    auto ret = *result;
1222    env->SubCfgExit();
1223    return ret;
1224}
1225
1226GateRef BuiltinsStringStubBuilder::CreateStringBySingleCharCode(GateRef glue, GateRef charCode)
1227{
1228    auto env = GetEnvironment();
1229    Label entry(env);
1230    env->SubCfgEntry(&entry);
1231    DEFVARIABLE(result, VariableType::JS_POINTER(), Hole());
1232
1233    NewObjectStubBuilder newBuilder(this);
1234    newBuilder.SetParameters(glue, 0);
1235
1236    Label exit(env);
1237    Label utf8(env);
1238    Label utf16(env);
1239    Label afterNew(env);
1240    GateRef canStoreAsUtf8 = IsASCIICharacter(charCode);
1241    BRANCH(canStoreAsUtf8, &utf8, &utf16);
1242    Bind(&utf8);
1243    {
1244        GateRef singleCharTable = GetSingleCharTable(glue);
1245        result = GetValueFromTaggedArray(singleCharTable, charCode);
1246        Jump(&exit);
1247    }
1248    Bind(&utf16);
1249    {
1250        newBuilder.AllocLineStringObject(&result, &afterNew, Int32(1), false);
1251    }
1252    Bind(&afterNew);
1253    {
1254        Label isUtf8Copy(env);
1255        Label isUtf16Copy(env);
1256        GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
1257        BRANCH(canStoreAsUtf8, &isUtf8Copy, &isUtf16Copy);
1258        Bind(&isUtf8Copy);
1259        {
1260            Store(VariableType::INT8(), glue, dst, IntPtr(0), TruncInt32ToInt8(charCode));
1261            Jump(&exit);
1262        }
1263        Bind(&isUtf16Copy);
1264        {
1265            Store(VariableType::INT16(), glue, dst, IntPtr(0), TruncInt32ToInt16(charCode));
1266            Jump(&exit);
1267        }
1268    }
1269
1270    Bind(&exit);
1271    auto ret = *result;
1272    env->SubCfgExit();
1273    return ret;
1274}
1275
1276GateRef BuiltinsStringStubBuilder::CreateFromEcmaString(GateRef glue, GateRef index,
1277    const StringInfoGateRef &stringInfoGate)
1278{
1279    auto env = GetEnvironment();
1280    Label entry(env);
1281    env->SubCfgEntry(&entry);
1282    DEFVARIABLE(result, VariableType::JS_POINTER(), Hole());
1283    DEFVARIABLE(canBeCompressed, VariableType::BOOL(), False());
1284    DEFVARIABLE(data, VariableType::INT16(), Int32(0));
1285
1286    Label exit(env);
1287    Label isUtf16(env);
1288    Label isUtf8(env);
1289    Label allocString(env);
1290    GateRef dataUtf = GetNormalStringData(stringInfoGate);
1291    BRANCH(IsUtf16String(stringInfoGate.GetString()), &isUtf16, &isUtf8);
1292    Bind(&isUtf16);
1293    {
1294        GateRef dataAddr = PtrAdd(dataUtf, PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))));
1295        data = Load(VariableType::INT16(), dataAddr);
1296        canBeCompressed = CanBeCompressed(dataAddr, Int32(1), true);
1297        Jump(&allocString);
1298    }
1299    Bind(&isUtf8);
1300    {
1301        GateRef dataAddr = PtrAdd(dataUtf, PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))));
1302        data = ZExtInt8ToInt16(Load(VariableType::INT8(), dataAddr));
1303        canBeCompressed = CanBeCompressed(dataAddr, Int32(1), false);
1304        Jump(&allocString);
1305    }
1306    Bind(&allocString);
1307    {
1308        Label afterNew(env);
1309        Label isUtf8Next(env);
1310        Label isUtf16Next(env);
1311        NewObjectStubBuilder newBuilder(this);
1312        newBuilder.SetParameters(glue, 0);
1313        BRANCH(*canBeCompressed, &isUtf8Next, &isUtf16Next);
1314        Bind(&isUtf8Next);
1315        {
1316            GateRef singleCharTable = GetSingleCharTable(glue);
1317            result = GetValueFromTaggedArray(singleCharTable, ZExtInt16ToInt32(*data));
1318            Jump(&exit);
1319        }
1320        Bind(&isUtf16Next);
1321        {
1322            newBuilder.AllocLineStringObject(&result, &afterNew, Int32(1), false);
1323        }
1324        Bind(&afterNew);
1325        {
1326            Label isUtf8Copy(env);
1327            Label isUtf16Copy(env);
1328            GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
1329            BRANCH(*canBeCompressed, &isUtf8Copy, &isUtf16Copy);
1330            Bind(&isUtf8Copy);
1331            {
1332                Store(VariableType::INT8(), glue, dst, IntPtr(0), TruncInt16ToInt8(*data));
1333                Jump(&exit);
1334            }
1335            Bind(&isUtf16Copy);
1336            {
1337                Store(VariableType::INT16(), glue, dst, IntPtr(0), *data);
1338                Jump(&exit);
1339            }
1340        }
1341    }
1342    Bind(&exit);
1343    auto ret = *result;
1344    env->SubCfgExit();
1345    return ret;
1346}
1347
1348GateRef BuiltinsStringStubBuilder::FastSubString(GateRef glue, GateRef thisValue, GateRef from,
1349    GateRef len, const StringInfoGateRef &stringInfoGate)
1350{
1351    auto env = GetEnvironment();
1352    Label entry(env);
1353    env->SubCfgEntry(&entry);
1354    DEFVARIABLE(result, VariableType::JS_POINTER(), thisValue);
1355
1356    Label exit(env);
1357    Label lenEqualZero(env);
1358    Label lenNotEqualZero(env);
1359    Label fromEqualZero(env);
1360    Label next(env);
1361    Label isUtf8(env);
1362    Label isUtf16(env);
1363
1364    BRANCH(Int32Equal(len, Int32(0)), &lenEqualZero, &lenNotEqualZero);
1365    Bind(&lenEqualZero);
1366    {
1367        result = GetGlobalConstantValue(
1368            VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
1369        Jump(&exit);
1370    }
1371    Bind(&lenNotEqualZero);
1372    {
1373        BRANCH(Int32Equal(from, Int32(0)), &fromEqualZero, &next);
1374        Bind(&fromEqualZero);
1375        {
1376            GateRef thisLen = stringInfoGate.GetLength();
1377            BRANCH(Int32Equal(len, thisLen), &exit, &next);
1378        }
1379        Bind(&next);
1380        {
1381            BRANCH(IsUtf8String(thisValue), &isUtf8, &isUtf16);
1382            Bind(&isUtf8);
1383            {
1384                result = FastSubUtf8String(glue, from, len, stringInfoGate);
1385                Jump(&exit);
1386            }
1387            Bind(&isUtf16);
1388            {
1389                result = FastSubUtf16String(glue, from, len, stringInfoGate);
1390                Jump(&exit);
1391            }
1392        }
1393    }
1394    Bind(&exit);
1395    auto ret = *result;
1396    env->SubCfgExit();
1397    return ret;
1398}
1399
1400GateRef BuiltinsStringStubBuilder::FastSubUtf8String(GateRef glue, GateRef from, GateRef len,
1401    const StringInfoGateRef &stringInfoGate)
1402{
1403    auto env = GetEnvironment();
1404    Label entry(env);
1405    env->SubCfgEntry(&entry);
1406    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
1407    Label exit(env);
1408
1409    NewObjectStubBuilder newBuilder(this);
1410    newBuilder.SetParameters(glue, 0);
1411    Label afterNew(env);
1412    newBuilder.AllocLineStringObject(&result, &afterNew, len, true);
1413    Bind(&afterNew);
1414    {
1415        GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
1416        GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), ZExtInt32ToPtr(from));
1417        CopyChars(glue, dst, source, len, IntPtr(sizeof(uint8_t)), VariableType::INT8());
1418        Jump(&exit);
1419    }
1420    Bind(&exit);
1421    auto ret = *result;
1422    env->SubCfgExit();
1423    return ret;
1424}
1425
1426GateRef BuiltinsStringStubBuilder::FastSubUtf16String(GateRef glue, GateRef from, GateRef len,
1427    const StringInfoGateRef &stringInfoGate)
1428{
1429    auto env = GetEnvironment();
1430    Label entry(env);
1431    env->SubCfgEntry(&entry);
1432    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
1433
1434    Label exit(env);
1435    Label isUtf16(env);
1436    Label isUtf8(env);
1437    Label isUtf8Next(env);
1438    Label isUtf16Next(env);
1439
1440    GateRef fromOffset = PtrMul(ZExtInt32ToPtr(from), IntPtr(sizeof(uint16_t) / sizeof(uint8_t)));
1441    GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
1442    GateRef canBeCompressed = CanBeCompressed(source, len, true);
1443    NewObjectStubBuilder newBuilder(this);
1444    newBuilder.SetParameters(glue, 0);
1445    Label afterNew(env);
1446    BRANCH(canBeCompressed, &isUtf8, &isUtf16);
1447    Bind(&isUtf8);
1448    {
1449        newBuilder.AllocLineStringObject(&result, &afterNew, len, true);
1450    }
1451    Bind(&isUtf16);
1452    {
1453        newBuilder.AllocLineStringObject(&result, &afterNew, len, false);
1454    }
1455    Bind(&afterNew);
1456    {
1457        GateRef source1 = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
1458        GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
1459        BRANCH(canBeCompressed, &isUtf8Next, &isUtf16Next);
1460        Bind(&isUtf8Next);
1461        {
1462            CopyUtf16AsUtf8(glue, dst, source1, len);
1463            Jump(&exit);
1464        }
1465        Bind(&isUtf16Next);
1466        {
1467            CopyChars(glue, dst, source1, len, IntPtr(sizeof(uint16_t)), VariableType::INT16());
1468            Jump(&exit);
1469        }
1470    }
1471    Bind(&exit);
1472    auto ret = *result;
1473    env->SubCfgExit();
1474    return ret;
1475}
1476
1477GateRef BuiltinsStringStubBuilder::GetSubstitution(GateRef glue, GateRef searchString, GateRef thisString,
1478    GateRef pos, GateRef replaceString)
1479{
1480    auto env = GetEnvironment();
1481
1482    Label entry(env);
1483    env->SubCfgEntry(&entry);
1484
1485    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
1486
1487    Label dollarFlattenFastPath(env);
1488    Label replaceFlattenFastPath(env);
1489    Label notFound(env);
1490    Label slowPath(env);
1491    Label exit(env);
1492
1493    GateRef dollarString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::DOLLAR_INDEX);
1494    FlatStringStubBuilder dollarFlat(this);
1495    dollarFlat.FlattenString(glue, dollarString, &dollarFlattenFastPath);
1496    Bind(&dollarFlattenFastPath);
1497    StringInfoGateRef dollarStringInfoGate(&dollarFlat);
1498    FlatStringStubBuilder replaceFlat(this);
1499    replaceFlat.FlattenString(glue, replaceString, &replaceFlattenFastPath);
1500    Bind(&replaceFlattenFastPath);
1501    StringInfoGateRef replaceStringInfoGate(&replaceFlat);
1502    GateRef nextDollarIndex = StringIndexOf(replaceStringInfoGate, dollarStringInfoGate, Int32(-1));
1503    BRANCH(Int32LessThan(nextDollarIndex, Int32(0)), &notFound, &slowPath);
1504    Bind(&notFound);
1505    {
1506        result = replaceString;
1507        Jump(&exit);
1508    }
1509    Bind(&slowPath);
1510    {
1511        result = CallRuntime(glue, RTSTUB_ID(RTSubstitution),
1512            {searchString, thisString, IntToTaggedInt(pos), replaceString});
1513        Jump(&exit);
1514    }
1515    Bind(&exit);
1516    auto ret = *result;
1517    env->SubCfgExit();
1518    return ret;
1519}
1520
1521void BuiltinsStringStubBuilder::CopyChars(GateRef glue, GateRef dst, GateRef source,
1522    GateRef sourceLength, GateRef size, VariableType type)
1523{
1524    auto env = GetEnvironment();
1525    Label entry(env);
1526    env->SubCfgEntry(&entry);
1527    // Are used NATIVE_POINTERs instead JS_POINTERs, becasuse "CopyChars" have parameters "dst" and "source" which
1528    // already NATIVE_POINTER to buffer of strings. We can't track original string objects, so can't insert SafePoints
1529    // and call GC
1530    DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
1531    DEFVARIABLE(sourceTmp, VariableType::NATIVE_POINTER(), source);
1532    DEFVARIABLE(len, VariableType::INT32(), sourceLength);
1533    Label loopHead(env);
1534    Label loopEnd(env);
1535    Label storeTail(env);
1536    Label exit(env);
1537    uint8_t elemSize = 0;
1538    MachineType mt = type.GetMachineType();
1539    if (mt == I8) {
1540        elemSize = sizeof(int8_t);
1541    } else if (mt == I16) {
1542        elemSize = sizeof(int16_t);
1543    } else {
1544        LOG_COMPILER(FATAL) << "Unhandled VariableType: " << mt;
1545    };
1546    const constexpr int32_t batchBytes = 2 * sizeof(int64_t); // copy 16 bytes in one iterator.
1547    uint8_t elemInBatch = batchBytes / elemSize;
1548
1549    Jump(&loopHead);
1550    LoopBegin(&loopHead);
1551    {
1552        // loop copy, copy 16 bytes in every iteration. Until the remain is less than 16 bytes.
1553        Label body(env);
1554        BRANCH_NO_WEIGHT(Int32GreaterThanOrEqual(*len, Int32(elemInBatch)), &body, &storeTail); // len>=16
1555        Bind(&body);
1556        {
1557            len = Int32Sub(*len, Int32(elemInBatch));
1558            GateRef elem = Load(VariableType::INT64(), *sourceTmp);
1559            Store(VariableType::INT64(), glue, *dstTmp, IntPtr(0), elem);
1560            elem = Load(VariableType::INT64(), PtrAdd(*sourceTmp, IntPtr(sizeof(int64_t))));
1561            Store(VariableType::INT64(), glue, *dstTmp, IntPtr(sizeof(int64_t)), elem);
1562            Jump(&loopEnd);
1563        }
1564    }
1565    Bind(&loopEnd);
1566    sourceTmp = PtrAdd(*sourceTmp, IntPtr(batchBytes));
1567    dstTmp = PtrAdd(*dstTmp, IntPtr(batchBytes));
1568    // Work with low level buffers, we can't call GC. Loop is simple.
1569    LoopEnd(&loopHead);
1570
1571    uint8_t elemInInt64 = sizeof(int64_t) / elemSize;
1572    Bind(&storeTail);
1573    {
1574        // If the remain larger than 8 bytes, copy once and make the remain less than 8 bytes.
1575        Label storeTail8_16(env);
1576        Label storeTail0_8(env);
1577        // 16 > len >= 8
1578        BRANCH_NO_WEIGHT(Int32GreaterThanOrEqual(*len, Int32(elemInInt64)), &storeTail8_16, &storeTail0_8);
1579        Bind(&storeTail8_16);
1580        {
1581            GateRef elem = Load(VariableType::INT64(), *sourceTmp);
1582            Store(VariableType::INT64(), glue, *dstTmp, IntPtr(0), elem);
1583            len = Int32Sub(*len, Int32(elemInInt64));
1584            sourceTmp = PtrAdd(*sourceTmp, IntPtr(sizeof(int64_t)));
1585            dstTmp = PtrAdd(*dstTmp, IntPtr(sizeof(int64_t)));
1586            Jump(&storeTail0_8);
1587        }
1588        Bind(&storeTail0_8);
1589        {
1590            Label tailLoopHead(env);
1591            Label tailLoopEnd(env);
1592            Jump(&tailLoopHead);
1593            LoopBegin(&tailLoopHead);
1594            {
1595                Label body(env);
1596                // 8 > len > 0
1597                BRANCH_NO_WEIGHT(Int32GreaterThan(*len, Int32(0)), &body, &exit);
1598                Bind(&body);
1599                {
1600                    len = Int32Sub(*len, Int32(1));
1601                    GateRef i = Load(type, *sourceTmp);
1602                    Store(type, glue, *dstTmp, IntPtr(0), i);
1603                    Jump(&tailLoopEnd);
1604                }
1605            }
1606            Bind(&tailLoopEnd);
1607            sourceTmp = PtrAdd(*sourceTmp, size);
1608            dstTmp = PtrAdd(*dstTmp, size);
1609            // Work with low level buffers, we can't call GC. Loop is simple.
1610            LoopEnd(&tailLoopHead);
1611        }
1612    }
1613    Bind(&exit);
1614    env->SubCfgExit();
1615    return;
1616}
1617
1618GateRef BuiltinsStringStubBuilder::CanBeCompressed(GateRef data, GateRef len, bool isUtf16)
1619{
1620    auto env = GetEnvironment();
1621    Label entry(env);
1622    env->SubCfgEntry(&entry);
1623    DEFVARIABLE(result, VariableType::BOOL(), True());
1624    DEFVARIABLE(i, VariableType::INT32(), Int32(0));
1625    Label loopHead(env);
1626    Label loopEnd(env);
1627    Label nextCount(env);
1628    Label isNotASCIICharacter(env);
1629    Label exit(env);
1630    Jump(&loopHead);
1631    LoopBegin(&loopHead);
1632    {
1633        BRANCH(Int32LessThan(*i, len), &nextCount, &exit);
1634        Bind(&nextCount);
1635        {
1636            if (isUtf16) {
1637                GateRef tmp = Load(VariableType::INT16(), data,
1638                    PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(uint16_t))));
1639                BRANCH(IsASCIICharacter(ZExtInt16ToInt32(tmp)), &loopEnd, &isNotASCIICharacter);
1640            } else {
1641                GateRef tmp = Load(VariableType::INT8(), data,
1642                    PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(uint8_t))));
1643                BRANCH(IsASCIICharacter(ZExtInt8ToInt32(tmp)), &loopEnd, &isNotASCIICharacter);
1644            }
1645            Bind(&isNotASCIICharacter);
1646            {
1647                result = False();
1648                Jump(&exit);
1649            }
1650        }
1651    }
1652    Bind(&loopEnd);
1653    i = Int32Add(*i, Int32(1));
1654    LoopEnd(&loopHead);
1655
1656    Bind(&exit);
1657    auto ret = *result;
1658    env->SubCfgExit();
1659    return ret;
1660}
1661
1662// source is utf8, dst is utf16
1663void BuiltinsStringStubBuilder::CopyUtf8AsUtf16(GateRef glue, GateRef dst, GateRef src,
1664    GateRef sourceLength)
1665{
1666    auto env = GetEnvironment();
1667    Label entry(env);
1668    env->SubCfgEntry(&entry);
1669    // Are used NATIVE_POINTERs instead JS_POINTERs, becasuse "CopyUtf8AsUtf16" have parameters "dst" and "src" which
1670    // already NATIVE_POINTER to buffer of strings. We can't track original string objects, so can't insert SafePoints
1671    // and call GC
1672    DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
1673    DEFVARIABLE(sourceTmp, VariableType::NATIVE_POINTER(), src);
1674    DEFVARIABLE(len, VariableType::INT32(), sourceLength);
1675    Label loopHead(env);
1676    Label loopEnd(env);
1677    Label next(env);
1678    Label exit(env);
1679    Jump(&loopHead);
1680    LoopBegin(&loopHead);
1681    {
1682        BRANCH(Int32GreaterThan(*len, Int32(0)), &next, &exit);
1683        Bind(&next);
1684        {
1685            len = Int32Sub(*len, Int32(1));
1686            GateRef i = Load(VariableType::INT8(), *sourceTmp);
1687            Store(VariableType::INT16(), glue, *dstTmp, IntPtr(0), ZExtInt8ToInt16(i));
1688            Jump(&loopEnd);
1689        }
1690    }
1691
1692    Bind(&loopEnd);
1693    sourceTmp = PtrAdd(*sourceTmp, IntPtr(sizeof(uint8_t)));
1694    dstTmp = PtrAdd(*dstTmp, IntPtr(sizeof(uint16_t)));
1695    // Work with low level buffers, we can't call GC. Loop is simple.
1696    LoopEnd(&loopHead);
1697
1698    Bind(&exit);
1699    env->SubCfgExit();
1700    return;
1701}
1702
1703// source is utf16, dst is utf8
1704void BuiltinsStringStubBuilder::CopyUtf16AsUtf8(GateRef glue, GateRef dst, GateRef src,
1705    GateRef sourceLength)
1706{
1707    auto env = GetEnvironment();
1708    Label entry(env);
1709    env->SubCfgEntry(&entry);
1710    // Are used NATIVE_POINTERs instead JS_POINTERs, becasuse "CopyUtf8AsUtf16" have parameters "dst" and "src" which
1711    // already NATIVE_POINTER to buffer of strings. We can't track original string objects, so can't insert SafePoints
1712    // and call GC.
1713    DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
1714    DEFVARIABLE(sourceTmp, VariableType::NATIVE_POINTER(), src);
1715    DEFVARIABLE(len, VariableType::INT32(), sourceLength);
1716    Label loopHead(env);
1717    Label loopEnd(env);
1718    Label next(env);
1719    Label exit(env);
1720    Jump(&loopHead);
1721    LoopBegin(&loopHead);
1722    {
1723        BRANCH(Int32GreaterThan(*len, Int32(0)), &next, &exit);
1724        Bind(&next);
1725        {
1726            len = Int32Sub(*len, Int32(1));
1727            GateRef i = Load(VariableType::INT16(), *sourceTmp);
1728            Store(VariableType::INT8(), glue, *dstTmp, IntPtr(0), TruncInt16ToInt8(i));
1729            Jump(&loopEnd);
1730        }
1731    }
1732
1733    Bind(&loopEnd);
1734    sourceTmp = PtrAdd(*sourceTmp, IntPtr(sizeof(uint16_t)));
1735    dstTmp = PtrAdd(*dstTmp, IntPtr(sizeof(uint8_t)));
1736    // Work with low level buffers, we can't call GC. Loop is simple.
1737    LoopEnd(&loopHead);
1738
1739    Bind(&exit);
1740    env->SubCfgExit();
1741    return;
1742}
1743
1744GateRef BuiltinsStringStubBuilder::GetUtf16Data(GateRef stringData, GateRef index)
1745{
1746    return ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(stringData,
1747        PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))))));
1748}
1749
1750GateRef BuiltinsStringStubBuilder::IsASCIICharacter(GateRef data)
1751{
1752    return Int32UnsignedLessThan(Int32Sub(data, Int32(1)), Int32(base::utf_helper::UTF8_1B_MAX));
1753}
1754
1755GateRef BuiltinsStringStubBuilder::GetUtf8Data(GateRef stringData, GateRef index)
1756{
1757    return ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(stringData,
1758        PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
1759}
1760
1761GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhsData, bool lhsIsUtf8, GateRef rhsData, bool rhsIsUtf8,
1762                                                 GateRef pos, GateRef max, GateRef rhsCount)
1763{
1764    auto env = GetEnvironment();
1765    Label entry(env);
1766    env->SubCfgEntry(&entry);
1767    DEFVARIABLE(i, VariableType::INT32(), pos);
1768    DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
1769    DEFVARIABLE(j, VariableType::INT32(), Int32(0));
1770    DEFVARIABLE(k, VariableType::INT32(), Int32(1));
1771    Label exit(env);
1772    Label next(env);
1773    Label continueFor(env);
1774    Label lhsNotEqualFirst(env);
1775    Label continueCount(env);
1776    Label lessEnd(env);
1777    Label equalEnd(env);
1778    Label loopHead(env);
1779    Label loopEnd(env);
1780    Label nextCount(env);
1781    Label nextCount1(env);
1782    Label nextCount2(env);
1783    GateRef first;
1784    if (rhsIsUtf8) {
1785        first = ZExtInt8ToInt32(Load(VariableType::INT8(), rhsData));
1786    } else {
1787        first = ZExtInt16ToInt32(Load(VariableType::INT16(), rhsData));
1788    }
1789    Jump(&loopHead);
1790    LoopBegin(&loopHead);
1791    BRANCH(Int32LessThanOrEqual(*i, max), &next, &exit);
1792    Bind(&next);
1793    {
1794        Label loopHead1(env);
1795        Label loopEnd1(env);
1796        GateRef lhsTemp;
1797        if (lhsIsUtf8) {
1798            lhsTemp = GetUtf8Data(lhsData, *i);
1799        } else {
1800            lhsTemp = GetUtf16Data(lhsData, *i);
1801        }
1802        BRANCH(Int32NotEqual(lhsTemp, first), &nextCount1, &nextCount);
1803        Bind(&nextCount1);
1804        {
1805            i = Int32Add(*i, Int32(1));
1806            Jump(&loopHead1);
1807        }
1808        LoopBegin(&loopHead1);
1809        {
1810            BRANCH(Int32LessThanOrEqual(*i, max), &continueFor, &nextCount);
1811            Bind(&continueFor);
1812            {
1813                GateRef lhsTemp1;
1814                if (lhsIsUtf8) {
1815                    lhsTemp1 = GetUtf8Data(lhsData, *i);
1816                } else {
1817                    lhsTemp1 = GetUtf16Data(lhsData, *i);
1818                }
1819                BRANCH(Int32NotEqual(lhsTemp1, first), &lhsNotEqualFirst, &nextCount);
1820                Bind(&lhsNotEqualFirst);
1821                {
1822                    i = Int32Add(*i, Int32(1));
1823                    Jump(&loopEnd1);
1824                }
1825            }
1826        }
1827        Bind(&loopEnd1);
1828        LoopEnd(&loopHead1);
1829        Bind(&nextCount);
1830        {
1831            BRANCH(Int32LessThanOrEqual(*i, max), &continueCount, &loopEnd);
1832            Bind(&continueCount);
1833            {
1834                Label loopHead2(env);
1835                Label loopEnd2(env);
1836                j = Int32Add(*i, Int32(1));
1837                GateRef end = Int32Sub(Int32Add(*j, rhsCount), Int32(1));
1838                k = Int32(1);
1839                Jump(&loopHead2);
1840                LoopBegin(&loopHead2);
1841                {
1842                    BRANCH(Int32LessThan(*j, end), &lessEnd, &nextCount2);
1843                    Bind(&lessEnd);
1844                    {
1845                        GateRef lhsTemp2;
1846                        if (lhsIsUtf8) {
1847                            lhsTemp2 = GetUtf8Data(lhsData, *j);
1848                        } else {
1849                            lhsTemp2 = GetUtf16Data(lhsData, *j);
1850                        }
1851                        GateRef rhsTemp;
1852                        if (rhsIsUtf8) {
1853                            rhsTemp = GetUtf8Data(rhsData, *k);
1854                        } else {
1855                            rhsTemp = GetUtf16Data(rhsData, *k);
1856                        }
1857                        BRANCH(Int32Equal(lhsTemp2, rhsTemp), &loopEnd2, &nextCount2);
1858                    }
1859                }
1860                Bind(&loopEnd2);
1861                j = Int32Add(*j, Int32(1));
1862                k = Int32Add(*k, Int32(1));
1863                LoopEnd(&loopHead2);
1864                Bind(&nextCount2);
1865                {
1866                    BRANCH(Int32Equal(*j, end), &equalEnd, &loopEnd);
1867                    Bind(&equalEnd);
1868                    result = *i;
1869                    Jump(&exit);
1870                }
1871            }
1872        }
1873    }
1874    Bind(&loopEnd);
1875    i = Int32Add(*i, Int32(1));
1876    LoopEnd(&loopHead);
1877
1878    Bind(&exit);
1879    auto ret = *result;
1880    env->SubCfgExit();
1881    return ret;
1882}
1883
1884
1885void BuiltinsStringStubBuilder::StoreParent(GateRef glue, GateRef object, GateRef parent)
1886{
1887    Store(VariableType::JS_POINTER(), glue, object, IntPtr(SlicedString::PARENT_OFFSET), parent);
1888}
1889
1890void BuiltinsStringStubBuilder::StoreStartIndex(GateRef glue, GateRef object, GateRef startIndex)
1891{
1892    Store(VariableType::INT32(), glue, object, IntPtr(SlicedString::STARTINDEX_OFFSET), startIndex);
1893}
1894
1895void BuiltinsStringStubBuilder::StoreHasBackingStore(GateRef glue, GateRef object, GateRef hasBackingStore)
1896{
1897    Store(VariableType::INT32(), glue, object, IntPtr(SlicedString::BACKING_STORE_FLAG), hasBackingStore);
1898}
1899
1900GateRef BuiltinsStringStubBuilder::StringIndexOf(const StringInfoGateRef &lStringInfoGate,
1901    const StringInfoGateRef &rStringInfoGate, GateRef pos)
1902{
1903    auto env = GetEnvironment();
1904    Label entry(env);
1905    env->SubCfgEntry(&entry);
1906    DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
1907    DEFVARIABLE(posTag, VariableType::INT32(), pos);
1908    Label exit(env);
1909    Label rhsCountEqualZero(env);
1910    Label nextCount(env);
1911    Label rhsCountNotEqualZero(env);
1912    Label posLessZero(env);
1913    Label posNotLessZero(env);
1914    Label maxNotLessZero(env);
1915    Label rhsIsUtf8(env);
1916    Label rhsIsUtf16(env);
1917    Label posRMaxNotGreaterLhs(env);
1918
1919    GateRef lhsCount = lStringInfoGate.GetLength();
1920    GateRef rhsCount = rStringInfoGate.GetLength();
1921
1922    BRANCH(Int32GreaterThan(pos, lhsCount), &exit, &nextCount);
1923    Bind(&nextCount);
1924    {
1925        BRANCH(Int32Equal(rhsCount, Int32(0)), &rhsCountEqualZero, &rhsCountNotEqualZero);
1926        Bind(&rhsCountEqualZero);
1927        {
1928            result = pos;
1929            Jump(&exit);
1930        }
1931        Bind(&rhsCountNotEqualZero);
1932        {
1933            BRANCH(Int32LessThan(pos, Int32(0)), &posLessZero, &posNotLessZero);
1934            Bind(&posLessZero);
1935            {
1936                posTag = Int32(0);
1937                Jump(&posNotLessZero);
1938            }
1939            Bind(&posNotLessZero);
1940            {
1941                GateRef max = Int32Sub(lhsCount, rhsCount);
1942                BRANCH(Int32LessThan(max, Int32(0)), &exit, &maxNotLessZero);
1943                Bind(&maxNotLessZero);
1944                {
1945                    GateRef posRMax = Int32Add(*posTag, rhsCount);
1946                    BRANCH(Int32GreaterThan(posRMax, lhsCount), &exit, &posRMaxNotGreaterLhs);
1947                    Bind(&posRMaxNotGreaterLhs);
1948                    GateRef rhsData = GetNormalStringData(rStringInfoGate);
1949                    GateRef lhsData = GetNormalStringData(lStringInfoGate);
1950                    BRANCH(IsUtf8String(rStringInfoGate.GetString()), &rhsIsUtf8, &rhsIsUtf16);
1951                    Bind(&rhsIsUtf8);
1952                    {
1953                        Label lhsIsUtf8(env);
1954                        Label lhsIsUtf16(env);
1955                        BRANCH(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
1956                        Bind(&lhsIsUtf8);
1957                        {
1958                            result = StringIndexOf(lhsData, true, rhsData, true, *posTag, max, rhsCount);
1959                            Jump(&exit);
1960                        }
1961                        Bind(&lhsIsUtf16);
1962                        {
1963                            result = StringIndexOf(lhsData, false, rhsData, true, *posTag, max, rhsCount);
1964                            Jump(&exit);
1965                        }
1966                    }
1967                    Bind(&rhsIsUtf16);
1968                    {
1969                        Label lhsIsUtf8(env);
1970                        Label lhsIsUtf16(env);
1971                        BRANCH(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
1972                        Bind(&lhsIsUtf8);
1973                        {
1974                            result = StringIndexOf(lhsData, true, rhsData, false, *posTag, max, rhsCount);
1975                            Jump(&exit);
1976                        }
1977                        Bind(&lhsIsUtf16);
1978                        {
1979                            result = StringIndexOf(lhsData, false, rhsData, false, *posTag, max, rhsCount);
1980                            Jump(&exit);
1981                        }
1982                    }
1983                }
1984            }
1985        }
1986    }
1987    Bind(&exit);
1988    auto ret = *result;
1989    env->SubCfgExit();
1990    return ret;
1991}
1992
1993void FlatStringStubBuilder::FlattenString(GateRef glue, GateRef str, Label *fastPath)
1994{
1995    auto env = GetEnvironment();
1996    Label notLineString(env);
1997    Label exit(env);
1998    length_ = GetLengthFromString(str);
1999    BRANCH(IsLiteralString(str), &exit, &notLineString);
2000    Bind(&notLineString);
2001    {
2002        Label isTreeString(env);
2003        Label notTreeString(env);
2004        Label isSlicedString(env);
2005        BRANCH(IsTreeString(str), &isTreeString, &notTreeString);
2006        Bind(&isTreeString);
2007        {
2008            Label isFlat(env);
2009            Label notFlat(env);
2010            BRANCH(TreeStringIsFlat(str), &isFlat, &notFlat);
2011            Bind(&isFlat);
2012            {
2013                flatString_.WriteVariable(GetFirstFromTreeString(str));
2014                Jump(fastPath);
2015            }
2016            Bind(&notFlat);
2017            {
2018                flatString_.WriteVariable(CallRuntime(glue, RTSTUB_ID(SlowFlattenString), { str }));
2019                Jump(fastPath);
2020            }
2021        }
2022        Bind(&notTreeString);
2023        BRANCH(IsSlicedString(str), &isSlicedString, &exit);
2024        Bind(&isSlicedString);
2025        {
2026            flatString_.WriteVariable(GetParentFromSlicedString(str));
2027            startIndex_.WriteVariable(GetStartIndexFromSlicedString(str));
2028            Jump(fastPath);
2029        }
2030    }
2031    Bind(&exit);
2032    {
2033        flatString_.WriteVariable(str);
2034        Jump(fastPath);
2035    }
2036}
2037
2038void FlatStringStubBuilder::FlattenStringWithIndex(GateRef glue, GateRef str, Variable *index, Label *fastPath)
2039{
2040    // Note this method modifies "index" variable for Sliced String
2041    auto env = GetEnvironment();
2042    Label notLineString(env);
2043    Label exit(env);
2044    BRANCH(IsLiteralString(str), &exit, &notLineString);
2045    Bind(&notLineString);
2046    {
2047        Label isTreeString(env);
2048        Label notTreeString(env);
2049        Label isSlicedString(env);
2050        BRANCH(IsTreeString(str), &isTreeString, &notTreeString);
2051        Bind(&isTreeString);
2052        {
2053            Label isFlat(env);
2054            Label notFlat(env);
2055            BRANCH(TreeStringIsFlat(str), &isFlat, &notFlat);
2056            Bind(&isFlat);
2057            {
2058                flatString_.WriteVariable(GetFirstFromTreeString(str));
2059                Jump(fastPath);
2060            }
2061            Bind(&notFlat);
2062            {
2063                flatString_.WriteVariable(CallRuntime(glue, RTSTUB_ID(SlowFlattenString), { str }));
2064                Jump(fastPath);
2065            }
2066        }
2067        Bind(&notTreeString);
2068        BRANCH(IsSlicedString(str), &isSlicedString, &exit);
2069        Bind(&isSlicedString);
2070        {
2071            flatString_.WriteVariable(GetParentFromSlicedString(str));
2072            startIndex_.WriteVariable(GetStartIndexFromSlicedString(str));
2073            index->WriteVariable(Int32Add(*startIndex_, index->ReadVariable()));
2074            Jump(fastPath);
2075        }
2076    }
2077    Bind(&exit);
2078    {
2079        flatString_.WriteVariable(str);
2080        Jump(fastPath);
2081    }
2082}
2083
2084GateRef BuiltinsStringStubBuilder::GetStringDataFromLineOrConstantString(GateRef str)
2085{
2086    auto env = GetEnvironment();
2087    Label entry(env);
2088    env->SubCfgEntry(&entry);
2089    Label exit(env);
2090    Label isConstantString(env);
2091    Label isLineString(env);
2092    DEFVARIABLE(result, VariableType::NATIVE_POINTER(), IntPtr(0));
2093    BRANCH(IsConstantString(str), &isConstantString, &isLineString);
2094    Bind(&isConstantString);
2095    {
2096        GateRef address = ChangeStringTaggedPointerToInt64(PtrAdd(str, IntPtr(ConstantString::CONSTANT_DATA_OFFSET)));
2097        result = Load(VariableType::NATIVE_POINTER(), address, IntPtr(0));
2098        Jump(&exit);
2099    }
2100    Bind(&isLineString);
2101    {
2102        result = ChangeStringTaggedPointerToInt64(PtrAdd(str, IntPtr(LineEcmaString::DATA_OFFSET)));
2103        Jump(&exit);
2104    }
2105    Bind(&exit);
2106    auto ret = *result;
2107    env->SubCfgExit();
2108    return ret;
2109}
2110
2111void BuiltinsStringStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef numArgs,
2112    Variable *res, Label *exit, Label *slowPath)
2113{
2114    auto env = GetEnvironment();
2115    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2116
2117    Label objNotUndefinedAndNull(env);
2118
2119    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2120    Bind(&objNotUndefinedAndNull);
2121    {
2122        Label thisIsHeapObj(env);
2123        Label isString(env);
2124
2125        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2126        Bind(&thisIsHeapObj);
2127        BRANCH(IsString(thisValue), &isString, slowPath);
2128        Bind(&isString);
2129        {
2130            Label noPara(env);
2131            Label hasPara(env);
2132            BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &noPara, &hasPara);
2133            Bind(&noPara);
2134            {
2135                res->WriteVariable(thisValue);
2136                Jump(exit);
2137            }
2138            Bind(&hasPara);
2139            {
2140                Label argc1(env);
2141                Label notArgc1(env);
2142                Label argc2(env);
2143                Label notArgc2(env);
2144                Label argc3(env);
2145                Label notArgc3(env);
2146                Label arg0IsValid(env);
2147                Label arg1IsValid(env);
2148                Label arg2IsValid(env);
2149                Label next(env);
2150                Label next1(env);
2151                GateRef arg0 = TaggedArgument(static_cast<size_t>(BuiltinsArgs::ARG0_OR_ARGV));
2152                BRANCH(TaggedIsString(arg0), &arg0IsValid, slowPath);
2153                Bind(&arg0IsValid);
2154                {
2155                    BRANCH(Int64Equal(IntPtr(1), numArgs), &argc1, &notArgc1);
2156                    Bind(&argc1);
2157                    {
2158                        res->WriteVariable(StringConcat(glue, thisValue, arg0));
2159                        Jump(exit);
2160                    }
2161                    Bind(&notArgc1);
2162                    {
2163                        result = StringConcat(glue, thisValue, arg0);
2164                        BRANCH(TaggedIsException(*result), slowPath, &next);
2165                        Bind(&next);
2166                        GateRef arg1 = TaggedArgument(static_cast<size_t>(BuiltinsArgs::ARG1));
2167                        BRANCH(TaggedIsString(arg1), &arg1IsValid, slowPath);
2168                        Bind(&arg1IsValid);
2169                        BRANCH(Int64Equal(IntPtr(2), numArgs), &argc2, &notArgc2); // 2: number of parameters.
2170                        Bind(&argc2);
2171                        {
2172                            res->WriteVariable(StringConcat(glue, *result, arg1));
2173                            Jump(exit);
2174                        }
2175                        Bind(&notArgc2);
2176                        result = StringConcat(glue, *result, arg1);
2177                        BRANCH(TaggedIsException(*result), slowPath, &next1);
2178                        Bind(&next1);
2179                        GateRef arg2 = TaggedArgument(static_cast<size_t>(BuiltinsArgs::ARG2));
2180                        BRANCH(TaggedIsString(arg2), &arg2IsValid, slowPath);
2181                        Bind(&arg2IsValid);
2182                        BRANCH(Int64Equal(IntPtr(3), numArgs), &argc3, slowPath); // 3: number of parameters.
2183                        Bind(&argc3);
2184                        {
2185                            res->WriteVariable(StringConcat(glue, *result, arg2));
2186                            Jump(exit);
2187                        }
2188                    }
2189                }
2190            }
2191        }
2192    }
2193}
2194
2195void BuiltinsStringStubBuilder::ToLowerCase(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2196    Variable *res, Label *exit, Label *slowPath)
2197{
2198    auto env = GetEnvironment();
2199    Label objNotUndefinedAndNull(env);
2200    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2201    Bind(&objNotUndefinedAndNull);
2202    {
2203        Label thisIsHeapObj(env);
2204        Label isString(env);
2205
2206        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2207        Bind(&thisIsHeapObj);
2208        BRANCH(IsString(thisValue), &isString, slowPath);
2209        Bind(&isString);
2210        {
2211            Label isUtf8(env);
2212            Label hasPara(env);
2213            Label isUtf8Next(env);
2214            Label flattenFastPath(env);
2215            BRANCH(IsUtf8String(thisValue), &isUtf8, slowPath);
2216            Bind(&isUtf8);
2217            {
2218                GateRef srcLength = GetLengthFromString(thisValue);
2219                DEFVARIABLE(len, VariableType::INT32(), srcLength);
2220                NewObjectStubBuilder newBuilder(this);
2221                newBuilder.SetParameters(glue, 0);
2222                newBuilder.AllocLineStringObject(res, &isUtf8Next, srcLength, true);
2223                Bind(&isUtf8Next);
2224                {
2225                    FlatStringStubBuilder thisFlat(this);
2226                    thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
2227                    Bind(&flattenFastPath);
2228                    StringInfoGateRef stringInfoGate(&thisFlat);
2229                    GateRef dataUtf8 = GetNormalStringData(stringInfoGate);
2230                    GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(res->ReadVariable(),
2231                        IntPtr(LineEcmaString::DATA_OFFSET)));
2232                    DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
2233                    DEFVARIABLE(sourceTmp, VariableType::NATIVE_POINTER(), dataUtf8);
2234                    Label loopHead(env);
2235                    Label loopEnd(env);
2236                    Label next(env);
2237                    Label toLower(env);
2238                    Label notLower(env);
2239                    Jump(&loopHead);
2240                    LoopBegin(&loopHead);
2241                    {
2242                        BRANCH(Int32GreaterThan(*len, Int32(0)), &next, exit);
2243                        Bind(&next);
2244                        {
2245                            len = Int32Sub(*len, Int32(1));
2246                            GateRef i = Load(VariableType::INT8(), *sourceTmp);
2247                            // 65: means 'A', 90: means 'Z'
2248                            GateRef needLower = BitAnd(Int8GreaterThanOrEqual(i, Int8(65)),
2249                                Int8GreaterThanOrEqual(Int8(90), i));
2250                            BRANCH(needLower, &toLower, &notLower);
2251                            Bind(&toLower);
2252                            GateRef j = Int8Xor(i, Int8(1 << 5));
2253                            Store(VariableType::INT8(), glue, *dstTmp, IntPtr(0), j);
2254                            Jump(&loopEnd);
2255                            Bind(&notLower);
2256                            Store(VariableType::INT8(), glue, *dstTmp, IntPtr(0), i);
2257                            Jump(&loopEnd);
2258                        }
2259                    }
2260                    Bind(&loopEnd);
2261                    sourceTmp = PtrAdd(*sourceTmp, IntPtr(sizeof(uint8_t)));
2262                    dstTmp = PtrAdd(*dstTmp, IntPtr(sizeof(uint8_t)));
2263                    LoopEnd(&loopHead);
2264                }
2265            }
2266        }
2267    }
2268}
2269
2270GateRef BuiltinsStringStubBuilder::StringConcat(GateRef glue, GateRef leftString, GateRef rightString)
2271{
2272    auto env = GetEnvironment();
2273    Label entry(env);
2274    env->SubCfgEntry(&entry);
2275    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2276    Label exit(env);
2277    Label equalZero(env);
2278    Label notEqualZero(env);
2279    Label lessThanMax(env);
2280    Label throwError(env);
2281
2282    GateRef leftLength = GetLengthFromString(leftString);
2283    GateRef rightLength = GetLengthFromString(rightString);
2284    GateRef newLength = Int32Add(leftLength, rightLength);
2285    BRANCH(Int32GreaterThanOrEqual(newLength, Int32(EcmaString::MAX_STRING_LENGTH)), &throwError, &lessThanMax);
2286    Bind(&throwError);
2287    {
2288        GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InvalidStringLength));
2289        CallRuntime(glue, RTSTUB_ID(ThrowRangeError), { IntToTaggedInt(taggedId) });
2290        Jump(&exit);
2291    }
2292    Bind(&lessThanMax);
2293    BRANCH(Int32Equal(newLength, Int32(0)), &equalZero, &notEqualZero);
2294    Bind(&equalZero);
2295    {
2296        result = GetGlobalConstantValue(
2297            VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
2298        Jump(&exit);
2299    }
2300    Bind(&notEqualZero);
2301    {
2302        Label leftEqualZero(env);
2303        Label leftNotEqualZero(env);
2304        Label rightEqualZero(env);
2305        Label rightNotEqualZero(env);
2306        Label newLineString(env);
2307        Label newTreeString(env);
2308        BRANCH(Int32Equal(leftLength, Int32(0)), &leftEqualZero, &leftNotEqualZero);
2309        Bind(&leftEqualZero);
2310        {
2311            result = rightString;
2312            Jump(&exit);
2313        }
2314        Bind(&leftNotEqualZero);
2315        BRANCH(Int32Equal(rightLength, Int32(0)), &rightEqualZero, &rightNotEqualZero);
2316        Bind(&rightEqualZero);
2317        {
2318            result = leftString;
2319            Jump(&exit);
2320        }
2321        Bind(&rightNotEqualZero);
2322        {
2323            GateRef leftIsUtf8 = IsUtf8String(leftString);
2324            GateRef rightIsUtf8 = IsUtf8String(rightString);
2325            GateRef canBeCompressed = BitAnd(leftIsUtf8, rightIsUtf8);
2326            NewObjectStubBuilder newBuilder(this);
2327            newBuilder.SetParameters(glue, 0);
2328            GateRef isTreeOrSlicedString = Int32LessThan(newLength,
2329                Int32(std::min(TreeEcmaString::MIN_TREE_ECMASTRING_LENGTH,
2330                               SlicedString::MIN_SLICED_ECMASTRING_LENGTH)));
2331            BRANCH(isTreeOrSlicedString, &newLineString, &newTreeString);
2332            Bind(&newLineString);
2333            {
2334                Label isUtf8(env);
2335                Label isUtf16(env);
2336                Label isUtf8Next(env);
2337                Label isUtf16Next(env);
2338                BRANCH(canBeCompressed, &isUtf8, &isUtf16);
2339                Bind(&isUtf8);
2340                {
2341                    newBuilder.AllocLineStringObject(&result, &isUtf8Next, newLength, true);
2342                }
2343                Bind(&isUtf16);
2344                {
2345                    newBuilder.AllocLineStringObject(&result, &isUtf16Next, newLength, false);
2346                }
2347                Bind(&isUtf8Next);
2348                {
2349                    GateRef leftSource = GetStringDataFromLineOrConstantString(leftString);
2350                    GateRef rightSource = GetStringDataFromLineOrConstantString(rightString);
2351                    GateRef leftDst = ChangeStringTaggedPointerToInt64(
2352                        PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
2353                    GateRef rightDst = ChangeStringTaggedPointerToInt64(PtrAdd(leftDst, ZExtInt32ToPtr(leftLength)));
2354                    CopyChars(glue, leftDst, leftSource, leftLength, IntPtr(sizeof(uint8_t)), VariableType::INT8());
2355                    CopyChars(glue, rightDst, rightSource, rightLength, IntPtr(sizeof(uint8_t)), VariableType::INT8());
2356                    Jump(&exit);
2357                }
2358                Bind(&isUtf16Next);
2359                {
2360                    Label leftIsUtf8L(env);
2361                    Label leftIsUtf16L(env);
2362                    Label rightIsUtf8L(env);
2363                    Label rightIsUtf16L(env);
2364                    GateRef leftSource = GetStringDataFromLineOrConstantString(leftString);
2365                    GateRef rightSource = GetStringDataFromLineOrConstantString(rightString);
2366                    GateRef leftDst = ChangeStringTaggedPointerToInt64(
2367                        PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
2368                    GateRef rightDst = ChangeStringTaggedPointerToInt64(
2369                        PtrAdd(leftDst, PtrMul(ZExtInt32ToPtr(leftLength), IntPtr(sizeof(uint16_t)))));
2370                    BRANCH(leftIsUtf8, &leftIsUtf8L, &leftIsUtf16L);
2371                    Bind(&leftIsUtf8L);
2372                    {
2373                        // left is utf8,right string must utf16
2374                        CopyUtf8AsUtf16(glue, leftDst, leftSource, leftLength);
2375                        CopyChars(glue, rightDst, rightSource, rightLength,
2376                            IntPtr(sizeof(uint16_t)), VariableType::INT16());
2377                        Jump(&exit);
2378                    }
2379                    Bind(&leftIsUtf16L);
2380                    {
2381                        CopyChars(glue, leftDst, leftSource, leftLength,
2382                            IntPtr(sizeof(uint16_t)), VariableType::INT16());
2383                        BRANCH(rightIsUtf8, &rightIsUtf8L, &rightIsUtf16L);
2384                        Bind(&rightIsUtf8L);
2385                        CopyUtf8AsUtf16(glue, rightDst, rightSource, rightLength);
2386                        Jump(&exit);
2387                        Bind(&rightIsUtf16L);
2388                        CopyChars(glue, rightDst, rightSource, rightLength,
2389                            IntPtr(sizeof(uint16_t)), VariableType::INT16());
2390                        Jump(&exit);
2391                    }
2392                }
2393            }
2394            Bind(&newTreeString);
2395            {
2396                Label isUtf8(env);
2397                Label isUtf16(env);
2398                BRANCH(canBeCompressed, &isUtf8, &isUtf16);
2399                Bind(&isUtf8);
2400                {
2401                    newBuilder.AllocTreeStringObject(&result, &exit, leftString, rightString, newLength, true);
2402                }
2403                Bind(&isUtf16);
2404                {
2405                    newBuilder.AllocTreeStringObject(&result, &exit, leftString, rightString, newLength, false);
2406                }
2407            }
2408        }
2409    }
2410    Bind(&exit);
2411    auto ret = *result;
2412    env->SubCfgExit();
2413    return ret;
2414}
2415
2416void BuiltinsStringStubBuilder::LocaleCompare([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
2417                                              [[maybe_unused]] Variable *res, [[maybe_unused]] Label *exit,
2418                                              Label *slowPath)
2419{
2420    auto env = GetEnvironment();
2421
2422    Label thisIsHeapObj(env);
2423    BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2424    Bind(&thisIsHeapObj);
2425    {
2426        Label thisValueIsString(env);
2427        Label fristArgIsString(env);
2428        Label arg0IsHeapObj(env);
2429        BRANCH(IsString(thisValue), &thisValueIsString, slowPath);
2430        Bind(&thisValueIsString);
2431        GateRef arg0 = GetCallArg0(numArgs);
2432        BRANCH(TaggedIsHeapObject(arg0), &arg0IsHeapObj, slowPath);
2433        Bind(&arg0IsHeapObj);
2434        BRANCH(IsString(arg0), &fristArgIsString, slowPath);
2435        Bind(&fristArgIsString);
2436#ifdef ARK_SUPPORT_INTL
2437        GateRef locales = GetCallArg1(numArgs);
2438
2439        GateRef options = GetCallArg2(numArgs);
2440        GateRef localesIsUndefOrString =
2441            LogicOrBuilder(env).Or(TaggedIsUndefined(locales)).Or(TaggedIsString(locales)).Done();
2442        GateRef cacheable = LogicAndBuilder(env).And(localesIsUndefOrString).And(TaggedIsUndefined(options)).Done();
2443        Label optionsIsString(env);
2444        Label cacheAble(env);
2445        Label uncacheable(env);
2446
2447        BRANCH(cacheable, &cacheAble, &uncacheable);
2448        Bind(&cacheAble);
2449        {
2450            Label defvalue(env);
2451            GateRef resValue = CallRuntime(glue, RTSTUB_ID(LocaleCompareCacheable), {locales, thisValue, arg0});
2452            BRANCH(TaggedIsUndefined(resValue), &uncacheable, &defvalue);
2453            Bind(&defvalue);
2454            *res = resValue;
2455            Jump(exit);
2456        }
2457        Bind(&uncacheable);
2458        {
2459            res->WriteVariable(CallRuntime(glue, RTSTUB_ID(LocaleCompareWithGc), {locales, thisValue, arg0, options}));
2460            Jump(exit);
2461        }
2462#else
2463    Jump(slowPath);
2464#endif
2465    }
2466}
2467
2468void BuiltinsStringStubBuilder::GetStringIterator(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2469                                                  Variable *res, Label *exit, Label *slowPath)
2470{
2471    auto env = GetEnvironment();
2472    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2473
2474    Label thisIsHeapObj(env);
2475    BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2476    Bind(&thisIsHeapObj);
2477    {
2478        Label thisValueIsString(env);
2479        BRANCH(IsString(thisValue), &thisValueIsString, slowPath);
2480        Bind(&thisValueIsString);
2481        GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
2482        GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
2483        GateRef strIterClass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
2484                                                 GlobalEnv::STRING_ITERATOR_CLASS_INDEX);
2485        Label afterNew(env);
2486        NewObjectStubBuilder newBuilder(this);
2487        newBuilder.SetParameters(glue, 0);
2488        newBuilder.NewJSObject(&result, &afterNew, strIterClass);
2489        Bind(&afterNew);
2490        Store(VariableType::JS_POINTER(), glue, *result, IntPtr(JSStringIterator::ITERATED_STRING_OFFSET), thisValue);
2491        Store(VariableType::INT32(), glue, *result, IntPtr(JSStringIterator::STRING_ITERATOR_NEXT_INDEX_OFFSET),
2492              Int32(0));
2493        res->WriteVariable(*result);
2494        Jump(exit);
2495    }
2496}
2497
2498void BuiltinsStringStubBuilder::StringIteratorNext(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2499                                                   Variable *res, Label *exit, Label *slowPath)
2500{
2501    auto env = GetEnvironment();
2502    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2503
2504    Label thisIsHeapObj(env);
2505    Label thisIsStringIterator(env);
2506    Label strNotUndefined(env);
2507    Label strIsHeapObj(env);
2508    Label strIsString(env);
2509    Label iterDone(env);
2510    BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2511    Bind(&thisIsHeapObj);
2512    BRANCH(TaggedIsStringIterator(thisValue), &thisIsStringIterator, slowPath);
2513    Bind(&thisIsStringIterator);
2514    GateRef str = Load(VariableType::JS_POINTER(), thisValue, IntPtr(JSStringIterator::ITERATED_STRING_OFFSET));
2515    BRANCH(TaggedIsUndefined(str), &iterDone, &strNotUndefined);
2516    Bind(&strNotUndefined);
2517    BRANCH(TaggedIsHeapObject(str), &strIsHeapObj, slowPath);
2518    Bind(&strIsHeapObj);
2519    BRANCH(TaggedIsString(str), &strIsString, slowPath);
2520    Bind(&strIsString);
2521    {
2522        Label getFirst(env);
2523        Label afterFlat(env);
2524        Label getStringFromSingleCharTable(env);
2525        GateRef position = Load(VariableType::INT32(), thisValue,
2526                                IntPtr(JSStringIterator::STRING_ITERATOR_NEXT_INDEX_OFFSET));
2527        GateRef len = GetLengthFromString(str);
2528        BRANCH(Int32GreaterThanOrEqual(position, len), &iterDone, &getFirst);
2529        Bind(&getFirst);
2530        FlatStringStubBuilder strFlat(this);
2531        strFlat.FlattenString(glue, str, &afterFlat);
2532        Bind(&afterFlat);
2533        StringInfoGateRef strInfo(&strFlat);
2534        GateRef first = StringAt(strInfo, position);
2535        GateRef canStoreAsUtf8 = IsASCIICharacter(first);
2536        BRANCH(canStoreAsUtf8, &getStringFromSingleCharTable, slowPath);
2537        Bind(&getStringFromSingleCharTable);
2538        GateRef singleCharTable = GetSingleCharTable(glue);
2539        GateRef firstStr = GetValueFromTaggedArray(singleCharTable, ZExtInt16ToInt32(first));
2540        Store(VariableType::INT32(), glue, thisValue, IntPtr(JSStringIterator::STRING_ITERATOR_NEXT_INDEX_OFFSET),
2541              Int32Add(position, Int32(1)));
2542        // CreateIterResultObject(firstStr, false)
2543        GateRef iterResultClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
2544                                                         ConstantIndex::ITERATOR_RESULT_CLASS);
2545        Label afterNew(env);
2546        NewObjectStubBuilder newBuilder(this);
2547        newBuilder.SetParameters(glue, 0);
2548        newBuilder.NewJSObject(&result, &afterNew, iterResultClass);
2549        Bind(&afterNew);
2550        SetPropertyInlinedProps(glue, *result, iterResultClass, firstStr,
2551                                Int32(JSIterator::VALUE_INLINE_PROPERTY_INDEX));
2552        SetPropertyInlinedProps(glue, *result, iterResultClass, TaggedFalse(),
2553                                Int32(JSIterator::DONE_INLINE_PROPERTY_INDEX));
2554        res->WriteVariable(*result);
2555        Jump(exit);
2556    }
2557    Bind(&iterDone);
2558    {
2559        Store(VariableType::JS_POINTER(), glue, thisValue, IntPtr(JSStringIterator::ITERATED_STRING_OFFSET),
2560              Undefined());
2561        // CreateIterResultObject(undefined, true)
2562        GateRef iterResultClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
2563                                                         ConstantIndex::ITERATOR_RESULT_CLASS);
2564        Label afterNew(env);
2565        NewObjectStubBuilder newBuilder(this);
2566        newBuilder.SetParameters(glue, 0);
2567        newBuilder.NewJSObject(&result, &afterNew, iterResultClass);
2568        Bind(&afterNew);
2569        SetPropertyInlinedProps(glue, *result, iterResultClass, Undefined(),
2570                                Int32(JSIterator::VALUE_INLINE_PROPERTY_INDEX));
2571        SetPropertyInlinedProps(glue, *result, iterResultClass, TaggedTrue(),
2572                                Int32(JSIterator::DONE_INLINE_PROPERTY_INDEX));
2573        res->WriteVariable(*result);
2574        Jump(exit);
2575    }
2576}
2577
2578GateRef BuiltinsStringStubBuilder::EcmaStringTrim(GateRef glue, GateRef thisValue, GateRef trimMode)
2579{
2580    auto env = GetEnvironment();
2581
2582    Label entry(env);
2583    env->SubCfgEntry(&entry);
2584
2585    DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2586
2587    Label emptyString(env);
2588    Label notEmpty(env);
2589    Label exit(env);
2590
2591    GateRef srcLen = GetLengthFromString(thisValue);
2592    BRANCH(Int32Equal(srcLen, Int32(0)), &emptyString, &notEmpty);
2593    Bind(&emptyString);
2594    {
2595        result = GetGlobalConstantValue(
2596            VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
2597        Jump(&exit);
2598    }
2599    Bind(&notEmpty);
2600    {
2601        Label srcFlattenFastPath(env);
2602
2603        FlatStringStubBuilder srcFlat(this);
2604        srcFlat.FlattenString(glue, thisValue, &srcFlattenFastPath);
2605        Bind(&srcFlattenFastPath);
2606        StringInfoGateRef srcStringInfoGate(&srcFlat);
2607        result = EcmaStringTrimBody(glue, thisValue, srcStringInfoGate, trimMode, IsUtf8String(thisValue));
2608        Jump(&exit);
2609    }
2610    Bind(&exit);
2611    auto ret = *result;
2612    env->SubCfgExit();
2613    return ret;
2614}
2615
2616GateRef BuiltinsStringStubBuilder::EcmaStringTrimBody(GateRef glue, GateRef thisValue,
2617    StringInfoGateRef srcStringInfoGate, GateRef trimMode, GateRef isUtf8)
2618{
2619    auto env = GetEnvironment();
2620
2621    Label entry(env);
2622    env->SubCfgEntry(&entry);
2623
2624    GateRef srcLen = srcStringInfoGate.GetLength();
2625    GateRef srcString = srcStringInfoGate.GetString();
2626    GateRef startIndex = srcStringInfoGate.GetStartIndex();
2627
2628    DEFVARIABLE(start, VariableType::INT32(), Int32(0));
2629    DEFVARIABLE(end, VariableType::INT32(), Int32Sub(srcLen, Int32(1)));
2630
2631    Label trimOrTrimStart(env);
2632    Label notTrimStart(env);
2633    Label next(env);
2634
2635    BRANCH(Int32GreaterThanOrEqual(trimMode, Int32(0)), &trimOrTrimStart, &notTrimStart);
2636    Bind(&trimOrTrimStart); // mode = TrimMode::TRIM or TrimMode::TRIM_START
2637    {
2638        start = CallNGCRuntime(glue, RTSTUB_ID(StringGetStart), {isUtf8, srcString, srcLen, startIndex});
2639        Jump(&notTrimStart);
2640    }
2641    Bind(&notTrimStart);
2642    {
2643        Label trimOrTrimEnd(env);
2644        BRANCH(Int32LessThanOrEqual(trimMode, Int32(0)), &trimOrTrimEnd, &next);
2645        Bind(&trimOrTrimEnd); // mode = TrimMode::TRIM or TrimMode::TRIM_END
2646        {
2647            end = CallNGCRuntime(glue, RTSTUB_ID(StringGetEnd), {isUtf8, srcString, *start, srcLen, startIndex});
2648            Jump(&next);
2649        }
2650    }
2651    Bind(&next);
2652    {
2653        auto ret = FastSubString(glue, thisValue, *start,
2654                                 Int32Add(Int32Sub(*end, *start), Int32(1)), srcStringInfoGate);
2655        env->SubCfgExit();
2656        return ret;
2657    }
2658}
2659
2660GateRef BuiltinsStringStubBuilder::IsSubStringAt(GateRef lhsData, bool lhsIsUtf8, GateRef rhsData,
2661                                                 bool rhsIsUtf8, GateRef pos, GateRef rhsCount)
2662{
2663    auto env = GetEnvironment();
2664    Label entry(env);
2665    env->SubCfgEntry(&entry);
2666
2667    DEFVARIABLE(i, VariableType::INT32(), Int32(0));
2668    DEFVARIABLE(result, VariableType::JS_ANY(), TaggedTrue());
2669
2670    Label exit(env);
2671    Label next(env);
2672    Label loopHead(env);
2673    Label loopEnd(env);
2674    Label notEqual(env);
2675
2676    Jump(&loopHead);
2677    LoopBegin(&loopHead);
2678    BRANCH(Int32LessThan(*i, rhsCount), &next, &exit);
2679    Bind(&next);
2680    {
2681        GateRef lhsTemp;
2682        GateRef rhsTemp;
2683        if (lhsIsUtf8) {
2684            lhsTemp = GetUtf8Data(lhsData, Int32Add(*i, pos));
2685        } else {
2686            lhsTemp = GetUtf16Data(lhsData, Int32Add(*i, pos));
2687        }
2688        if (rhsIsUtf8) {
2689            rhsTemp = GetUtf8Data(rhsData, *i);
2690        } else {
2691            rhsTemp = GetUtf16Data(rhsData, *i);
2692        }
2693        BRANCH(Int32Equal(lhsTemp, rhsTemp), &loopEnd, &notEqual);
2694        Bind(&notEqual);
2695        {
2696            result = TaggedFalse();
2697            Jump(&exit);
2698        }
2699    }
2700    Bind(&loopEnd);
2701    i = Int32Add(*i, Int32(1));
2702    LoopEnd(&loopHead);
2703
2704    Bind(&exit);
2705    auto ret = *result;
2706    env->SubCfgExit();
2707    return ret;
2708}
2709
2710GateRef BuiltinsStringStubBuilder::IsSubStringAt(const StringInfoGateRef &lStringInfoGate,
2711                                                 const StringInfoGateRef &rStringInfoGate, GateRef pos)
2712{
2713    auto env = GetEnvironment();
2714    Label entry(env);
2715    env->SubCfgEntry(&entry);
2716    Label exit(env);
2717    Label rhsIsUtf8(env);
2718    Label rhsIsUtf16(env);
2719
2720    DEFVARIABLE(result, VariableType::JS_ANY(), TaggedFalse());
2721    GateRef rhsCount = rStringInfoGate.GetLength();
2722    GateRef rhsData = GetNormalStringData(rStringInfoGate);
2723    GateRef lhsData = GetNormalStringData(lStringInfoGate);
2724    BRANCH(IsUtf8String(rStringInfoGate.GetString()), &rhsIsUtf8, &rhsIsUtf16);
2725    Bind(&rhsIsUtf8);
2726    {
2727        Label lhsIsUtf8(env);
2728        Label lhsIsUtf16(env);
2729        BRANCH(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
2730        Bind(&lhsIsUtf8);
2731        {
2732            result = IsSubStringAt(lhsData, true, rhsData, true, pos, rhsCount);
2733            Jump(&exit);
2734        }
2735        Bind(&lhsIsUtf16);
2736        {
2737            result = IsSubStringAt(lhsData, false, rhsData, true, pos, rhsCount);
2738            Jump(&exit);
2739        }
2740    }
2741    Bind(&rhsIsUtf16);
2742    {
2743        Label lhsIsUtf8(env);
2744        Label lhsIsUtf16(env);
2745        BRANCH(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
2746        Bind(&lhsIsUtf8);
2747        {
2748            result = IsSubStringAt(lhsData, true, rhsData, false, pos, rhsCount);
2749            Jump(&exit);
2750        }
2751        Bind(&lhsIsUtf16);
2752        {
2753            result = IsSubStringAt(lhsData, false, rhsData, false, pos, rhsCount);
2754            Jump(&exit);
2755        }
2756    }
2757
2758    Bind(&exit);
2759    auto ret = *result;
2760    env->SubCfgExit();
2761    return ret;
2762}
2763
2764void BuiltinsStringStubBuilder::StartsWith(GateRef glue, GateRef thisValue, GateRef numArgs,
2765    Variable *res, Label *exit, Label *slowPath)
2766{
2767    auto env = GetEnvironment();
2768    DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
2769
2770    Label objNotUndefinedAndNull(env);
2771    Label thisIsHeapobject(env);
2772    Label isString(env);
2773    Label searchTagIsHeapObject(env);
2774    Label isSearchString(env);
2775    Label next(env);
2776    Label posTagNotUndefined(env);
2777    Label posTagIsInt(env);
2778    Label posTagNotInt(env);
2779    Label posTagIsDouble(env);
2780    Label posTagIsPositiveInfinity(env);
2781    Label posTagNotPositiveInfinity(env);
2782
2783    Label posNotLessThanLen(env);
2784    Label flattenFastPath(env);
2785    Label flattenFastPath1(env);
2786    Label resPosEqualPos(env);
2787    Label resPosNotEqualPos(env);
2788
2789    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2790    Bind(&objNotUndefinedAndNull);
2791    {
2792        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
2793        Bind(&thisIsHeapobject);
2794        BRANCH(IsString(thisValue), &isString, slowPath);
2795        Bind(&isString);
2796        {
2797            GateRef searchTag = GetCallArg0(numArgs);
2798            BRANCH(TaggedIsHeapObject(searchTag), &searchTagIsHeapObject, slowPath);
2799            Bind(&searchTagIsHeapObject);
2800            BRANCH(IsString(searchTag), &isSearchString, slowPath);
2801            Bind(&isSearchString);
2802            {
2803                GateRef thisLen = GetLengthFromString(thisValue);
2804                GateRef searchLen = GetLengthFromString(searchTag);
2805                BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &next, &posTagNotUndefined);
2806                Bind(&posTagNotUndefined);
2807                {
2808                    GateRef posTag = GetCallArg1(numArgs);
2809                    BRANCH(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
2810                    Bind(&posTagIsInt);
2811                    pos = GetInt32OfTInt(posTag);
2812                    Jump(&next);
2813                    Bind(&posTagNotInt);
2814                    BRANCH(TaggedIsDouble(posTag), &posTagIsDouble, slowPath);
2815                    Bind(&posTagIsDouble);
2816                    BRANCH(DoubleEqual(GetDoubleOfTDouble(posTag), Double(builtins::BuiltinsNumber::POSITIVE_INFINITY)),
2817                        &posTagIsPositiveInfinity, &posTagNotPositiveInfinity);
2818                    Bind(&posTagIsPositiveInfinity);
2819                    pos = thisLen;
2820                    Jump(&next);
2821                    Bind(&posTagNotPositiveInfinity);
2822                    pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
2823                    Jump(&next);
2824                }
2825                Bind(&next);
2826                {
2827                    Label posGreaterThanZero(env);
2828                    Label posNotGreaterThanZero(env);
2829                    Label nextCount(env);
2830                    BRANCH(Int32GreaterThan(*pos, Int32(0)), &posGreaterThanZero, &posNotGreaterThanZero);
2831                    Bind(&posNotGreaterThanZero);
2832                    {
2833                        pos = Int32(0);
2834                        Jump(&nextCount);
2835                    }
2836                    Bind(&posGreaterThanZero);
2837                    {
2838                        BRANCH(Int32LessThanOrEqual(*pos, thisLen), &nextCount, &posNotLessThanLen);
2839                        Bind(&posNotLessThanLen);
2840                        {
2841                            pos = thisLen;
2842                            Jump(&nextCount);
2843                        }
2844                    }
2845                    Bind(&nextCount);
2846                    {
2847                        Label notGreaterThanThisLen(env);
2848                        Label greaterThanThisLen(env);
2849
2850                        GateRef posAddSearchLen = Int32Add(*pos, searchLen);
2851                        BRANCH(Int32GreaterThan(posAddSearchLen, thisLen), &greaterThanThisLen, &notGreaterThanThisLen);
2852                        Bind(&greaterThanThisLen);
2853                        {
2854                            res->WriteVariable(TaggedFalse());
2855                            Jump(exit);
2856                        }
2857                        Bind(&notGreaterThanThisLen);
2858                        FlatStringStubBuilder thisFlat(this);
2859                        thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
2860                        Bind(&flattenFastPath);
2861                        FlatStringStubBuilder searchFlat(this);
2862                        searchFlat.FlattenString(glue, searchTag, &flattenFastPath1);
2863                        Bind(&flattenFastPath1);
2864                        {
2865                            StringInfoGateRef thisStringInfoGate(&thisFlat);
2866                            StringInfoGateRef searchStringInfoGate(&searchFlat);
2867                            GateRef result = IsSubStringAt(thisStringInfoGate, searchStringInfoGate, *pos);
2868                            res->WriteVariable(result);
2869                            Jump(exit);
2870                        }
2871                    }
2872                }
2873            }
2874        }
2875    }
2876}
2877
2878void BuiltinsStringStubBuilder::EndsWith(GateRef glue, GateRef thisValue, GateRef numArgs,
2879    Variable *res, Label *exit, Label *slowPath)
2880{
2881    auto env = GetEnvironment();
2882    DEFVARIABLE(searchPos, VariableType::INT32(), Int32(0));
2883    DEFVARIABLE(startPos, VariableType::INT32(), Int32(0));
2884    DEFVARIABLE(endPos, VariableType::INT32(), Int32(0));
2885    Label thisExists(env);
2886    Label thisIsHeapObject(env);
2887    Label thisIsString(env);
2888    Label searchTagExists(env);
2889    Label searchTagIsHeapObject(env);
2890    Label searchTagIsString(env);
2891    Label posTagExists(env);
2892    Label posTagNotExists(env);
2893    Label posTagIsNumber(env);
2894    Label posTagIsInt(env);
2895    Label afterCallArg(env);
2896    Label endPosLessThanZero(env);
2897    Label endPosNotLessThanZero(env);
2898    Label endPosMoreThanThisLen(env);
2899    Label endPosNotMoreThanThisLen(env);
2900    Label startPosLessThanZero(env);
2901    Label startPosNotLessThanZero(env);
2902    Label flattenFastPath1(env);
2903    Label flattenFastPath2(env);
2904    Label resultIndexEqualStartPos(env);
2905
2906    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
2907    Bind(&thisExists);
2908    {
2909        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObject, slowPath);
2910        Bind(&thisIsHeapObject);
2911        BRANCH(IsString(thisValue), &thisIsString, slowPath);
2912        Bind(&thisIsString);
2913        BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), slowPath, &searchTagExists);
2914        Bind(&searchTagExists);
2915        {
2916            GateRef searchTag = GetCallArg0(numArgs);
2917            BRANCH(TaggedIsHeapObject(searchTag), &searchTagIsHeapObject, slowPath);
2918            Bind(&searchTagIsHeapObject);
2919            BRANCH(IsString(searchTag), &searchTagIsString, slowPath);
2920            Bind(&searchTagIsString);
2921            {
2922                GateRef thisLen = GetLengthFromString(thisValue);
2923                GateRef searchLen = GetLengthFromString(searchTag);
2924                BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &posTagNotExists, &posTagExists);
2925                Bind(&posTagExists);
2926                {
2927                    GateRef posTag = GetCallArg1(numArgs);
2928                    BRANCH(TaggedIsNumber(posTag), &posTagIsNumber, slowPath);
2929                    Bind(&posTagIsNumber);
2930                    BRANCH(TaggedIsInt(posTag), &posTagIsInt, slowPath);
2931                    Bind(&posTagIsInt);
2932                    {
2933                        searchPos = GetInt32OfTInt(posTag);
2934                        Jump(&afterCallArg);
2935                    }
2936                }
2937                Bind(&posTagNotExists);
2938                {
2939                    searchPos = thisLen;
2940                    Jump(&afterCallArg);
2941                }
2942                Bind(&afterCallArg);
2943                {
2944                    endPos = *searchPos;
2945                    BRANCH(Int32GreaterThanOrEqual(*endPos, Int32(0)), &endPosNotLessThanZero, &endPosLessThanZero);
2946                    Bind(&endPosLessThanZero);
2947                    {
2948                        endPos = Int32(0);
2949                        Jump(&endPosNotLessThanZero);
2950                    }
2951                    Bind(&endPosNotLessThanZero);
2952                    {
2953                        BRANCH(Int32LessThanOrEqual(*endPos, thisLen), &endPosNotMoreThanThisLen,
2954                            &endPosMoreThanThisLen);
2955                        Bind(&endPosMoreThanThisLen);
2956                        {
2957                            endPos = thisLen;
2958                            Jump(&endPosNotMoreThanThisLen);
2959                        }
2960                        Bind(&endPosNotMoreThanThisLen);
2961                        {
2962                            startPos = Int32Sub(*endPos, searchLen);
2963                            BRANCH(Int32LessThan(*startPos, Int32(0)), &startPosLessThanZero,
2964                                &startPosNotLessThanZero);
2965                            Bind(&startPosNotLessThanZero);
2966                            {
2967                                FlatStringStubBuilder thisFlat(this);
2968                                thisFlat.FlattenString(glue, thisValue, &flattenFastPath1);
2969                                Bind(&flattenFastPath1);
2970                                FlatStringStubBuilder searchFlat(this);
2971                                searchFlat.FlattenString(glue, searchTag, &flattenFastPath2);
2972                                Bind(&flattenFastPath2);
2973                                {
2974                                    StringInfoGateRef thisStringInfoGate(&thisFlat);
2975                                    StringInfoGateRef searchStringInfoGate(&searchFlat);
2976                                    GateRef result = IsSubStringAt(thisStringInfoGate, searchStringInfoGate, *startPos);
2977                                    res->WriteVariable(result);
2978                                    Jump(exit);
2979                                }
2980                            }
2981                            Bind(&startPosLessThanZero);
2982                            {
2983                                res->WriteVariable(TaggedFalse());
2984                                Jump(exit);
2985                            }
2986                        }
2987                    }
2988                }
2989            }
2990        }
2991    }
2992}
2993
2994void BuiltinsStringStubBuilder::TrimStart(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2995    Variable *res, Label *exit, Label *slowPath)
2996{
2997    auto env = GetEnvironment();
2998    Label objNotUndefinedAndNull(env);
2999    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
3000    Bind(&objNotUndefinedAndNull);
3001    {
3002        Label thisIsHeapObj(env);
3003        Label thisIsString(env);
3004        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
3005        Bind(&thisIsHeapObj);
3006        BRANCH(IsString(thisValue), &thisIsString, slowPath);
3007        Bind(&thisIsString);
3008        GateRef result = EcmaStringTrim(glue, thisValue, Int32(1)); // 1: mode = TrimMode::start
3009        res->WriteVariable(result);
3010        Jump(exit);
3011    }
3012}
3013
3014void BuiltinsStringStubBuilder::TrimEnd(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
3015    Variable *res, Label *exit, Label *slowPath)
3016{
3017    auto env = GetEnvironment();
3018    Label objNotUndefinedAndNull(env);
3019    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
3020    Bind(&objNotUndefinedAndNull);
3021    {
3022        Label thisIsHeapObj(env);
3023        Label thisIsString(env);
3024        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
3025        Bind(&thisIsHeapObj);
3026        BRANCH(IsString(thisValue), &thisIsString, slowPath);
3027        Bind(&thisIsString);
3028        GateRef result = EcmaStringTrim(glue, thisValue, Int32(-1)); // -1: mode = TrimMode::end
3029        res->WriteVariable(result);
3030        Jump(exit);
3031    }
3032}
3033
3034void BuiltinsStringStubBuilder::TrimLeft(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
3035    Variable *res, Label *exit, Label *slowPath)
3036{
3037    auto env = GetEnvironment();
3038    Label objNotUndefinedAndNull(env);
3039    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
3040    Bind(&objNotUndefinedAndNull);
3041    {
3042        Label thisIsHeapObj(env);
3043        Label thisIsString(env);
3044        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
3045        Bind(&thisIsHeapObj);
3046        BRANCH(IsString(thisValue), &thisIsString, slowPath);
3047        Bind(&thisIsString);
3048        GateRef result = EcmaStringTrim(glue, thisValue, Int32(1)); // 1: mode = TrimMode::start
3049        res->WriteVariable(result);
3050        Jump(exit);
3051    }
3052}
3053
3054void BuiltinsStringStubBuilder::TrimRight(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
3055    Variable *res, Label *exit, Label *slowPath)
3056{
3057    auto env = GetEnvironment();
3058    Label objNotUndefinedAndNull(env);
3059    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
3060    Bind(&objNotUndefinedAndNull);
3061    {
3062        Label thisIsHeapObj(env);
3063        Label thisIsString(env);
3064        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
3065        Bind(&thisIsHeapObj);
3066        BRANCH(IsString(thisValue), &thisIsString, slowPath);
3067        Bind(&thisIsString);
3068        GateRef result = EcmaStringTrim(glue, thisValue, Int32(-1)); // -1: mode = TrimMode::end
3069        res->WriteVariable(result);
3070        Jump(exit);
3071    }
3072}
3073
3074void BuiltinsStringStubBuilder::PadStart(GateRef glue, GateRef thisValue, GateRef numArgs,
3075    Variable* res, Label *exit, Label *slowPath)
3076{
3077    auto env = GetEnvironment();
3078    DEFVARIABLE(tempStringLength, VariableType::INT32(), Int32(0));
3079    DEFVARIABLE(newStringLength, VariableType::INT32(), Int32(0));
3080    DEFVARIABLE(tempStr, VariableType::JS_ANY(), Undefined());
3081
3082    Label objNotUndefinedAndNull(env);
3083    Label isString(env);
3084    Label isPanString(env);
3085    Label next(env);
3086    Label padTagIsHeapObject(env);
3087    Label padStringNotUndefined(env);
3088    Label lengthIsInt(env);
3089    Label lengthNotInt(env);
3090    Label lengthIsDouble(env);
3091    Label thisIsHeapobject(env);
3092    Label newLengthIsNotNaN(env);
3093    Label newLengthIsNotINF(env);
3094    Label isSelf(env);
3095    Label isNotSelf(env);
3096    Label padStringNotEmpty(env);
3097    Label fillLessThanPad(env);
3098    Label fillNotLessThanPad(env);
3099    Label resultString(env);
3100    Label newLengthInRange(env);
3101
3102    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
3103    Bind(&objNotUndefinedAndNull);
3104    {
3105        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
3106        Bind(&thisIsHeapobject);
3107        BRANCH(IsString(thisValue), &isString, slowPath);
3108        Bind(&isString);
3109        {
3110            GateRef newLength = GetCallArg0(numArgs);
3111            BRANCH(TaggedIsInt(newLength), &lengthIsInt, &lengthNotInt);
3112            Bind(&lengthIsInt);
3113            {
3114                newStringLength = GetInt32OfTInt(newLength);
3115                BRANCH(Int32GreaterThanOrEqual(*newStringLength, Int32(EcmaString::MAX_STRING_LENGTH)),
3116                    slowPath, &next);
3117            }
3118            Bind(&lengthNotInt);
3119            {
3120                BRANCH(TaggedIsDouble(newLength), &lengthIsDouble, slowPath);
3121                Bind(&lengthIsDouble);
3122                BRANCH(DoubleIsNAN(GetDoubleOfTDouble(newLength)), slowPath, &newLengthIsNotNaN);
3123                Bind(&newLengthIsNotNaN);
3124                BRANCH(DoubleIsINF(GetDoubleOfTDouble(newLength)), slowPath, &newLengthIsNotINF);
3125                Bind(&newLengthIsNotINF);
3126                BRANCH(DoubleGreaterThanOrEqual(GetDoubleOfTDouble(newLength), Double(EcmaString::MAX_STRING_LENGTH)),
3127                    slowPath, &newLengthInRange);
3128                Bind(&newLengthInRange);
3129                newStringLength = DoubleToInt(glue, GetDoubleOfTDouble(newLength));
3130                Jump(&next);
3131            }
3132            Bind(&next);
3133            GateRef thisLen = GetLengthFromString(thisValue);
3134            BRANCH(Int32GreaterThanOrEqual(thisLen, *newStringLength), &isSelf, &isNotSelf);
3135            Bind(&isSelf);
3136            {
3137                res->WriteVariable(thisValue);
3138                Jump(exit);
3139            }
3140            Bind(&isNotSelf);
3141            {
3142                BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), slowPath, &padStringNotUndefined);
3143                Bind(&padStringNotUndefined);
3144                {
3145                    GateRef panTag = GetCallArg1(numArgs);
3146                    BRANCH(TaggedIsHeapObject(panTag), &padTagIsHeapObject, slowPath);
3147                    Bind(&padTagIsHeapObject);
3148                    BRANCH(IsString(panTag), &isPanString, slowPath);
3149                    Bind(&isPanString);
3150                    GateRef padStringLen = GetLengthFromString(panTag);
3151                    BRANCH(Int32LessThanOrEqual(padStringLen, Int32(0)), slowPath, &padStringNotEmpty);
3152                    Bind(&padStringNotEmpty);
3153                    {
3154                        GateRef fillStringLen = Int32Sub(*newStringLength, thisLen);
3155                        BRANCH(Int32LessThan(fillStringLen, padStringLen), &fillLessThanPad, &fillNotLessThanPad);
3156                        Bind(&fillLessThanPad);
3157                        {
3158                            tempStr = GetSubString(glue, panTag, Int32(0), fillStringLen);
3159                            Jump(&resultString);
3160                        }
3161                        Bind(&fillNotLessThanPad);
3162                        {
3163                            tempStr = panTag;
3164                            tempStringLength = Int32Add(padStringLen, padStringLen);
3165                            Label loopHead(env);
3166                            Label loopEnd(env);
3167                            Label loopNext(env);
3168                            Label loopExit(env);
3169                            Jump(&loopHead);
3170
3171                            LoopBegin(&loopHead);
3172                            {
3173                                BRANCH(Int32GreaterThan(*tempStringLength, fillStringLen), &loopExit, &loopNext);
3174                                Bind(&loopNext);
3175                                {
3176                                    tempStr = StringConcat(glue, panTag, *tempStr);
3177                                    Jump(&loopEnd);
3178                                }
3179                            }
3180                            Bind(&loopEnd);
3181                            tempStringLength = Int32Add(*tempStringLength, padStringLen);
3182                            LoopEnd(&loopHead, env, glue);
3183                            Bind(&loopExit);
3184                            GateRef lastLen = Int32Sub(padStringLen, Int32Sub(*tempStringLength, fillStringLen));
3185                            GateRef lastPadString = GetSubString(glue, panTag, Int32(0), lastLen);
3186                            tempStr = StringConcat(glue, *tempStr, lastPadString);
3187                            Jump(&resultString);
3188                        }
3189                        Bind(&resultString);
3190                        {
3191                            tempStr = StringConcat(glue, *tempStr, thisValue);
3192                            res->WriteVariable(*tempStr);
3193                            Jump(exit);
3194                        }
3195                    }
3196                }
3197            }
3198        }
3199    }
3200}
3201
3202void BuiltinsStringStubBuilder::PadEnd(GateRef glue, GateRef thisValue, GateRef numArgs,
3203    Variable* res, Label *exit, Label *slowPath)
3204{
3205    auto env = GetEnvironment();
3206    DEFVARIABLE(tempStringLength, VariableType::INT32(), Int32(0));
3207    DEFVARIABLE(newStringLength, VariableType::INT32(), Int32(0));
3208    DEFVARIABLE(tempStr, VariableType::JS_ANY(), Undefined());
3209
3210    Label objNotUndefinedAndNull(env);
3211    Label isString(env);
3212    Label isPanString(env);
3213    Label next(env);
3214    Label padTagIsHeapObject(env);
3215    Label padStringNotUndefined(env);
3216    Label lengthIsInt(env);
3217    Label lengthNotInt(env);
3218    Label lengthIsDouble(env);
3219    Label thisIsHeapobject(env);
3220    Label newLenthGreatZero(env);
3221    Label isSelf(env);
3222    Label isNotSelf(env);
3223    Label padLengthIsNotNaN(env);
3224    Label padLengthIsNotINF(env);
3225    Label newLengthInRange(env);
3226
3227    BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
3228    Bind(&objNotUndefinedAndNull);
3229    {
3230        BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
3231        Bind(&thisIsHeapobject);
3232        BRANCH(IsString(thisValue), &isString, slowPath);
3233        Bind(&isString);
3234        {
3235            GateRef newLength = GetCallArg0(numArgs);
3236            BRANCH(TaggedIsInt(newLength), &lengthIsInt, &lengthNotInt);
3237            Bind(&lengthIsInt);
3238            {
3239                newStringLength = GetInt32OfTInt(newLength);
3240                BRANCH(Int32GreaterThanOrEqual(*newStringLength, Int32(EcmaString::MAX_STRING_LENGTH)),
3241                    slowPath, &next);
3242            }
3243            Bind(&lengthNotInt);
3244            {
3245                BRANCH(TaggedIsDouble(newLength), &lengthIsDouble, slowPath);
3246                Bind(&lengthIsDouble);
3247                BRANCH(DoubleIsNAN(GetDoubleOfTDouble(newLength)), slowPath, &padLengthIsNotNaN);
3248                Bind(&padLengthIsNotNaN);
3249                BRANCH(DoubleIsINF(GetDoubleOfTDouble(newLength)), slowPath, &padLengthIsNotINF);
3250                Bind(&padLengthIsNotINF);
3251                BRANCH(DoubleGreaterThanOrEqual(GetDoubleOfTDouble(newLength), Double(EcmaString::MAX_STRING_LENGTH)),
3252                    slowPath, &newLengthInRange);
3253                Bind(&newLengthInRange);
3254                newStringLength = DoubleToInt(glue, GetDoubleOfTDouble(newLength));
3255                Jump(&next);
3256            }
3257            Bind(&next);
3258            GateRef thisLen = GetLengthFromString(thisValue);
3259            BRANCH(Int32GreaterThanOrEqual(thisLen, *newStringLength), &isSelf, &isNotSelf);
3260            Bind(&isSelf);
3261            {
3262                res->WriteVariable(thisValue);
3263                Jump(exit);
3264            }
3265            Bind(&isNotSelf);
3266            {
3267                tempStr = thisValue;
3268                BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), slowPath, &padStringNotUndefined);
3269                Bind(&padStringNotUndefined);
3270                {
3271                    GateRef panTag = GetCallArg1(numArgs);
3272                    BRANCH(TaggedIsHeapObject(panTag), &padTagIsHeapObject, slowPath);
3273                    Bind(&padTagIsHeapObject);
3274                    BRANCH(IsString(panTag), &isPanString, slowPath);
3275                    Bind(&isPanString);
3276                    {
3277                        GateRef padStringLen = GetLengthFromString(panTag);
3278                        BRANCH(Int32GreaterThanOrEqual(Int32(0), padStringLen), slowPath, &newLenthGreatZero);
3279                        Bind(&newLenthGreatZero);
3280                        {
3281                            tempStringLength = Int32Add(thisLen, padStringLen);
3282                            Label loopHead(env);
3283                            Label loopEnd(env);
3284                            Label loopNext(env);
3285                            Label loopExit(env);
3286                            Jump(&loopHead);
3287
3288                            LoopBegin(&loopHead);
3289                            {
3290                                BRANCH(Int32GreaterThan(*tempStringLength, *newStringLength), &loopExit, &loopNext);
3291                                Bind(&loopNext);
3292                                {
3293                                    tempStr = StringConcat(glue, *tempStr, panTag);
3294                                    Jump(&loopEnd);
3295                                }
3296                            }
3297                            Bind(&loopEnd);
3298                            tempStringLength = Int32Add(*tempStringLength, padStringLen);
3299                            LoopEnd(&loopHead, env, glue);
3300                            Bind(&loopExit);
3301                            GateRef lastLen = Int32Sub(padStringLen, Int32Sub(*tempStringLength, *newStringLength));
3302                            GateRef lastPadString = GetSubString(glue, panTag, Int32(0), lastLen);
3303                            tempStr = StringConcat(glue, *tempStr, lastPadString);
3304                            res->WriteVariable(*tempStr);
3305                            Jump(exit);
3306                        }
3307                    }
3308                }
3309            }
3310        }
3311    }
3312}
3313}  // namespace panda::ecmascript::kungfu
3314