• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notHole);
59         Bind(&hole);
60         {
61             currentDeletedElements = Int32Add(*currentDeletedElements, Int32(1));
62             SetDeletedNum(linkedTable, *i, *currentDeletedElements);
63             Jump(&loopEnd);
64         }
65         Bind(&notHole);
66         {
67             Label weak(env);
68             Label notWeak(env);
69             BRANCH(TaggedIsWeak(*key), &weak, &notWeak);
70             Bind(&weak);
71             {
72                 key = RemoveTaggedWeakTag(*key);
73                 Jump(&notWeak);
74             }
75             Bind(&notWeak);
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, &notHole);
266             Bind(&notHole);
267             {
268                 Label weak(env);
269                 Label notWeak(env);
270                 BRANCH(TaggedIsWeak(*element), &weak, &notWeak);
271                 Bind(&weak);
272                 {
273                     element = RemoveTaggedWeakTag(*element);
274                     Jump(&notWeak);
275                 }
276                 Bind(&notWeak);
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, &notHasException);
476         Bind(&hasException);
477         {
478             res = retValue;
479             Jump(&exit);
480         }
481         Bind(&notHasException);
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)), &notFind, &findEntry);
541     Bind(&findEntry);
542     {
543         SetValue(linkedTable, entry, value);
544         Jump(&exit);
545     }
546     Bind(&notFind);
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