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/linked_hashtable_stub_builder.h" 17 18#include "ecmascript/compiler/builtins/builtins_stubs.h" 19#include "ecmascript/compiler/call_stub_builder.h" 20#include "ecmascript/compiler/hash_stub_builder.h" 21#include "ecmascript/compiler/new_object_stub_builder.h" 22#include "ecmascript/linked_hash_table.h" 23#include "ecmascript/js_set.h" 24#include "ecmascript/js_map.h" 25 26namespace panda::ecmascript::kungfu { 27template <typename LinkedHashTableType, typename LinkedHashTableObject> 28void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Rehash( 29 GateRef linkedTable, GateRef newTable) 30{ 31 auto env = GetEnvironment(); 32 Label entryLabel(env); 33 env->SubCfgEntry(&entryLabel); 34 35 GateRef numberOfAllElements = Int32Add(GetNumberOfElements(linkedTable), 36 GetNumberOfDeletedElements(linkedTable)); 37 38 DEFVARIABLE(desEntry, VariableType::INT32(), Int32(0)); 39 DEFVARIABLE(currentDeletedElements, VariableType::INT32(), Int32(0)); 40 SetNextTable(linkedTable, newTable); 41 42 Label loopHead(env); 43 Label loopEnd(env); 44 Label next(env); 45 Label loopExit(env); 46 47 DEFVARIABLE(i, VariableType::INT32(), Int32(0)); 48 Jump(&loopHead); 49 LoopBegin(&loopHead); 50 { 51 BRANCH(Int32LessThan(*i, numberOfAllElements), &next, &loopExit); 52 Bind(&next); 53 54 GateRef fromIndex = EntryToIndex(linkedTable, *i); 55 DEFVARIABLE(key, VariableType::JS_ANY(), GetElement(linkedTable, fromIndex)); 56 Label hole(env); 57 Label notHole(env); 58 BRANCH(TaggedIsHole(*key), &hole, ¬Hole); 59 Bind(&hole); 60 { 61 currentDeletedElements = Int32Add(*currentDeletedElements, Int32(1)); 62 SetDeletedNum(linkedTable, *i, *currentDeletedElements); 63 Jump(&loopEnd); 64 } 65 Bind(¬Hole); 66 { 67 Label weak(env); 68 Label notWeak(env); 69 BRANCH(TaggedIsWeak(*key), &weak, ¬Weak); 70 Bind(&weak); 71 { 72 key = RemoveTaggedWeakTag(*key); 73 Jump(¬Weak); 74 } 75 Bind(¬Weak); 76 77 HashStubBuilder hashBuilder(this, glue_); 78 GateRef hash = hashBuilder.GetHash(*key); 79 GateRef bucket = HashToBucket(newTable, hash); 80 InsertNewEntry(newTable, bucket, *desEntry); 81 GateRef desIndex = EntryToIndex(newTable, *desEntry); 82 83 Label loopHead1(env); 84 Label loopEnd1(env); 85 Label next1(env); 86 Label loopExit1(env); 87 DEFVARIABLE(j, VariableType::INT32(), Int32(0)); 88 Jump(&loopHead1); 89 LoopBegin(&loopHead1); 90 { 91 BRANCH(Int32LessThan(*j, Int32(LinkedHashTableObject::ENTRY_SIZE)), &next1, &loopExit1); 92 Bind(&next1); 93 GateRef ele = GetElement(linkedTable, Int32Add(fromIndex, *j)); 94 SetElement(newTable, Int32Add(desIndex, *j), ele); 95 Jump(&loopEnd1); 96 } 97 Bind(&loopEnd1); 98 j = Int32Add(*j, Int32(1)); 99 LoopEnd(&loopHead1); 100 Bind(&loopExit1); 101 desEntry = Int32Add(*desEntry, Int32(1)); 102 Jump(&loopEnd); 103 } 104 } 105 Bind(&loopEnd); 106 i = Int32Add(*i, Int32(1)); 107 LoopEnd(&loopHead, env, glue_); 108 Bind(&loopExit); 109 110 SetNumberOfElements(newTable, GetNumberOfElements(linkedTable)); 111 SetNumberOfDeletedElements(newTable, Int32(0)); 112 env->SubCfgExit(); 113} 114 115template <typename LinkedHashTableType, typename LinkedHashTableObject> 116GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GrowCapacity( 117 GateRef linkedTable, GateRef numberOfAddedElements) 118{ 119 auto env = GetEnvironment(); 120 Label entryLabel(env); 121 env->SubCfgEntry(&entryLabel); 122 Label exit(env); 123 DEFVARIABLE(res, VariableType::JS_ANY(), linkedTable); 124 125 GateRef hasSufficient = HasSufficientCapacity(linkedTable, numberOfAddedElements); 126 Label grow(env); 127 BRANCH(hasSufficient, &exit, &grow); 128 Bind(&grow); 129 { 130 GateRef newCapacity = ComputeCapacity(Int32Add(GetNumberOfElements(linkedTable), numberOfAddedElements)); 131 GateRef newTable = Create(newCapacity); 132 Rehash(linkedTable, newTable); 133 res = newTable; 134 Jump(&exit); 135 } 136 Bind(&exit); 137 auto ret = *res; 138 env->SubCfgExit(); 139 return ret; 140} 141 142template <typename LinkedHashTableType, typename LinkedHashTableObject> 143GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::ComputeCapacity( 144 GateRef atLeastSpaceFor) 145{ 146 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) { 147 return TaggedGetInt(CallRuntime(glue_, RTSTUB_ID(LinkedHashMapComputeCapacity), { 148 IntToTaggedInt(atLeastSpaceFor) })); 149 } else { 150 return TaggedGetInt(CallRuntime(glue_, RTSTUB_ID(LinkedHashSetComputeCapacity), { 151 IntToTaggedInt(atLeastSpaceFor) })); 152 } 153} 154 155template <typename LinkedHashTableType, typename LinkedHashTableObject> 156void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::RemoveEntry( 157 GateRef linkedTable, GateRef entry) 158{ 159 auto env = GetEnvironment(); 160 Label entryLabel(env); 161 Label exit(env); 162 env->SubCfgEntry(&entryLabel); 163 DEFVARIABLE(i, VariableType::INT32(), Int32(0)); 164 165 Label loopHead(env); 166 Label loopEnd(env); 167 Label next(env); 168 Label loopExit(env); 169 GateRef index = EntryToIndex(linkedTable, entry); 170 Jump(&loopHead); 171 LoopBegin(&loopHead); 172 { 173 BRANCH(Int32LessThan(*i, Int32(LinkedHashTableObject::ENTRY_SIZE)), &next, &loopExit); 174 Bind(&next); 175 176 GateRef idx = Int32Add(index, *i); 177 SetElement(linkedTable, idx, Hole()); 178 Jump(&loopEnd); 179 } 180 Bind(&loopEnd); 181 i = Int32Add(*i, Int32(1)); 182 LoopEnd(&loopHead, env, glue_); 183 Bind(&loopExit); 184 185 GateRef newNofe = Int32Sub(GetNumberOfElements(linkedTable), Int32(1)); 186 SetNumberOfElements(linkedTable, newNofe); 187 GateRef newNofd = Int32Add(GetNumberOfDeletedElements(linkedTable), Int32(1)); 188 SetNumberOfDeletedElements(linkedTable, newNofd); 189 env->SubCfgExit(); 190} 191 192template <typename LinkedHashTableType, typename LinkedHashTableObject> 193GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::HasSufficientCapacity( 194 GateRef linkedTable, GateRef numOfAddElements) 195{ 196 auto env = GetEnvironment(); 197 Label entryLabel(env); 198 Label exit(env); 199 env->SubCfgEntry(&entryLabel); 200 DEFVARIABLE(res, VariableType::BOOL(), False()); 201 202 GateRef numberOfElements = GetNumberOfElements(linkedTable); 203 GateRef numOfDelElements = GetNumberOfDeletedElements(linkedTable); 204 GateRef nof = Int32Add(numberOfElements, numOfAddElements); 205 GateRef capacity = GetCapacity(linkedTable); 206 GateRef isLess = LogicAndBuilder(env) 207 .And(Int32LessThan(nof, capacity)) 208 .And(Int32LessThanOrEqual(numOfDelElements, Int32Div(Int32Sub(capacity, nof), Int32(2)))) 209 .Done(); 210 Label lessLable(env); 211 BRANCH(isLess, &lessLable, &exit); 212 Bind(&lessLable); 213 { 214 Label need(env); 215 BRANCH(Int32LessThanOrEqual(Int32Add(nof, Int32Div(nof, Int32(2))), capacity), &need, &exit); // 2: half 216 Bind(&need); 217 { 218 res = True(); 219 Jump(&exit); 220 } 221 } 222 Bind(&exit); 223 auto ret = *res; 224 env->SubCfgExit(); 225 return ret; 226} 227 228template <typename LinkedHashTableType, typename LinkedHashTableObject> 229GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::HashObjectIsMatch( 230 GateRef key, GateRef other) 231{ 232 return SameValueZero(glue_, key, other); 233} 234 235template <typename LinkedHashTableType, typename LinkedHashTableObject> 236GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::FindElement( 237 GateRef linkedTable, GateRef key, GateRef hash) 238{ 239 auto env = GetEnvironment(); 240 Label entryLabel(env); 241 env->SubCfgEntry(&entryLabel); 242 243 DEFVARIABLE(res, VariableType::INT32(), Int32(-1)); 244 Label exit(env); 245 Label isKey(env); 246 BRANCH(IsKey(key), &isKey, &exit); 247 Bind(&isKey); 248 { 249 GateRef bucket = HashToBucket(linkedTable, hash); 250 GateRef index = BucketToIndex(bucket); 251 DEFVARIABLE(entry, VariableType::JS_ANY(), GetElement(linkedTable, index)); 252 Label loopHead(env); 253 Label loopEnd(env); 254 Label next(env); 255 Label loopExit(env); 256 257 Jump(&loopHead); 258 LoopBegin(&loopHead); 259 { 260 BRANCH(TaggedIsHole(*entry), &loopExit, &next); 261 Bind(&next); 262 263 DEFVARIABLE(element, VariableType::JS_ANY(), GetKey(linkedTable, TaggedGetInt(*entry))); 264 Label notHole(env); 265 BRANCH(TaggedIsHole(*element), &loopEnd, ¬Hole); 266 Bind(¬Hole); 267 { 268 Label weak(env); 269 Label notWeak(env); 270 BRANCH(TaggedIsWeak(*element), &weak, ¬Weak); 271 Bind(&weak); 272 { 273 element = RemoveTaggedWeakTag(*element); 274 Jump(¬Weak); 275 } 276 Bind(¬Weak); 277 Label match(env); 278 BRANCH(HashObjectIsMatch(key, *element), &match, &loopEnd); 279 Bind(&match); 280 { 281 res = TaggedGetInt(*entry); 282 Jump(&loopExit); 283 } 284 } 285 } 286 Bind(&loopEnd); 287 entry = GetNextEntry(linkedTable, TaggedGetInt(*entry)); 288 LoopEnd(&loopHead, env, glue_); 289 Bind(&loopExit); 290 Jump(&exit); 291 } 292 Bind(&exit); 293 auto ret = *res; 294 env->SubCfgExit(); 295 return ret; 296} 297 298template <typename LinkedHashTableType, typename LinkedHashTableObject> 299GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GetDeletedElementsAt( 300 GateRef linkedTable, GateRef entry) 301{ 302 auto env = GetEnvironment(); 303 Label entryLabel(env); 304 env->SubCfgEntry(&entryLabel); 305 Label exit(env); 306 DEFVARIABLE(res, VariableType::INT32(), Int32(0)); 307 DEFVARIABLE(currentEntry, VariableType::INT32(), Int32Sub(entry, Int32(1))); 308 Label loopHead(env); 309 Label loopEnd(env); 310 Label next(env); 311 Label loopExit(env); 312 313 Jump(&loopHead); 314 LoopBegin(&loopHead); 315 { 316 BRANCH(Int32GreaterThanOrEqual(*currentEntry, Int32(0)), &next, &loopExit); 317 Bind(&next); 318 GateRef key = GetKey(linkedTable, *currentEntry); 319 Label hole(env); 320 BRANCH(TaggedIsHole(key), &hole, &loopEnd); 321 Bind(&hole); 322 { 323 GateRef deletedNum = GetDeletedNum(linkedTable, *currentEntry); 324 res = deletedNum; 325 Jump(&exit); 326 } 327 } 328 Bind(&loopEnd); 329 currentEntry = Int32Sub(*currentEntry, Int32(1)); 330 LoopEnd(&loopHead, env, glue_); 331 Bind(&loopExit); 332 Jump(&exit); 333 Bind(&exit); 334 auto ret = *res; 335 env->SubCfgExit(); 336 return ret; 337} 338 339template<typename LinkedHashTableType, typename LinkedHashTableObject> 340GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Create(GateRef numberOfElements) 341{ 342 auto env = GetEnvironment(); 343 Label entry(env); 344 env->SubCfgEntry(&entry); 345 Label exit(env); 346 347 // new LinkedHashTable 348 GateRef length = CalNewTaggedArrayLength(numberOfElements); 349 NewObjectStubBuilder newBuilder(this); 350 GateRef array = newBuilder.NewTaggedArray(glue_, length); 351 352 Label noException(env); 353 BRANCH(TaggedIsException(array), &exit, &noException); 354 Bind(&noException); 355 { 356 // SetNumberOfElements 357 SetNumberOfElements(array, Int32(0)); 358 // SetNumberOfDeletedElements 359 SetNumberOfDeletedElements(array, Int32(0)); 360 // SetCapacity 361 SetCapacity(array, numberOfElements); 362 Jump(&exit); 363 } 364 Bind(&exit); 365 env->SubCfgExit(); 366 return array; 367} 368 369template<typename LinkedHashTableType, typename LinkedHashTableObject> 370GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Clear(GateRef linkedTable) 371{ 372 auto env = GetEnvironment(); 373 Label entry(env); 374 env->SubCfgEntry(&entry); 375 Label exit(env); 376 Label setLinked(env); 377 DEFVARIABLE(result, VariableType::JS_ANY(), linkedTable); 378 379 Label reuseExistingTable(env); 380 Label createNewTable(env); 381 GateRef cap = GetCapacity(linkedTable); 382 GateRef minCapacity = Int32(LinkedHashTableType::MIN_CAPACITY); 383 BRANCH(Equal(cap, minCapacity), &reuseExistingTable, &createNewTable); 384 385 Bind(&reuseExistingTable); 386 size_t length = static_cast<size_t>(LinkedHashTableType::GetLengthOfTable(LinkedHashTableType::MIN_CAPACITY)); 387 for (size_t i = LinkedHashTableType::ELEMENTS_START_INDEX; i < length; ++i) { 388 SetValueToTaggedArray(VariableType::JS_NOT_POINTER(), glue_, linkedTable, Int32(i), Hole()); 389 } 390 GateRef numberOfElements = GetNumberOfElements(linkedTable); 391 GateRef numberOfDeletedElements = GetNumberOfDeletedElements(linkedTable); 392 SetNumberOfElements(linkedTable, Int32(0)); 393 SetNumberOfDeletedElements(linkedTable, Int32Add(numberOfElements, numberOfDeletedElements)); 394 Jump(&exit); 395 396 Bind(&createNewTable); 397 GateRef newTable = Create(minCapacity); 398 result = newTable; 399 Label noException(env); 400 BRANCH(TaggedIsException(newTable), &exit, &noException); 401 Bind(&noException); 402 403 Label capGreaterZero(env); 404 BRANCH(Int32GreaterThan(cap, Int32(0)), &capGreaterZero, &exit); 405 Bind(&capGreaterZero); 406 { 407 // NextTable 408 SetNextTable(linkedTable, newTable); 409 // SetNumberOfDeletedElements 410 SetNumberOfDeletedElements(linkedTable, Int32(-1)); 411 Jump(&exit); 412 } 413 414 Bind(&exit); 415 GateRef res = *result; 416 env->SubCfgExit(); 417 return res; 418} 419 420template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Clear(GateRef); 421template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::Clear(GateRef); 422 423template <typename LinkedHashTableType, typename LinkedHashTableObject> 424GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::ForEach(GateRef thisValue, 425 GateRef srcLinkedTable, GateRef callbackFnHandle, GateRef thisArg) 426{ 427 auto env = GetEnvironment(); 428 Label entry(env); 429 env->SubCfgEntry(&entry); 430 Label exit(env); 431 DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); 432 DEFVARIABLE(linkedTable, VariableType::JS_ANY(), srcLinkedTable); 433 434 GateRef numberOfElements = GetNumberOfElements(*linkedTable); 435 GateRef numberOfDeletedElements = GetNumberOfDeletedElements(*linkedTable); 436 GateRef tmpTotalElements = Int32Add(numberOfElements, numberOfDeletedElements); 437 DEFVARIABLE(totalElements, VariableType::INT32(), tmpTotalElements); 438 DEFVARIABLE(index, VariableType::INT32(), Int32(0)); 439 440 Label loopHead(env); 441 Label loopEnd(env); 442 Label next(env); 443 Label loopExit(env); 444 Jump(&loopHead); 445 LoopBegin(&loopHead); 446 { 447 BRANCH(Int32LessThan(*index, *totalElements), &next, &loopExit); 448 Bind(&next); 449 GateRef valueIndex = *index; 450 451 GateRef key = GetKey(*linkedTable, *index); 452 index = Int32Add(*index, Int32(1)); 453 Label keyNotHole(env); 454 BRANCH(TaggedIsHole(key), &loopEnd, &keyNotHole); 455 Bind(&keyNotHole); 456 457 GateRef value = key; 458 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) { 459 value = GetValue(*linkedTable, valueIndex); 460 } 461 Label hasException(env); 462 Label notHasException(env); 463 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN); 464 callArgs.callThisArg3WithReturnArgs = { thisArg, value, key, thisValue }; 465 CallStubBuilder callBuilder(this, glue_, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr, 466 Circuit::NullGate(), callArgs, ProfileOperation(), false); 467 GateRef retValue = callBuilder.JSCallDispatch(); 468 BRANCH(HasPendingException(glue_), &hasException, ¬HasException); 469 Bind(&hasException); 470 { 471 res = retValue; 472 Jump(&exit); 473 } 474 Bind(¬HasException); 475 { 476 // Maybe add or delete, get next table 477 GateRef tmpNextTable = GetNextTable(*linkedTable); 478 DEFVARIABLE(nextTable, VariableType::JS_ANY(), tmpNextTable); 479 Label loopHead1(env); 480 Label loopEnd1(env); 481 Label next1(env); 482 Label loopExit1(env); 483 Jump(&loopHead1); 484 LoopBegin(&loopHead1); 485 { 486 BRANCH(TaggedIsHole(*nextTable), &loopExit1, &next1); 487 Bind(&next1); 488 GateRef deleted = GetDeletedElementsAt(*linkedTable, *index); 489 index = Int32Sub(*index, deleted); 490 linkedTable = *nextTable; 491 nextTable = GetNextTable(*linkedTable); 492 Jump(&loopEnd1); 493 } 494 Bind(&loopEnd1); 495 LoopEnd(&loopHead1); 496 Bind(&loopExit1); 497 // update totalElements 498 GateRef numberOfEle = GetNumberOfElements(*linkedTable); 499 GateRef numberOfDeletedEle = GetNumberOfDeletedElements(*linkedTable); 500 totalElements = Int32Add(numberOfEle, numberOfDeletedEle); 501 Jump(&loopEnd); 502 } 503 } 504 Bind(&loopEnd); 505 LoopEnd(&loopHead); 506 Bind(&loopExit); 507 Jump(&exit); 508 509 Bind(&exit); 510 env->SubCfgExit(); 511 return *res; 512} 513 514template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::ForEach(GateRef thisValue, 515 GateRef linkedTable, GateRef callbackFnHandle, GateRef thisArg); 516template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::ForEach(GateRef thisValue, 517 GateRef linkedTable, GateRef callbackFnHandle, GateRef thisArg); 518 519template <typename LinkedHashTableType, typename LinkedHashTableObject> 520GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Insert( 521 GateRef linkedTable, GateRef key, GateRef value) 522{ 523 auto env = GetEnvironment(); 524 Label cfgEntry(env); 525 env->SubCfgEntry(&cfgEntry); 526 Label exit(env); 527 DEFVARIABLE(res, VariableType::JS_ANY(), linkedTable); 528 HashStubBuilder hashBuilder(this, glue_); 529 GateRef hash = hashBuilder.GetHash(key); 530 GateRef entry = FindElement(linkedTable, key, hash); 531 Label findEntry(env); 532 Label notFind(env); 533 BRANCH(Int32Equal(entry, Int32(-1)), ¬Find, &findEntry); 534 Bind(&findEntry); 535 { 536 SetValue(linkedTable, entry, value); 537 Jump(&exit); 538 } 539 Bind(¬Find); 540 { 541 GateRef newTable = GrowCapacity(linkedTable, Int32(1)); 542 res = newTable; 543 GateRef bucket = HashToBucket(newTable, hash); 544 GateRef numberOfElements = GetNumberOfElements(newTable); 545 546 GateRef newEntry = Int32Add(numberOfElements, GetNumberOfDeletedElements(newTable)); 547 InsertNewEntry(newTable, bucket, newEntry); 548 SetKey(newTable, newEntry, key); 549 SetValue(newTable, newEntry, value); 550 GateRef newNumberOfElements = Int32Add(numberOfElements, Int32(1)); 551 SetNumberOfElements(newTable, newNumberOfElements); 552 Jump(&exit); 553 } 554 555 Bind(&exit); 556 auto ret = *res; 557 env->SubCfgExit(); 558 return ret; 559} 560 561template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Insert( 562 GateRef linkedTable, GateRef key, GateRef value); 563template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::Insert( 564 GateRef linkedTable, GateRef key, GateRef value); 565 566template <typename LinkedHashTableType, typename LinkedHashTableObject> 567GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Delete( 568 GateRef linkedTable, GateRef key) 569{ 570 auto env = GetEnvironment(); 571 Label cfgEntry(env); 572 env->SubCfgEntry(&cfgEntry); 573 Label exit(env); 574 DEFVARIABLE(res, VariableType::BOOL(), False()); 575 HashStubBuilder hashBuilder(this, glue_); 576 GateRef hash = hashBuilder.GetHash(key); 577 GateRef entry = FindElement(linkedTable, key, hash); 578 Label findEntry(env); 579 BRANCH(Int32Equal(entry, Int32(-1)), &exit, &findEntry); 580 Bind(&findEntry); 581 { 582 RemoveEntry(linkedTable, entry); 583 res = True(); 584 Jump(&exit); 585 } 586 587 Bind(&exit); 588 auto ret = *res; 589 env->SubCfgExit(); 590 return ret; 591} 592 593template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Delete( 594 GateRef linkedTable, GateRef key); 595template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::Delete( 596 GateRef linkedTable, GateRef key); 597 598template <typename LinkedHashTableType, typename LinkedHashTableObject> 599GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Has( 600 GateRef linkedTable, GateRef key) 601{ 602 auto env = GetEnvironment(); 603 Label cfgEntry(env); 604 env->SubCfgEntry(&cfgEntry); 605 HashStubBuilder hashBuilder(this, glue_); 606 GateRef hash = hashBuilder.GetHash(key); 607 GateRef entry = FindElement(linkedTable, key, hash); 608 GateRef ret = Int32NotEqual(entry, Int32(-1)); 609 env->SubCfgExit(); 610 return ret; 611} 612 613template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Has( 614 GateRef linkedTable, GateRef key); 615template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::Has( 616 GateRef linkedTable, GateRef key); 617 618template <typename LinkedHashTableType, typename LinkedHashTableObject> 619void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::StoreHashTableToNewObject( 620 GateRef newTargetHClass, Variable& returnValue) 621{ 622 NewObjectStubBuilder newBuilder(this); 623 GateRef res = newBuilder.NewJSObject(glue_, newTargetHClass); 624 returnValue.WriteVariable(res); 625 GateRef table; 626 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) { 627 table = Create(Int32(LinkedHashMap::MIN_CAPACITY)); 628 Store(VariableType::JS_ANY(), glue_, *returnValue, IntPtr(JSMap::LINKED_MAP_OFFSET), table); 629 } else if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashSet>) { 630 table = Create(Int32(LinkedHashSet::MIN_CAPACITY)); 631 Store(VariableType::JS_ANY(), glue_, *returnValue, IntPtr(JSSet::LINKED_SET_OFFSET), table); 632 } 633} 634 635template void LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::StoreHashTableToNewObject( 636 GateRef newTargetHClass, Variable& returnValue); 637template void LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::StoreHashTableToNewObject( 638 GateRef newTargetHClass, Variable& returnValue); 639 640template <typename LinkedHashTableType, typename LinkedHashTableObject> 641void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GenMapSetConstructor( 642 GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs, GateRef arg0, GateRef argv) 643{ 644 auto env = GetEnvironment(); 645 DEFVARIABLE(returnValue, VariableType::JS_ANY(), Undefined()); 646 647 Label newTargetObject(env); 648 Label newTargetNotObject(env); 649 Label newTargetFunction(env); 650 Label slowPath(env); 651 Label exit(env); 652 653 // 1.If NewTarget is undefined, throw a TypeError exception 654 BRANCH(TaggedIsHeapObject(newTarget), &newTargetObject, &newTargetNotObject); 655 656 Bind(&newTargetObject); 657 BRANCH(IsJSFunction(newTarget), &newTargetFunction, &slowPath); 658 659 Bind(&newTargetFunction); 660 Label fastGetHClass(env); 661 Label intialHClassIsHClass(env); 662 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); 663 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset); 664 GateRef mapOrSetFunc; 665 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) { 666 mapOrSetFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, 667 GlobalEnv::BUILTINS_MAP_FUNCTION_INDEX); 668 } else if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashSet>) { 669 mapOrSetFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, 670 GlobalEnv::BUILTINS_SET_FUNCTION_INDEX); 671 } 672 GateRef newTargetHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); 673 BRANCH(LogicAndBuilder(env).And(Equal(mapOrSetFunc, newTarget)).And(IsJSHClass(newTargetHClass)).Done(), 674 &fastGetHClass, &slowPath); 675 676 Bind(&fastGetHClass); 677 Label isUndefinedOrNull(env); 678 BRANCH(TaggedIsUndefinedOrNull(arg0), &isUndefinedOrNull, &slowPath); 679 680 Bind(&isUndefinedOrNull); 681 StoreHashTableToNewObject(newTargetHClass, returnValue); 682 Jump(&exit); 683 684 Bind(&newTargetNotObject); 685 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InvalidNewTarget)); 686 CallRuntime(glue_, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) }); 687 returnValue = Exception(); 688 Jump(&exit); 689 690 Bind(&slowPath); 691 returnValue = CallBuiltinRuntimeWithNewTarget(glue_, {glue_, nativeCode, func, thisValue, 692 numArgs, argv, newTarget}); 693 Jump(&exit); 694 695 Bind(&exit); 696 Return(*returnValue); 697} 698 699template void LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::GenMapSetConstructor( 700 GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs, 701 GateRef arg0, GateRef argv); 702template void LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::GenMapSetConstructor( 703 GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs, 704 GateRef arg0, GateRef argv); 705 706template <typename LinkedHashTableType, typename LinkedHashTableObject> 707GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GetLinked(GateRef jsThis) 708{ 709 GateRef linkedTableOffset = GetLinkedOffset(); 710 return Load(VariableType::JS_ANY(), jsThis, linkedTableOffset); 711} 712 713template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::GetLinked( 714 GateRef jsThis); 715template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::GetLinked( 716 GateRef jsThis); 717 718template <typename LinkedHashTableType, typename LinkedHashTableObject> 719void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::SetLinked(GateRef jsThis, GateRef newTable) 720{ 721 GateRef linkedTableOffset = GetLinkedOffset(); 722 Store(VariableType::JS_ANY(), glue_, jsThis, linkedTableOffset, newTable); 723} 724 725template void LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::SetLinked( 726 GateRef jsThis, GateRef newTable); 727template void LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::SetLinked( 728 GateRef jsThis, GateRef newTable); 729 730template <typename LinkedHashTableType, typename LinkedHashTableObject> 731GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Get( 732 GateRef linkedTable, GateRef key) 733{ 734 auto env = GetEnvironment(); 735 Label cfgEntry(env); 736 env->SubCfgEntry(&cfgEntry); 737 Label exit(env); 738 DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); 739 HashStubBuilder hashBuilder(this, glue_); 740 GateRef hash = hashBuilder.GetHash(key); 741 GateRef entry = FindElement(linkedTable, key, hash); 742 Label findEntry(env); 743 Branch(Int32Equal(entry, Int32(-1)), &exit, &findEntry); 744 Bind(&findEntry); 745 { 746 res = GetValue(linkedTable, entry); 747 Jump(&exit); 748 } 749 750 Bind(&exit); 751 auto ret = *res; 752 env->SubCfgExit(); 753 return ret; 754} 755 756template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Get( 757 GateRef linkedTable, GateRef key); 758 759template <typename LinkedHashTableType, typename LinkedHashTableObject> 760GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GetLinkedOffset() 761{ 762 int32_t linkedTableOffset = 0; 763 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) { 764 linkedTableOffset = JSMap::LINKED_MAP_OFFSET; 765 } else { 766 static_assert(std::is_same_v<LinkedHashTableType, LinkedHashSet>); 767 linkedTableOffset = JSSet::LINKED_SET_OFFSET; 768 } 769 return IntPtr(linkedTableOffset); 770} 771 772template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::GetLinkedOffset(); 773template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::GetLinkedOffset(); 774 775} // namespace panda::ecmascript::kungfu 776