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