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/containers_stub_builder.h" 17#include "ecmascript/compiler/builtins/containers_vector_stub_builder.h" 18 19#include "ecmascript/compiler/call_stub_builder.h" 20 21namespace panda::ecmascript::kungfu { 22// common IR for containers apis that use function call 23void ContainersStubBuilder::ContainersCommonFuncCall(GateRef glue, GateRef thisValue, 24 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) 25{ 26 auto env = GetEnvironment(); 27 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); 28 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); 29 DEFVARIABLE(key, VariableType::INT64(), Int64(0)); 30 DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined()); 31 DEFVARIABLE(length, VariableType::INT32(), Int32(0)); 32 DEFVARIABLE(k, VariableType::INT32(), Int32(0)); 33 Label valueIsJSAPIVector(env); 34 Label valueNotJSAPIVector(env); 35 Label objIsJSProxy(env); 36 Label objNotJSProxy(env); 37 Label objIsJSAPIVector(env); 38 Label thisArgUndefined(env); 39 Label thisArgNotUndefined(env); 40 Label callbackUndefined(env); 41 Label callbackNotUndefined(env); 42 Label nextCount(env); 43 Label loopHead(env); 44 Label loopEnd(env); 45 Label next(env); 46 Label afterLoop(env); 47 GateRef callbackFnHandle; 48 BRANCH(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector); 49 Bind(&valueNotJSAPIVector); 50 { 51 BRANCH(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); 52 Bind(&objIsJSProxy); 53 { 54 GateRef tempObj = GetTarget(*thisObj); 55 BRANCH(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath); 56 Bind(&objIsJSAPIVector); 57 { 58 thisObj = tempObj; 59 Jump(&valueIsJSAPIVector); 60 } 61 } 62 Bind(&objNotJSProxy); 63 Jump(slowPath); 64 } 65 Bind(&valueIsJSAPIVector); 66 { 67 BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); 68 Bind(&callbackUndefined); 69 Jump(slowPath); 70 Bind(&callbackNotUndefined); 71 { 72 Label isCall(env); 73 Label notCall(env); 74 Label isHeapObj(env); 75 callbackFnHandle = GetCallArg0(numArgs); 76 BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath); 77 Bind(&isHeapObj); 78 BRANCH(IsCallable(callbackFnHandle), &isCall, ¬Call); 79 Bind(¬Call); 80 Jump(slowPath); 81 Bind(&isCall); 82 { 83 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); 84 Bind(&thisArgUndefined); 85 Jump(&nextCount); 86 Bind(&thisArgNotUndefined); 87 thisArg = GetCallArg1(numArgs); 88 Jump(&nextCount); 89 } 90 } 91 } 92 Bind(&nextCount); 93 { 94 length = ContainerGetSize(*thisObj, type); 95 Jump(&loopHead); 96 LoopBegin(&loopHead); 97 { 98 Label lenChange(env); 99 Label hasException(env); 100 Label notHasException(env); 101 Label setValue(env); 102 BRANCH(Int32LessThan(*k, *length), &next, &afterLoop); 103 Bind(&next); 104 { 105 kValue = ContainerGetValue(*thisObj, *k, type); 106 if (IsPlainArray(type)) { 107 key = PlainArrayGetKey(*thisObj, *k); 108 } else { 109 key = IntToTaggedInt(*k); 110 } 111 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN); 112 callArgs.callThisArg3WithReturnArgs = { *thisArg, *kValue, *key, *thisObj }; 113 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr, 114 Circuit::NullGate(), callArgs); 115 GateRef retValue = callBuilder.JSCallDispatch(); 116 BRANCH(HasPendingException(glue), &hasException, ¬HasException); 117 Bind(&hasException); 118 { 119 result->WriteVariable(retValue); 120 Jump(exit); 121 } 122 Bind(¬HasException); 123 GateRef tempLen = ContainerGetSize(*thisObj, type); 124 BRANCH(Int32NotEqual(tempLen, *length), &lenChange, &setValue); 125 Bind(&lenChange); 126 if (!IsArrayListReplaceAllelements(type)) { 127 length = tempLen; 128 } 129 BRANCH(Int32GreaterThanOrEqual(*k, *length), &afterLoop, &setValue); 130 Bind(&setValue); 131 if (IsReplaceAllElements(type)) { 132 ContainerSet(glue, *thisObj, *k, retValue, type); 133 } 134 Jump(&loopEnd); 135 } 136 } 137 Bind(&loopEnd); 138 k = Int32Add(*k, Int32(1)); 139 LoopEnd(&loopHead, env, glue); 140 } 141 Bind(&afterLoop); 142 Jump(exit); 143} 144 145void ContainersStubBuilder::QueueCommonFuncCall(GateRef glue, GateRef thisValue, 146 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) 147{ 148 auto env = GetEnvironment(); 149 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); 150 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); 151 DEFVARIABLE(key, VariableType::INT64(), Int64(0)); 152 DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined()); 153 DEFVARIABLE(length, VariableType::INT32(), Int32(0)); 154 DEFVARIABLE(k, VariableType::INT32(), Int32(0)); 155 DEFVARIABLE(index, VariableType::INT32(), Int32(0)); 156 Label valueIsJSAPIVector(env); 157 Label valueNotJSAPIVector(env); 158 Label objIsJSProxy(env); 159 Label objNotJSProxy(env); 160 Label objIsJSAPIVector(env); 161 Label thisArgUndefined(env); 162 Label thisArgNotUndefined(env); 163 Label callbackUndefined(env); 164 Label callbackNotUndefined(env); 165 Label nextCount(env); 166 Label loopHead(env); 167 Label loopEnd(env); 168 Label next(env); 169 Label afterLoop(env); 170 GateRef callbackFnHandle; 171 BRANCH(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector); 172 Bind(&valueNotJSAPIVector); 173 { 174 BRANCH(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); 175 Bind(&objIsJSProxy); 176 { 177 GateRef tempObj = GetTarget(*thisObj); 178 BRANCH(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath); 179 Bind(&objIsJSAPIVector); 180 { 181 thisObj = tempObj; 182 Jump(&valueIsJSAPIVector); 183 } 184 } 185 Bind(&objNotJSProxy); 186 Jump(slowPath); 187 } 188 Bind(&valueIsJSAPIVector); 189 { 190 BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); 191 Bind(&callbackUndefined); 192 Jump(slowPath); 193 Bind(&callbackNotUndefined); 194 { 195 Label isCall(env); 196 Label notCall(env); 197 Label isHeapObj(env); 198 callbackFnHandle = GetCallArg0(numArgs); 199 BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath); 200 Bind(&isHeapObj); 201 BRANCH(IsCallable(callbackFnHandle), &isCall, ¬Call); 202 Bind(¬Call); 203 Jump(slowPath); 204 Bind(&isCall); 205 { 206 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); 207 Bind(&thisArgUndefined); 208 Jump(&nextCount); 209 Bind(&thisArgNotUndefined); 210 thisArg = GetCallArg1(numArgs); 211 Jump(&nextCount); 212 } 213 } 214 } 215 Bind(&nextCount); 216 { 217 length = ContainerGetSize(*thisObj, type); 218 Jump(&loopHead); 219 LoopBegin(&loopHead); 220 { 221 Label lenChange(env); 222 Label hasException(env); 223 Label notHasException(env); 224 Label setValue(env); 225 BRANCH(Int32LessThan(*k, *length), &next, &afterLoop); 226 Bind(&next); 227 { 228 kValue = ContainerGetValue(*thisObj, *index, type); 229 index = QueueGetNextPosition(*thisObj, *index); 230 key = IntToTaggedInt(*k); 231 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN); 232 callArgs.callThisArg3WithReturnArgs = { *thisArg, *kValue, *key, *thisObj }; 233 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr, 234 Circuit::NullGate(), callArgs); 235 GateRef retValue = callBuilder.JSCallDispatch(); 236 BRANCH(HasPendingException(glue), &hasException, ¬HasException); 237 Bind(&hasException); 238 { 239 result->WriteVariable(retValue); 240 Jump(exit); 241 } 242 Bind(¬HasException); 243 Jump(&loopEnd); 244 } 245 } 246 Bind(&loopEnd); 247 k = Int32Add(*k, Int32(1)); 248 LoopEnd(&loopHead, env, glue); 249 } 250 Bind(&afterLoop); 251 Jump(exit); 252} 253 254void ContainersStubBuilder::DequeCommonFuncCall(GateRef glue, GateRef thisValue, 255 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) 256{ 257 auto env = GetEnvironment(); 258 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); 259 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); 260 DEFVARIABLE(key, VariableType::INT64(), Int64(0)); 261 DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined()); 262 DEFVARIABLE(length, VariableType::INT32(), Int32(0)); 263 DEFVARIABLE(first, VariableType::INT32(), Int32(0)); 264 DEFVARIABLE(index, VariableType::INT32(), Int32(0)); 265 Label valueIsJSAPIVector(env); 266 Label valueNotJSAPIVector(env); 267 Label objIsJSProxy(env); 268 Label objNotJSProxy(env); 269 Label objIsJSAPIVector(env); 270 Label thisArgUndefined(env); 271 Label thisArgNotUndefined(env); 272 Label callbackUndefined(env); 273 Label callbackNotUndefined(env); 274 Label nextCount(env); 275 Label loopHead(env); 276 Label loopEnd(env); 277 Label next(env); 278 Label afterLoop(env); 279 GateRef callbackFnHandle; 280 BRANCH(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector); 281 Bind(&valueNotJSAPIVector); 282 { 283 BRANCH(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); 284 Bind(&objIsJSProxy); 285 { 286 GateRef tempObj = GetTarget(*thisObj); 287 BRANCH(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath); 288 Bind(&objIsJSAPIVector); 289 { 290 thisObj = tempObj; 291 Jump(&valueIsJSAPIVector); 292 } 293 } 294 Bind(&objNotJSProxy); 295 Jump(slowPath); 296 } 297 Bind(&valueIsJSAPIVector); 298 { 299 BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); 300 Bind(&callbackUndefined); 301 Jump(slowPath); 302 Bind(&callbackNotUndefined); 303 { 304 Label isCall(env); 305 Label notCall(env); 306 Label isHeapObj(env); 307 callbackFnHandle = GetCallArg0(numArgs); 308 BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath); 309 Bind(&isHeapObj); 310 BRANCH(IsCallable(callbackFnHandle), &isCall, ¬Call); 311 Bind(¬Call); 312 Jump(slowPath); 313 Bind(&isCall); 314 { 315 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); 316 Bind(&thisArgUndefined); 317 Jump(&nextCount); 318 Bind(&thisArgNotUndefined); 319 thisArg = GetCallArg1(numArgs); 320 Jump(&nextCount); 321 } 322 } 323 } 324 Bind(&nextCount); 325 { 326 ContainersDequeStubBuilder dequeBuilder(this); 327 first = dequeBuilder.GetFirst(*thisObj); 328 GateRef last = dequeBuilder.GetLast(*thisObj); 329 GateRef capacity = dequeBuilder.GetElementsLength(*thisObj); 330 Jump(&loopHead); 331 LoopBegin(&loopHead); 332 { 333 Label lenChange(env); 334 Label hasException(env); 335 Label notHasException(env); 336 Label setValue(env); 337 BRANCH(Int32NotEqual(*first, last), &next, &afterLoop); 338 Bind(&next); 339 { 340 kValue = ContainerGetValue(*thisObj, *index, type); 341 key = IntToTaggedInt(*index); 342 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN); 343 callArgs.callThisArg3WithReturnArgs = { *thisArg, *kValue, *key, *thisObj }; 344 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr, 345 Circuit::NullGate(), callArgs); 346 GateRef retValue = callBuilder.JSCallDispatch(); 347 BRANCH(HasPendingException(glue), &hasException, ¬HasException); 348 Bind(&hasException); 349 { 350 result->WriteVariable(retValue); 351 Jump(exit); 352 } 353 Bind(¬HasException); 354 Jump(&loopEnd); 355 } 356 } 357 Bind(&loopEnd); 358 first = Int32Mod(Int32Add(*first, Int32(1)), capacity); 359 index = Int32Add(*index, Int32(1)); 360 LoopEnd(&loopHead, env, glue); 361 } 362 Bind(&afterLoop); 363 Jump(exit); 364} 365 366void ContainersStubBuilder::ContainersLightWeightCall(GateRef glue, GateRef thisValue, 367 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) 368{ 369 auto env = GetEnvironment(); 370 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); 371 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); 372 DEFVARIABLE(key, VariableType::JS_ANY(), Undefined()); 373 DEFVARIABLE(value, VariableType::JS_ANY(), Undefined()); 374 DEFVARIABLE(length, VariableType::INT32(), Int32(0)); 375 DEFVARIABLE(index, VariableType::INT32(), Int32(0)); 376 Label valueIsJSAPILightWeight(env); 377 Label valueNotJSAPILightWeight(env); 378 Label objIsJSProxy(env); 379 Label objNotJSProxy(env); 380 Label objIsJSAPILightWeight(env); 381 Label thisArgUndefined(env); 382 Label thisArgNotUndefined(env); 383 Label callbackUndefined(env); 384 Label callbackNotUndefined(env); 385 Label nextCount(env); 386 Label loopHead(env); 387 Label loopEnd(env); 388 Label next(env); 389 Label afterLoop(env); 390 GateRef callbackFnHandle; 391 BRANCH(IsContainer(*thisObj, type), &valueIsJSAPILightWeight, &valueNotJSAPILightWeight); 392 Bind(&valueNotJSAPILightWeight); 393 { 394 BRANCH(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); 395 Bind(&objIsJSProxy); 396 { 397 GateRef tempObj = GetTarget(*thisObj); 398 BRANCH(IsContainer(tempObj, type), &objIsJSAPILightWeight, slowPath); 399 Bind(&objIsJSAPILightWeight); 400 { 401 thisObj = tempObj; 402 Jump(&valueIsJSAPILightWeight); 403 } 404 } 405 Bind(&objNotJSProxy); 406 Jump(slowPath); 407 } 408 Bind(&valueIsJSAPILightWeight); 409 { 410 BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); 411 Bind(&callbackUndefined); 412 Jump(slowPath); 413 Bind(&callbackNotUndefined); 414 { 415 Label isCall(env); 416 Label notCall(env); 417 Label isHeapObj(env); 418 callbackFnHandle = GetCallArg0(numArgs); 419 BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath); 420 Bind(&isHeapObj); 421 BRANCH(IsCallable(callbackFnHandle), &isCall, ¬Call); 422 Bind(¬Call); 423 Jump(slowPath); 424 Bind(&isCall); 425 { 426 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); 427 Bind(&thisArgUndefined); 428 Jump(&nextCount); 429 Bind(&thisArgNotUndefined); 430 thisArg = GetCallArg1(numArgs); 431 Jump(&nextCount); 432 } 433 } 434 } 435 Bind(&nextCount); 436 { 437 length = ContainerGetSize(*thisObj, type); 438 Jump(&loopHead); 439 LoopBegin(&loopHead); 440 { 441 Label lenChange(env); 442 Label hasException(env); 443 Label notHasException(env); 444 BRANCH(Int32LessThan(*index, *length), &next, &afterLoop); 445 Bind(&next); 446 { 447 value = ContainerGetValue(*thisObj, *index, type); 448 key = ContainerGetKey(*thisObj, *index, type); 449 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN); 450 callArgs.callThisArg3WithReturnArgs = { *thisArg, *value, *key, *thisObj }; 451 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr, 452 Circuit::NullGate(), callArgs); 453 GateRef retValue = callBuilder.JSCallDispatch(); 454 BRANCH(HasPendingException(glue), &hasException, ¬HasException); 455 Bind(&hasException); 456 { 457 result->WriteVariable(retValue); 458 Jump(exit); 459 } 460 Bind(¬HasException); 461 GateRef currentLen = ContainerGetSize(*thisObj, type); 462 BRANCH(Int32NotEqual(currentLen, *length), &lenChange, &loopEnd); 463 Bind(&lenChange); 464 length = currentLen; 465 Jump(&loopEnd); 466 } 467 } 468 Bind(&loopEnd); 469 index = Int32Add(*index, Int32(1)); 470 LoopEnd(&loopHead, env, glue); 471 } 472 Bind(&afterLoop); 473 Jump(exit); 474} 475 476void ContainersStubBuilder::ContainersHashCall(GateRef glue, GateRef thisValue, 477 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) 478{ 479 auto env = GetEnvironment(); 480 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); 481 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); 482 DEFVARIABLE(node, VariableType::JS_ANY(), Undefined()); 483 DEFVARIABLE(key, VariableType::JS_ANY(), Undefined()); 484 DEFVARIABLE(value, VariableType::JS_ANY(), Undefined()); 485 DEFVARIABLE(length, VariableType::INT32(), Int32(0)); 486 DEFVARIABLE(index, VariableType::INT32(), Int32(0)); 487 Label valueIsJSAPIHash(env); 488 Label valueNotJSAPIHash(env); 489 Label objIsJSProxy(env); 490 Label objNotJSProxy(env); 491 Label objIsJSAPIHash(env); 492 Label thisArgUndefined(env); 493 Label thisArgNotUndefined(env); 494 Label callbackUndefined(env); 495 Label callbackNotUndefined(env); 496 Label nextCount(env); 497 Label nodeNotHole(env); 498 Label nodeIsLinked(env); 499 Label nodeIsRBTree(env); 500 Label loopLinked(env); 501 Label loopHead(env); 502 Label loopEnd(env); 503 Label next(env); 504 Label afterLoop(env); 505 GateRef callbackFnHandle; 506 BRANCH(IsContainer(*thisObj, type), &valueIsJSAPIHash, &valueNotJSAPIHash); 507 Bind(&valueNotJSAPIHash); 508 { 509 BRANCH(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); 510 Bind(&objIsJSProxy); 511 { 512 GateRef tempObj = GetTarget(*thisObj); 513 BRANCH(IsContainer(tempObj, type), &objIsJSAPIHash, slowPath); 514 Bind(&objIsJSAPIHash); 515 { 516 thisObj = tempObj; 517 Jump(&valueIsJSAPIHash); 518 } 519 } 520 Bind(&objNotJSProxy); 521 Jump(slowPath); 522 } 523 Bind(&valueIsJSAPIHash); 524 { 525 BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); 526 Bind(&callbackUndefined); 527 Jump(slowPath); 528 Bind(&callbackNotUndefined); 529 { 530 Label isCall(env); 531 Label notCall(env); 532 Label isHeapObj(env); 533 callbackFnHandle = GetCallArg0(numArgs); 534 BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, ¬Call); 535 Bind(&isHeapObj); 536 BRANCH(IsCallable(callbackFnHandle), &isCall, ¬Call); 537 Bind(¬Call); 538 Jump(slowPath); 539 Bind(&isCall); 540 { 541 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); 542 Bind(&thisArgUndefined); 543 Jump(&nextCount); 544 Bind(&thisArgNotUndefined); 545 thisArg = GetCallArg1(numArgs); 546 Jump(&nextCount); 547 } 548 } 549 } 550 Bind(&nextCount); 551 { 552 length = ContainerGetSize(*thisObj, type); 553 Jump(&loopHead); 554 LoopBegin(&loopHead); 555 { 556 Label hasExceptionLinked(env); 557 Label notHasExceptionLinked(env); 558 Label hasExceptionRBTree(env); 559 Label notHasExceptionRBTree(env); 560 BRANCH(Int32LessThan(*index, *length), &next, &afterLoop); 561 Bind(&next); 562 { 563 node = ContainerGetNode(*thisObj, *index, type); 564 BRANCH(TaggedIsHole(*node), &loopEnd, &nodeNotHole); 565 Bind(&nodeNotHole); 566 BRANCH(IsLinkedNode(*node), &nodeIsLinked, &nodeIsRBTree); 567 LoopBegin(&nodeIsLinked); 568 { 569 value = Load(VariableType::JS_POINTER(), *node, IntPtr( 570 type == ContainersType::HASHSET_FOREACH ? LinkedNode::KEY_OFFSET : LinkedNode::VALUE_OFFSET)); 571 key = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::KEY_OFFSET)); 572 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN); 573 callArgs.callThisArg3WithReturnArgs = { *thisArg, *value, *key, *thisObj }; 574 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, 575 nullptr, Circuit::NullGate(), callArgs); 576 GateRef retValue = callBuilder.JSCallDispatch(); 577 BRANCH(HasPendingException(glue), &hasExceptionLinked, ¬HasExceptionLinked); 578 Bind(&hasExceptionLinked); 579 { 580 result->WriteVariable(retValue); 581 Jump(exit); 582 } 583 Bind(¬HasExceptionLinked); 584 node = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::NEXT_OFFSET)); 585 BRANCH(TaggedIsHole(*node), &loopEnd, &loopLinked); 586 } 587 Bind(&loopLinked); 588 LoopEnd(&nodeIsLinked); 589 Bind(&nodeIsRBTree); 590 { 591 GateRef retValue = CallRuntime(glue, RTSTUB_ID(ContainerRBTreeForEach), 592 { *node, callbackFnHandle, *thisArg, *thisObj, 593 IntToTaggedInt(Int32(static_cast<int32_t>(type))) }); 594 BRANCH(HasPendingException(glue), &hasExceptionRBTree, ¬HasExceptionRBTree); 595 Bind(&hasExceptionRBTree); 596 { 597 result->WriteVariable(retValue); 598 Jump(exit); 599 } 600 Bind(¬HasExceptionRBTree); 601 Jump(&loopEnd); 602 } 603 } 604 } 605 Bind(&loopEnd); 606 index = Int32Add(*index, Int32(1)); 607 LoopEnd(&loopHead, env, glue); 608 } 609 Bind(&afterLoop); 610 Jump(exit); 611} 612 613void ContainersStubBuilder::ContainersLinkedListCall(GateRef glue, GateRef thisValue, 614 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type) 615{ 616 auto env = GetEnvironment(); 617 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue); 618 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined()); 619 DEFVARIABLE(valueNode, VariableType::INT32(), Int32(0)); 620 DEFVARIABLE(key, VariableType::JS_ANY(), Undefined()); 621 DEFVARIABLE(value, VariableType::JS_ANY(), Undefined()); 622 DEFVARIABLE(length, VariableType::INT32(), Int32(0)); 623 DEFVARIABLE(index, VariableType::INT32(), Int32(0)); 624 Label valueIsJSAPILinkedList(env); 625 Label valueNotJSAPILinkedList(env); 626 Label objIsJSProxy(env); 627 Label objNotJSProxy(env); 628 Label objIsJSAPILinkedList(env); 629 Label thisArgUndefined(env); 630 Label thisArgNotUndefined(env); 631 Label callbackUndefined(env); 632 Label callbackNotUndefined(env); 633 Label nextCount(env); 634 Label valueNotHole(env); 635 Label loopHead(env); 636 Label loopEnd(env); 637 Label next(env); 638 Label afterLoop(env); 639 GateRef callbackFnHandle; 640 BRANCH(IsContainer(*thisObj, type), &valueIsJSAPILinkedList, &valueNotJSAPILinkedList); 641 Bind(&valueNotJSAPILinkedList); 642 { 643 BRANCH(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy); 644 Bind(&objIsJSProxy); 645 { 646 GateRef tempObj = GetTarget(*thisObj); 647 BRANCH(IsContainer(tempObj, type), &objIsJSAPILinkedList, slowPath); 648 Bind(&objIsJSAPILinkedList); 649 { 650 thisObj = tempObj; 651 Jump(&valueIsJSAPILinkedList); 652 } 653 } 654 Bind(&objNotJSProxy); 655 Jump(slowPath); 656 } 657 Bind(&valueIsJSAPILinkedList); 658 { 659 BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined); 660 Bind(&callbackUndefined); 661 Jump(slowPath); 662 Bind(&callbackNotUndefined); 663 { 664 Label isCall(env); 665 Label notCall(env); 666 Label isHeapObj(env); 667 callbackFnHandle = GetCallArg0(numArgs); 668 BRANCH(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, ¬Call); 669 Bind(&isHeapObj); 670 BRANCH(IsCallable(callbackFnHandle), &isCall, ¬Call); 671 Bind(¬Call); 672 Jump(slowPath); 673 Bind(&isCall); 674 { 675 BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined); 676 Bind(&thisArgUndefined); 677 Jump(&nextCount); 678 Bind(&thisArgNotUndefined); 679 thisArg = GetCallArg1(numArgs); 680 Jump(&nextCount); 681 } 682 } 683 } 684 Bind(&nextCount); 685 { 686 length = ContainerGetSize(*thisObj, type); 687 valueNode = Int32(TaggedList<TaggedArray>::ELEMENTS_START_INDEX); 688 Jump(&loopHead); 689 LoopBegin(&loopHead); 690 { 691 Label hasException(env); 692 Label notHasException(env); 693 BRANCH(Int32LessThan(*index, *length), &next, &afterLoop); 694 Bind(&next); 695 { 696 valueNode = TaggedGetInt(ContainerGetNode(*thisObj, 697 Int32Add(*valueNode, Int32(TaggedList<TaggedArray>::NEXT_PTR_OFFSET)), type)); 698 value = ContainerGetNode(*thisObj, *valueNode, type); 699 BRANCH(TaggedIsHole(*value), &loopEnd, &valueNotHole); 700 Bind(&valueNotHole); 701 key = IntToTaggedInt(*index); 702 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN); 703 callArgs.callThisArg3WithReturnArgs = { *thisArg, *value, *key, *thisObj }; 704 CallStubBuilder callBuilder(this, glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr, 705 Circuit::NullGate(), callArgs); 706 GateRef retValue = callBuilder.JSCallDispatch(); 707 BRANCH(HasPendingException(glue), &hasException, ¬HasException); 708 Bind(&hasException); 709 { 710 result->WriteVariable(retValue); 711 Jump(exit); 712 } 713 Bind(¬HasException); 714 Jump(&loopEnd); 715 } 716 } 717 Bind(&loopEnd); 718 index = Int32Add(*index, Int32(1)); 719 LoopEnd(&loopHead, env, glue); 720 } 721 Bind(&afterLoop); 722 Jump(exit); 723} 724} // namespace panda::ecmascript::kungfu 725