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