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