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