1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/compiler/builtins/linked_hashtable_stub_builder.h"
17
18 #include "ecmascript/compiler/builtins/builtins_stubs.h"
19 #include "ecmascript/compiler/call_stub_builder.h"
20 #include "ecmascript/compiler/hash_stub_builder.h"
21 #include "ecmascript/compiler/new_object_stub_builder.h"
22 #include "ecmascript/linked_hash_table.h"
23 #include "ecmascript/js_set.h"
24 #include "ecmascript/js_map.h"
25
26 namespace panda::ecmascript::kungfu {
27 template <typename LinkedHashTableType, typename LinkedHashTableObject>
Rehash(GateRef linkedTable,GateRef newTable)28 void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::Rehash(
29 GateRef linkedTable, GateRef newTable)
30 {
31 auto env = GetEnvironment();
32 Label entryLabel(env);
33 env->SubCfgEntry(&entryLabel);
34
35 GateRef numberOfAllElements = Int32Add(GetNumberOfElements(linkedTable),
36 GetNumberOfDeletedElements(linkedTable));
37
38 DEFVARIABLE(desEntry, VariableType::INT32(), Int32(0));
39 DEFVARIABLE(currentDeletedElements, VariableType::INT32(), Int32(0));
40 SetNextTable(linkedTable, newTable);
41
42 Label loopHead(env);
43 Label loopEnd(env);
44 Label next(env);
45 Label loopExit(env);
46
47 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
48 Jump(&loopHead);
49 LoopBegin(&loopHead);
50 {
51 BRANCH(Int32LessThan(*i, numberOfAllElements), &next, &loopExit);
52 Bind(&next);
53
54 GateRef fromIndex = EntryToIndex(linkedTable, *i);
55 DEFVARIABLE(key, VariableType::JS_ANY(), GetElement(linkedTable, fromIndex));
56 Label hole(env);
57 Label notHole(env);
58 BRANCH(TaggedIsHole(*key), &hole, ¬Hole);
59 Bind(&hole);
60 {
61 currentDeletedElements = Int32Add(*currentDeletedElements, Int32(1));
62 SetDeletedNum(linkedTable, *i, *currentDeletedElements);
63 Jump(&loopEnd);
64 }
65 Bind(¬Hole);
66 {
67 Label weak(env);
68 Label notWeak(env);
69 BRANCH(TaggedIsWeak(*key), &weak, ¬Weak);
70 Bind(&weak);
71 {
72 key = RemoveTaggedWeakTag(*key);
73 Jump(¬Weak);
74 }
75 Bind(¬Weak);
76
77 HashStubBuilder hashBuilder(this, glue_);
78 GateRef hash = hashBuilder.GetHash(*key);
79 GateRef bucket = HashToBucket(newTable, hash);
80 InsertNewEntry(newTable, bucket, *desEntry);
81 GateRef desIndex = EntryToIndex(newTable, *desEntry);
82
83 Label loopHead1(env);
84 Label loopEnd1(env);
85 Label next1(env);
86 Label loopExit1(env);
87 DEFVARIABLE(j, VariableType::INT32(), Int32(0));
88 Jump(&loopHead1);
89 LoopBegin(&loopHead1);
90 {
91 BRANCH(Int32LessThan(*j, Int32(LinkedHashTableObject::ENTRY_SIZE)), &next1, &loopExit1);
92 Bind(&next1);
93 GateRef ele = GetElement(linkedTable, Int32Add(fromIndex, *j));
94 SetElement(newTable, Int32Add(desIndex, *j), ele);
95 Jump(&loopEnd1);
96 }
97 Bind(&loopEnd1);
98 j = Int32Add(*j, Int32(1));
99 LoopEnd(&loopHead1);
100 Bind(&loopExit1);
101 desEntry = Int32Add(*desEntry, Int32(1));
102 Jump(&loopEnd);
103 }
104 }
105 Bind(&loopEnd);
106 i = Int32Add(*i, Int32(1));
107 LoopEnd(&loopHead, env, glue_);
108 Bind(&loopExit);
109
110 SetNumberOfElements(newTable, GetNumberOfElements(linkedTable));
111 SetNumberOfDeletedElements(newTable, Int32(0));
112 env->SubCfgExit();
113 }
114
115 template <typename LinkedHashTableType, typename LinkedHashTableObject>
GrowCapacity(GateRef linkedTable,GateRef numberOfAddedElements)116 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GrowCapacity(
117 GateRef linkedTable, GateRef numberOfAddedElements)
118 {
119 auto env = GetEnvironment();
120 Label entryLabel(env);
121 env->SubCfgEntry(&entryLabel);
122 Label exit(env);
123 DEFVARIABLE(res, VariableType::JS_ANY(), linkedTable);
124
125 GateRef hasSufficient = HasSufficientCapacity(linkedTable, numberOfAddedElements);
126 Label grow(env);
127 BRANCH(hasSufficient, &exit, &grow);
128 Bind(&grow);
129 {
130 GateRef newCapacity = ComputeCapacity(Int32Add(GetNumberOfElements(linkedTable), numberOfAddedElements));
131 GateRef newTable = Create(newCapacity);
132 Rehash(linkedTable, newTable);
133 res = newTable;
134 Jump(&exit);
135 }
136 Bind(&exit);
137 auto ret = *res;
138 env->SubCfgExit();
139 return ret;
140 }
141
142 template <typename LinkedHashTableType, typename LinkedHashTableObject>
ComputeCapacity(GateRef atLeastSpaceFor)143 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::ComputeCapacity(
144 GateRef atLeastSpaceFor)
145 {
146 if constexpr (std::is_same_v<LinkedHashTableType, LinkedHashMap>) {
147 return TaggedGetInt(CallRuntime(glue_, RTSTUB_ID(LinkedHashMapComputeCapacity), {
148 IntToTaggedInt(atLeastSpaceFor) }));
149 } else {
150 return TaggedGetInt(CallRuntime(glue_, RTSTUB_ID(LinkedHashSetComputeCapacity), {
151 IntToTaggedInt(atLeastSpaceFor) }));
152 }
153 }
154
155 template <typename LinkedHashTableType, typename LinkedHashTableObject>
RemoveEntry(GateRef linkedTable,GateRef entry)156 void LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::RemoveEntry(
157 GateRef linkedTable, GateRef entry)
158 {
159 auto env = GetEnvironment();
160 Label entryLabel(env);
161 Label exit(env);
162 env->SubCfgEntry(&entryLabel);
163 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
164
165 Label loopHead(env);
166 Label loopEnd(env);
167 Label next(env);
168 Label loopExit(env);
169 GateRef index = EntryToIndex(linkedTable, entry);
170 Jump(&loopHead);
171 LoopBegin(&loopHead);
172 {
173 BRANCH(Int32LessThan(*i, Int32(LinkedHashTableObject::ENTRY_SIZE)), &next, &loopExit);
174 Bind(&next);
175
176 GateRef idx = Int32Add(index, *i);
177 SetElement(linkedTable, idx, Hole());
178 Jump(&loopEnd);
179 }
180 Bind(&loopEnd);
181 i = Int32Add(*i, Int32(1));
182 LoopEnd(&loopHead, env, glue_);
183 Bind(&loopExit);
184
185 GateRef newNofe = Int32Sub(GetNumberOfElements(linkedTable), Int32(1));
186 SetNumberOfElements(linkedTable, newNofe);
187 GateRef newNofd = Int32Add(GetNumberOfDeletedElements(linkedTable), Int32(1));
188 SetNumberOfDeletedElements(linkedTable, newNofd);
189 env->SubCfgExit();
190 }
191
192 template <typename LinkedHashTableType, typename LinkedHashTableObject>
HasSufficientCapacity(GateRef linkedTable,GateRef numOfAddElements)193 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::HasSufficientCapacity(
194 GateRef linkedTable, GateRef numOfAddElements)
195 {
196 auto env = GetEnvironment();
197 Label entryLabel(env);
198 Label exit(env);
199 env->SubCfgEntry(&entryLabel);
200 DEFVARIABLE(res, VariableType::BOOL(), False());
201
202 GateRef numberOfElements = GetNumberOfElements(linkedTable);
203 GateRef numOfDelElements = GetNumberOfDeletedElements(linkedTable);
204 GateRef nof = Int32Add(numberOfElements, numOfAddElements);
205 GateRef capacity = GetCapacity(linkedTable);
206 GateRef isLess = LogicAndBuilder(env)
207 .And(Int32LessThan(nof, capacity))
208 .And(Int32LessThanOrEqual(numOfDelElements, Int32Div(Int32Sub(capacity, nof), Int32(2))))
209 .Done();
210 Label lessLable(env);
211 BRANCH(isLess, &lessLable, &exit);
212 Bind(&lessLable);
213 {
214 Label need(env);
215 BRANCH(Int32LessThanOrEqual(Int32Add(nof, Int32Div(nof, Int32(2))), capacity), &need, &exit); // 2 : div 2
216 Bind(&need);
217 {
218 res = True();
219 Jump(&exit);
220 }
221 }
222 Bind(&exit);
223 auto ret = *res;
224 env->SubCfgExit();
225 return ret;
226 }
227
228 template <typename LinkedHashTableType, typename LinkedHashTableObject>
HashObjectIsMatch(GateRef key,GateRef other)229 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::HashObjectIsMatch(
230 GateRef key, GateRef other)
231 {
232 return SameValueZero(glue_, key, other);
233 }
234
235 template <typename LinkedHashTableType, typename LinkedHashTableObject>
FindElement(GateRef linkedTable,GateRef key,GateRef hash)236 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::FindElement(
237 GateRef linkedTable, GateRef key, GateRef hash)
238 {
239 auto env = GetEnvironment();
240 Label entryLabel(env);
241 env->SubCfgEntry(&entryLabel);
242
243 DEFVARIABLE(res, VariableType::INT32(), Int32(-1));
244 Label exit(env);
245 Label isKey(env);
246 BRANCH(IsKey(key), &isKey, &exit);
247 Bind(&isKey);
248 {
249 GateRef bucket = HashToBucket(linkedTable, hash);
250 GateRef index = BucketToIndex(bucket);
251 DEFVARIABLE(entry, VariableType::JS_ANY(), GetElement(linkedTable, index));
252 Label loopHead(env);
253 Label loopEnd(env);
254 Label next(env);
255 Label loopExit(env);
256
257 Jump(&loopHead);
258 LoopBegin(&loopHead);
259 {
260 BRANCH(TaggedIsHole(*entry), &loopExit, &next);
261 Bind(&next);
262
263 DEFVARIABLE(element, VariableType::JS_ANY(), GetKey(linkedTable, TaggedGetInt(*entry)));
264 Label notHole(env);
265 BRANCH(TaggedIsHole(*element), &loopEnd, ¬Hole);
266 Bind(¬Hole);
267 {
268 Label weak(env);
269 Label notWeak(env);
270 BRANCH(TaggedIsWeak(*element), &weak, ¬Weak);
271 Bind(&weak);
272 {
273 element = RemoveTaggedWeakTag(*element);
274 Jump(¬Weak);
275 }
276 Bind(¬Weak);
277 Label match(env);
278 BRANCH(HashObjectIsMatch(key, *element), &match, &loopEnd);
279 Bind(&match);
280 {
281 res = TaggedGetInt(*entry);
282 Jump(&loopExit);
283 }
284 }
285 }
286 Bind(&loopEnd);
287 entry = GetNextEntry(linkedTable, TaggedGetInt(*entry));
288 LoopEnd(&loopHead, env, glue_);
289 Bind(&loopExit);
290 Jump(&exit);
291 }
292 Bind(&exit);
293 auto ret = *res;
294 env->SubCfgExit();
295 return ret;
296 }
297
298 template <typename LinkedHashTableType, typename LinkedHashTableObject>
GetDeletedElementsAt(GateRef linkedTable,GateRef entry)299 GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::GetDeletedElementsAt(
300 GateRef linkedTable, GateRef entry)
301 {
302 auto env = GetEnvironment();
303 Label entryLabel(env);
304 env->SubCfgEntry(&entryLabel);
305 Label exit(env);
306 DEFVARIABLE(res, VariableType::INT32(), Int32(0));
307 DEFVARIABLE(currentEntry, VariableType::INT32(), Int32Sub(entry, Int32(1)));
308 Label loopHead(env);
309 Label loopEnd(env);
310 Label next(env);
311 Label loopExit(env);
312
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, ¬HasException);
469 Bind(&hasException);
470 {
471 res = retValue;
472 Jump(&exit);
473 }
474 Bind(¬HasException);
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)), ¬Find, &findEntry);
534 Bind(&findEntry);
535 {
536 SetValue(linkedTable, entry, value);
537 Jump(&exit);
538 }
539 Bind(¬Find);
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