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, ¬Hole);
58 Bind(&hole);
59 {
60 currentDeletedElements = Int32Add(*currentDeletedElements, Int32(1));
61 SetDeletedNum(linkedTable, *i, *currentDeletedElements);
62 Jump(&loopEnd);
63 }
64 Bind(¬Hole);
65 {
66 Label weak(env);
67 Label notWeak(env);
68 BRANCH(TaggedIsWeak(*key), &weak, ¬Weak);
69 Bind(&weak);
70 {
71 key = RemoveTaggedWeakTag(*key);
72 Jump(¬Weak);
73 }
74 Bind(¬Weak);
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 LoopEnd(&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 LoopEnd(&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, ¬Hole);
265 Bind(¬Hole);
266 {
267 Label weak(env);
268 Label notWeak(env);
269 BRANCH(TaggedIsWeak(*element), &weak, ¬Weak);
270 Bind(&weak);
271 {
272 element = RemoveTaggedWeakTag(*element);
273 Jump(¬Weak);
274 }
275 Bind(¬Weak);
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 LoopEnd(&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 LoopEnd(&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, ¬HasException);
475 Bind(&hasException);
476 {
477 res = retValue;
478 Jump(&exit);
479 }
480 Bind(¬HasException);
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)), ¬Find, &findEntry);
540 Bind(&findEntry);
541 {
542 SetValue(linkedTable, entry, value);
543 Jump(&exit);
544 }
545 Bind(¬Find);
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(newTarget), &newTargetFunction, &slowPath);
664
665 Bind(&newTargetFunction);
666 Label fastGetHClass(env);
667 Label intialHClassIsHClass(env);
668 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
669 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset);
670 GateRef mapOrSetFunc;
671 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) {
672 mapOrSetFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
673 GlobalEnv::BUILTINS_MAP_FUNCTION_INDEX);
674 } else if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashSet>) {
675 mapOrSetFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv,
676 GlobalEnv::BUILTINS_SET_FUNCTION_INDEX);
677 }
678 GateRef newTargetHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
679 BRANCH(LogicAndBuilder(env).And(Equal(mapOrSetFunc, newTarget)).And(IsJSHClass(newTargetHClass)).Done(),
680 &fastGetHClass, &slowPath);
681
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