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