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