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