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