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
26 namespace panda::ecmascript::kungfu {
27 template <typename LinkedHashTableType, typename LinkedHashTableObject>
Rehash(GateRef linkedTable,GateRef newTable)28 void 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
115 template <typename LinkedHashTableType, typename LinkedHashTableObject>
GrowCapacity(GateRef linkedTable,GateRef numberOfAddedElements)116 GateRef 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
142 template <typename LinkedHashTableType, typename LinkedHashTableObject>
ComputeCapacity(GateRef atLeastSpaceFor)143 GateRef 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
155 template <typename LinkedHashTableType, typename LinkedHashTableObject>
RemoveEntry(GateRef linkedTable,GateRef entry)156 void 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
192 template <typename LinkedHashTableType, typename LinkedHashTableObject>
HasSufficientCapacity(GateRef linkedTable,GateRef numOfAddElements)193 GateRef 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 : div 2
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
228 template <typename LinkedHashTableType, typename LinkedHashTableObject>
HashObjectIsMatch(GateRef key,GateRef other)229 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::HashObjectIsMatch(
230 GateRef key, GateRef other)
231 {
232 return SameValueZero(glue_, key, other);
233 }
234
235 template <typename LinkedHashTableType, typename LinkedHashTableObject>
FindElement(GateRef linkedTable,GateRef key,GateRef hash)236 GateRef 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
298 template <typename LinkedHashTableType, typename LinkedHashTableObject>
GetDeletedElementsAt(GateRef linkedTable,GateRef entry)299 GateRef 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 Label noNumberOfDeletedElements(env);
313
314 BRANCH(Int32Equal(GetNumberOfDeletedElements(linkedTable), Int32(-1)), &noNumberOfDeletedElements, &loopHead);
315 Bind(&noNumberOfDeletedElements);
316 {
317 res = entry;
318 Jump(&exit);
319 }
320
321 LoopBegin(&loopHead);
322 {
323 BRANCH(Int32GreaterThanOrEqual(*currentEntry, Int32(0)), &next, &loopExit);
324 Bind(&next);
325 GateRef key = GetKey(linkedTable, *currentEntry);
326 Label hole(env);
327 BRANCH(TaggedIsHole(key), &hole, &loopEnd);
328 Bind(&hole);
329 {
330 GateRef deletedNum = GetDeletedNum(linkedTable, *currentEntry);
331 res = deletedNum;
332 Jump(&exit);
333 }
334 }
335 Bind(&loopEnd);
336 currentEntry = Int32Sub(*currentEntry, Int32(1));
337 LoopEnd(&loopHead, env, glue_);
338 Bind(&loopExit);
339 Jump(&exit);
340 Bind(&exit);
341 auto ret = *res;
342 env->SubCfgExit();
343 return ret;
344 }
345
346 template<typename LinkedHashTableType, typename LinkedHashTableObject>
Create(GateRef numberOfElements)347 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Create(GateRef numberOfElements)
348 {
349 auto env = GetEnvironment();
350 Label entry(env);
351 env->SubCfgEntry(&entry);
352 Label exit(env);
353
354 // new LinkedHashTable
355 GateRef length = CalNewTaggedArrayLength(numberOfElements);
356 NewObjectStubBuilder newBuilder(this);
357 GateRef array = newBuilder.NewTaggedArray(glue_, length);
358
359 Label noException(env);
360 BRANCH(TaggedIsException(array), &exit, &noException);
361 Bind(&noException);
362 {
363 // SetNumberOfElements
364 SetNumberOfElements(array, Int32(0));
365 // SetNumberOfDeletedElements
366 SetNumberOfDeletedElements(array, Int32(0));
367 // SetCapacity
368 SetCapacity(array, numberOfElements);
369 Jump(&exit);
370 }
371 Bind(&exit);
372 env->SubCfgExit();
373 return array;
374 }
375
376 template<typename LinkedHashTableType, typename LinkedHashTableObject>
Clear(GateRef linkedTable)377 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Clear(GateRef linkedTable)
378 {
379 auto env = GetEnvironment();
380 Label entry(env);
381 env->SubCfgEntry(&entry);
382 Label exit(env);
383 Label setLinked(env);
384 DEFVARIABLE(result, VariableType::JS_ANY(), linkedTable);
385
386 Label reuseExistingTable(env);
387 Label createNewTable(env);
388 GateRef cap = GetCapacity(linkedTable);
389 GateRef minCapacity = Int32(LinkedHashTableType::MIN_CAPACITY);
390 BRANCH(Equal(cap, minCapacity), &reuseExistingTable, &createNewTable);
391
392 Bind(&reuseExistingTable);
393 size_t length = static_cast<size_t>(LinkedHashTableType::GetLengthOfTable(LinkedHashTableType::MIN_CAPACITY));
394 for (size_t i = LinkedHashTableType::ELEMENTS_START_INDEX; i < length; ++i) {
395 SetValueToTaggedArray(VariableType::JS_NOT_POINTER(), glue_, linkedTable, Int32(i), Hole());
396 }
397 GateRef numberOfElements = GetNumberOfElements(linkedTable);
398 GateRef numberOfDeletedElements = GetNumberOfDeletedElements(linkedTable);
399 SetNumberOfElements(linkedTable, Int32(0));
400 SetNumberOfDeletedElements(linkedTable, Int32Add(numberOfElements, numberOfDeletedElements));
401 Jump(&exit);
402
403 Bind(&createNewTable);
404 GateRef newTable = Create(minCapacity);
405 result = newTable;
406 Label noException(env);
407 BRANCH(TaggedIsException(newTable), &exit, &noException);
408 Bind(&noException);
409
410 Label capGreaterZero(env);
411 BRANCH(Int32GreaterThan(cap, Int32(0)), &capGreaterZero, &exit);
412 Bind(&capGreaterZero);
413 {
414 // NextTable
415 SetNextTable(linkedTable, newTable);
416 // SetNumberOfDeletedElements
417 SetNumberOfDeletedElements(linkedTable, Int32(-1));
418 Jump(&exit);
419 }
420
421 Bind(&exit);
422 GateRef res = *result;
423 env->SubCfgExit();
424 return res;
425 }
426
427 template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Clear(GateRef);
428 template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::Clear(GateRef);
429
430 template <typename LinkedHashTableType, typename LinkedHashTableObject>
ForEach(GateRef thisValue,GateRef srcLinkedTable,GateRef callbackFnHandle,GateRef thisArg)431 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::ForEach(GateRef thisValue,
432 GateRef srcLinkedTable, GateRef callbackFnHandle, GateRef thisArg)
433 {
434 auto env = GetEnvironment();
435 Label entry(env);
436 env->SubCfgEntry(&entry);
437 Label exit(env);
438 DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
439 DEFVARIABLE(linkedTable, VariableType::JS_ANY(), srcLinkedTable);
440
441 GateRef numberOfElements = GetNumberOfElements(*linkedTable);
442 GateRef numberOfDeletedElements = GetNumberOfDeletedElements(*linkedTable);
443 GateRef tmpTotalElements = Int32Add(numberOfElements, numberOfDeletedElements);
444 DEFVARIABLE(totalElements, VariableType::INT32(), tmpTotalElements);
445 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
446
447 Label loopHead(env);
448 Label loopEnd(env);
449 Label next(env);
450 Label loopExit(env);
451 Jump(&loopHead);
452 LoopBegin(&loopHead);
453 {
454 BRANCH(Int32LessThan(*index, *totalElements), &next, &loopExit);
455 Bind(&next);
456 GateRef valueIndex = *index;
457
458 GateRef key = GetKey(*linkedTable, *index);
459 index = Int32Add(*index, Int32(1));
460 Label keyNotHole(env);
461 BRANCH(TaggedIsHole(key), &loopEnd, &keyNotHole);
462 Bind(&keyNotHole);
463
464 GateRef value = key;
465 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) {
466 value = GetValue(*linkedTable, valueIndex);
467 }
468 Label hasException(env);
469 Label notHasException(env);
470 JSCallArgs callArgs(JSCallMode::CALL_THIS_ARG3_WITH_RETURN);
471 callArgs.callThisArg3WithReturnArgs = { thisArg, value, key, thisValue };
472 CallStubBuilder callBuilder(this, glue_, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, nullptr,
473 Circuit::NullGate(), callArgs, ProfileOperation(), false);
474 GateRef retValue = callBuilder.JSCallDispatch();
475 BRANCH(HasPendingException(glue_), &hasException, ¬HasException);
476 Bind(&hasException);
477 {
478 res = retValue;
479 Jump(&exit);
480 }
481 Bind(¬HasException);
482 {
483 // Maybe add or delete, get next table
484 GateRef tmpNextTable = GetNextTable(*linkedTable);
485 DEFVARIABLE(nextTable, VariableType::JS_ANY(), tmpNextTable);
486 Label loopHead1(env);
487 Label loopEnd1(env);
488 Label next1(env);
489 Label loopExit1(env);
490 Jump(&loopHead1);
491 LoopBegin(&loopHead1);
492 {
493 BRANCH(TaggedIsHole(*nextTable), &loopExit1, &next1);
494 Bind(&next1);
495 GateRef deleted = GetDeletedElementsAt(*linkedTable, *index);
496 index = Int32Sub(*index, deleted);
497 linkedTable = *nextTable;
498 nextTable = GetNextTable(*linkedTable);
499 Jump(&loopEnd1);
500 }
501 Bind(&loopEnd1);
502 LoopEnd(&loopHead1);
503 Bind(&loopExit1);
504 // update totalElements
505 GateRef numberOfEle = GetNumberOfElements(*linkedTable);
506 GateRef numberOfDeletedEle = GetNumberOfDeletedElements(*linkedTable);
507 totalElements = Int32Add(numberOfEle, numberOfDeletedEle);
508 Jump(&loopEnd);
509 }
510 }
511 Bind(&loopEnd);
512 LoopEnd(&loopHead);
513 Bind(&loopExit);
514 Jump(&exit);
515
516 Bind(&exit);
517 env->SubCfgExit();
518 return *res;
519 }
520
521 template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::ForEach(GateRef thisValue,
522 GateRef linkedTable, GateRef callbackFnHandle, GateRef thisArg);
523 template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::ForEach(GateRef thisValue,
524 GateRef linkedTable, GateRef callbackFnHandle, GateRef thisArg);
525
526 template <typename LinkedHashTableType, typename LinkedHashTableObject>
Insert(GateRef linkedTable,GateRef key,GateRef value)527 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Insert(
528 GateRef linkedTable, GateRef key, GateRef value)
529 {
530 auto env = GetEnvironment();
531 Label cfgEntry(env);
532 env->SubCfgEntry(&cfgEntry);
533 Label exit(env);
534 DEFVARIABLE(res, VariableType::JS_ANY(), linkedTable);
535 HashStubBuilder hashBuilder(this, glue_);
536 GateRef hash = hashBuilder.GetHash(key);
537 GateRef entry = FindElement(linkedTable, key, hash);
538 Label findEntry(env);
539 Label notFind(env);
540 BRANCH(Int32Equal(entry, Int32(-1)), ¬Find, &findEntry);
541 Bind(&findEntry);
542 {
543 SetValue(linkedTable, entry, value);
544 Jump(&exit);
545 }
546 Bind(¬Find);
547 {
548 GateRef newTable = GrowCapacity(linkedTable, Int32(1));
549 res = newTable;
550 GateRef bucket = HashToBucket(newTable, hash);
551 GateRef numberOfElements = GetNumberOfElements(newTable);
552
553 GateRef newEntry = Int32Add(numberOfElements, GetNumberOfDeletedElements(newTable));
554 InsertNewEntry(newTable, bucket, newEntry);
555 SetKey(newTable, newEntry, key);
556 SetValue(newTable, newEntry, value);
557 GateRef newNumberOfElements = Int32Add(numberOfElements, Int32(1));
558 SetNumberOfElements(newTable, newNumberOfElements);
559 Jump(&exit);
560 }
561
562 Bind(&exit);
563 auto ret = *res;
564 env->SubCfgExit();
565 return ret;
566 }
567
568 template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Insert(
569 GateRef linkedTable, GateRef key, GateRef value);
570 template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::Insert(
571 GateRef linkedTable, GateRef key, GateRef value);
572
573 template <typename LinkedHashTableType, typename LinkedHashTableObject>
Delete(GateRef linkedTable,GateRef key)574 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Delete(
575 GateRef linkedTable, GateRef key)
576 {
577 auto env = GetEnvironment();
578 Label cfgEntry(env);
579 env->SubCfgEntry(&cfgEntry);
580 Label exit(env);
581 DEFVARIABLE(res, VariableType::BOOL(), False());
582 HashStubBuilder hashBuilder(this, glue_);
583 GateRef hash = hashBuilder.GetHash(key);
584 GateRef entry = FindElement(linkedTable, key, hash);
585 Label findEntry(env);
586 BRANCH(Int32Equal(entry, Int32(-1)), &exit, &findEntry);
587 Bind(&findEntry);
588 {
589 RemoveEntry(linkedTable, entry);
590 res = True();
591 Jump(&exit);
592 }
593
594 Bind(&exit);
595 auto ret = *res;
596 env->SubCfgExit();
597 return ret;
598 }
599
600 template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Delete(
601 GateRef linkedTable, GateRef key);
602 template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::Delete(
603 GateRef linkedTable, GateRef key);
604
605 template <typename LinkedHashTableType, typename LinkedHashTableObject>
Has(GateRef linkedTable,GateRef key)606 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Has(
607 GateRef linkedTable, GateRef key)
608 {
609 auto env = GetEnvironment();
610 Label cfgEntry(env);
611 env->SubCfgEntry(&cfgEntry);
612 HashStubBuilder hashBuilder(this, glue_);
613 GateRef hash = hashBuilder.GetHash(key);
614 GateRef entry = FindElement(linkedTable, key, hash);
615 GateRef ret = Int32NotEqual(entry, Int32(-1));
616 env->SubCfgExit();
617 return ret;
618 }
619
620 template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Has(
621 GateRef linkedTable, GateRef key);
622 template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::Has(
623 GateRef linkedTable, GateRef key);
624
625 template <typename LinkedHashTableType, typename LinkedHashTableObject>
StoreHashTableToNewObject(GateRef newTargetHClass,Variable & returnValue)626 void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::StoreHashTableToNewObject(
627 GateRef newTargetHClass, Variable& returnValue)
628 {
629 NewObjectStubBuilder newBuilder(this);
630 GateRef res = newBuilder.NewJSObject(glue_, newTargetHClass);
631 returnValue.WriteVariable(res);
632 GateRef table;
633 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) {
634 table = Create(Int32(LinkedHashMap::MIN_CAPACITY));
635 Store(VariableType::JS_ANY(), glue_, *returnValue, IntPtr(JSMap::LINKED_MAP_OFFSET), table);
636 } else if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashSet>) {
637 table = Create(Int32(LinkedHashSet::MIN_CAPACITY));
638 Store(VariableType::JS_ANY(), glue_, *returnValue, IntPtr(JSSet::LINKED_SET_OFFSET), table);
639 }
640 }
641
642 template void LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::StoreHashTableToNewObject(
643 GateRef newTargetHClass, Variable& returnValue);
644 template void LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::StoreHashTableToNewObject(
645 GateRef newTargetHClass, Variable& returnValue);
646
647 template <typename LinkedHashTableType, typename LinkedHashTableObject>
GenMapSetConstructor(GateRef nativeCode,GateRef func,GateRef newTarget,GateRef thisValue,GateRef numArgs,GateRef arg0,GateRef argv)648 void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GenMapSetConstructor(
649 GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs, GateRef arg0, GateRef argv)
650 {
651 auto env = GetEnvironment();
652 DEFVARIABLE(returnValue, VariableType::JS_ANY(), Undefined());
653
654 Label newTargetObject(env);
655 Label newTargetNotObject(env);
656 Label newTargetFunction(env);
657 Label slowPath(env);
658 Label exit(env);
659
660 // 1.If NewTarget is undefined, throw a TypeError exception
661 Branch(TaggedIsHeapObject(newTarget), &newTargetObject, &newTargetNotObject);
662
663 Bind(&newTargetObject);
664 Branch(IsJSFunction(newTarget), &newTargetFunction, &slowPath);
665
666 Bind(&newTargetFunction);
667 Label fastGetHClass(env);
668 Label intialHClassIsHClass(env);
669 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
670 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset);
671 GateRef mapOrSetFunc;
672 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) {
673 mapOrSetFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
674 GlobalEnv::BUILTINS_MAP_FUNCTION_INDEX);
675 } else if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashSet>) {
676 mapOrSetFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
677 GlobalEnv::BUILTINS_SET_FUNCTION_INDEX);
678 }
679 GateRef newTargetHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
680 BRANCH(LogicAndBuilder(env).And(Equal(mapOrSetFunc, newTarget)).And(IsJSHClass(newTargetHClass)).Done(),
681 &fastGetHClass, &slowPath);
682 Bind(&fastGetHClass);
683 Label isUndefinedOrNull(env);
684 Branch(TaggedIsUndefinedOrNull(arg0), &isUndefinedOrNull, &slowPath);
685
686 Bind(&isUndefinedOrNull);
687 StoreHashTableToNewObject(newTargetHClass, returnValue);
688 Jump(&exit);
689
690 Bind(&newTargetNotObject);
691 GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InvalidNewTarget));
692 CallRuntime(glue_, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) });
693 returnValue = Exception();
694 Jump(&exit);
695
696 Bind(&slowPath);
697 returnValue = CallBuiltinRuntimeWithNewTarget(glue_, {glue_, nativeCode, func, thisValue,
698 numArgs, argv, newTarget});
699 Jump(&exit);
700
701 Bind(&exit);
702 Return(*returnValue);
703 }
704
705 template void LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::GenMapSetConstructor(
706 GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs,
707 GateRef arg0, GateRef argv);
708 template void LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::GenMapSetConstructor(
709 GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs,
710 GateRef arg0, GateRef argv);
711
712 template <typename LinkedHashTableType, typename LinkedHashTableObject>
GetLinked(GateRef jsThis)713 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GetLinked(GateRef jsThis)
714 {
715 GateRef linkedTableOffset = GetLinkedOffset();
716 return Load(VariableType::JS_ANY(), jsThis, linkedTableOffset);
717 }
718
719 template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::GetLinked(
720 GateRef jsThis);
721 template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::GetLinked(
722 GateRef jsThis);
723
724 template <typename LinkedHashTableType, typename LinkedHashTableObject>
SetLinked(GateRef jsThis,GateRef newTable)725 void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::SetLinked(GateRef jsThis, GateRef newTable)
726 {
727 GateRef linkedTableOffset = GetLinkedOffset();
728 Store(VariableType::JS_ANY(), glue_, jsThis, linkedTableOffset, newTable);
729 }
730
731 template void LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::SetLinked(
732 GateRef jsThis, GateRef newTable);
733 template void LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::SetLinked(
734 GateRef jsThis, GateRef newTable);
735
736 template <typename LinkedHashTableType, typename LinkedHashTableObject>
Get(GateRef linkedTable,GateRef key)737 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Get(
738 GateRef linkedTable, GateRef key)
739 {
740 auto env = GetEnvironment();
741 Label cfgEntry(env);
742 env->SubCfgEntry(&cfgEntry);
743 Label exit(env);
744 DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
745 HashStubBuilder hashBuilder(this, glue_);
746 GateRef hash = hashBuilder.GetHash(key);
747 GateRef entry = FindElement(linkedTable, key, hash);
748 Label findEntry(env);
749 Branch(Int32Equal(entry, Int32(-1)), &exit, &findEntry);
750 Bind(&findEntry);
751 {
752 res = GetValue(linkedTable, entry);
753 Jump(&exit);
754 }
755
756 Bind(&exit);
757 auto ret = *res;
758 env->SubCfgExit();
759 return ret;
760 }
761
762 template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Get(
763 GateRef linkedTable, GateRef key);
764
765 template <typename LinkedHashTableType, typename LinkedHashTableObject>
GetLinkedOffset()766 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GetLinkedOffset()
767 {
768 int32_t linkedTableOffset = 0;
769 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) {
770 linkedTableOffset = JSMap::LINKED_MAP_OFFSET;
771 } else {
772 static_assert(std::is_same_v<LinkedHashTableType, LinkedHashSet>);
773 linkedTableOffset = JSSet::LINKED_SET_OFFSET;
774 }
775 return IntPtr(linkedTableOffset);
776 }
777
778 template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::GetLinkedOffset();
779 template GateRef LinkedHashTableStubBuilder<LinkedHashSet, LinkedHashSetObject>::GetLinkedOffset();
780
781 } // namespace panda::ecmascript::kungfu
782