• 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 writeRes(env);
2046                 Label notArgc1(env);
2047                 Label notArgc2(env);
2048                 Label argc3(env);
2049                 Label arg0IsValid(env);
2050                 Label arg1IsValid(env);
2051                 Label arg2IsValid(env);
2052                 Label notException1(env);
2053                 Label notException2(env);
2054                 GateRef arg0 = TaggedArgument(static_cast<size_t>(BuiltinsArgs::ARG0_OR_ARGV));
2055                 BRANCH(TaggedIsString(arg0), &arg0IsValid, slowPath);
2056                 Bind(&arg0IsValid);
2057                 {
2058                     result = StringConcat(glue, thisValue, arg0);
2059                     BRANCH(TaggedIsException(*result), &writeRes, &notException1);
2060                     Bind(&notException1);
2061                     BRANCH(Int64Equal(IntPtr(1), numArgs), &writeRes, &notArgc1);
2062                     Bind(&notArgc1);
2063                     {
2064                         GateRef arg1 = TaggedArgument(static_cast<size_t>(BuiltinsArgs::ARG1));
2065                         BRANCH(TaggedIsString(arg1), &arg1IsValid, slowPath);
2066                         Bind(&arg1IsValid);
2067                         result = StringConcat(glue, *result, arg1);
2068                         BRANCH(TaggedIsException(*result), &writeRes, &notException2);
2069                         Bind(&notException2);
2070                         BRANCH(Int64Equal(IntPtr(2), numArgs), &writeRes, &notArgc2); // 2: number of parameters.
2071                         Bind(&notArgc2);
2072                         GateRef arg2 = TaggedArgument(static_cast<size_t>(BuiltinsArgs::ARG2));
2073                         BRANCH(TaggedIsString(arg2), &arg2IsValid, slowPath);
2074                         Bind(&arg2IsValid);
2075                         BRANCH(Int64Equal(IntPtr(3), numArgs), &argc3, slowPath); // 3: number of parameters.
2076                         Bind(&argc3);
2077                         result = StringConcat(glue, *result, arg2);
2078                         Jump(&writeRes);
2079                     }
2080                     Bind(&writeRes);
2081                     res->WriteVariable(*result);
2082                     Jump(exit);
2083                 }
2084             }
2085         }
2086     }
2087 }
2088 
ToLowerCase(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2089 void BuiltinsStringStubBuilder::ToLowerCase(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2090     Variable *res, Label *exit, Label *slowPath)
2091 {
2092     auto env = GetEnvironment();
2093     Label objNotUndefinedAndNull(env);
2094     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2095     Bind(&objNotUndefinedAndNull);
2096     {
2097         Label thisIsHeapObj(env);
2098         Label isString(env);
2099 
2100         BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2101         Bind(&thisIsHeapObj);
2102         BRANCH(IsString(thisValue), &isString, slowPath);
2103         Bind(&isString);
2104         {
2105             Label isUtf8(env);
2106             Label hasPara(env);
2107             Label isUtf8Next(env);
2108             Label flattenFastPath(env);
2109             BRANCH(IsUtf8String(thisValue), &isUtf8, slowPath);
2110             Bind(&isUtf8);
2111             {
2112                 GateRef srcLength = GetLengthFromString(thisValue);
2113                 DEFVARIABLE(len, VariableType::INT32(), srcLength);
2114                 NewObjectStubBuilder newBuilder(this);
2115                 newBuilder.SetParameters(glue, 0);
2116                 newBuilder.AllocLineStringObject(res, &isUtf8Next, srcLength, true);
2117                 Bind(&isUtf8Next);
2118                 {
2119                     FlatStringStubBuilder thisFlat(this);
2120                     thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
2121                     Bind(&flattenFastPath);
2122                     StringInfoGateRef stringInfoGate(&thisFlat);
2123                     GateRef dataUtf8 = GetNormalStringData(stringInfoGate);
2124                     GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(res->ReadVariable(),
2125                         IntPtr(LineEcmaString::DATA_OFFSET)));
2126                     DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
2127                     DEFVARIABLE(sourceTmp, VariableType::NATIVE_POINTER(), dataUtf8);
2128                     Label loopHead(env);
2129                     Label loopEnd(env);
2130                     Label next(env);
2131                     Label toLower(env);
2132                     Label notLower(env);
2133                     Jump(&loopHead);
2134                     LoopBegin(&loopHead);
2135                     {
2136                         BRANCH(Int32GreaterThan(*len, Int32(0)), &next, exit);
2137                         Bind(&next);
2138                         {
2139                             len = Int32Sub(*len, Int32(1));
2140                             GateRef i = Load(VariableType::INT8(), *sourceTmp);
2141                             // 65: means 'A', 90: means 'Z'
2142                             GateRef needLower = BitAnd(Int8GreaterThanOrEqual(i, Int8(65)),
2143                                 Int8GreaterThanOrEqual(Int8(90), i));
2144                             BRANCH(needLower, &toLower, &notLower);
2145                             Bind(&toLower);
2146                             GateRef j = Int8Xor(i, Int8(1 << 5));
2147                             Store(VariableType::INT8(), glue, *dstTmp, IntPtr(0), j);
2148                             Jump(&loopEnd);
2149                             Bind(&notLower);
2150                             Store(VariableType::INT8(), glue, *dstTmp, IntPtr(0), i);
2151                             Jump(&loopEnd);
2152                         }
2153                     }
2154                     Bind(&loopEnd);
2155                     sourceTmp = PtrAdd(*sourceTmp, IntPtr(sizeof(uint8_t)));
2156                     dstTmp = PtrAdd(*dstTmp, IntPtr(sizeof(uint8_t)));
2157                     LoopEnd(&loopHead);
2158                 }
2159             }
2160         }
2161     }
2162 }
2163 
StringConcat(GateRef glue,GateRef leftString,GateRef rightString)2164 GateRef BuiltinsStringStubBuilder::StringConcat(GateRef glue, GateRef leftString, GateRef rightString)
2165 {
2166     auto env = GetEnvironment();
2167     Label entry(env);
2168     env->SubCfgEntry(&entry);
2169     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2170     Label exit(env);
2171     Label equalZero(env);
2172     Label notEqualZero(env);
2173     Label lessThanMax(env);
2174     Label throwError(env);
2175 
2176     GateRef leftLength = GetLengthFromString(leftString);
2177     GateRef rightLength = GetLengthFromString(rightString);
2178     GateRef newLength = Int32Add(leftLength, rightLength);
2179     BRANCH(Int32UnsignedGreaterThanOrEqual(newLength, Int32(EcmaString::MAX_STRING_LENGTH)), &throwError, &lessThanMax);
2180     Bind(&throwError);
2181     {
2182         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InvalidStringLength));
2183         CallRuntime(glue, RTSTUB_ID(ThrowRangeError), { IntToTaggedInt(taggedId) });
2184         result = Exception();
2185         Jump(&exit);
2186     }
2187     Bind(&lessThanMax);
2188     BRANCH(Int32Equal(newLength, Int32(0)), &equalZero, &notEqualZero);
2189     Bind(&equalZero);
2190     {
2191         result = GetGlobalConstantValue(
2192             VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
2193         Jump(&exit);
2194     }
2195     Bind(&notEqualZero);
2196     {
2197         Label leftEqualZero(env);
2198         Label leftNotEqualZero(env);
2199         Label rightEqualZero(env);
2200         Label rightNotEqualZero(env);
2201         Label newLineString(env);
2202         Label newTreeString(env);
2203         BRANCH(Int32Equal(leftLength, Int32(0)), &leftEqualZero, &leftNotEqualZero);
2204         Bind(&leftEqualZero);
2205         {
2206             result = rightString;
2207             Jump(&exit);
2208         }
2209         Bind(&leftNotEqualZero);
2210         BRANCH(Int32Equal(rightLength, Int32(0)), &rightEqualZero, &rightNotEqualZero);
2211         Bind(&rightEqualZero);
2212         {
2213             result = leftString;
2214             Jump(&exit);
2215         }
2216         Bind(&rightNotEqualZero);
2217         {
2218             GateRef leftIsUtf8 = IsUtf8String(leftString);
2219             GateRef rightIsUtf8 = IsUtf8String(rightString);
2220             GateRef canBeCompressed = BitAnd(leftIsUtf8, rightIsUtf8);
2221             NewObjectStubBuilder newBuilder(this);
2222             newBuilder.SetParameters(glue, 0);
2223             GateRef isTreeOrSlicedString = Int32UnsignedLessThan(newLength,
2224                 Int32(std::min(TreeEcmaString::MIN_TREE_ECMASTRING_LENGTH,
2225                                SlicedString::MIN_SLICED_ECMASTRING_LENGTH)));
2226             BRANCH(isTreeOrSlicedString, &newLineString, &newTreeString);
2227             Bind(&newLineString);
2228             {
2229                 Label isUtf8(env);
2230                 Label isUtf16(env);
2231                 Label isUtf8Next(env);
2232                 Label isUtf16Next(env);
2233                 BRANCH(canBeCompressed, &isUtf8, &isUtf16);
2234                 Bind(&isUtf8);
2235                 {
2236                     newBuilder.AllocLineStringObject(&result, &isUtf8Next, newLength, true);
2237                 }
2238                 Bind(&isUtf16);
2239                 {
2240                     newBuilder.AllocLineStringObject(&result, &isUtf16Next, newLength, false);
2241                 }
2242                 Bind(&isUtf8Next);
2243                 {
2244                     GateRef leftSource = GetStringDataFromLineOrConstantString(leftString);
2245                     GateRef rightSource = GetStringDataFromLineOrConstantString(rightString);
2246                     GateRef leftDst = ChangeStringTaggedPointerToInt64(
2247                         PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
2248                     GateRef rightDst = ChangeStringTaggedPointerToInt64(PtrAdd(leftDst, ZExtInt32ToPtr(leftLength)));
2249                     CopyChars(glue, leftDst, leftSource, leftLength, IntPtr(sizeof(uint8_t)), VariableType::INT8());
2250                     CopyChars(glue, rightDst, rightSource, rightLength, IntPtr(sizeof(uint8_t)), VariableType::INT8());
2251                     Jump(&exit);
2252                 }
2253                 Bind(&isUtf16Next);
2254                 {
2255                     Label leftIsUtf8L(env);
2256                     Label leftIsUtf16L(env);
2257                     Label rightIsUtf8L(env);
2258                     Label rightIsUtf16L(env);
2259                     GateRef leftSource = GetStringDataFromLineOrConstantString(leftString);
2260                     GateRef rightSource = GetStringDataFromLineOrConstantString(rightString);
2261                     GateRef leftDst = ChangeStringTaggedPointerToInt64(
2262                         PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
2263                     GateRef rightDst = ChangeStringTaggedPointerToInt64(
2264                         PtrAdd(leftDst, PtrMul(ZExtInt32ToPtr(leftLength), IntPtr(sizeof(uint16_t)))));
2265                     BRANCH(leftIsUtf8, &leftIsUtf8L, &leftIsUtf16L);
2266                     Bind(&leftIsUtf8L);
2267                     {
2268                         // left is utf8,right string must utf16
2269                         CopyUtf8AsUtf16(glue, leftDst, leftSource, leftLength);
2270                         CopyChars(glue, rightDst, rightSource, rightLength,
2271                             IntPtr(sizeof(uint16_t)), VariableType::INT16());
2272                         Jump(&exit);
2273                     }
2274                     Bind(&leftIsUtf16L);
2275                     {
2276                         CopyChars(glue, leftDst, leftSource, leftLength,
2277                             IntPtr(sizeof(uint16_t)), VariableType::INT16());
2278                         BRANCH(rightIsUtf8, &rightIsUtf8L, &rightIsUtf16L);
2279                         Bind(&rightIsUtf8L);
2280                         CopyUtf8AsUtf16(glue, rightDst, rightSource, rightLength);
2281                         Jump(&exit);
2282                         Bind(&rightIsUtf16L);
2283                         CopyChars(glue, rightDst, rightSource, rightLength,
2284                             IntPtr(sizeof(uint16_t)), VariableType::INT16());
2285                         Jump(&exit);
2286                     }
2287                 }
2288             }
2289             Bind(&newTreeString);
2290             {
2291                 Label isUtf8(env);
2292                 Label isUtf16(env);
2293                 BRANCH(canBeCompressed, &isUtf8, &isUtf16);
2294                 Bind(&isUtf8);
2295                 {
2296                     newBuilder.AllocTreeStringObject(&result, &exit, leftString, rightString, newLength, true);
2297                 }
2298                 Bind(&isUtf16);
2299                 {
2300                     newBuilder.AllocTreeStringObject(&result, &exit, leftString, rightString, newLength, false);
2301                 }
2302             }
2303         }
2304     }
2305     Bind(&exit);
2306     auto ret = *result;
2307     env->SubCfgExit();
2308     return ret;
2309 }
2310 
LocaleCompare(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2311 void BuiltinsStringStubBuilder::LocaleCompare([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
2312                                               [[maybe_unused]] Variable *res, [[maybe_unused]] Label *exit,
2313                                               Label *slowPath)
2314 {
2315     auto env = GetEnvironment();
2316 
2317     Label thisIsHeapObj(env);
2318     BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2319     Bind(&thisIsHeapObj);
2320     {
2321         Label thisValueIsString(env);
2322         Label fristArgIsString(env);
2323         Label arg0IsHeapObj(env);
2324         BRANCH(IsString(thisValue), &thisValueIsString, slowPath);
2325         Bind(&thisValueIsString);
2326         GateRef arg0 = GetCallArg0(numArgs);
2327         BRANCH(TaggedIsHeapObject(arg0), &arg0IsHeapObj, slowPath);
2328         Bind(&arg0IsHeapObj);
2329         BRANCH(IsString(arg0), &fristArgIsString, slowPath);
2330         Bind(&fristArgIsString);
2331 #ifdef ARK_SUPPORT_INTL
2332         GateRef locales = GetCallArg1(numArgs);
2333 
2334         GateRef options = GetCallArg2(numArgs);
2335         GateRef localesIsUndefOrString =
2336             LogicOrBuilder(env).Or(TaggedIsUndefined(locales)).Or(TaggedIsString(locales)).Done();
2337         GateRef cacheable = LogicAndBuilder(env).And(localesIsUndefOrString).And(TaggedIsUndefined(options)).Done();
2338         Label optionsIsString(env);
2339         Label cacheAble(env);
2340         Label uncacheable(env);
2341 
2342         BRANCH(cacheable, &cacheAble, &uncacheable);
2343         Bind(&cacheAble);
2344         {
2345             Label defvalue(env);
2346             GateRef resValue = CallRuntime(glue, RTSTUB_ID(LocaleCompareCacheable), {locales, thisValue, arg0});
2347             BRANCH(TaggedIsUndefined(resValue), &uncacheable, &defvalue);
2348             Bind(&defvalue);
2349             *res = resValue;
2350             Jump(exit);
2351         }
2352         Bind(&uncacheable);
2353         {
2354             res->WriteVariable(CallRuntime(glue, RTSTUB_ID(LocaleCompareWithGc), {locales, thisValue, arg0, options}));
2355             Jump(exit);
2356         }
2357 #else
2358     Jump(slowPath);
2359 #endif
2360     }
2361 }
2362 
GetStringIterator(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2363 void BuiltinsStringStubBuilder::GetStringIterator(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2364                                                   Variable *res, Label *exit, Label *slowPath)
2365 {
2366     auto env = GetEnvironment();
2367     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2368 
2369     Label thisIsHeapObj(env);
2370     Branch(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2371     Bind(&thisIsHeapObj);
2372     {
2373         Label thisValueIsString(env);
2374         Branch(IsString(thisValue), &thisValueIsString, slowPath);
2375         Bind(&thisValueIsString);
2376         GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
2377         GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
2378         GateRef strIterClass = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
2379                                                  GlobalEnv::STRING_ITERATOR_CLASS_INDEX);
2380         Label afterNew(env);
2381         NewObjectStubBuilder newBuilder(this);
2382         newBuilder.SetParameters(glue, 0);
2383         newBuilder.NewJSObject(&result, &afterNew, strIterClass);
2384         Bind(&afterNew);
2385         Store(VariableType::JS_POINTER(), glue, *result, IntPtr(JSStringIterator::ITERATED_STRING_OFFSET), thisValue);
2386         Store(VariableType::INT32(), glue, *result, IntPtr(JSStringIterator::STRING_ITERATOR_NEXT_INDEX_OFFSET),
2387               Int32(0));
2388         res->WriteVariable(*result);
2389         Jump(exit);
2390     }
2391 }
2392 
StringIteratorNext(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2393 void BuiltinsStringStubBuilder::StringIteratorNext(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2394                                                    Variable *res, Label *exit, Label *slowPath)
2395 {
2396     auto env = GetEnvironment();
2397     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2398 
2399     Label thisIsHeapObj(env);
2400     Label thisIsStringIterator(env);
2401     Label strNotUndefined(env);
2402     Label strIsHeapObj(env);
2403     Label strIsString(env);
2404     Label iterDone(env);
2405     Branch(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2406     Bind(&thisIsHeapObj);
2407     Branch(TaggedIsStringIterator(thisValue), &thisIsStringIterator, slowPath);
2408     Bind(&thisIsStringIterator);
2409     GateRef str = Load(VariableType::JS_POINTER(), thisValue, IntPtr(JSStringIterator::ITERATED_STRING_OFFSET));
2410     Branch(TaggedIsUndefined(str), &iterDone, &strNotUndefined);
2411     Bind(&strNotUndefined);
2412     Branch(TaggedIsHeapObject(str), &strIsHeapObj, slowPath);
2413     Bind(&strIsHeapObj);
2414     Branch(TaggedIsString(str), &strIsString, slowPath);
2415     Bind(&strIsString);
2416     {
2417         Label getFirst(env);
2418         Label afterFlat(env);
2419         Label getStringFromSingleCharTable(env);
2420         GateRef position = Load(VariableType::INT32(), thisValue,
2421                                 IntPtr(JSStringIterator::STRING_ITERATOR_NEXT_INDEX_OFFSET));
2422         GateRef len = GetLengthFromString(str);
2423         Branch(Int32GreaterThanOrEqual(position, len), &iterDone, &getFirst);
2424         Bind(&getFirst);
2425         FlatStringStubBuilder strFlat(this);
2426         strFlat.FlattenString(glue, str, &afterFlat);
2427         Bind(&afterFlat);
2428         StringInfoGateRef strInfo(&strFlat);
2429         GateRef first = StringAt(strInfo, position);
2430         GateRef canStoreAsUtf8 = IsASCIICharacter(first);
2431         Branch(canStoreAsUtf8, &getStringFromSingleCharTable, slowPath);
2432         Bind(&getStringFromSingleCharTable);
2433         GateRef singleCharTable = GetSingleCharTable(glue);
2434         GateRef firstStr = GetValueFromTaggedArray(singleCharTable, ZExtInt16ToInt32(first));
2435         Store(VariableType::INT32(), glue, thisValue, IntPtr(JSStringIterator::STRING_ITERATOR_NEXT_INDEX_OFFSET),
2436               Int32Add(position, Int32(1)));
2437         // CreateIterResultObject(firstStr, false)
2438         GateRef iterResultClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
2439                                                          ConstantIndex::ITERATOR_RESULT_CLASS);
2440         Label afterNew(env);
2441         NewObjectStubBuilder newBuilder(this);
2442         newBuilder.SetParameters(glue, 0);
2443         newBuilder.NewJSObject(&result, &afterNew, iterResultClass);
2444         Bind(&afterNew);
2445         SetPropertyInlinedProps(glue, *result, iterResultClass, firstStr,
2446                                 Int32(JSIterator::VALUE_INLINE_PROPERTY_INDEX));
2447         SetPropertyInlinedProps(glue, *result, iterResultClass, TaggedFalse(),
2448                                 Int32(JSIterator::DONE_INLINE_PROPERTY_INDEX));
2449         res->WriteVariable(*result);
2450         Jump(exit);
2451     }
2452     Bind(&iterDone);
2453     {
2454         Store(VariableType::JS_POINTER(), glue, thisValue, IntPtr(JSStringIterator::ITERATED_STRING_OFFSET),
2455               Undefined());
2456         // CreateIterResultObject(undefined, true)
2457         GateRef iterResultClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue,
2458                                                          ConstantIndex::ITERATOR_RESULT_CLASS);
2459         Label afterNew(env);
2460         NewObjectStubBuilder newBuilder(this);
2461         newBuilder.SetParameters(glue, 0);
2462         newBuilder.NewJSObject(&result, &afterNew, iterResultClass);
2463         Bind(&afterNew);
2464         SetPropertyInlinedProps(glue, *result, iterResultClass, Undefined(),
2465                                 Int32(JSIterator::VALUE_INLINE_PROPERTY_INDEX));
2466         SetPropertyInlinedProps(glue, *result, iterResultClass, TaggedTrue(),
2467                                 Int32(JSIterator::DONE_INLINE_PROPERTY_INDEX));
2468         res->WriteVariable(*result);
2469         Jump(exit);
2470     }
2471 }
2472 
EcmaStringTrim(GateRef glue,GateRef thisValue,GateRef trimMode)2473 GateRef BuiltinsStringStubBuilder::EcmaStringTrim(GateRef glue, GateRef thisValue, GateRef trimMode)
2474 {
2475     auto env = GetEnvironment();
2476 
2477     Label entry(env);
2478     env->SubCfgEntry(&entry);
2479 
2480     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
2481 
2482     Label emptyString(env);
2483     Label notEmpty(env);
2484     Label exit(env);
2485 
2486     GateRef srcLen = GetLengthFromString(thisValue);
2487     BRANCH(Int32Equal(srcLen, Int32(0)), &emptyString, &notEmpty);
2488     Bind(&emptyString);
2489     {
2490         result = GetGlobalConstantValue(
2491             VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
2492         Jump(&exit);
2493     }
2494     Bind(&notEmpty);
2495     {
2496         Label srcFlattenFastPath(env);
2497 
2498         FlatStringStubBuilder srcFlat(this);
2499         srcFlat.FlattenString(glue, thisValue, &srcFlattenFastPath);
2500         Bind(&srcFlattenFastPath);
2501         StringInfoGateRef srcStringInfoGate(&srcFlat);
2502         result = EcmaStringTrimBody(glue, thisValue, srcStringInfoGate, trimMode, IsUtf8String(thisValue));
2503         Jump(&exit);
2504     }
2505     Bind(&exit);
2506     auto ret = *result;
2507     env->SubCfgExit();
2508     return ret;
2509 }
2510 
EcmaStringTrimBody(GateRef glue,GateRef thisValue,StringInfoGateRef srcStringInfoGate,GateRef trimMode,GateRef isUtf8)2511 GateRef BuiltinsStringStubBuilder::EcmaStringTrimBody(GateRef glue, GateRef thisValue,
2512     StringInfoGateRef srcStringInfoGate, GateRef trimMode, GateRef isUtf8)
2513 {
2514     auto env = GetEnvironment();
2515 
2516     Label entry(env);
2517     env->SubCfgEntry(&entry);
2518 
2519     GateRef srcLen = srcStringInfoGate.GetLength();
2520     GateRef srcString = srcStringInfoGate.GetString();
2521     GateRef startIndex = srcStringInfoGate.GetStartIndex();
2522 
2523     DEFVARIABLE(start, VariableType::INT32(), Int32(0));
2524     DEFVARIABLE(end, VariableType::INT32(), Int32Sub(srcLen, Int32(1)));
2525 
2526     Label trimOrTrimStart(env);
2527     Label notTrimStart(env);
2528     Label next(env);
2529 
2530     BRANCH(Int32GreaterThanOrEqual(trimMode, Int32(0)), &trimOrTrimStart, &notTrimStart);
2531     Bind(&trimOrTrimStart); // mode = TrimMode::TRIM or TrimMode::TRIM_START
2532     {
2533         start = CallNGCRuntime(glue, RTSTUB_ID(StringGetStart), {isUtf8, srcString, srcLen, startIndex});
2534         Jump(&notTrimStart);
2535     }
2536     Bind(&notTrimStart);
2537     {
2538         Label trimOrTrimEnd(env);
2539         BRANCH(Int32LessThanOrEqual(trimMode, Int32(0)), &trimOrTrimEnd, &next);
2540         Bind(&trimOrTrimEnd); // mode = TrimMode::TRIM or TrimMode::TRIM_END
2541         {
2542             end = CallNGCRuntime(glue, RTSTUB_ID(StringGetEnd), {isUtf8, srcString, *start, srcLen, startIndex});
2543             Jump(&next);
2544         }
2545     }
2546     Bind(&next);
2547     {
2548         auto ret = FastSubString(glue, thisValue, *start,
2549                                  Int32Add(Int32Sub(*end, *start), Int32(1)), srcStringInfoGate);
2550         env->SubCfgExit();
2551         return ret;
2552     }
2553 }
2554 
IsSubStringAt(GateRef lhsData,bool lhsIsUtf8,GateRef rhsData,bool rhsIsUtf8,GateRef pos,GateRef rhsCount)2555 GateRef BuiltinsStringStubBuilder::IsSubStringAt(GateRef lhsData, bool lhsIsUtf8, GateRef rhsData,
2556                                                  bool rhsIsUtf8, GateRef pos, GateRef rhsCount)
2557 {
2558     auto env = GetEnvironment();
2559     Label entry(env);
2560     env->SubCfgEntry(&entry);
2561 
2562     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
2563     DEFVARIABLE(result, VariableType::JS_ANY(), TaggedTrue());
2564 
2565     Label exit(env);
2566     Label next(env);
2567     Label loopHead(env);
2568     Label loopEnd(env);
2569     Label notEqual(env);
2570 
2571     Jump(&loopHead);
2572     LoopBegin(&loopHead);
2573     BRANCH(Int32LessThan(*i, rhsCount), &next, &exit);
2574     Bind(&next);
2575     {
2576         GateRef lhsTemp;
2577         GateRef rhsTemp;
2578         if (lhsIsUtf8) {
2579             lhsTemp = GetUtf8Data(lhsData, Int32Add(*i, pos));
2580         } else {
2581             lhsTemp = GetUtf16Data(lhsData, Int32Add(*i, pos));
2582         }
2583         if (rhsIsUtf8) {
2584             rhsTemp = GetUtf8Data(rhsData, *i);
2585         } else {
2586             rhsTemp = GetUtf16Data(rhsData, *i);
2587         }
2588         BRANCH(Int32Equal(lhsTemp, rhsTemp), &loopEnd, &notEqual);
2589         Bind(&notEqual);
2590         {
2591             result = TaggedFalse();
2592             Jump(&exit);
2593         }
2594     }
2595     Bind(&loopEnd);
2596     i = Int32Add(*i, Int32(1));
2597     LoopEnd(&loopHead);
2598 
2599     Bind(&exit);
2600     auto ret = *result;
2601     env->SubCfgExit();
2602     return ret;
2603 }
2604 
IsSubStringAt(const StringInfoGateRef & lStringInfoGate,const StringInfoGateRef & rStringInfoGate,GateRef pos)2605 GateRef BuiltinsStringStubBuilder::IsSubStringAt(const StringInfoGateRef &lStringInfoGate,
2606                                                  const StringInfoGateRef &rStringInfoGate, GateRef pos)
2607 {
2608     auto env = GetEnvironment();
2609     Label entry(env);
2610     env->SubCfgEntry(&entry);
2611     Label exit(env);
2612     Label rhsIsUtf8(env);
2613     Label rhsIsUtf16(env);
2614 
2615     DEFVARIABLE(result, VariableType::JS_ANY(), TaggedFalse());
2616     GateRef rhsCount = rStringInfoGate.GetLength();
2617     GateRef rhsData = GetNormalStringData(rStringInfoGate);
2618     GateRef lhsData = GetNormalStringData(lStringInfoGate);
2619     BRANCH(IsUtf8String(rStringInfoGate.GetString()), &rhsIsUtf8, &rhsIsUtf16);
2620     Bind(&rhsIsUtf8);
2621     {
2622         Label lhsIsUtf8(env);
2623         Label lhsIsUtf16(env);
2624         BRANCH(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
2625         Bind(&lhsIsUtf8);
2626         {
2627             result = IsSubStringAt(lhsData, true, rhsData, true, pos, rhsCount);
2628             Jump(&exit);
2629         }
2630         Bind(&lhsIsUtf16);
2631         {
2632             result = IsSubStringAt(lhsData, false, rhsData, true, pos, rhsCount);
2633             Jump(&exit);
2634         }
2635     }
2636     Bind(&rhsIsUtf16);
2637     {
2638         Label lhsIsUtf8(env);
2639         Label lhsIsUtf16(env);
2640         BRANCH(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
2641         Bind(&lhsIsUtf8);
2642         {
2643             result = IsSubStringAt(lhsData, true, rhsData, false, pos, rhsCount);
2644             Jump(&exit);
2645         }
2646         Bind(&lhsIsUtf16);
2647         {
2648             result = IsSubStringAt(lhsData, false, rhsData, false, pos, rhsCount);
2649             Jump(&exit);
2650         }
2651     }
2652 
2653     Bind(&exit);
2654     auto ret = *result;
2655     env->SubCfgExit();
2656     return ret;
2657 }
2658 
StartsWith(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2659 void BuiltinsStringStubBuilder::StartsWith(GateRef glue, GateRef thisValue, GateRef numArgs,
2660     Variable *res, Label *exit, Label *slowPath)
2661 {
2662     auto env = GetEnvironment();
2663     DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
2664 
2665     Label objNotUndefinedAndNull(env);
2666     Label thisIsHeapobject(env);
2667     Label isString(env);
2668     Label searchTagIsHeapObject(env);
2669     Label isSearchString(env);
2670     Label next(env);
2671     Label posTagNotUndefined(env);
2672     Label posTagIsInt(env);
2673     Label posTagNotInt(env);
2674     Label posTagIsDouble(env);
2675     Label posTagIsPositiveInfinity(env);
2676     Label posTagNotPositiveInfinity(env);
2677 
2678     Label posNotLessThanLen(env);
2679     Label flattenFastPath(env);
2680     Label flattenFastPath1(env);
2681     Label resPosEqualPos(env);
2682     Label resPosNotEqualPos(env);
2683 
2684     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2685     Bind(&objNotUndefinedAndNull);
2686     {
2687         BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
2688         Bind(&thisIsHeapobject);
2689         BRANCH(IsString(thisValue), &isString, slowPath);
2690         Bind(&isString);
2691         {
2692             GateRef searchTag = GetCallArg0(numArgs);
2693             BRANCH(TaggedIsHeapObject(searchTag), &searchTagIsHeapObject, slowPath);
2694             Bind(&searchTagIsHeapObject);
2695             BRANCH(IsString(searchTag), &isSearchString, slowPath);
2696             Bind(&isSearchString);
2697             {
2698                 GateRef thisLen = GetLengthFromString(thisValue);
2699                 GateRef searchLen = GetLengthFromString(searchTag);
2700                 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &next, &posTagNotUndefined);
2701                 Bind(&posTagNotUndefined);
2702                 {
2703                     GateRef posTag = GetCallArg1(numArgs);
2704                     BRANCH(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
2705                     Bind(&posTagIsInt);
2706                     pos = GetInt32OfTInt(posTag);
2707                     Jump(&next);
2708                     Bind(&posTagNotInt);
2709                     BRANCH(TaggedIsDouble(posTag), &posTagIsDouble, slowPath);
2710                     Bind(&posTagIsDouble);
2711                     BRANCH(DoubleEqual(GetDoubleOfTDouble(posTag), Double(builtins::BuiltinsNumber::POSITIVE_INFINITY)),
2712                         &posTagIsPositiveInfinity, &posTagNotPositiveInfinity);
2713                     Bind(&posTagIsPositiveInfinity);
2714                     pos = thisLen;
2715                     Jump(&next);
2716                     Bind(&posTagNotPositiveInfinity);
2717                     pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
2718                     Jump(&next);
2719                 }
2720                 Bind(&next);
2721                 {
2722                     Label posGreaterThanZero(env);
2723                     Label posNotGreaterThanZero(env);
2724                     Label nextCount(env);
2725                     BRANCH(Int32GreaterThan(*pos, Int32(0)), &posGreaterThanZero, &posNotGreaterThanZero);
2726                     Bind(&posNotGreaterThanZero);
2727                     {
2728                         pos = Int32(0);
2729                         Jump(&nextCount);
2730                     }
2731                     Bind(&posGreaterThanZero);
2732                     {
2733                         BRANCH(Int32LessThanOrEqual(*pos, thisLen), &nextCount, &posNotLessThanLen);
2734                         Bind(&posNotLessThanLen);
2735                         {
2736                             pos = thisLen;
2737                             Jump(&nextCount);
2738                         }
2739                     }
2740                     Bind(&nextCount);
2741                     {
2742                         Label notGreaterThanThisLen(env);
2743                         Label greaterThanThisLen(env);
2744 
2745                         GateRef posAddSearchLen = Int32Add(*pos, searchLen);
2746                         BRANCH(Int32GreaterThan(posAddSearchLen, thisLen), &greaterThanThisLen, &notGreaterThanThisLen);
2747                         Bind(&greaterThanThisLen);
2748                         {
2749                             res->WriteVariable(TaggedFalse());
2750                             Jump(exit);
2751                         }
2752                         Bind(&notGreaterThanThisLen);
2753                         FlatStringStubBuilder thisFlat(this);
2754                         thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
2755                         Bind(&flattenFastPath);
2756                         FlatStringStubBuilder searchFlat(this);
2757                         searchFlat.FlattenString(glue, searchTag, &flattenFastPath1);
2758                         Bind(&flattenFastPath1);
2759                         {
2760                             StringInfoGateRef thisStringInfoGate(&thisFlat);
2761                             StringInfoGateRef searchStringInfoGate(&searchFlat);
2762                             GateRef result = IsSubStringAt(thisStringInfoGate, searchStringInfoGate, *pos);
2763                             res->WriteVariable(result);
2764                             Jump(exit);
2765                         }
2766                     }
2767                 }
2768             }
2769         }
2770     }
2771 }
2772 
EndsWith(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2773 void BuiltinsStringStubBuilder::EndsWith(GateRef glue, GateRef thisValue, GateRef numArgs,
2774     Variable *res, Label *exit, Label *slowPath)
2775 {
2776     auto env = GetEnvironment();
2777     DEFVARIABLE(searchPos, VariableType::INT32(), Int32(0));
2778     DEFVARIABLE(startPos, VariableType::INT32(), Int32(0));
2779     DEFVARIABLE(endPos, VariableType::INT32(), Int32(0));
2780     Label thisExists(env);
2781     Label thisIsHeapObject(env);
2782     Label thisIsString(env);
2783     Label searchTagExists(env);
2784     Label searchTagIsHeapObject(env);
2785     Label searchTagIsString(env);
2786     Label posTagExists(env);
2787     Label posTagNotExists(env);
2788     Label posTagIsNumber(env);
2789     Label posTagIsInt(env);
2790     Label afterCallArg(env);
2791     Label endPosLessThanZero(env);
2792     Label endPosNotLessThanZero(env);
2793     Label endPosMoreThanThisLen(env);
2794     Label endPosNotMoreThanThisLen(env);
2795     Label startPosLessThanZero(env);
2796     Label startPosNotLessThanZero(env);
2797     Label flattenFastPath1(env);
2798     Label flattenFastPath2(env);
2799     Label resultIndexEqualStartPos(env);
2800 
2801     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists);
2802     Bind(&thisExists);
2803     {
2804         BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObject, slowPath);
2805         Bind(&thisIsHeapObject);
2806         BRANCH(IsString(thisValue), &thisIsString, slowPath);
2807         Bind(&thisIsString);
2808         BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), slowPath, &searchTagExists);
2809         Bind(&searchTagExists);
2810         {
2811             GateRef searchTag = GetCallArg0(numArgs);
2812             BRANCH(TaggedIsHeapObject(searchTag), &searchTagIsHeapObject, slowPath);
2813             Bind(&searchTagIsHeapObject);
2814             BRANCH(IsString(searchTag), &searchTagIsString, slowPath);
2815             Bind(&searchTagIsString);
2816             {
2817                 GateRef thisLen = GetLengthFromString(thisValue);
2818                 GateRef searchLen = GetLengthFromString(searchTag);
2819                 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &posTagNotExists, &posTagExists);
2820                 Bind(&posTagExists);
2821                 {
2822                     GateRef posTag = GetCallArg1(numArgs);
2823                     BRANCH(TaggedIsNumber(posTag), &posTagIsNumber, slowPath);
2824                     Bind(&posTagIsNumber);
2825                     BRANCH(TaggedIsInt(posTag), &posTagIsInt, slowPath);
2826                     Bind(&posTagIsInt);
2827                     {
2828                         searchPos = GetInt32OfTInt(posTag);
2829                         Jump(&afterCallArg);
2830                     }
2831                 }
2832                 Bind(&posTagNotExists);
2833                 {
2834                     searchPos = thisLen;
2835                     Jump(&afterCallArg);
2836                 }
2837                 Bind(&afterCallArg);
2838                 {
2839                     endPos = *searchPos;
2840                     BRANCH(Int32GreaterThanOrEqual(*endPos, Int32(0)), &endPosNotLessThanZero, &endPosLessThanZero);
2841                     Bind(&endPosLessThanZero);
2842                     {
2843                         endPos = Int32(0);
2844                         Jump(&endPosNotLessThanZero);
2845                     }
2846                     Bind(&endPosNotLessThanZero);
2847                     {
2848                         BRANCH(Int32LessThanOrEqual(*endPos, thisLen), &endPosNotMoreThanThisLen,
2849                             &endPosMoreThanThisLen);
2850                         Bind(&endPosMoreThanThisLen);
2851                         {
2852                             endPos = thisLen;
2853                             Jump(&endPosNotMoreThanThisLen);
2854                         }
2855                         Bind(&endPosNotMoreThanThisLen);
2856                         {
2857                             startPos = Int32Sub(*endPos, searchLen);
2858                             BRANCH(Int32LessThan(*startPos, Int32(0)), &startPosLessThanZero,
2859                                 &startPosNotLessThanZero);
2860                             Bind(&startPosNotLessThanZero);
2861                             {
2862                                 FlatStringStubBuilder thisFlat(this);
2863                                 thisFlat.FlattenString(glue, thisValue, &flattenFastPath1);
2864                                 Bind(&flattenFastPath1);
2865                                 FlatStringStubBuilder searchFlat(this);
2866                                 searchFlat.FlattenString(glue, searchTag, &flattenFastPath2);
2867                                 Bind(&flattenFastPath2);
2868                                 {
2869                                     StringInfoGateRef thisStringInfoGate(&thisFlat);
2870                                     StringInfoGateRef searchStringInfoGate(&searchFlat);
2871                                     GateRef result = IsSubStringAt(thisStringInfoGate, searchStringInfoGate, *startPos);
2872                                     res->WriteVariable(result);
2873                                     Jump(exit);
2874                                 }
2875                             }
2876                             Bind(&startPosLessThanZero);
2877                             {
2878                                 res->WriteVariable(TaggedFalse());
2879                                 Jump(exit);
2880                             }
2881                         }
2882                     }
2883                 }
2884             }
2885         }
2886     }
2887 }
2888 
TrimStart(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2889 void BuiltinsStringStubBuilder::TrimStart(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2890     Variable *res, Label *exit, Label *slowPath)
2891 {
2892     auto env = GetEnvironment();
2893     Label objNotUndefinedAndNull(env);
2894     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2895     Bind(&objNotUndefinedAndNull);
2896     {
2897         Label thisIsHeapObj(env);
2898         Label thisIsString(env);
2899         BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2900         Bind(&thisIsHeapObj);
2901         BRANCH(IsString(thisValue), &thisIsString, slowPath);
2902         Bind(&thisIsString);
2903         GateRef result = EcmaStringTrim(glue, thisValue, Int32(1)); // 1: mode = TrimMode::start
2904         res->WriteVariable(result);
2905         Jump(exit);
2906     }
2907 }
2908 
TrimEnd(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2909 void BuiltinsStringStubBuilder::TrimEnd(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2910     Variable *res, Label *exit, Label *slowPath)
2911 {
2912     auto env = GetEnvironment();
2913     Label objNotUndefinedAndNull(env);
2914     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2915     Bind(&objNotUndefinedAndNull);
2916     {
2917         Label thisIsHeapObj(env);
2918         Label thisIsString(env);
2919         BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2920         Bind(&thisIsHeapObj);
2921         BRANCH(IsString(thisValue), &thisIsString, slowPath);
2922         Bind(&thisIsString);
2923         GateRef result = EcmaStringTrim(glue, thisValue, Int32(-1)); // -1: mode = TrimMode::end
2924         res->WriteVariable(result);
2925         Jump(exit);
2926     }
2927 }
2928 
TrimLeft(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2929 void BuiltinsStringStubBuilder::TrimLeft(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2930     Variable *res, Label *exit, Label *slowPath)
2931 {
2932     auto env = GetEnvironment();
2933     Label objNotUndefinedAndNull(env);
2934     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2935     Bind(&objNotUndefinedAndNull);
2936     {
2937         Label thisIsHeapObj(env);
2938         Label thisIsString(env);
2939         BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2940         Bind(&thisIsHeapObj);
2941         BRANCH(IsString(thisValue), &thisIsString, slowPath);
2942         Bind(&thisIsString);
2943         GateRef result = EcmaStringTrim(glue, thisValue, Int32(1)); // 1: mode = TrimMode::start
2944         res->WriteVariable(result);
2945         Jump(exit);
2946     }
2947 }
2948 
TrimRight(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2949 void BuiltinsStringStubBuilder::TrimRight(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs,
2950     Variable *res, Label *exit, Label *slowPath)
2951 {
2952     auto env = GetEnvironment();
2953     Label objNotUndefinedAndNull(env);
2954     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2955     Bind(&objNotUndefinedAndNull);
2956     {
2957         Label thisIsHeapObj(env);
2958         Label thisIsString(env);
2959         BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
2960         Bind(&thisIsHeapObj);
2961         BRANCH(IsString(thisValue), &thisIsString, slowPath);
2962         Bind(&thisIsString);
2963         GateRef result = EcmaStringTrim(glue, thisValue, Int32(-1)); // -1: mode = TrimMode::end
2964         res->WriteVariable(result);
2965         Jump(exit);
2966     }
2967 }
2968 
PadStart(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)2969 void BuiltinsStringStubBuilder::PadStart(GateRef glue, GateRef thisValue, GateRef numArgs,
2970     Variable* res, Label *exit, Label *slowPath)
2971 {
2972     auto env = GetEnvironment();
2973     DEFVARIABLE(tempStringLength, VariableType::INT32(), Int32(0));
2974     DEFVARIABLE(newStringLength, VariableType::INT32(), Int32(0));
2975     DEFVARIABLE(tempStr, VariableType::JS_ANY(), Undefined());
2976 
2977     Label objNotUndefinedAndNull(env);
2978     Label isString(env);
2979     Label isPanString(env);
2980     Label next(env);
2981     Label padTagIsHeapObject(env);
2982     Label padStringNotUndefined(env);
2983     Label lengthIsInt(env);
2984     Label lengthNotInt(env);
2985     Label lengthIsDouble(env);
2986     Label thisIsHeapobject(env);
2987     Label newLengthIsNotNaN(env);
2988     Label newLengthIsNotINF(env);
2989     Label isSelf(env);
2990     Label isNotSelf(env);
2991     Label padStringNotEmpty(env);
2992     Label fillLessThanPad(env);
2993     Label fillNotLessThanPad(env);
2994     Label resultString(env);
2995     Label newLengthInRange(env);
2996 
2997     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
2998     Bind(&objNotUndefinedAndNull);
2999     {
3000         BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
3001         Bind(&thisIsHeapobject);
3002         BRANCH(IsString(thisValue), &isString, slowPath);
3003         Bind(&isString);
3004         {
3005             GateRef newLength = GetCallArg0(numArgs);
3006             BRANCH(TaggedIsInt(newLength), &lengthIsInt, &lengthNotInt);
3007             Bind(&lengthIsInt);
3008             {
3009                 newStringLength = GetInt32OfTInt(newLength);
3010                 BRANCH(Int32GreaterThanOrEqual(*newStringLength, Int32(EcmaString::MAX_STRING_LENGTH)),
3011                     slowPath, &next);
3012             }
3013             Bind(&lengthNotInt);
3014             {
3015                 BRANCH(TaggedIsDouble(newLength), &lengthIsDouble, slowPath);
3016                 Bind(&lengthIsDouble);
3017                 BRANCH(DoubleIsNAN(GetDoubleOfTDouble(newLength)), slowPath, &newLengthIsNotNaN);
3018                 Bind(&newLengthIsNotNaN);
3019                 BRANCH(DoubleIsINF(GetDoubleOfTDouble(newLength)), slowPath, &newLengthIsNotINF);
3020                 Bind(&newLengthIsNotINF);
3021                 BRANCH(DoubleGreaterThanOrEqual(GetDoubleOfTDouble(newLength), Double(EcmaString::MAX_STRING_LENGTH)),
3022                     slowPath, &newLengthInRange);
3023                 Bind(&newLengthInRange);
3024                 newStringLength = DoubleToInt(glue, GetDoubleOfTDouble(newLength));
3025                 Jump(&next);
3026             }
3027             Bind(&next);
3028             GateRef thisLen = GetLengthFromString(thisValue);
3029             BRANCH(Int32GreaterThanOrEqual(thisLen, *newStringLength), &isSelf, &isNotSelf);
3030             Bind(&isSelf);
3031             {
3032                 res->WriteVariable(thisValue);
3033                 Jump(exit);
3034             }
3035             Bind(&isNotSelf);
3036             {
3037                 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), slowPath, &padStringNotUndefined);
3038                 Bind(&padStringNotUndefined);
3039                 {
3040                     GateRef panTag = GetCallArg1(numArgs);
3041                     BRANCH(TaggedIsHeapObject(panTag), &padTagIsHeapObject, slowPath);
3042                     Bind(&padTagIsHeapObject);
3043                     BRANCH(IsString(panTag), &isPanString, slowPath);
3044                     Bind(&isPanString);
3045                     GateRef padStringLen = GetLengthFromString(panTag);
3046                     BRANCH(Int32LessThanOrEqual(padStringLen, Int32(0)), slowPath, &padStringNotEmpty);
3047                     Bind(&padStringNotEmpty);
3048                     {
3049                         GateRef fillStringLen = Int32Sub(*newStringLength, thisLen);
3050                         BRANCH(Int32LessThan(fillStringLen, padStringLen), &fillLessThanPad, &fillNotLessThanPad);
3051                         Bind(&fillLessThanPad);
3052                         {
3053                             tempStr = GetSubString(glue, panTag, Int32(0), fillStringLen);
3054                             Jump(&resultString);
3055                         }
3056                         Bind(&fillNotLessThanPad);
3057                         {
3058                             tempStr = panTag;
3059                             tempStringLength = Int32Add(padStringLen, padStringLen);
3060                             Label loopHead(env);
3061                             Label loopEnd(env);
3062                             Label loopNext(env);
3063                             Label loopExit(env);
3064                             Jump(&loopHead);
3065 
3066                             LoopBegin(&loopHead);
3067                             {
3068                                 BRANCH(Int32GreaterThan(*tempStringLength, fillStringLen), &loopExit, &loopNext);
3069                                 Bind(&loopNext);
3070                                 {
3071                                     tempStr = StringConcat(glue, panTag, *tempStr);
3072                                     Jump(&loopEnd);
3073                                 }
3074                             }
3075                             Bind(&loopEnd);
3076                             tempStringLength = Int32Add(*tempStringLength, padStringLen);
3077                             LoopEnd(&loopHead, env, glue);
3078                             Bind(&loopExit);
3079                             GateRef lastLen = Int32Sub(padStringLen, Int32Sub(*tempStringLength, fillStringLen));
3080                             GateRef lastPadString = GetSubString(glue, panTag, Int32(0), lastLen);
3081                             tempStr = StringConcat(glue, *tempStr, lastPadString);
3082                             Jump(&resultString);
3083                         }
3084                         Bind(&resultString);
3085                         {
3086                             tempStr = StringConcat(glue, *tempStr, thisValue);
3087                             res->WriteVariable(*tempStr);
3088                             Jump(exit);
3089                         }
3090                     }
3091                 }
3092             }
3093         }
3094     }
3095 }
3096 
PadEnd(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)3097 void BuiltinsStringStubBuilder::PadEnd(GateRef glue, GateRef thisValue, GateRef numArgs,
3098     Variable* res, Label *exit, Label *slowPath)
3099 {
3100     auto env = GetEnvironment();
3101     DEFVARIABLE(tempStringLength, VariableType::INT32(), Int32(0));
3102     DEFVARIABLE(newStringLength, VariableType::INT32(), Int32(0));
3103     DEFVARIABLE(tempStr, VariableType::JS_ANY(), Undefined());
3104 
3105     Label objNotUndefinedAndNull(env);
3106     Label isString(env);
3107     Label isPanString(env);
3108     Label next(env);
3109     Label padTagIsHeapObject(env);
3110     Label padStringNotUndefined(env);
3111     Label lengthIsInt(env);
3112     Label lengthNotInt(env);
3113     Label lengthIsDouble(env);
3114     Label thisIsHeapobject(env);
3115     Label newLenthGreatZero(env);
3116     Label isSelf(env);
3117     Label isNotSelf(env);
3118     Label padLengthIsNotNaN(env);
3119     Label padLengthIsNotINF(env);
3120     Label newLengthInRange(env);
3121 
3122     BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
3123     Bind(&objNotUndefinedAndNull);
3124     {
3125         BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
3126         Bind(&thisIsHeapobject);
3127         BRANCH(IsString(thisValue), &isString, slowPath);
3128         Bind(&isString);
3129         {
3130             GateRef newLength = GetCallArg0(numArgs);
3131             BRANCH(TaggedIsInt(newLength), &lengthIsInt, &lengthNotInt);
3132             Bind(&lengthIsInt);
3133             {
3134                 newStringLength = GetInt32OfTInt(newLength);
3135                 BRANCH(Int32GreaterThanOrEqual(*newStringLength, Int32(EcmaString::MAX_STRING_LENGTH)),
3136                     slowPath, &next);
3137             }
3138             Bind(&lengthNotInt);
3139             {
3140                 BRANCH(TaggedIsDouble(newLength), &lengthIsDouble, slowPath);
3141                 Bind(&lengthIsDouble);
3142                 BRANCH(DoubleIsNAN(GetDoubleOfTDouble(newLength)), slowPath, &padLengthIsNotNaN);
3143                 Bind(&padLengthIsNotNaN);
3144                 BRANCH(DoubleIsINF(GetDoubleOfTDouble(newLength)), slowPath, &padLengthIsNotINF);
3145                 Bind(&padLengthIsNotINF);
3146                 BRANCH(DoubleGreaterThanOrEqual(GetDoubleOfTDouble(newLength), Double(EcmaString::MAX_STRING_LENGTH)),
3147                     slowPath, &newLengthInRange);
3148                 Bind(&newLengthInRange);
3149                 newStringLength = DoubleToInt(glue, GetDoubleOfTDouble(newLength));
3150                 Jump(&next);
3151             }
3152             Bind(&next);
3153             GateRef thisLen = GetLengthFromString(thisValue);
3154             BRANCH(Int32GreaterThanOrEqual(thisLen, *newStringLength), &isSelf, &isNotSelf);
3155             Bind(&isSelf);
3156             {
3157                 res->WriteVariable(thisValue);
3158                 Jump(exit);
3159             }
3160             Bind(&isNotSelf);
3161             {
3162                 tempStr = thisValue;
3163                 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), slowPath, &padStringNotUndefined);
3164                 Bind(&padStringNotUndefined);
3165                 {
3166                     GateRef panTag = GetCallArg1(numArgs);
3167                     BRANCH(TaggedIsHeapObject(panTag), &padTagIsHeapObject, slowPath);
3168                     Bind(&padTagIsHeapObject);
3169                     BRANCH(IsString(panTag), &isPanString, slowPath);
3170                     Bind(&isPanString);
3171                     {
3172                         GateRef padStringLen = GetLengthFromString(panTag);
3173                         BRANCH(Int32GreaterThanOrEqual(Int32(0), padStringLen), slowPath, &newLenthGreatZero);
3174                         Bind(&newLenthGreatZero);
3175                         {
3176                             tempStringLength = Int32Add(thisLen, padStringLen);
3177                             Label loopHead(env);
3178                             Label loopEnd(env);
3179                             Label loopNext(env);
3180                             Label loopExit(env);
3181                             Jump(&loopHead);
3182 
3183                             LoopBegin(&loopHead);
3184                             {
3185                                 BRANCH(Int32GreaterThan(*tempStringLength, *newStringLength), &loopExit, &loopNext);
3186                                 Bind(&loopNext);
3187                                 {
3188                                     tempStr = StringConcat(glue, *tempStr, panTag);
3189                                     Jump(&loopEnd);
3190                                 }
3191                             }
3192                             Bind(&loopEnd);
3193                             tempStringLength = Int32Add(*tempStringLength, padStringLen);
3194                             LoopEnd(&loopHead, env, glue);
3195                             Bind(&loopExit);
3196                             GateRef lastLen = Int32Sub(padStringLen, Int32Sub(*tempStringLength, *newStringLength));
3197                             GateRef lastPadString = GetSubString(glue, panTag, Int32(0), lastLen);
3198                             tempStr = StringConcat(glue, *tempStr, lastPadString);
3199                             res->WriteVariable(*tempStr);
3200                             Jump(exit);
3201                         }
3202                     }
3203                 }
3204             }
3205         }
3206     }
3207 }
3208 }  // namespace panda::ecmascript::kungfu
3209