• 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/compiler/builtins/builtins_stubs.h"
19 #include "ecmascript/compiler/new_object_stub_builder.h"
20 
21 namespace panda::ecmascript::kungfu {
FromCharCode(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)22 void BuiltinsStringStubBuilder::FromCharCode(GateRef glue, [[maybe_unused]] GateRef thisValue,
23     GateRef numArgs, Variable* res, Label *exit, Label *slowPath)
24 {
25     auto env = GetEnvironment();
26     DEFVARIABLE(value, VariableType::INT16(), Int16(0));
27     Label lengthIsZero(env);
28     Label lengthNotZero(env);
29     Label lengthIsOne(env);
30     Label canBeCompress(env);
31     Label isInt(env);
32     Label notInt(env);
33     Label newObj(env);
34     Label canNotBeCompress(env);
35     Label isPendingException(env);
36     Label noPendingException(env);
37     Branch(Int64Equal(IntPtr(0), numArgs), &lengthIsZero, &lengthNotZero);
38     Bind(&lengthIsZero);
39     res->WriteVariable(GetGlobalConstantValue(
40         VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX));
41     Jump(exit);
42     Bind(&lengthNotZero);
43     {
44         Branch(Int64Equal(IntPtr(1), numArgs), &lengthIsOne, slowPath);
45         Bind(&lengthIsOne);
46         {
47             GateRef codePointTag = GetCallArg0(numArgs);
48             GateRef codePointValue = ToNumber(glue, codePointTag);
49             Branch(HasPendingException(glue), &isPendingException, &noPendingException);
50             Bind(&isPendingException);
51             {
52                 res->WriteVariable(Exception());
53                 Jump(exit);
54             }
55             Bind(&noPendingException);
56             {
57                 Branch(TaggedIsInt(codePointValue), &isInt, &notInt);
58                 Bind(&isInt);
59                 {
60                     value = TruncInt32ToInt16(GetInt32OfTInt(codePointValue));
61                     Jump(&newObj);
62                 }
63                 Bind(&notInt);
64                 {
65                     value = TruncInt32ToInt16(DoubleToInt(glue, GetDoubleOfTDouble(codePointValue), base::INT16_BITS));
66                     Jump(&newObj);
67                 }
68                 Bind(&newObj);
69                 Branch(IsASCIICharacter(ZExtInt16ToInt32(*value)), &canBeCompress, &canNotBeCompress);
70                 NewObjectStubBuilder newBuilder(this);
71                 newBuilder.SetParameters(glue, 0);
72                 Bind(&canBeCompress);
73                 {
74                     GateRef singleCharTable = GetSingleCharTable(glue);
75                     res->WriteVariable(GetValueFromTaggedArray(singleCharTable, ZExtInt16ToInt32(*value)));
76                     Jump(exit);
77                 }
78                 Bind(&canNotBeCompress);
79                 {
80                     Label afterNew1(env);
81                     newBuilder.AllocLineStringObject(res, &afterNew1, Int32(1), false);
82                     Bind(&afterNew1);
83                     {
84                         GateRef dst = ChangeStringTaggedPointerToInt64(
85                             PtrAdd(res->ReadVariable(), IntPtr(LineEcmaString::DATA_OFFSET)));
86                         Store(VariableType::INT16(), glue, dst, IntPtr(0), *value);
87                         Jump(exit);
88                     }
89                 }
90             }
91         }
92     }
93 }
94 
CharAt(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)95 void BuiltinsStringStubBuilder::CharAt(GateRef glue, GateRef thisValue, GateRef numArgs,
96     Variable* res, Label *exit, Label *slowPath)
97 {
98     auto env = GetEnvironment();
99     DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
100     DEFVARIABLE(doubleValue, VariableType::FLOAT64(), Double(0));
101     Label objNotUndefinedAndNull(env);
102     Label isString(env);
103     Label next(env);
104     Label posTagNotUndefined(env);
105     Label posTagIsInt(env);
106     Label posTagNotInt(env);
107     Label isINF(env);
108     Label isNotINF(env);
109     Label posNotGreaterLen(env);
110     Label posGreaterLen(env);
111     Label posNotLessZero(env);
112     Label posTagIsDouble(env);
113     Label thisIsHeapobject(env);
114     Label flattenFastPath(env);
115 
116     Branch(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
117     Bind(&objNotUndefinedAndNull);
118     {
119         Branch(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
120         Bind(&thisIsHeapobject);
121         Branch(IsString(thisValue), &isString, slowPath);
122         Bind(&isString);
123         {
124             FlatStringStubBuilder thisFlat(this);
125             thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
126             Bind(&flattenFastPath);
127             GateRef thisLen = GetLengthFromString(thisValue);
128             Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &posTagNotUndefined);
129             Bind(&posTagNotUndefined);
130             {
131                 GateRef posTag = GetCallArg0(numArgs);
132                 Branch(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
133                 Bind(&posTagIsInt);
134                 pos = GetInt32OfTInt(posTag);
135                 Jump(&next);
136                 Bind(&posTagNotInt);
137                 Branch(TaggedIsDouble(posTag), &posTagIsDouble, slowPath);
138                 Bind(&posTagIsDouble);
139                 doubleValue = GetDoubleOfTDouble(posTag);
140                 Branch(DoubleIsINF(*doubleValue), &posGreaterLen, &isNotINF);
141                 Bind(&isNotINF);
142                 pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
143                 Jump(&next);
144             }
145             Bind(&next);
146             {
147                 Branch(Int32GreaterThanOrEqual(*pos, thisLen), &posGreaterLen, &posNotGreaterLen);
148                 Bind(&posNotGreaterLen);
149                 {
150                     Branch(Int32LessThan(*pos, Int32(0)), &posGreaterLen, &posNotLessZero);
151                     Bind(&posNotLessZero);
152                     {
153                         StringInfoGateRef stringInfoGate(&thisFlat);
154                         res->WriteVariable(CreateFromEcmaString(glue, *pos, stringInfoGate));
155                         Jump(exit);
156                     }
157                 }
158                 Bind(&posGreaterLen);
159                 {
160                     res->WriteVariable(GetGlobalConstantValue(
161                         VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX));
162                     Jump(exit);
163                 }
164             }
165         }
166     }
167 }
168 
CharCodeAt(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)169 void BuiltinsStringStubBuilder::CharCodeAt(GateRef glue, GateRef thisValue, GateRef numArgs,
170     Variable* res, Label *exit, Label *slowPath)
171 {
172     auto env = GetEnvironment();
173     DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
174     DEFVARIABLE(doubleValue, VariableType::FLOAT64(), Double(0));
175     Label objNotUndefinedAndNull(env);
176     Label isString(env);
177     Label next(env);
178     Label posTagNotUndefined(env);
179     Label isINF(env);
180     Label isNotINF(env);
181     Label posTagIsInt(env);
182     Label posTagNotInt(env);
183     Label posNotGreaterLen(env);
184     Label posNotLessZero(env);
185     Label posTagIsDouble(env);
186     Label thisIsHeapobject(env);
187     Label flattenFastPath(env);
188 
189     Branch(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
190     Bind(&objNotUndefinedAndNull);
191     {
192         Branch(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
193         Bind(&thisIsHeapobject);
194         Branch(IsString(thisValue), &isString, slowPath);
195         Bind(&isString);
196         {
197             FlatStringStubBuilder thisFlat(this);
198             thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
199             Bind(&flattenFastPath);
200             GateRef thisLen = GetLengthFromString(thisValue);
201             Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &posTagNotUndefined);
202             Bind(&posTagNotUndefined);
203             {
204                 GateRef posTag = GetCallArg0(numArgs);
205                 Branch(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
206                 Bind(&posTagIsInt);
207                 {
208                     pos = GetInt32OfTInt(posTag);
209                     Jump(&next);
210                 }
211                 Bind(&posTagNotInt);
212                 {
213                     Branch(TaggedIsDouble(posTag), &posTagIsDouble, slowPath);
214                     Bind(&posTagIsDouble);
215                     doubleValue = GetDoubleOfTDouble(posTag);
216                     Branch(DoubleIsINF(*doubleValue), exit, &isNotINF);
217                     Bind(&isNotINF);
218                     pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
219                     Jump(&next);
220                 }
221             }
222             Bind(&next);
223             {
224                 Branch(Int32GreaterThanOrEqual(*pos, thisLen), exit, &posNotGreaterLen);
225                 Bind(&posNotGreaterLen);
226                 {
227                     Branch(Int32LessThan(*pos, Int32(0)), exit, &posNotLessZero);
228                     Bind(&posNotLessZero);
229                     {
230                         StringInfoGateRef stringInfoGate(&thisFlat);
231                         res->WriteVariable(IntToTaggedPtr(StringAt(stringInfoGate, *pos)));
232                         Jump(exit);
233                     }
234                 }
235             }
236         }
237     }
238 }
239 
IndexOf(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)240 void BuiltinsStringStubBuilder::IndexOf(GateRef glue, GateRef thisValue, GateRef numArgs,
241     Variable* res, Label *exit, Label *slowPath)
242 {
243     auto env = GetEnvironment();
244     DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
245 
246     Label objNotUndefinedAndNull(env);
247     Label isString(env);
248     Label isSearchString(env);
249     Label next(env);
250     Label resPosGreaterZero(env);
251     Label searchTagIsHeapObject(env);
252     Label posTagNotUndefined(env);
253     Label posTagIsInt(env);
254     Label posTagNotInt(env);
255     Label posTagIsDouble(env);
256     Label nextCount(env);
257     Label posNotLessThanLen(env);
258     Label thisIsHeapobject(env);
259     Label flattenFastPath(env);
260     Label flattenFastPath1(env);
261 
262     Branch(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
263     Bind(&objNotUndefinedAndNull);
264     {
265         Branch(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
266         Bind(&thisIsHeapobject);
267         Branch(IsString(thisValue), &isString, slowPath);
268         Bind(&isString);
269         {
270             GateRef searchTag = GetCallArg0(numArgs);
271             Branch(TaggedIsHeapObject(searchTag), &searchTagIsHeapObject, slowPath);
272             Bind(&searchTagIsHeapObject);
273             Branch(IsString(searchTag), &isSearchString, slowPath);
274             Bind(&isSearchString);
275             {
276                 GateRef thisLen = GetLengthFromString(thisValue);
277                 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &next, &posTagNotUndefined);
278                 Bind(&posTagNotUndefined);
279                 {
280                     GateRef posTag = GetCallArg1(numArgs);
281                     Branch(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
282                     Bind(&posTagIsInt);
283                     pos = GetInt32OfTInt(posTag);
284                     Jump(&next);
285                     Bind(&posTagNotInt);
286                     Branch(TaggedIsDouble(posTag), &posTagIsDouble, slowPath);
287                     Bind(&posTagIsDouble);
288                     pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
289                     Jump(&next);
290                 }
291                 Bind(&next);
292                 {
293                     Label posGreaterThanZero(env);
294                     Label posNotGreaterThanZero(env);
295                     Branch(Int32GreaterThan(*pos, Int32(0)), &posGreaterThanZero, &posNotGreaterThanZero);
296                     Bind(&posNotGreaterThanZero);
297                     {
298                         pos = Int32(0);
299                         Jump(&nextCount);
300                     }
301                     Bind(&posGreaterThanZero);
302                     {
303                         Branch(Int32LessThanOrEqual(*pos, thisLen), &nextCount, &posNotLessThanLen);
304                         Bind(&posNotLessThanLen);
305                         {
306                             pos = thisLen;
307                             Jump(&nextCount);
308                         }
309                     }
310                     Bind(&nextCount);
311                     {
312                         FlatStringStubBuilder thisFlat(this);
313                         thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
314                         Bind(&flattenFastPath);
315                         FlatStringStubBuilder searchFlat(this);
316                         searchFlat.FlattenString(glue, searchTag, &flattenFastPath1);
317                         Bind(&flattenFastPath1);
318                         StringInfoGateRef thisStringInfoGate(&thisFlat);
319                         StringInfoGateRef searchStringInfoGate(&searchFlat);
320                         GateRef resPos = StringIndexOf(thisStringInfoGate, searchStringInfoGate, *pos);
321                         Branch(Int32GreaterThanOrEqual(resPos, Int32(0)), &resPosGreaterZero, exit);
322                         Bind(&resPosGreaterZero);
323                         {
324                             Label resPosLessZero(env);
325                             Branch(Int32LessThanOrEqual(resPos, thisLen), &resPosLessZero, exit);
326                             Bind(&resPosLessZero);
327                             {
328                                 res->WriteVariable(IntToTaggedPtr(resPos));
329                                 Jump(exit);
330                             }
331                         }
332                     }
333                 }
334             }
335         }
336     }
337 }
338 
Substring(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)339 void BuiltinsStringStubBuilder::Substring(GateRef glue, GateRef thisValue, GateRef numArgs,
340     Variable* res, Label *exit, Label *slowPath)
341 {
342     auto env = GetEnvironment();
343     DEFVARIABLE(start, VariableType::INT32(), Int32(0));
344     DEFVARIABLE(end, VariableType::INT32(), Int32(0));
345     DEFVARIABLE(from, VariableType::INT32(), Int32(0));
346     DEFVARIABLE(to, VariableType::INT32(), Int32(0));
347 
348     Label objNotUndefinedAndNull(env);
349     Label isString(env);
350     Label isSearchString(env);
351     Label countStart(env);
352     Label endTagIsUndefined(env);
353     Label startNotGreatZero(env);
354     Label countEnd(env);
355     Label endNotGreatZero(env);
356     Label countFrom(env);
357     Label countRes(env);
358     Label startTagNotUndefined(env);
359     Label posTagIsInt(env);
360     Label posTagNotInt(env);
361     Label posTagIsDouble(env);
362     Label endTagNotUndefined(env);
363     Label endTagIsInt(env);
364     Label endTagNotInt(env);
365     Label endTagIsDouble(env);
366     Label endGreatZero(env);
367     Label endGreatLen(env);
368     Label startGreatZero(env);
369     Label startGreatEnd(env);
370     Label startNotGreatEnd(env);
371     Label thisIsHeapobject(env);
372 
373     Branch(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
374     Bind(&objNotUndefinedAndNull);
375     {
376         Branch(TaggedIsHeapObject(thisValue), &thisIsHeapobject, slowPath);
377         Bind(&thisIsHeapobject);
378         Branch(IsString(thisValue), &isString, slowPath);
379         Bind(&isString);
380         {
381             Label next(env);
382             GateRef thisLen = GetLengthFromString(thisValue);
383             Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &startTagNotUndefined);
384             Bind(&startTagNotUndefined);
385             {
386                 GateRef startTag = GetCallArg0(numArgs);
387                 Branch(TaggedIsInt(startTag), &posTagIsInt, &posTagNotInt);
388                 Bind(&posTagIsInt);
389                 start = GetInt32OfTInt(startTag);
390                 Jump(&next);
391                 Bind(&posTagNotInt);
392                 Branch(TaggedIsDouble(startTag), &posTagIsDouble, slowPath);
393                 Bind(&posTagIsDouble);
394                 start = DoubleToInt(glue, GetDoubleOfTDouble(startTag));
395                 Jump(&next);
396             }
397             Bind(&next);
398             {
399                 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &endTagIsUndefined, &endTagNotUndefined);
400                 Bind(&endTagIsUndefined);
401                 {
402                     end = thisLen;
403                     Jump(&countStart);
404                 }
405                 Bind(&endTagNotUndefined);
406                 {
407                     GateRef endTag = GetCallArg1(numArgs);
408                     Branch(TaggedIsInt(endTag), &endTagIsInt, &endTagNotInt);
409                     Bind(&endTagIsInt);
410                     end = GetInt32OfTInt(endTag);
411                     Jump(&countStart);
412                     Bind(&endTagNotInt);
413                     Branch(TaggedIsDouble(endTag), &endTagIsDouble, slowPath);
414                     Bind(&endTagIsDouble);
415                     end = DoubleToInt(glue, GetDoubleOfTDouble(endTag));
416                     Jump(&countStart);
417                 }
418             }
419             Bind(&countStart);
420             {
421                 Label startGreatLen(env);
422                 Branch(Int32GreaterThan(*start, Int32(0)), &startGreatZero, &startNotGreatZero);
423                 Bind(&startNotGreatZero);
424                 {
425                     start = Int32(0);
426                     Jump(&countEnd);
427                 }
428                 Bind(&startGreatZero);
429                 {
430                     Branch(Int32GreaterThan(*start, thisLen), &startGreatLen, &countEnd);
431                     Bind(&startGreatLen);
432                     {
433                         start = thisLen;
434                         Jump(&countEnd);
435                     }
436                 }
437             }
438             Bind(&countEnd);
439             {
440                 Branch(Int32GreaterThan(*end, Int32(0)), &endGreatZero, &endNotGreatZero);
441                 Bind(&endNotGreatZero);
442                 {
443                     end = Int32(0);
444                     Jump(&countFrom);
445                 }
446                 Bind(&endGreatZero);
447                 {
448                     Branch(Int32GreaterThan(*end, thisLen), &endGreatLen, &countFrom);
449                     Bind(&endGreatLen);
450                     {
451                         end = thisLen;
452                         Jump(&countFrom);
453                     }
454                 }
455             }
456             Bind(&countFrom);
457             {
458                 Branch(Int32GreaterThan(*start, *end), &startGreatEnd, &startNotGreatEnd);
459                 Bind(&startGreatEnd);
460                 {
461                     from = *end;
462                     to = *start;
463                     Jump(&countRes);
464                 }
465                 Bind(&startNotGreatEnd);
466                 {
467                     from = *start;
468                     to = *end;
469                     Jump(&countRes);
470                 }
471             }
472             Bind(&countRes);
473             {
474                 GateRef len = Int32Sub(*to, *from);
475                 res->WriteVariable(GetSubString(glue, thisValue, *from, len));
476                 Jump(exit);
477             }
478         }
479     }
480 }
481 
GetSubString(GateRef glue,GateRef thisValue,GateRef from,GateRef len)482 GateRef BuiltinsStringStubBuilder::GetSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
483 {
484     auto env = GetEnvironment();
485     Label entry(env);
486     env->SubCfgEntry(&entry);
487     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
488 
489     Label exit(env);
490     Label flattenFastPath(env);
491     Label sliceString(env);
492     Label mayGetSliceString(env);
493     Label fastSubstring(env);
494     Label isUtf16(env);
495     Label isUtf8(env);
496     Label afterNew(env);
497     FlatStringStubBuilder thisFlat(this);
498     thisFlat.FlattenString(glue, thisValue, &flattenFastPath);
499     Bind(&flattenFastPath);
500     {
501         Branch(Int32GreaterThanOrEqual(len, Int32(SlicedString::MIN_SLICED_ECMASTRING_LENGTH)),
502             &mayGetSliceString, &fastSubstring);
503         Bind(&mayGetSliceString);
504         {
505             Branch(IsUtf16String(thisValue), &isUtf16, &sliceString);
506             Bind(&isUtf16);
507             {
508                 StringInfoGateRef stringInfoGate(&thisFlat);
509                 GateRef fromOffset = PtrMul(ZExtInt32ToPtr(from), IntPtr(sizeof(uint16_t) / sizeof(uint8_t)));
510                 GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
511                 GateRef canBeCompressed = CanBeCompressed(source, len, true);
512                 Branch(canBeCompressed, &isUtf8, &sliceString);
513                 Bind(&isUtf8);
514                 {
515                     NewObjectStubBuilder newBuilder(this);
516                     newBuilder.SetParameters(glue, 0);
517                     newBuilder.AllocLineStringObject(&result, &afterNew, len, true);
518                     Bind(&afterNew);
519                     {
520                         GateRef source1 = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
521                         GateRef dst =
522                             ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
523                         CopyUtf16AsUtf8(glue, dst, source1, len);
524                         Jump(&exit);
525                     }
526                 }
527             }
528             Bind(&sliceString);
529             {
530                 NewObjectStubBuilder newBuilder(this);
531                 newBuilder.SetParameters(glue, 0);
532                 newBuilder.AllocSlicedStringObject(&result, &exit, from, len, &thisFlat);
533             }
534         }
535         Bind(&fastSubstring);
536         StringInfoGateRef stringInfoGate(&thisFlat);
537         result = FastSubString(glue, thisValue, from, len, stringInfoGate);
538         Jump(&exit);
539     }
540     Bind(&exit);
541     auto ret = *result;
542     env->SubCfgExit();
543     return ret;
544 }
545 
Replace(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)546 void BuiltinsStringStubBuilder::Replace(GateRef glue, GateRef thisValue, GateRef numArgs,
547     Variable *res, Label *exit, Label *slowPath)
548 {
549     auto env = GetEnvironment();
550 
551     Label objNotUndefinedAndNull(env);
552 
553     Branch(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
554     Bind(&objNotUndefinedAndNull);
555     {
556         Label thisIsHeapObj(env);
557         Label tagsDefined(env);
558         Label searchIsHeapObj(env);
559         Label replaceIsHeapObj(env);
560 
561         Branch(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
562         Bind(&thisIsHeapObj);
563         Branch(Int64Equal(IntPtr(2), numArgs), &tagsDefined, slowPath); // 2: number of parameters. search & replace Tag
564         Bind(&tagsDefined);
565         {
566             Label next(env);
567 
568             GateRef searchTag = GetCallArg0(numArgs);
569             Branch(TaggedIsHeapObject(searchTag), &searchIsHeapObj, slowPath);
570             Bind(&searchIsHeapObj);
571             GateRef replaceTag = GetCallArg1(numArgs);
572             Branch(TaggedIsHeapObject(replaceTag), &replaceIsHeapObj, slowPath);
573             Bind(&replaceIsHeapObj);
574             Branch(BoolOr(IsJSRegExp(searchTag), IsEcmaObject(searchTag)), slowPath, &next);
575             Bind(&next);
576             {
577                 Label allAreStrings(env);
578                 GateRef thisIsString = IsString(thisValue);
579                 GateRef searchIsString = IsString(searchTag);
580                 GateRef replaceIsString = IsString(replaceTag);
581                 Branch(BoolAnd(BoolAnd(thisIsString, searchIsString), replaceIsString), &allAreStrings, slowPath);
582                 Bind(&allAreStrings);
583                 {
584                     Label replaceTagNotCallable(env);
585 
586                     GateRef replaceTagIsCallable = IsCallable(replaceTag);
587 
588                     Branch(replaceTagIsCallable, slowPath, &replaceTagNotCallable);
589                     Bind(&replaceTagNotCallable);
590                     {
591                         Label thisFlattenFastPath(env);
592                         Label searchFlattenFastPath(env);
593                         Label noReplace(env);
594                         Label nextProcess(env);
595 
596                         FlatStringStubBuilder thisFlat(this);
597                         thisFlat.FlattenString(glue, thisValue, &thisFlattenFastPath);
598                         Bind(&thisFlattenFastPath);
599                         StringInfoGateRef thisStringInfoGate(&thisFlat);
600                         FlatStringStubBuilder searchFlat(this);
601                         searchFlat.FlattenString(glue, searchTag, &searchFlattenFastPath);
602                         Bind(&searchFlattenFastPath);
603                         StringInfoGateRef searchStringInfoGate(&searchFlat);
604                         GateRef pos = StringIndexOf(thisStringInfoGate, searchStringInfoGate, Int32(-1));
605                         Branch(Int32Equal(pos, Int32(-1)), &noReplace, &nextProcess);
606                         Bind(&noReplace);
607                         {
608                             res->WriteVariable(thisValue);
609                             Jump(exit);
610                         }
611                         Bind(&nextProcess);
612                         {
613                             Label functionalReplaceFalse(env);
614 
615                             Branch(replaceTagIsCallable, slowPath, &functionalReplaceFalse);
616                             Bind(&functionalReplaceFalse);
617                             {
618                                 Label replHandleIsString(env);
619 
620                                 GateRef replHandle = GetSubstitution(glue, searchTag, thisValue, pos, replaceTag);
621                                 Branch(IsString(replHandle), &replHandleIsString, slowPath);
622                                 Bind(&replHandleIsString);
623                                 {
624                                     GateRef tailPos = Int32Add(pos, searchStringInfoGate.GetLength());
625                                     GateRef prefixString = FastSubString(glue, thisValue, Int32(0),
626                                         pos, thisStringInfoGate);
627                                     GateRef thisLen = thisStringInfoGate.GetLength();
628                                     GateRef suffixString = FastSubString(glue, thisValue, tailPos,
629                                         Int32Sub(thisLen, tailPos), thisStringInfoGate);
630                                     GateRef tempStr = StringConcat(glue, prefixString, replHandle);
631                                     GateRef resultStr = StringConcat(glue, tempStr, suffixString);
632                                     res->WriteVariable(resultStr);
633                                     Jump(exit);
634                                 }
635                             }
636                         }
637                     }
638                 }
639             }
640         }
641     }
642 }
643 
ConvertAndClampRelativeIndex(GateRef index,GateRef length)644 GateRef BuiltinsStringStubBuilder::ConvertAndClampRelativeIndex(GateRef index, GateRef length)
645 {
646     auto env = GetEnvironment();
647 
648     Label entry(env);
649     env->SubCfgEntry(&entry);
650 
651     DEFVARIABLE(relativeIndex, VariableType::INT32(), Int32(-1));
652 
653     Label indexGreaterThanOrEqualZero(env);
654     Label indexLessThanZero(env);
655     Label next(env);
656 
657     Branch(Int32GreaterThanOrEqual(index, Int32(0)), &indexGreaterThanOrEqualZero, &indexLessThanZero);
658     Bind(&indexGreaterThanOrEqualZero);
659     {
660         relativeIndex = index;
661         Jump(&next);
662     }
663     Bind(&indexLessThanZero);
664     {
665         relativeIndex = Int32Add(index, length);
666         Jump(&next);
667     }
668     Bind(&next);
669     {
670         Label relativeIndexLessThanZero(env);
671         Label elseCheck(env);
672         Label exit(env);
673 
674         Branch(Int32LessThan(*relativeIndex, Int32(0)), &relativeIndexLessThanZero, &elseCheck);
675         Bind(&relativeIndexLessThanZero);
676         {
677             relativeIndex = Int32(0);
678             Jump(&exit);
679         }
680         Bind(&elseCheck);
681         {
682             Label relativeIndexGreaterThanLength(env);
683 
684             Branch(Int32GreaterThan(*relativeIndex, length), &relativeIndexGreaterThanLength, &exit);
685             Bind(&relativeIndexGreaterThanLength);
686             {
687                 relativeIndex = length;
688                 Jump(&exit);
689             }
690         }
691         Bind(&exit);
692         auto ret = *relativeIndex;
693         env->SubCfgExit();
694         return ret;
695     }
696 }
697 
Slice(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)698 void BuiltinsStringStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef numArgs,
699     Variable *res, Label *exit, Label *slowPath)
700 {
701     auto env = GetEnvironment();
702 
703     DEFVARIABLE(start, VariableType::INT32(), Int32(-1));
704     DEFVARIABLE(end, VariableType::INT32(), Int32(-1));
705     DEFVARIABLE(sliceLen, VariableType::INT32(), Int32(-1));
706     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
707 
708     Label objNotUndefinedAndNull(env);
709 
710     Branch(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
711     Bind(&objNotUndefinedAndNull);
712     {
713         Label thisIsHeapObj(env);
714         Label isString(env);
715 
716         Branch(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
717         Bind(&thisIsHeapObj);
718         Branch(IsString(thisValue), &isString, slowPath);
719         Bind(&isString);
720         {
721             Label startTagDefined(env);
722 
723             Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), slowPath, &startTagDefined);
724             Bind(&startTagDefined);
725             {
726                 Label startTagIsInt(env);
727                 Label endTagUndefined(env);
728                 Label endTagDefined(env);
729                 Label endTagIsInt(env);
730                 Label next(env);
731 
732                 GateRef startTag = GetCallArg0(numArgs);
733                 Branch(TaggedIsInt(startTag), &startTagIsInt, slowPath);
734                 Bind(&startTagIsInt);
735                 GateRef thisLen = GetLengthFromString(thisValue);
736                 start = ConvertAndClampRelativeIndex(GetInt32OfTInt(startTag), thisLen);
737                 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &endTagUndefined, &endTagDefined);
738                 Bind(&endTagUndefined);
739                 {
740                     end = thisLen;
741                     Jump(&next);
742                 }
743                 Bind(&endTagDefined);
744                 {
745                     GateRef endTag = GetCallArg1(numArgs);
746                     Branch(TaggedIsInt(endTag), &endTagIsInt, slowPath);
747                     Bind(&endTagIsInt);
748                     end = ConvertAndClampRelativeIndex(GetInt32OfTInt(endTag), thisLen);
749                     Jump(&next);
750                 }
751                 Bind(&next);
752                 {
753                     Label emptyString(env);
754                     Label fastSubString(env);
755                     Label finish(env);
756 
757                     sliceLen = Int32Sub(*end, *start);
758                     Branch(Int32LessThanOrEqual(*sliceLen, Int32(0)), &emptyString, &fastSubString);
759                     Bind(&emptyString);
760                     {
761                         result = GetGlobalConstantValue(
762                             VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
763                         Jump(&finish);
764                     }
765                     Bind(&fastSubString);
766                     {
767                         Label thisFlattenFastPath(env);
768                         FlatStringStubBuilder thisFlat(this);
769                         thisFlat.FlattenString(glue, thisValue, &thisFlattenFastPath);
770                         Bind(&thisFlattenFastPath);
771                         StringInfoGateRef stringInfoGate(&thisFlat);
772                         result = FastSubString(glue, thisValue, *start, *sliceLen, stringInfoGate);
773                         Jump(&finish);
774                     }
775                     Bind(&finish);
776                     res->WriteVariable(*result);
777                     Jump(exit);
778                 }
779             }
780         }
781     }
782 }
783 
Trim(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)784 void BuiltinsStringStubBuilder::Trim(GateRef glue, GateRef thisValue, GateRef numArgs [[maybe_unused]],
785     Variable *res, Label *exit, Label *slowPath)
786 {
787     auto env = GetEnvironment();
788     DEFVARIABLE(start, VariableType::INT32(), Int32(-1));
789     DEFVARIABLE(end, VariableType::INT32(), Int32(-1));
790     DEFVARIABLE(sliceLen, VariableType::INT32(), Int32(-1));
791 
792     Label objNotUndefinedAndNull(env);
793 
794     Branch(TaggedIsUndefinedOrNull(thisValue), slowPath, &objNotUndefinedAndNull);
795     Bind(&objNotUndefinedAndNull);
796     {
797         Label thisIsHeapObj(env);
798         Label thisIsString(env);
799 
800         Branch(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
801         Bind(&thisIsHeapObj);
802         Branch(IsString(thisValue), &thisIsString, slowPath);
803         Bind(&thisIsString);
804         GateRef result = EcmaStringTrim(glue, thisValue, Int32(0)); // 0: mode = TrimMode::TRIM
805         res->WriteVariable(result);
806         Jump(exit);
807     }
808 }
809 
StringAt(const StringInfoGateRef & stringInfoGate,GateRef index)810 GateRef BuiltinsStringStubBuilder::StringAt(const StringInfoGateRef &stringInfoGate, GateRef index)
811 {
812     auto env = GetEnvironment();
813     Label entry(env);
814     env->SubCfgEntry(&entry);
815     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
816 
817     Label exit(env);
818     Label isUtf16(env);
819     Label isUtf8(env);
820     Label doIntOp(env);
821     Label leftIsNumber(env);
822     Label rightIsNumber(env);
823     GateRef dataUtf16 = GetNormalStringData(stringInfoGate);
824     Branch(IsUtf16String(stringInfoGate.GetString()), &isUtf16, &isUtf8);
825     Bind(&isUtf16);
826     {
827         result = ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(dataUtf16,
828             PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))))));
829         Jump(&exit);
830     }
831     Bind(&isUtf8);
832     {
833         result = ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(dataUtf16,
834             PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
835         Jump(&exit);
836     }
837     Bind(&exit);
838     auto ret = *result;
839     env->SubCfgExit();
840     return ret;
841 }
842 
GetSingleCharCodeByIndex(GateRef str,GateRef index)843 GateRef BuiltinsStringStubBuilder::GetSingleCharCodeByIndex(GateRef str, GateRef index)
844 {
845     // Note: This method cannot handle treestring.
846     auto env = GetEnvironment();
847     Label entry(env);
848     env->SubCfgEntry(&entry);
849     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
850 
851     Label isConstantString(env);
852     Label lineStringCheck(env);
853     Label isLineString(env);
854     Label slicedStringCheck(env);
855     Label isSlicedString(env);
856     Label exit(env);
857 
858     Branch(IsConstantString(str), &isConstantString, &lineStringCheck);
859     Bind(&isConstantString);
860     {
861         result = GetSingleCharCodeFromConstantString(str, index);
862         Jump(&exit);
863     }
864     Bind(&lineStringCheck);
865     Branch(IsLineString(str), &isLineString, &slicedStringCheck);
866     Bind(&isLineString);
867     {
868         result = GetSingleCharCodeFromLineString(str, index);
869         Jump(&exit);
870     }
871     Bind(&slicedStringCheck);
872     Branch(IsSlicedString(str), &isSlicedString, &exit);
873     Bind(&isSlicedString);
874     {
875         result = GetSingleCharCodeFromSlicedString(str, index);
876         Jump(&exit);
877     }
878 
879     Bind(&exit);
880     auto ret = *result;
881     env->SubCfgExit();
882     return ret;
883 }
884 
GetSingleCharCodeFromConstantString(GateRef str,GateRef index)885 GateRef BuiltinsStringStubBuilder::GetSingleCharCodeFromConstantString(GateRef str, GateRef index)
886 {
887     auto env = GetEnvironment();
888     Label entry(env);
889     env->SubCfgEntry(&entry);
890     GateRef offset = ChangeStringTaggedPointerToInt64(PtrAdd(str, IntPtr(ConstantString::CONSTANT_DATA_OFFSET)));
891     GateRef dataAddr = Load(VariableType::NATIVE_POINTER(), offset, IntPtr(0));
892     GateRef result = ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(dataAddr,
893         PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
894     env->SubCfgExit();
895     return result;
896 }
897 
GetSingleCharCodeFromLineString(GateRef str,GateRef index)898 GateRef BuiltinsStringStubBuilder::GetSingleCharCodeFromLineString(GateRef str, GateRef index)
899 {
900     auto env = GetEnvironment();
901     Label entry(env);
902     env->SubCfgEntry(&entry);
903     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
904     GateRef dataAddr = ChangeStringTaggedPointerToInt64(PtrAdd(str, IntPtr(LineEcmaString::DATA_OFFSET)));
905     Label isUtf16(env);
906     Label isUtf8(env);
907     Label exit(env);
908     Branch(IsUtf16String(str), &isUtf16, &isUtf8);
909     Bind(&isUtf16);
910     {
911         result = ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(dataAddr,
912             PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))))));
913         Jump(&exit);
914     }
915     Bind(&isUtf8);
916     {
917         result = ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(dataAddr,
918             PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
919         Jump(&exit);
920     }
921     Bind(&exit);
922     auto ret = *result;
923     env->SubCfgExit();
924     return ret;
925 }
926 
GetSingleCharCodeFromSlicedString(GateRef str,GateRef index)927 GateRef BuiltinsStringStubBuilder::GetSingleCharCodeFromSlicedString(GateRef str, GateRef index)
928 {
929     auto env = GetEnvironment();
930     Label entry(env);
931     env->SubCfgEntry(&entry);
932     DEFVARIABLE(result, VariableType::INT32(), Int32(0));
933     Label isLineString(env);
934     Label notLineString(env);
935     Label exit(env);
936 
937     GateRef parent = Load(VariableType::JS_POINTER(), str, IntPtr(SlicedString::PARENT_OFFSET));
938     GateRef startIndex = Load(VariableType::INT32(), str, IntPtr(SlicedString::STARTINDEX_OFFSET));
939     Branch(IsLineString(parent), &isLineString, &notLineString);
940     Bind(&isLineString);
941     {
942         result = GetSingleCharCodeFromLineString(parent, Int32Add(startIndex, index));
943         Jump(&exit);
944     }
945     Bind(&notLineString);
946     {
947         result = GetSingleCharCodeFromConstantString(parent, Int32Add(startIndex, index));
948         Jump(&exit);
949     }
950     Bind(&exit);
951     auto ret = *result;
952     env->SubCfgExit();
953     return ret;
954 }
955 
CreateStringBySingleCharCode(GateRef glue,GateRef charCode)956 GateRef BuiltinsStringStubBuilder::CreateStringBySingleCharCode(GateRef glue, GateRef charCode)
957 {
958     auto env = GetEnvironment();
959     Label entry(env);
960     env->SubCfgEntry(&entry);
961     DEFVARIABLE(result, VariableType::JS_POINTER(), Hole());
962 
963     NewObjectStubBuilder newBuilder(this);
964     newBuilder.SetParameters(glue, 0);
965 
966     Label exit(env);
967     Label utf8(env);
968     Label utf16(env);
969     Label afterNew(env);
970     GateRef canStoreAsUtf8 = IsASCIICharacter(charCode);
971     Branch(canStoreAsUtf8, &utf8, &utf16);
972     Bind(&utf8);
973     {
974         newBuilder.AllocLineStringObject(&result, &afterNew, Int32(1), true);
975     }
976     Bind(&utf16);
977     {
978         newBuilder.AllocLineStringObject(&result, &afterNew, Int32(1), false);
979     }
980     Bind(&afterNew);
981     {
982         Label isUtf8Copy(env);
983         Label isUtf16Copy(env);
984         GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
985         Branch(canStoreAsUtf8, &isUtf8Copy, &isUtf16Copy);
986         Bind(&isUtf8Copy);
987         {
988             Store(VariableType::INT8(), glue, dst, IntPtr(0), TruncInt32ToInt8(charCode));
989             Jump(&exit);
990         }
991         Bind(&isUtf16Copy);
992         {
993             Store(VariableType::INT16(), glue, dst, IntPtr(0), TruncInt32ToInt16(charCode));
994             Jump(&exit);
995         }
996     }
997 
998     Bind(&exit);
999     auto ret = *result;
1000     env->SubCfgExit();
1001     return ret;
1002 }
1003 
CreateFromEcmaString(GateRef glue,GateRef index,const StringInfoGateRef & stringInfoGate)1004 GateRef BuiltinsStringStubBuilder::CreateFromEcmaString(GateRef glue, GateRef index,
1005     const StringInfoGateRef &stringInfoGate)
1006 {
1007     auto env = GetEnvironment();
1008     Label entry(env);
1009     env->SubCfgEntry(&entry);
1010     DEFVARIABLE(result, VariableType::JS_POINTER(), Hole());
1011     DEFVARIABLE(canBeCompressed, VariableType::BOOL(), False());
1012     DEFVARIABLE(data, VariableType::INT16(), Int32(0));
1013 
1014     Label exit(env);
1015     Label isUtf16(env);
1016     Label isUtf8(env);
1017     Label allocString(env);
1018     GateRef dataUtf = GetNormalStringData(stringInfoGate);
1019     Branch(IsUtf16String(stringInfoGate.GetString()), &isUtf16, &isUtf8);
1020     Bind(&isUtf16);
1021     {
1022         GateRef dataAddr = PtrAdd(dataUtf, PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))));
1023         data = Load(VariableType::INT16(), dataAddr);
1024         canBeCompressed = CanBeCompressed(dataAddr, Int32(1), true);
1025         Jump(&allocString);
1026     }
1027     Bind(&isUtf8);
1028     {
1029         GateRef dataAddr = PtrAdd(dataUtf, PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))));
1030         data = ZExtInt8ToInt16(Load(VariableType::INT8(), dataAddr));
1031         canBeCompressed = CanBeCompressed(dataAddr, Int32(1), false);
1032         Jump(&allocString);
1033     }
1034     Bind(&allocString);
1035     {
1036         Label afterNew(env);
1037         Label isUtf8Next(env);
1038         Label isUtf16Next(env);
1039         NewObjectStubBuilder newBuilder(this);
1040         newBuilder.SetParameters(glue, 0);
1041         Branch(*canBeCompressed, &isUtf8Next, &isUtf16Next);
1042         Bind(&isUtf8Next);
1043         {
1044             GateRef singleCharTable = GetSingleCharTable(glue);
1045             result = GetValueFromTaggedArray(singleCharTable, ZExtInt16ToInt32(*data));
1046             Jump(&exit);
1047         }
1048         Bind(&isUtf16Next);
1049         {
1050             newBuilder.AllocLineStringObject(&result, &afterNew, Int32(1), false);
1051         }
1052         Bind(&afterNew);
1053         {
1054             Label isUtf8Copy(env);
1055             Label isUtf16Copy(env);
1056             GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
1057             Branch(*canBeCompressed, &isUtf8Copy, &isUtf16Copy);
1058             Bind(&isUtf8Copy);
1059             {
1060                 Store(VariableType::INT8(), glue, dst, IntPtr(0), TruncInt16ToInt8(*data));
1061                 Jump(&exit);
1062             }
1063             Bind(&isUtf16Copy);
1064             {
1065                 Store(VariableType::INT16(), glue, dst, IntPtr(0), *data);
1066                 Jump(&exit);
1067             }
1068         }
1069     }
1070     Bind(&exit);
1071     auto ret = *result;
1072     env->SubCfgExit();
1073     return ret;
1074 }
1075 
FastSubString(GateRef glue,GateRef thisValue,GateRef from,GateRef len,const StringInfoGateRef & stringInfoGate)1076 GateRef BuiltinsStringStubBuilder::FastSubString(GateRef glue, GateRef thisValue, GateRef from,
1077     GateRef len, const StringInfoGateRef &stringInfoGate)
1078 {
1079     auto env = GetEnvironment();
1080     Label entry(env);
1081     env->SubCfgEntry(&entry);
1082     DEFVARIABLE(result, VariableType::JS_POINTER(), thisValue);
1083 
1084     Label exit(env);
1085     Label lenEqualZero(env);
1086     Label lenNotEqualZero(env);
1087     Label fromEqualZero(env);
1088     Label next(env);
1089     Label isUtf8(env);
1090     Label isUtf16(env);
1091 
1092     Branch(Int32Equal(len, Int32(0)), &lenEqualZero, &lenNotEqualZero);
1093     Bind(&lenEqualZero);
1094     {
1095         result = GetGlobalConstantValue(
1096             VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
1097         Jump(&exit);
1098     }
1099     Bind(&lenNotEqualZero);
1100     {
1101         Branch(Int32Equal(from, Int32(0)), &fromEqualZero, &next);
1102         Bind(&fromEqualZero);
1103         {
1104             GateRef thisLen = stringInfoGate.GetLength();
1105             Branch(Int32Equal(len, thisLen), &exit, &next);
1106         }
1107         Bind(&next);
1108         {
1109             Branch(IsUtf8String(thisValue), &isUtf8, &isUtf16);
1110             Bind(&isUtf8);
1111             {
1112                 result = FastSubUtf8String(glue, from, len, stringInfoGate);
1113                 Jump(&exit);
1114             }
1115             Bind(&isUtf16);
1116             {
1117                 result = FastSubUtf16String(glue, from, len, stringInfoGate);
1118                 Jump(&exit);
1119             }
1120         }
1121     }
1122     Bind(&exit);
1123     auto ret = *result;
1124     env->SubCfgExit();
1125     return ret;
1126 }
1127 
FastSubUtf8String(GateRef glue,GateRef from,GateRef len,const StringInfoGateRef & stringInfoGate)1128 GateRef BuiltinsStringStubBuilder::FastSubUtf8String(GateRef glue, GateRef from, GateRef len,
1129     const StringInfoGateRef &stringInfoGate)
1130 {
1131     auto env = GetEnvironment();
1132     Label entry(env);
1133     env->SubCfgEntry(&entry);
1134     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
1135     Label exit(env);
1136 
1137     NewObjectStubBuilder newBuilder(this);
1138     newBuilder.SetParameters(glue, 0);
1139     Label afterNew(env);
1140     newBuilder.AllocLineStringObject(&result, &afterNew, len, true);
1141     Bind(&afterNew);
1142     {
1143         GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
1144         GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), ZExtInt32ToPtr(from));
1145         CopyChars(glue, dst, source, len, IntPtr(sizeof(uint8_t)), VariableType::INT8());
1146         Jump(&exit);
1147     }
1148     Bind(&exit);
1149     auto ret = *result;
1150     env->SubCfgExit();
1151     return ret;
1152 }
1153 
FastSubUtf16String(GateRef glue,GateRef from,GateRef len,const StringInfoGateRef & stringInfoGate)1154 GateRef BuiltinsStringStubBuilder::FastSubUtf16String(GateRef glue, GateRef from, GateRef len,
1155     const StringInfoGateRef &stringInfoGate)
1156 {
1157     auto env = GetEnvironment();
1158     Label entry(env);
1159     env->SubCfgEntry(&entry);
1160     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
1161 
1162     Label exit(env);
1163     Label isUtf16(env);
1164     Label isUtf8(env);
1165     Label isUtf8Next(env);
1166     Label isUtf16Next(env);
1167 
1168     GateRef fromOffset = PtrMul(ZExtInt32ToPtr(from), IntPtr(sizeof(uint16_t) / sizeof(uint8_t)));
1169     GateRef source = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
1170     GateRef canBeCompressed = CanBeCompressed(source, len, true);
1171     NewObjectStubBuilder newBuilder(this);
1172     newBuilder.SetParameters(glue, 0);
1173     Label afterNew(env);
1174     Branch(canBeCompressed, &isUtf8, &isUtf16);
1175     Bind(&isUtf8);
1176     {
1177         newBuilder.AllocLineStringObject(&result, &afterNew, len, true);
1178     }
1179     Bind(&isUtf16);
1180     {
1181         newBuilder.AllocLineStringObject(&result, &afterNew, len, false);
1182     }
1183     Bind(&afterNew);
1184     {
1185         GateRef source1 = PtrAdd(GetNormalStringData(stringInfoGate), fromOffset);
1186         GateRef dst = ChangeStringTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
1187         Branch(canBeCompressed, &isUtf8Next, &isUtf16Next);
1188         Bind(&isUtf8Next);
1189         {
1190             CopyUtf16AsUtf8(glue, dst, source1, len);
1191             Jump(&exit);
1192         }
1193         Bind(&isUtf16Next);
1194         {
1195             CopyChars(glue, dst, source1, len, IntPtr(sizeof(uint16_t)), VariableType::INT16());
1196             Jump(&exit);
1197         }
1198     }
1199     Bind(&exit);
1200     auto ret = *result;
1201     env->SubCfgExit();
1202     return ret;
1203 }
1204 
GetSubstitution(GateRef glue,GateRef searchString,GateRef thisString,GateRef pos,GateRef replaceString)1205 GateRef BuiltinsStringStubBuilder::GetSubstitution(GateRef glue, GateRef searchString, GateRef thisString,
1206     GateRef pos, GateRef replaceString)
1207 {
1208     auto env = GetEnvironment();
1209 
1210     Label entry(env);
1211     env->SubCfgEntry(&entry);
1212 
1213     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
1214 
1215     Label dollarFlattenFastPath(env);
1216     Label replaceFlattenFastPath(env);
1217     Label notFound(env);
1218     Label slowPath(env);
1219     Label exit(env);
1220 
1221     GateRef dollarString = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::DOLLAR_INDEX);
1222     FlatStringStubBuilder dollarFlat(this);
1223     dollarFlat.FlattenString(glue, dollarString, &dollarFlattenFastPath);
1224     Bind(&dollarFlattenFastPath);
1225     StringInfoGateRef dollarStringInfoGate(&dollarFlat);
1226     FlatStringStubBuilder replaceFlat(this);
1227     replaceFlat.FlattenString(glue, replaceString, &replaceFlattenFastPath);
1228     Bind(&replaceFlattenFastPath);
1229     StringInfoGateRef replaceStringInfoGate(&replaceFlat);
1230     GateRef nextDollarIndex = StringIndexOf(replaceStringInfoGate, dollarStringInfoGate, Int32(-1));
1231     Branch(Int32LessThan(nextDollarIndex, Int32(0)), &notFound, &slowPath);
1232     Bind(&notFound);
1233     {
1234         result = replaceString;
1235         Jump(&exit);
1236     }
1237     Bind(&slowPath);
1238     {
1239         result = CallRuntime(glue, RTSTUB_ID(RTSubstitution),
1240             {searchString, thisString, IntToTaggedInt(pos), replaceString});
1241         Jump(&exit);
1242     }
1243     Bind(&exit);
1244     auto ret = *result;
1245     env->SubCfgExit();
1246     return ret;
1247 }
1248 
CopyChars(GateRef glue,GateRef dst,GateRef source,GateRef sourceLength,GateRef size,VariableType type)1249 void BuiltinsStringStubBuilder::CopyChars(GateRef glue, GateRef dst, GateRef source,
1250     GateRef sourceLength, GateRef size, VariableType type)
1251 {
1252     auto env = GetEnvironment();
1253     Label entry(env);
1254     env->SubCfgEntry(&entry);
1255     DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
1256     DEFVARIABLE(sourceTmp, VariableType::NATIVE_POINTER(), source);
1257     DEFVARIABLE(len, VariableType::INT32(), sourceLength);
1258     Label loopHead(env);
1259     Label loopEnd(env);
1260     Label next(env);
1261     Label exit(env);
1262     Jump(&loopHead);
1263 
1264     LoopBegin(&loopHead);
1265     {
1266         Branch(Int32GreaterThan(*len, Int32(0)), &next, &exit);
1267         Bind(&next);
1268         {
1269             len = Int32Sub(*len, Int32(1));
1270             GateRef i = Load(type, *sourceTmp);
1271             Store(type, glue, *dstTmp, IntPtr(0), i);
1272             Jump(&loopEnd);
1273         }
1274     }
1275     Bind(&loopEnd);
1276     sourceTmp = PtrAdd(*sourceTmp, size);
1277     dstTmp = PtrAdd(*dstTmp, size);
1278     LoopEnd(&loopHead);
1279 
1280     Bind(&exit);
1281     env->SubCfgExit();
1282     return;
1283 }
1284 
CanBeCompressed(GateRef data,GateRef len,bool isUtf16)1285 GateRef BuiltinsStringStubBuilder::CanBeCompressed(GateRef data, GateRef len, bool isUtf16)
1286 {
1287     auto env = GetEnvironment();
1288     Label entry(env);
1289     env->SubCfgEntry(&entry);
1290     DEFVARIABLE(result, VariableType::BOOL(), True());
1291     DEFVARIABLE(i, VariableType::INT32(), Int32(0));
1292     Label loopHead(env);
1293     Label loopEnd(env);
1294     Label nextCount(env);
1295     Label isNotASCIICharacter(env);
1296     Label exit(env);
1297     Jump(&loopHead);
1298     LoopBegin(&loopHead);
1299     {
1300         Branch(Int32LessThan(*i, len), &nextCount, &exit);
1301         Bind(&nextCount);
1302         {
1303             if (isUtf16) {
1304                 GateRef tmp = Load(VariableType::INT16(), data,
1305                     PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(uint16_t))));
1306                 Branch(IsASCIICharacter(ZExtInt16ToInt32(tmp)), &loopEnd, &isNotASCIICharacter);
1307             } else {
1308                 GateRef tmp = Load(VariableType::INT8(), data,
1309                     PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(uint8_t))));
1310                 Branch(IsASCIICharacter(ZExtInt8ToInt32(tmp)), &loopEnd, &isNotASCIICharacter);
1311             }
1312             Bind(&isNotASCIICharacter);
1313             {
1314                 result = False();
1315                 Jump(&exit);
1316             }
1317         }
1318     }
1319     Bind(&loopEnd);
1320     i = Int32Add(*i, Int32(1));
1321     LoopEnd(&loopHead);
1322 
1323     Bind(&exit);
1324     auto ret = *result;
1325     env->SubCfgExit();
1326     return ret;
1327 }
1328 
1329 // source is utf8, dst is utf16
CopyUtf8AsUtf16(GateRef glue,GateRef dst,GateRef src,GateRef sourceLength)1330 void BuiltinsStringStubBuilder::CopyUtf8AsUtf16(GateRef glue, GateRef dst, GateRef src,
1331     GateRef sourceLength)
1332 {
1333     auto env = GetEnvironment();
1334     Label entry(env);
1335     env->SubCfgEntry(&entry);
1336     DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
1337     DEFVARIABLE(sourceTmp, VariableType::NATIVE_POINTER(), src);
1338     DEFVARIABLE(len, VariableType::INT32(), sourceLength);
1339     Label loopHead(env);
1340     Label loopEnd(env);
1341     Label next(env);
1342     Label exit(env);
1343     Jump(&loopHead);
1344     LoopBegin(&loopHead);
1345     {
1346         Branch(Int32GreaterThan(*len, Int32(0)), &next, &exit);
1347         Bind(&next);
1348         {
1349             len = Int32Sub(*len, Int32(1));
1350             GateRef i = Load(VariableType::INT8(), *sourceTmp);
1351             Store(VariableType::INT16(), glue, *dstTmp, IntPtr(0), ZExtInt8ToInt16(i));
1352             Jump(&loopEnd);
1353         }
1354     }
1355 
1356     Bind(&loopEnd);
1357     sourceTmp = PtrAdd(*sourceTmp, IntPtr(sizeof(uint8_t)));
1358     dstTmp = PtrAdd(*dstTmp, IntPtr(sizeof(uint16_t)));
1359     LoopEnd(&loopHead);
1360 
1361     Bind(&exit);
1362     env->SubCfgExit();
1363     return;
1364 }
1365 
1366 // source is utf16, dst is utf8
CopyUtf16AsUtf8(GateRef glue,GateRef dst,GateRef src,GateRef sourceLength)1367 void BuiltinsStringStubBuilder::CopyUtf16AsUtf8(GateRef glue, GateRef dst, GateRef src,
1368     GateRef sourceLength)
1369 {
1370     auto env = GetEnvironment();
1371     Label entry(env);
1372     env->SubCfgEntry(&entry);
1373     DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
1374     DEFVARIABLE(sourceTmp, VariableType::NATIVE_POINTER(), src);
1375     DEFVARIABLE(len, VariableType::INT32(), sourceLength);
1376     Label loopHead(env);
1377     Label loopEnd(env);
1378     Label next(env);
1379     Label exit(env);
1380     Jump(&loopHead);
1381     LoopBegin(&loopHead);
1382     {
1383         Branch(Int32GreaterThan(*len, Int32(0)), &next, &exit);
1384         Bind(&next);
1385         {
1386             len = Int32Sub(*len, Int32(1));
1387             GateRef i = Load(VariableType::INT16(), *sourceTmp);
1388             Store(VariableType::INT8(), glue, *dstTmp, IntPtr(0), TruncInt16ToInt8(i));
1389             Jump(&loopEnd);
1390         }
1391     }
1392 
1393     Bind(&loopEnd);
1394     sourceTmp = PtrAdd(*sourceTmp, IntPtr(sizeof(uint16_t)));
1395     dstTmp = PtrAdd(*dstTmp, IntPtr(sizeof(uint8_t)));
1396     LoopEnd(&loopHead);
1397 
1398     Bind(&exit);
1399     env->SubCfgExit();
1400     return;
1401 }
1402 
GetUtf16Data(GateRef stringData,GateRef index)1403 GateRef BuiltinsStringStubBuilder::GetUtf16Data(GateRef stringData, GateRef index)
1404 {
1405     return ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(stringData,
1406         PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))))));
1407 }
1408 
IsASCIICharacter(GateRef data)1409 GateRef BuiltinsStringStubBuilder::IsASCIICharacter(GateRef data)
1410 {
1411     return Int32UnsignedLessThan(Int32Sub(data, Int32(1)), Int32(base::utf_helper::UTF8_1B_MAX));
1412 }
1413 
GetUtf8Data(GateRef stringData,GateRef index)1414 GateRef BuiltinsStringStubBuilder::GetUtf8Data(GateRef stringData, GateRef index)
1415 {
1416     return ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(stringData,
1417         PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
1418 }
1419 
StringIndexOf(GateRef lhsData,bool lhsIsUtf8,GateRef rhsData,bool rhsIsUtf8,GateRef pos,GateRef max,GateRef rhsCount)1420 GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhsData, bool lhsIsUtf8, GateRef rhsData, bool rhsIsUtf8,
1421                                                  GateRef pos, GateRef max, GateRef rhsCount)
1422 {
1423     auto env = GetEnvironment();
1424     Label entry(env);
1425     env->SubCfgEntry(&entry);
1426     DEFVARIABLE(i, VariableType::INT32(), pos);
1427     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
1428     DEFVARIABLE(j, VariableType::INT32(), Int32(0));
1429     DEFVARIABLE(k, VariableType::INT32(), Int32(1));
1430     Label exit(env);
1431     Label next(env);
1432     Label continueFor(env);
1433     Label lhsNotEqualFirst(env);
1434     Label continueCount(env);
1435     Label lessEnd(env);
1436     Label equalEnd(env);
1437     Label loopHead(env);
1438     Label loopEnd(env);
1439     Label nextCount(env);
1440     Label nextCount1(env);
1441     Label nextCount2(env);
1442     GateRef first;
1443     if (rhsIsUtf8) {
1444         first = ZExtInt8ToInt32(Load(VariableType::INT8(), rhsData));
1445     } else {
1446         first = ZExtInt16ToInt32(Load(VariableType::INT16(), rhsData));
1447     }
1448     Jump(&loopHead);
1449     LoopBegin(&loopHead);
1450     Branch(Int32LessThanOrEqual(*i, max), &next, &exit);
1451     Bind(&next);
1452     {
1453         Label loopHead1(env);
1454         Label loopEnd1(env);
1455         GateRef lhsTemp;
1456         if (lhsIsUtf8) {
1457             lhsTemp = GetUtf8Data(lhsData, *i);
1458         } else {
1459             lhsTemp = GetUtf16Data(lhsData, *i);
1460         }
1461         Branch(Int32NotEqual(lhsTemp, first), &nextCount1, &nextCount);
1462         Bind(&nextCount1);
1463         {
1464             i = Int32Add(*i, Int32(1));
1465             Jump(&loopHead1);
1466         }
1467         LoopBegin(&loopHead1);
1468         {
1469             Branch(Int32LessThanOrEqual(*i, max), &continueFor, &nextCount);
1470             Bind(&continueFor);
1471             {
1472                 GateRef lhsTemp1;
1473                 if (lhsIsUtf8) {
1474                     lhsTemp1 = GetUtf8Data(lhsData, *i);
1475                 } else {
1476                     lhsTemp1 = GetUtf16Data(lhsData, *i);
1477                 }
1478                 Branch(Int32NotEqual(lhsTemp1, first), &lhsNotEqualFirst, &nextCount);
1479                 Bind(&lhsNotEqualFirst);
1480                 {
1481                     i = Int32Add(*i, Int32(1));
1482                     Jump(&loopEnd1);
1483                 }
1484             }
1485         }
1486         Bind(&loopEnd1);
1487         LoopEnd(&loopHead1);
1488         Bind(&nextCount);
1489         {
1490             Branch(Int32LessThanOrEqual(*i, max), &continueCount, &loopEnd);
1491             Bind(&continueCount);
1492             {
1493                 Label loopHead2(env);
1494                 Label loopEnd2(env);
1495                 j = Int32Add(*i, Int32(1));
1496                 GateRef end = Int32Sub(Int32Add(*j, rhsCount), Int32(1));
1497                 k = Int32(1);
1498                 Jump(&loopHead2);
1499                 LoopBegin(&loopHead2);
1500                 {
1501                     Branch(Int32LessThan(*j, end), &lessEnd, &nextCount2);
1502                     Bind(&lessEnd);
1503                     {
1504                         GateRef lhsTemp2;
1505                         if (lhsIsUtf8) {
1506                             lhsTemp2 = GetUtf8Data(lhsData, *j);
1507                         } else {
1508                             lhsTemp2 = GetUtf16Data(lhsData, *j);
1509                         }
1510                         GateRef rhsTemp;
1511                         if (rhsIsUtf8) {
1512                             rhsTemp = GetUtf8Data(rhsData, *k);
1513                         } else {
1514                             rhsTemp = GetUtf16Data(rhsData, *k);
1515                         }
1516                         Branch(Int32Equal(lhsTemp2, rhsTemp), &loopEnd2, &nextCount2);
1517                     }
1518                 }
1519                 Bind(&loopEnd2);
1520                 j = Int32Add(*j, Int32(1));
1521                 k = Int32Add(*k, Int32(1));
1522                 LoopEnd(&loopHead2);
1523                 Bind(&nextCount2);
1524                 {
1525                     Branch(Int32Equal(*j, end), &equalEnd, &loopEnd);
1526                     Bind(&equalEnd);
1527                     result = *i;
1528                     Jump(&exit);
1529                 }
1530             }
1531         }
1532     }
1533     Bind(&loopEnd);
1534     i = Int32Add(*i, Int32(1));
1535     LoopEnd(&loopHead);
1536 
1537     Bind(&exit);
1538     auto ret = *result;
1539     env->SubCfgExit();
1540     return ret;
1541 }
1542 
1543 
StoreParent(GateRef glue,GateRef object,GateRef parent)1544 void BuiltinsStringStubBuilder::StoreParent(GateRef glue, GateRef object, GateRef parent)
1545 {
1546     Store(VariableType::JS_POINTER(), glue, object, IntPtr(SlicedString::PARENT_OFFSET), parent);
1547 }
1548 
StoreStartIndex(GateRef glue,GateRef object,GateRef startIndex)1549 void BuiltinsStringStubBuilder::StoreStartIndex(GateRef glue, GateRef object, GateRef startIndex)
1550 {
1551     Store(VariableType::INT32(), glue, object, IntPtr(SlicedString::STARTINDEX_OFFSET), startIndex);
1552 }
1553 
StoreHasBackingStore(GateRef glue,GateRef object,GateRef hasBackingStore)1554 void BuiltinsStringStubBuilder::StoreHasBackingStore(GateRef glue, GateRef object, GateRef hasBackingStore)
1555 {
1556     Store(VariableType::INT32(), glue, object, IntPtr(SlicedString::BACKING_STORE_FLAG), hasBackingStore);
1557 }
1558 
StringIndexOf(const StringInfoGateRef & lStringInfoGate,const StringInfoGateRef & rStringInfoGate,GateRef pos)1559 GateRef BuiltinsStringStubBuilder::StringIndexOf(const StringInfoGateRef &lStringInfoGate,
1560     const StringInfoGateRef &rStringInfoGate, GateRef pos)
1561 {
1562     auto env = GetEnvironment();
1563     Label entry(env);
1564     env->SubCfgEntry(&entry);
1565     DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
1566     DEFVARIABLE(posTag, VariableType::INT32(), pos);
1567     Label exit(env);
1568     Label rhsCountEqualZero(env);
1569     Label nextCount(env);
1570     Label rhsCountNotEqualZero(env);
1571     Label posLessZero(env);
1572     Label posNotLessZero(env);
1573     Label maxNotLessZero(env);
1574     Label rhsIsUtf8(env);
1575     Label rhsIsUtf16(env);
1576     Label posRMaxNotGreaterLhs(env);
1577 
1578     GateRef lhsCount = lStringInfoGate.GetLength();
1579     GateRef rhsCount = rStringInfoGate.GetLength();
1580 
1581     Branch(Int32GreaterThan(pos, lhsCount), &exit, &nextCount);
1582     Bind(&nextCount);
1583     {
1584         Branch(Int32Equal(rhsCount, Int32(0)), &rhsCountEqualZero, &rhsCountNotEqualZero);
1585         Bind(&rhsCountEqualZero);
1586         {
1587             result = pos;
1588             Jump(&exit);
1589         }
1590         Bind(&rhsCountNotEqualZero);
1591         {
1592             Branch(Int32LessThan(pos, Int32(0)), &posLessZero, &posNotLessZero);
1593             Bind(&posLessZero);
1594             {
1595                 posTag = Int32(0);
1596                 Jump(&posNotLessZero);
1597             }
1598             Bind(&posNotLessZero);
1599             {
1600                 GateRef max = Int32Sub(lhsCount, rhsCount);
1601                 Branch(Int32LessThan(max, Int32(0)), &exit, &maxNotLessZero);
1602                 Bind(&maxNotLessZero);
1603                 {
1604                     GateRef posRMax = Int32Add(*posTag, rhsCount);
1605                     Branch(Int32GreaterThan(posRMax, lhsCount), &exit, &posRMaxNotGreaterLhs);
1606                     Bind(&posRMaxNotGreaterLhs);
1607                     GateRef rhsData = GetNormalStringData(rStringInfoGate);
1608                     GateRef lhsData = GetNormalStringData(lStringInfoGate);
1609                     Branch(IsUtf8String(rStringInfoGate.GetString()), &rhsIsUtf8, &rhsIsUtf16);
1610                     Bind(&rhsIsUtf8);
1611                     {
1612                         Label lhsIsUtf8(env);
1613                         Label lhsIsUtf16(env);
1614                         Branch(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
1615                         Bind(&lhsIsUtf8);
1616                         {
1617                             result = StringIndexOf(lhsData, true, rhsData, true, *posTag, max, rhsCount);
1618                             Jump(&exit);
1619                         }
1620                         Bind(&lhsIsUtf16);
1621                         {
1622                             result = StringIndexOf(lhsData, false, rhsData, true, *posTag, max, rhsCount);
1623                             Jump(&exit);
1624                         }
1625                     }
1626                     Bind(&rhsIsUtf16);
1627                     {
1628                         Label lhsIsUtf8(env);
1629                         Label lhsIsUtf16(env);
1630                         Branch(IsUtf8String(lStringInfoGate.GetString()), &lhsIsUtf8, &lhsIsUtf16);
1631                         Bind(&lhsIsUtf8);
1632                         {
1633                             result = StringIndexOf(lhsData, true, rhsData, false, *posTag, max, rhsCount);
1634                             Jump(&exit);
1635                         }
1636                         Bind(&lhsIsUtf16);
1637                         {
1638                             result = StringIndexOf(lhsData, false, rhsData, false, *posTag, max, rhsCount);
1639                             Jump(&exit);
1640                         }
1641                     }
1642                 }
1643             }
1644         }
1645     }
1646     Bind(&exit);
1647     auto ret = *result;
1648     env->SubCfgExit();
1649     return ret;
1650 }
1651 
FlattenString(GateRef glue,GateRef str,Label * fastPath)1652 void FlatStringStubBuilder::FlattenString(GateRef glue, GateRef str, Label *fastPath)
1653 {
1654     auto env = GetEnvironment();
1655     Label notLineString(env);
1656     Label exit(env);
1657     length_ = GetLengthFromString(str);
1658     Branch(BoolOr(IsLineString(str), IsConstantString(str)), &exit, &notLineString);
1659     Bind(&notLineString);
1660     {
1661         Label isTreeString(env);
1662         Label notTreeString(env);
1663         Label isSlicedString(env);
1664         Branch(IsTreeString(str), &isTreeString, &notTreeString);
1665         Bind(&isTreeString);
1666         {
1667             Label isFlat(env);
1668             Label notFlat(env);
1669             Branch(TreeStringIsFlat(str), &isFlat, &notFlat);
1670             Bind(&isFlat);
1671             {
1672                 flatString_.WriteVariable(GetFirstFromTreeString(str));
1673                 Jump(fastPath);
1674             }
1675             Bind(&notFlat);
1676             {
1677                 flatString_.WriteVariable(CallRuntime(glue, RTSTUB_ID(SlowFlattenString), { str }));
1678                 Jump(fastPath);
1679             }
1680         }
1681         Bind(&notTreeString);
1682         Branch(IsSlicedString(str), &isSlicedString, &exit);
1683         Bind(&isSlicedString);
1684         {
1685             flatString_.WriteVariable(GetParentFromSlicedString(str));
1686             startIndex_.WriteVariable(GetStartIndexFromSlicedString(str));
1687             Jump(fastPath);
1688         }
1689     }
1690     Bind(&exit);
1691     {
1692         flatString_.WriteVariable(str);
1693         Jump(fastPath);
1694     }
1695 }
1696 
GetStringDataFromLineOrConstantString(GateRef str)1697 GateRef BuiltinsStringStubBuilder::GetStringDataFromLineOrConstantString(GateRef str)
1698 {
1699     auto env = GetEnvironment();
1700     Label entry(env);
1701     env->SubCfgEntry(&entry);
1702     Label exit(env);
1703     Label isConstantString(env);
1704     Label isLineString(env);
1705     DEFVARIABLE(result, VariableType::NATIVE_POINTER(), IntPtr(0));
1706     Branch(IsConstantString(str), &isConstantString, &isLineString);
1707     Bind(&isConstantString);
1708     {
1709         GateRef address = ChangeStringTaggedPointerToInt64(PtrAdd(str, IntPtr(ConstantString::CONSTANT_DATA_OFFSET)));
1710         result = Load(VariableType::NATIVE_POINTER(), address, IntPtr(0));
1711         Jump(&exit);
1712     }
1713     Bind(&isLineString);
1714     {
1715         result = ChangeStringTaggedPointerToInt64(PtrAdd(str, IntPtr(LineEcmaString::DATA_OFFSET)));
1716         Jump(&exit);
1717     }
1718     Bind(&exit);
1719     auto ret = *result;
1720     env->SubCfgExit();
1721     return ret;
1722 }
1723 
StringConcat(GateRef glue,GateRef leftString,GateRef rightString)1724 GateRef BuiltinsStringStubBuilder::StringConcat(GateRef glue, GateRef leftString, GateRef rightString)
1725 {
1726     auto env = GetEnvironment();
1727     Label entry(env);
1728     env->SubCfgEntry(&entry);
1729     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
1730     Label exit(env);
1731     Label equalZero(env);
1732     Label notEqualZero(env);
1733     Label lessThanMax(env);
1734     Label throwError(env);
1735 
1736     GateRef leftLength = GetLengthFromString(leftString);
1737     GateRef rightLength = GetLengthFromString(rightString);
1738     GateRef newLength = Int32Add(leftLength, rightLength);
1739     Branch(Int32GreaterThanOrEqual(newLength, Int32(EcmaString::MAX_STRING_LENGTH)), &throwError, &lessThanMax);
1740     Bind(&throwError);
1741     {
1742         GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InvalidStringLength));
1743         CallRuntime(glue, RTSTUB_ID(ThrowRangeError), { IntToTaggedInt(taggedId) });
1744         Jump(&exit);
1745     }
1746     Bind(&lessThanMax);
1747     Branch(Int32Equal(newLength, Int32(0)), &equalZero, &notEqualZero);
1748     Bind(&equalZero);
1749     {
1750         result = GetGlobalConstantValue(
1751             VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
1752         Jump(&exit);
1753     }
1754     Bind(&notEqualZero);
1755     {
1756         Label leftEqualZero(env);
1757         Label leftNotEqualZero(env);
1758         Label rightEqualZero(env);
1759         Label rightNotEqualZero(env);
1760         Label newLineString(env);
1761         Label newTreeString(env);
1762         Branch(Int32Equal(leftLength, Int32(0)), &leftEqualZero, &leftNotEqualZero);
1763         Bind(&leftEqualZero);
1764         {
1765             result = rightString;
1766             Jump(&exit);
1767         }
1768         Bind(&leftNotEqualZero);
1769         Branch(Int32Equal(rightLength, Int32(0)), &rightEqualZero, &rightNotEqualZero);
1770         Bind(&rightEqualZero);
1771         {
1772             result = leftString;
1773             Jump(&exit);
1774         }
1775         Bind(&rightNotEqualZero);
1776         {
1777             GateRef leftIsUtf8 = IsUtf8String(leftString);
1778             GateRef rightIsUtf8 = IsUtf8String(rightString);
1779             GateRef canBeCompressed = BoolAnd(leftIsUtf8, rightIsUtf8);
1780             NewObjectStubBuilder newBuilder(this);
1781             newBuilder.SetParameters(glue, 0);
1782             GateRef isTreeOrSlicedString = Int32LessThan(newLength,
1783                 Int32(std::min(TreeEcmaString::MIN_TREE_ECMASTRING_LENGTH,
1784                                SlicedString::MIN_SLICED_ECMASTRING_LENGTH)));
1785             Branch(isTreeOrSlicedString, &newLineString, &newTreeString);
1786             Bind(&newLineString);
1787             {
1788                 Label isUtf8(env);
1789                 Label isUtf16(env);
1790                 Label isUtf8Next(env);
1791                 Label isUtf16Next(env);
1792                 Branch(canBeCompressed, &isUtf8, &isUtf16);
1793                 Bind(&isUtf8);
1794                 {
1795                     newBuilder.AllocLineStringObject(&result, &isUtf8Next, newLength, true);
1796                 }
1797                 Bind(&isUtf16);
1798                 {
1799                     newBuilder.AllocLineStringObject(&result, &isUtf16Next, newLength, false);
1800                 }
1801                 Bind(&isUtf8Next);
1802                 {
1803                     GateRef leftSource = GetStringDataFromLineOrConstantString(leftString);
1804                     GateRef rightSource = GetStringDataFromLineOrConstantString(rightString);
1805                     GateRef leftDst = ChangeStringTaggedPointerToInt64(
1806                         PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
1807                     GateRef rightDst = ChangeStringTaggedPointerToInt64(PtrAdd(leftDst, ZExtInt32ToPtr(leftLength)));
1808                     CopyChars(glue, leftDst, leftSource, leftLength, IntPtr(sizeof(uint8_t)), VariableType::INT8());
1809                     CopyChars(glue, rightDst, rightSource, rightLength, IntPtr(sizeof(uint8_t)), VariableType::INT8());
1810                     Jump(&exit);
1811                 }
1812                 Bind(&isUtf16Next);
1813                 {
1814                     Label leftIsUtf8L(env);
1815                     Label leftIsUtf16L(env);
1816                     Label rightIsUtf8L(env);
1817                     Label rightIsUtf16L(env);
1818                     GateRef leftSource = GetStringDataFromLineOrConstantString(leftString);
1819                     GateRef rightSource = GetStringDataFromLineOrConstantString(rightString);
1820                     GateRef leftDst = ChangeStringTaggedPointerToInt64(
1821                         PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
1822                     GateRef rightDst = ChangeStringTaggedPointerToInt64(
1823                         PtrAdd(leftDst, PtrMul(ZExtInt32ToPtr(leftLength), IntPtr(sizeof(uint16_t)))));
1824                     Branch(leftIsUtf8, &leftIsUtf8L, &leftIsUtf16L);
1825                     Bind(&leftIsUtf8L);
1826                     {
1827                         // left is utf8,right string must utf16
1828                         CopyUtf8AsUtf16(glue, leftDst, leftSource, leftLength);
1829                         CopyChars(glue, rightDst, rightSource, rightLength,
1830                             IntPtr(sizeof(uint16_t)), VariableType::INT16());
1831                         Jump(&exit);
1832                     }
1833                     Bind(&leftIsUtf16L);
1834                     {
1835                         CopyChars(glue, leftDst, leftSource, leftLength,
1836                             IntPtr(sizeof(uint16_t)), VariableType::INT16());
1837                         Branch(rightIsUtf8, &rightIsUtf8L, &rightIsUtf16L);
1838                         Bind(&rightIsUtf8L);
1839                         CopyUtf8AsUtf16(glue, rightDst, rightSource, rightLength);
1840                         Jump(&exit);
1841                         Bind(&rightIsUtf16L);
1842                         CopyChars(glue, rightDst, rightSource, rightLength,
1843                             IntPtr(sizeof(uint16_t)), VariableType::INT16());
1844                         Jump(&exit);
1845                     }
1846                 }
1847             }
1848             Bind(&newTreeString);
1849             {
1850                 Label isUtf8(env);
1851                 Label isUtf16(env);
1852                 Branch(canBeCompressed, &isUtf8, &isUtf16);
1853                 Bind(&isUtf8);
1854                 {
1855                     newBuilder.AllocTreeStringObject(&result, &exit, leftString, rightString, newLength, true);
1856                 }
1857                 Bind(&isUtf16);
1858                 {
1859                     newBuilder.AllocTreeStringObject(&result, &exit, leftString, rightString, newLength, false);
1860                 }
1861             }
1862         }
1863     }
1864     Bind(&exit);
1865     auto ret = *result;
1866     env->SubCfgExit();
1867     return ret;
1868 }
1869 
LocaleCompare(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)1870 void BuiltinsStringStubBuilder::LocaleCompare([[maybe_unused]] GateRef glue, GateRef thisValue, GateRef numArgs,
1871                                               [[maybe_unused]] Variable *res, [[maybe_unused]] Label *exit,
1872                                               Label *slowPath)
1873 {
1874     auto env = GetEnvironment();
1875 
1876     Label thisIsHeapObj(env);
1877     Branch(TaggedIsHeapObject(thisValue), &thisIsHeapObj, slowPath);
1878     Bind(&thisIsHeapObj);
1879     {
1880         Label thisValueIsString(env);
1881         Label fristArgIsString(env);
1882         Label arg0IsHeapObj(env);
1883         Branch(IsString(thisValue), &thisValueIsString, slowPath);
1884         Bind(&thisValueIsString);
1885         GateRef arg0 = GetCallArg0(numArgs);
1886         Branch(TaggedIsHeapObject(arg0), &arg0IsHeapObj, slowPath);
1887         Bind(&arg0IsHeapObj);
1888         Branch(IsString(arg0), &fristArgIsString, slowPath);
1889         Bind(&fristArgIsString);
1890 #ifdef ARK_SUPPORT_INTL
1891         GateRef locales = GetCallArg1(numArgs);
1892 
1893         GateRef options = GetCallArg2(numArgs);
1894         GateRef localesIsUndef = TaggedIsUndefined(locales);
1895         GateRef optionsIsUndef = TaggedIsUndefined(options);
1896         GateRef cacheable = BoolAnd(BoolOr(localesIsUndef, TaggedIsString(locales)), optionsIsUndef);
1897         Label optionsIsString(env);
1898         Label cacheAble(env);
1899         Label uncacheable(env);
1900 
1901         Branch(cacheable, &cacheAble, &uncacheable);
1902         Bind(&cacheAble);
1903         {
1904             Label defvalue(env);
1905             GateRef resValue = CallNGCRuntime(glue, RTSTUB_ID(LocaleCompareNoGc), {glue, locales, thisValue, arg0});
1906             Branch(TaggedIsUndefined(resValue), slowPath, &defvalue);
1907             Bind(&defvalue);
1908             *res = resValue;
1909             Jump(exit);
1910         }
1911         Bind(&uncacheable);
1912         {
1913             res->WriteVariable(CallRuntime(glue, RTSTUB_ID(LocaleCompareWithGc), {locales, thisValue, arg0, options}));
1914             Jump(exit);
1915         }
1916 #else
1917     Jump(slowPath);
1918 #endif
1919     }
1920 }
1921 
EcmaStringTrim(GateRef glue,GateRef thisValue,GateRef trimMode)1922 GateRef BuiltinsStringStubBuilder::EcmaStringTrim(GateRef glue, GateRef thisValue, GateRef trimMode)
1923 {
1924     auto env = GetEnvironment();
1925 
1926     Label entry(env);
1927     env->SubCfgEntry(&entry);
1928 
1929     DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
1930 
1931     Label emptyString(env);
1932     Label notEmpty(env);
1933     Label exit(env);
1934 
1935     GateRef srcLen = GetLengthFromString(thisValue);
1936     Branch(Int32Equal(srcLen, Int32(0)), &emptyString, &notEmpty);
1937     Bind(&emptyString);
1938     {
1939         result = GetGlobalConstantValue(
1940             VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
1941         Jump(&exit);
1942     }
1943     Bind(&notEmpty);
1944     {
1945         Label srcFlattenFastPath(env);
1946 
1947         FlatStringStubBuilder srcFlat(this);
1948         srcFlat.FlattenString(glue, thisValue, &srcFlattenFastPath);
1949         Bind(&srcFlattenFastPath);
1950         StringInfoGateRef srcStringInfoGate(&srcFlat);
1951         result = EcmaStringTrimBody(glue, thisValue, srcStringInfoGate, trimMode, IsUtf8String(thisValue));
1952         Jump(&exit);
1953     }
1954     Bind(&exit);
1955     auto ret = *result;
1956     env->SubCfgExit();
1957     return ret;
1958 }
1959 
EcmaStringTrimBody(GateRef glue,GateRef thisValue,StringInfoGateRef srcStringInfoGate,GateRef trimMode,GateRef isUtf8)1960 GateRef BuiltinsStringStubBuilder::EcmaStringTrimBody(GateRef glue, GateRef thisValue,
1961     StringInfoGateRef srcStringInfoGate, GateRef trimMode, GateRef isUtf8)
1962 {
1963     auto env = GetEnvironment();
1964 
1965     Label entry(env);
1966     env->SubCfgEntry(&entry);
1967 
1968     GateRef srcLen = srcStringInfoGate.GetLength();
1969     GateRef srcString = srcStringInfoGate.GetString();
1970     GateRef startIndex = srcStringInfoGate.GetStartIndex();
1971 
1972     DEFVARIABLE(start, VariableType::INT32(), Int32(0));
1973     DEFVARIABLE(end, VariableType::INT32(), Int32Sub(srcLen, Int32(1)));
1974 
1975     Label trimOrTrimStart(env);
1976     Label notTrimStart(env);
1977     Label next(env);
1978 
1979     Branch(Int32GreaterThanOrEqual(trimMode, Int32(0)), &trimOrTrimStart, &notTrimStart);
1980     Bind(&trimOrTrimStart); // mode = TrimMode::TRIM or TrimMode::TRIM_START
1981     {
1982         start = CallNGCRuntime(glue, RTSTUB_ID(StringGetStart), {isUtf8, srcString, srcLen, startIndex});
1983         Jump(&notTrimStart);
1984     }
1985     Bind(&notTrimStart);
1986     {
1987         Label trimOrTrimEnd(env);
1988         Branch(Int32LessThanOrEqual(trimMode, Int32(0)), &trimOrTrimEnd, &next);
1989         Bind(&trimOrTrimEnd); // mode = TrimMode::TRIM or TrimMode::TRIM_END
1990         {
1991             end = CallNGCRuntime(glue, RTSTUB_ID(StringGetEnd), {isUtf8, srcString, *start, srcLen, startIndex});
1992             Jump(&next);
1993         }
1994     }
1995     Bind(&next);
1996     {
1997         auto ret = FastSubString(glue, thisValue, *start,
1998                                  Int32Add(Int32Sub(*end, *start), Int32(1)), srcStringInfoGate);
1999         env->SubCfgExit();
2000         return ret;
2001     }
2002 }
2003 }  // namespace panda::ecmascript::kungfu
2004