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