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