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