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