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/containers_stub_builder.h"
17 #include "ecmascript/compiler/builtins/containers_vector_stub_builder.h"
18
19 namespace panda::ecmascript::kungfu {
20 // common IR for containers apis that use function call
ContainersCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)21 void ContainersStubBuilder::ContainersCommonFuncCall(GateRef glue, GateRef thisValue,
22 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
23 {
24 auto env = GetEnvironment();
25 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
26 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
27 DEFVARIABLE(key, VariableType::INT64(), Int64(0));
28 DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
29 DEFVARIABLE(length, VariableType::INT32(), Int32(0));
30 DEFVARIABLE(k, VariableType::INT32(), Int32(0));
31 Label valueIsJSAPIVector(env);
32 Label valueNotJSAPIVector(env);
33 Label objIsJSProxy(env);
34 Label objNotJSProxy(env);
35 Label objIsJSAPIVector(env);
36 Label thisArgUndefined(env);
37 Label thisArgNotUndefined(env);
38 Label callbackUndefined(env);
39 Label callbackNotUndefined(env);
40 Label nextCount(env);
41 Label loopHead(env);
42 Label loopEnd(env);
43 Label next(env);
44 Label afterLoop(env);
45 GateRef callbackFnHandle;
46 Branch(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector);
47 Bind(&valueNotJSAPIVector);
48 {
49 Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
50 Bind(&objIsJSProxy);
51 {
52 GateRef tempObj = GetTarget(*thisObj);
53 Branch(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath);
54 Bind(&objIsJSAPIVector);
55 {
56 thisObj = tempObj;
57 Jump(&valueIsJSAPIVector);
58 }
59 }
60 Bind(&objNotJSProxy);
61 Jump(slowPath);
62 }
63 Bind(&valueIsJSAPIVector);
64 {
65 Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
66 Bind(&callbackUndefined);
67 Jump(slowPath);
68 Bind(&callbackNotUndefined);
69 {
70 Label isCall(env);
71 Label notCall(env);
72 Label isHeapObj(env);
73 callbackFnHandle = GetCallArg0(numArgs);
74 Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
75 Bind(&isHeapObj);
76 Branch(IsCallable(callbackFnHandle), &isCall, ¬Call);
77 Bind(¬Call);
78 Jump(slowPath);
79 Bind(&isCall);
80 {
81 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
82 Bind(&thisArgUndefined);
83 Jump(&nextCount);
84 Bind(&thisArgNotUndefined);
85 thisArg = GetCallArg1(numArgs);
86 Jump(&nextCount);
87 }
88 }
89 }
90 Bind(&nextCount);
91 {
92 length = ContainerGetSize(*thisObj, type);
93 Jump(&loopHead);
94 LoopBegin(&loopHead);
95 {
96 Label lenChange(env);
97 Label hasException(env);
98 Label notHasException(env);
99 Label setValue(env);
100 Branch(Int32LessThan(*k, *length), &next, &afterLoop);
101 Bind(&next);
102 {
103 kValue = ContainerGetValue(*thisObj, *k, type);
104 if (IsPlainArray(type)) {
105 key = PlainArrayGetKey(*thisObj, *k);
106 } else {
107 key = IntToTaggedInt(*k);
108 }
109 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
110 Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *kValue, *key, *thisObj });
111 Branch(HasPendingException(glue), &hasException, ¬HasException);
112 Bind(&hasException);
113 {
114 result->WriteVariable(retValue);
115 Jump(exit);
116 }
117 Bind(¬HasException);
118 GateRef tempLen = ContainerGetSize(*thisObj, type);
119 Branch(Int32NotEqual(tempLen, *length), &lenChange, &setValue);
120 Bind(&lenChange);
121 length = tempLen;
122 Branch(Int32GreaterThanOrEqual(*k, *length), &afterLoop, &setValue);
123 Bind(&setValue);
124 if (IsReplaceAllElements(type)) {
125 ContainerSet(glue, *thisObj, *k, retValue, type);
126 }
127 Jump(&loopEnd);
128 }
129 }
130 Bind(&loopEnd);
131 k = Int32Add(*k, Int32(1));
132 LoopEnd(&loopHead);
133 }
134 Bind(&afterLoop);
135 Jump(exit);
136 }
137
QueueCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)138 void ContainersStubBuilder::QueueCommonFuncCall(GateRef glue, GateRef thisValue,
139 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
140 {
141 auto env = GetEnvironment();
142 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
143 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
144 DEFVARIABLE(key, VariableType::INT64(), Int64(0));
145 DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
146 DEFVARIABLE(length, VariableType::INT32(), Int32(0));
147 DEFVARIABLE(k, VariableType::INT32(), Int32(0));
148 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
149 Label valueIsJSAPIVector(env);
150 Label valueNotJSAPIVector(env);
151 Label objIsJSProxy(env);
152 Label objNotJSProxy(env);
153 Label objIsJSAPIVector(env);
154 Label thisArgUndefined(env);
155 Label thisArgNotUndefined(env);
156 Label callbackUndefined(env);
157 Label callbackNotUndefined(env);
158 Label nextCount(env);
159 Label loopHead(env);
160 Label loopEnd(env);
161 Label next(env);
162 Label afterLoop(env);
163 GateRef callbackFnHandle;
164 Branch(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector);
165 Bind(&valueNotJSAPIVector);
166 {
167 Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
168 Bind(&objIsJSProxy);
169 {
170 GateRef tempObj = GetTarget(*thisObj);
171 Branch(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath);
172 Bind(&objIsJSAPIVector);
173 {
174 thisObj = tempObj;
175 Jump(&valueIsJSAPIVector);
176 }
177 }
178 Bind(&objNotJSProxy);
179 Jump(slowPath);
180 }
181 Bind(&valueIsJSAPIVector);
182 {
183 Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
184 Bind(&callbackUndefined);
185 Jump(slowPath);
186 Bind(&callbackNotUndefined);
187 {
188 Label isCall(env);
189 Label notCall(env);
190 Label isHeapObj(env);
191 callbackFnHandle = GetCallArg0(numArgs);
192 Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
193 Bind(&isHeapObj);
194 Branch(IsCallable(callbackFnHandle), &isCall, ¬Call);
195 Bind(¬Call);
196 Jump(slowPath);
197 Bind(&isCall);
198 {
199 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
200 Bind(&thisArgUndefined);
201 Jump(&nextCount);
202 Bind(&thisArgNotUndefined);
203 thisArg = GetCallArg1(numArgs);
204 Jump(&nextCount);
205 }
206 }
207 }
208 Bind(&nextCount);
209 {
210 length = ContainerGetSize(*thisObj, type);
211 Jump(&loopHead);
212 LoopBegin(&loopHead);
213 {
214 Label lenChange(env);
215 Label hasException(env);
216 Label notHasException(env);
217 Label setValue(env);
218 Branch(Int32LessThan(*k, *length), &next, &afterLoop);
219 Bind(&next);
220 {
221 kValue = ContainerGetValue(*thisObj, *index, type);
222 index = QueueGetNextPosition(*thisObj, *index);
223 key = IntToTaggedInt(*k);
224 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
225 Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *kValue, *key, *thisObj });
226 Branch(HasPendingException(glue), &hasException, ¬HasException);
227 Bind(&hasException);
228 {
229 result->WriteVariable(retValue);
230 Jump(exit);
231 }
232 Bind(¬HasException);
233 Jump(&loopEnd);
234 }
235 }
236 Bind(&loopEnd);
237 k = Int32Add(*k, Int32(1));
238 LoopEnd(&loopHead);
239 }
240 Bind(&afterLoop);
241 Jump(exit);
242 }
243
DequeCommonFuncCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)244 void ContainersStubBuilder::DequeCommonFuncCall(GateRef glue, GateRef thisValue,
245 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
246 {
247 auto env = GetEnvironment();
248 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
249 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
250 DEFVARIABLE(key, VariableType::INT64(), Int64(0));
251 DEFVARIABLE(kValue, VariableType::JS_ANY(), Undefined());
252 DEFVARIABLE(length, VariableType::INT32(), Int32(0));
253 DEFVARIABLE(first, VariableType::INT32(), Int32(0));
254 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
255 Label valueIsJSAPIVector(env);
256 Label valueNotJSAPIVector(env);
257 Label objIsJSProxy(env);
258 Label objNotJSProxy(env);
259 Label objIsJSAPIVector(env);
260 Label thisArgUndefined(env);
261 Label thisArgNotUndefined(env);
262 Label callbackUndefined(env);
263 Label callbackNotUndefined(env);
264 Label nextCount(env);
265 Label loopHead(env);
266 Label loopEnd(env);
267 Label next(env);
268 Label afterLoop(env);
269 GateRef callbackFnHandle;
270 Branch(IsContainer(*thisObj, type), &valueIsJSAPIVector, &valueNotJSAPIVector);
271 Bind(&valueNotJSAPIVector);
272 {
273 Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
274 Bind(&objIsJSProxy);
275 {
276 GateRef tempObj = GetTarget(*thisObj);
277 Branch(IsContainer(tempObj, type), &objIsJSAPIVector, slowPath);
278 Bind(&objIsJSAPIVector);
279 {
280 thisObj = tempObj;
281 Jump(&valueIsJSAPIVector);
282 }
283 }
284 Bind(&objNotJSProxy);
285 Jump(slowPath);
286 }
287 Bind(&valueIsJSAPIVector);
288 {
289 Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
290 Bind(&callbackUndefined);
291 Jump(slowPath);
292 Bind(&callbackNotUndefined);
293 {
294 Label isCall(env);
295 Label notCall(env);
296 Label isHeapObj(env);
297 callbackFnHandle = GetCallArg0(numArgs);
298 Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
299 Bind(&isHeapObj);
300 Branch(IsCallable(callbackFnHandle), &isCall, ¬Call);
301 Bind(¬Call);
302 Jump(slowPath);
303 Bind(&isCall);
304 {
305 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
306 Bind(&thisArgUndefined);
307 Jump(&nextCount);
308 Bind(&thisArgNotUndefined);
309 thisArg = GetCallArg1(numArgs);
310 Jump(&nextCount);
311 }
312 }
313 }
314 Bind(&nextCount);
315 {
316 ContainersDequeStubBuilder dequeBuilder(this);
317 first = dequeBuilder.GetFirst(*thisObj);
318 GateRef last = dequeBuilder.GetLast(*thisObj);
319 GateRef capacity = dequeBuilder.GetElementsLength(*thisObj);
320 Jump(&loopHead);
321 LoopBegin(&loopHead);
322 {
323 Label lenChange(env);
324 Label hasException(env);
325 Label notHasException(env);
326 Label setValue(env);
327 Branch(Int32NotEqual(*first, last), &next, &afterLoop);
328 Bind(&next);
329 {
330 kValue = ContainerGetValue(*thisObj, *index, type);
331 key = IntToTaggedInt(*index);
332 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
333 Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *kValue, *key, *thisObj });
334 Branch(HasPendingException(glue), &hasException, ¬HasException);
335 Bind(&hasException);
336 {
337 result->WriteVariable(retValue);
338 Jump(exit);
339 }
340 Bind(¬HasException);
341 Jump(&loopEnd);
342 }
343 }
344 Bind(&loopEnd);
345 first = Int32Mod(Int32Add(*first, Int32(1)), capacity);
346 index = Int32Add(*index, Int32(1));
347 LoopEnd(&loopHead);
348 }
349 Bind(&afterLoop);
350 Jump(exit);
351 }
352
ContainersLightWeightCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)353 void ContainersStubBuilder::ContainersLightWeightCall(GateRef glue, GateRef thisValue,
354 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
355 {
356 auto env = GetEnvironment();
357 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
358 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
359 DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
360 DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
361 DEFVARIABLE(length, VariableType::INT32(), Int32(0));
362 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
363 Label valueIsJSAPILightWeight(env);
364 Label valueNotJSAPILightWeight(env);
365 Label objIsJSProxy(env);
366 Label objNotJSProxy(env);
367 Label objIsJSAPILightWeight(env);
368 Label thisArgUndefined(env);
369 Label thisArgNotUndefined(env);
370 Label callbackUndefined(env);
371 Label callbackNotUndefined(env);
372 Label nextCount(env);
373 Label loopHead(env);
374 Label loopEnd(env);
375 Label next(env);
376 Label afterLoop(env);
377 GateRef callbackFnHandle;
378 Branch(IsContainer(*thisObj, type), &valueIsJSAPILightWeight, &valueNotJSAPILightWeight);
379 Bind(&valueNotJSAPILightWeight);
380 {
381 Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
382 Bind(&objIsJSProxy);
383 {
384 GateRef tempObj = GetTarget(*thisObj);
385 Branch(IsContainer(tempObj, type), &objIsJSAPILightWeight, slowPath);
386 Bind(&objIsJSAPILightWeight);
387 {
388 thisObj = tempObj;
389 Jump(&valueIsJSAPILightWeight);
390 }
391 }
392 Bind(&objNotJSProxy);
393 Jump(slowPath);
394 }
395 Bind(&valueIsJSAPILightWeight);
396 {
397 Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
398 Bind(&callbackUndefined);
399 Jump(slowPath);
400 Bind(&callbackNotUndefined);
401 {
402 Label isCall(env);
403 Label notCall(env);
404 Label isHeapObj(env);
405 callbackFnHandle = GetCallArg0(numArgs);
406 Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, slowPath);
407 Bind(&isHeapObj);
408 Branch(IsCallable(callbackFnHandle), &isCall, ¬Call);
409 Bind(¬Call);
410 Jump(slowPath);
411 Bind(&isCall);
412 {
413 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
414 Bind(&thisArgUndefined);
415 Jump(&nextCount);
416 Bind(&thisArgNotUndefined);
417 thisArg = GetCallArg1(numArgs);
418 Jump(&nextCount);
419 }
420 }
421 }
422 Bind(&nextCount);
423 {
424 length = ContainerGetSize(*thisObj, type);
425 Jump(&loopHead);
426 LoopBegin(&loopHead);
427 {
428 Label lenChange(env);
429 Label hasException(env);
430 Label notHasException(env);
431 Branch(Int32LessThan(*index, *length), &next, &afterLoop);
432 Bind(&next);
433 {
434 value = ContainerGetValue(*thisObj, *index, type);
435 key = ContainerGetKey(*thisObj, *index, type);
436 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
437 Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *value, *key, *thisObj });
438 Branch(HasPendingException(glue), &hasException, ¬HasException);
439 Bind(&hasException);
440 {
441 result->WriteVariable(retValue);
442 Jump(exit);
443 }
444 Bind(¬HasException);
445 GateRef currentLen = ContainerGetSize(*thisObj, type);
446 Branch(Int32NotEqual(currentLen, *length), &lenChange, &loopEnd);
447 Bind(&lenChange);
448 length = currentLen;
449 Jump(&loopEnd);
450 }
451 }
452 Bind(&loopEnd);
453 index = Int32Add(*index, Int32(1));
454 LoopEnd(&loopHead);
455 }
456 Bind(&afterLoop);
457 Jump(exit);
458 }
459
ContainersHashCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)460 void ContainersStubBuilder::ContainersHashCall(GateRef glue, GateRef thisValue,
461 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
462 {
463 auto env = GetEnvironment();
464 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
465 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
466 DEFVARIABLE(node, VariableType::JS_ANY(), Undefined());
467 DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
468 DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
469 DEFVARIABLE(length, VariableType::INT32(), Int32(0));
470 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
471 Label valueIsJSAPIHash(env);
472 Label valueNotJSAPIHash(env);
473 Label objIsJSProxy(env);
474 Label objNotJSProxy(env);
475 Label objIsJSAPIHash(env);
476 Label thisArgUndefined(env);
477 Label thisArgNotUndefined(env);
478 Label callbackUndefined(env);
479 Label callbackNotUndefined(env);
480 Label nextCount(env);
481 Label nodeNotHole(env);
482 Label nodeIsLinked(env);
483 Label nodeIsRBTree(env);
484 Label loopLinked(env);
485 Label loopHead(env);
486 Label loopEnd(env);
487 Label next(env);
488 Label afterLoop(env);
489 GateRef callbackFnHandle;
490 Branch(IsContainer(*thisObj, type), &valueIsJSAPIHash, &valueNotJSAPIHash);
491 Bind(&valueNotJSAPIHash);
492 {
493 Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
494 Bind(&objIsJSProxy);
495 {
496 GateRef tempObj = GetTarget(*thisObj);
497 Branch(IsContainer(tempObj, type), &objIsJSAPIHash, slowPath);
498 Bind(&objIsJSAPIHash);
499 {
500 thisObj = tempObj;
501 Jump(&valueIsJSAPIHash);
502 }
503 }
504 Bind(&objNotJSProxy);
505 Jump(slowPath);
506 }
507 Bind(&valueIsJSAPIHash);
508 {
509 Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
510 Bind(&callbackUndefined);
511 Jump(slowPath);
512 Bind(&callbackNotUndefined);
513 {
514 Label isCall(env);
515 Label notCall(env);
516 Label isHeapObj(env);
517 callbackFnHandle = GetCallArg0(numArgs);
518 Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, ¬Call);
519 Bind(&isHeapObj);
520 Branch(IsCallable(callbackFnHandle), &isCall, ¬Call);
521 Bind(¬Call);
522 Jump(slowPath);
523 Bind(&isCall);
524 {
525 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
526 Bind(&thisArgUndefined);
527 Jump(&nextCount);
528 Bind(&thisArgNotUndefined);
529 thisArg = GetCallArg1(numArgs);
530 Jump(&nextCount);
531 }
532 }
533 }
534 Bind(&nextCount);
535 {
536 length = ContainerGetSize(*thisObj, type);
537 Jump(&loopHead);
538 LoopBegin(&loopHead);
539 {
540 Label hasExceptionLinked(env);
541 Label notHasExceptionLinked(env);
542 Label hasExceptionRBTree(env);
543 Label notHasExceptionRBTree(env);
544 Branch(Int32LessThan(*index, *length), &next, &afterLoop);
545 Bind(&next);
546 {
547 node = ContainerGetNode(*thisObj, *index, type);
548 Branch(TaggedIsHole(*node), &loopEnd, &nodeNotHole);
549 Bind(&nodeNotHole);
550 Branch(IsLinkedNode(*node), &nodeIsLinked, &nodeIsRBTree);
551 LoopBegin(&nodeIsLinked);
552 {
553 value = Load(VariableType::JS_POINTER(), *node, IntPtr(
554 type == ContainersType::HASHSET_FOREACH ? LinkedNode::KEY_OFFSET : LinkedNode::VALUE_OFFSET));
555 key = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::KEY_OFFSET));
556 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
557 Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN,
558 { *thisArg, *value, *key, *thisObj });
559 Branch(HasPendingException(glue), &hasExceptionLinked, ¬HasExceptionLinked);
560 Bind(&hasExceptionLinked);
561 {
562 result->WriteVariable(retValue);
563 Jump(exit);
564 }
565 Bind(¬HasExceptionLinked);
566 node = Load(VariableType::JS_POINTER(), *node, IntPtr(LinkedNode::NEXT_OFFSET));
567 Branch(TaggedIsHole(*node), &loopEnd, &loopLinked);
568 }
569 Bind(&loopLinked);
570 LoopEnd(&nodeIsLinked);
571 Bind(&nodeIsRBTree);
572 {
573 GateRef retValue = CallRuntime(glue, RTSTUB_ID(ContainerRBTreeForEach),
574 { *node, callbackFnHandle, *thisArg, *thisObj,
575 IntToTaggedInt(Int32(static_cast<int32_t>(type))) });
576 Branch(HasPendingException(glue), &hasExceptionRBTree, ¬HasExceptionRBTree);
577 Bind(&hasExceptionRBTree);
578 {
579 result->WriteVariable(retValue);
580 Jump(exit);
581 }
582 Bind(¬HasExceptionRBTree);
583 Jump(&loopEnd);
584 }
585 }
586 }
587 Bind(&loopEnd);
588 index = Int32Add(*index, Int32(1));
589 LoopEnd(&loopHead);
590 }
591 Bind(&afterLoop);
592 Jump(exit);
593 }
594
ContainersLinkedListCall(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * result,Label * exit,Label * slowPath,ContainersType type)595 void ContainersStubBuilder::ContainersLinkedListCall(GateRef glue, GateRef thisValue,
596 GateRef numArgs, Variable* result, Label *exit, Label *slowPath, ContainersType type)
597 {
598 auto env = GetEnvironment();
599 DEFVARIABLE(thisObj, VariableType::JS_ANY(), thisValue);
600 DEFVARIABLE(thisArg, VariableType::JS_ANY(), Undefined());
601 DEFVARIABLE(valueNode, VariableType::INT32(), Int32(0));
602 DEFVARIABLE(key, VariableType::JS_ANY(), Undefined());
603 DEFVARIABLE(value, VariableType::JS_ANY(), Undefined());
604 DEFVARIABLE(length, VariableType::INT32(), Int32(0));
605 DEFVARIABLE(index, VariableType::INT32(), Int32(0));
606 Label valueIsJSAPILinkedList(env);
607 Label valueNotJSAPILinkedList(env);
608 Label objIsJSProxy(env);
609 Label objNotJSProxy(env);
610 Label objIsJSAPILinkedList(env);
611 Label thisArgUndefined(env);
612 Label thisArgNotUndefined(env);
613 Label callbackUndefined(env);
614 Label callbackNotUndefined(env);
615 Label nextCount(env);
616 Label valueNotHole(env);
617 Label loopHead(env);
618 Label loopEnd(env);
619 Label next(env);
620 Label afterLoop(env);
621 GateRef callbackFnHandle;
622 Branch(IsContainer(*thisObj, type), &valueIsJSAPILinkedList, &valueNotJSAPILinkedList);
623 Bind(&valueNotJSAPILinkedList);
624 {
625 Branch(IsJsProxy(*thisObj), &objIsJSProxy, &objNotJSProxy);
626 Bind(&objIsJSProxy);
627 {
628 GateRef tempObj = GetTarget(*thisObj);
629 Branch(IsContainer(tempObj, type), &objIsJSAPILinkedList, slowPath);
630 Bind(&objIsJSAPILinkedList);
631 {
632 thisObj = tempObj;
633 Jump(&valueIsJSAPILinkedList);
634 }
635 }
636 Bind(&objNotJSProxy);
637 Jump(slowPath);
638 }
639 Bind(&valueIsJSAPILinkedList);
640 {
641 Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &callbackUndefined, &callbackNotUndefined);
642 Bind(&callbackUndefined);
643 Jump(slowPath);
644 Bind(&callbackNotUndefined);
645 {
646 Label isCall(env);
647 Label notCall(env);
648 Label isHeapObj(env);
649 callbackFnHandle = GetCallArg0(numArgs);
650 Branch(TaggedIsHeapObject(callbackFnHandle), &isHeapObj, ¬Call);
651 Bind(&isHeapObj);
652 Branch(IsCallable(callbackFnHandle), &isCall, ¬Call);
653 Bind(¬Call);
654 Jump(slowPath);
655 Bind(&isCall);
656 {
657 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &thisArgUndefined, &thisArgNotUndefined);
658 Bind(&thisArgUndefined);
659 Jump(&nextCount);
660 Bind(&thisArgNotUndefined);
661 thisArg = GetCallArg1(numArgs);
662 Jump(&nextCount);
663 }
664 }
665 }
666 Bind(&nextCount);
667 {
668 length = ContainerGetSize(*thisObj, type);
669 valueNode = Int32(TaggedList<TaggedArray>::ELEMENTS_START_INDEX);
670 Jump(&loopHead);
671 LoopBegin(&loopHead);
672 {
673 Label hasException(env);
674 Label notHasException(env);
675 Branch(Int32LessThan(*index, *length), &next, &afterLoop);
676 Bind(&next);
677 {
678 valueNode = TaggedGetInt(ContainerGetNode(*thisObj,
679 Int32Add(*valueNode, Int32(TaggedList<TaggedArray>::NEXT_PTR_OFFSET)), type));
680 value = ContainerGetNode(*thisObj, *valueNode, type);
681 Branch(TaggedIsHole(*value), &loopEnd, &valueNotHole);
682 Bind(&valueNotHole);
683 key = IntToTaggedInt(*index);
684 GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0,
685 Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { *thisArg, *value, *key, *thisObj });
686 Branch(HasPendingException(glue), &hasException, ¬HasException);
687 Bind(&hasException);
688 {
689 result->WriteVariable(retValue);
690 Jump(exit);
691 }
692 Bind(¬HasException);
693 Jump(&loopEnd);
694 }
695 }
696 Bind(&loopEnd);
697 index = Int32Add(*index, Int32(1));
698 LoopEnd(&loopHead);
699 }
700 Bind(&afterLoop);
701 Jump(exit);
702 }
703 } // namespace panda::ecmascript::kungfu
704