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/builtins_stubs.h"
17
18 #include "ecmascript/base/number_helper.h"
19 #include "ecmascript/compiler/builtins/builtins_call_signature.h"
20 #include "ecmascript/compiler/builtins/builtins_string_stub_builder.h"
21 #include "ecmascript/compiler/builtins/containers_vector_stub_builder.h"
22 #include "ecmascript/compiler/builtins/containers_stub_builder.h"
23 #include "ecmascript/compiler/interpreter_stub-inl.h"
24 #include "ecmascript/compiler/llvm_ir_builder.h"
25 #include "ecmascript/compiler/new_object_stub_builder.h"
26 #include "ecmascript/compiler/stub_builder-inl.h"
27 #include "ecmascript/compiler/variable_type.h"
28 #include "ecmascript/js_date.h"
29 #include "ecmascript/js_primitive_ref.h"
30
31 namespace panda::ecmascript::kungfu {
32 #if ECMASCRIPT_ENABLE_BUILTIN_LOG
33 #define DECLARE_BUILTINS(name) \
34 void name##StubBuilder::GenerateCircuit() \
35 { \
36 GateRef glue = PtrArgument(static_cast<size_t>(BuiltinsArgs::GLUE)); \
37 GateRef nativeCode = PtrArgument(static_cast<size_t>(BuiltinsArgs::NATIVECODE)); \
38 GateRef func = TaggedArgument(static_cast<size_t>(BuiltinsArgs::FUNC)); \
39 GateRef newTarget = TaggedArgument(static_cast<size_t>(BuiltinsArgs::NEWTARGET)); \
40 GateRef thisValue = TaggedArgument(static_cast<size_t>(BuiltinsArgs::THISVALUE)); \
41 GateRef numArgs = PtrArgument(static_cast<size_t>(BuiltinsArgs::NUMARGS)); \
42 DebugPrint(glue, { Int32(GET_MESSAGE_STRING_ID(name)) }); \
43 GenerateCircuitImpl(glue, nativeCode, func, newTarget, thisValue, numArgs); \
44 } \
45 void name##StubBuilder::GenerateCircuitImpl(GateRef glue, GateRef nativeCode, GateRef func, \
46 GateRef newTarget, GateRef thisValue, GateRef numArgs)
47 #else
48 #define DECLARE_BUILTINS(name) \
49 void name##StubBuilder::GenerateCircuit() \
50 { \
51 GateRef glue = PtrArgument(static_cast<size_t>(BuiltinsArgs::GLUE)); \
52 GateRef nativeCode = PtrArgument(static_cast<size_t>(BuiltinsArgs::NATIVECODE)); \
53 GateRef func = TaggedArgument(static_cast<size_t>(BuiltinsArgs::FUNC)); \
54 GateRef newTarget = TaggedArgument(static_cast<size_t>(BuiltinsArgs::NEWTARGET)); \
55 GateRef thisValue = TaggedArgument(static_cast<size_t>(BuiltinsArgs::THISVALUE)); \
56 GateRef numArgs = PtrArgument(static_cast<size_t>(BuiltinsArgs::NUMARGS)); \
57 GenerateCircuitImpl(glue, nativeCode, func, newTarget, thisValue, numArgs); \
58 } \
59 void name##StubBuilder::GenerateCircuitImpl(GateRef glue, GateRef nativeCode, GateRef func, \
60 GateRef newTarget, GateRef thisValue, GateRef numArgs)
61 #endif
62
GetArg(GateRef numArgs,GateRef index)63 GateRef BuiltinsStubBuilder::GetArg(GateRef numArgs, GateRef index)
64 {
65 auto env = GetEnvironment();
66 Label entry(env);
67 env->SubCfgEntry(&entry);
68 DEFVARIABLE(arg, VariableType::JS_ANY(), Undefined());
69 Label validIndex(env);
70 Label exit(env);
71 Branch(IntPtrGreaterThan(numArgs, index), &validIndex, &exit);
72 Bind(&validIndex);
73 {
74 GateRef argv = GetArgv();
75 arg = Load(VariableType::JS_ANY(), argv, PtrMul(index, IntPtr(JSTaggedValue::TaggedTypeSize())));
76 Jump(&exit);
77 }
78 Bind(&exit);
79 GateRef ret = *arg;
80 env->SubCfgExit();
81 return ret;
82 }
83
CallSlowPath(GateRef nativeCode,GateRef glue,GateRef thisValue,GateRef numArgs,GateRef func,GateRef newTarget)84 GateRef BuiltinsStubBuilder::CallSlowPath(GateRef nativeCode, GateRef glue, GateRef thisValue,
85 GateRef numArgs, GateRef func, GateRef newTarget)
86 {
87 auto env = GetEnvironment();
88 Label entry(env);
89 env->SubCfgEntry(&entry);
90 Label exit(env);
91 Label callThis0(env);
92 Label notcallThis0(env);
93 Label notcallThis1(env);
94 Label callThis1(env);
95 Label callThis2(env);
96 Label callThis3(env);
97 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
98 GateRef runtimeCallInfoArgs = PtrAdd(numArgs, IntPtr(NUM_MANDATORY_JSFUNC_ARGS));
99 Branch(Int64Equal(numArgs, IntPtr(0)), &callThis0, ¬callThis0);
100 Bind(&callThis0);
101 {
102 result = CallBuiltinRuntime(glue, { nativeCode, glue, runtimeCallInfoArgs, func, newTarget, thisValue });
103 Jump(&exit);
104 }
105 Bind(¬callThis0);
106 {
107 Branch(Int64Equal(numArgs, IntPtr(1)), &callThis1, ¬callThis1);
108 Bind(&callThis1);
109 {
110 GateRef arg0 = GetCallArg0();
111 result =
112 CallBuiltinRuntime(glue, { nativeCode, glue, runtimeCallInfoArgs, func, newTarget, thisValue, arg0 });
113 Jump(&exit);
114 }
115 Bind(¬callThis1);
116 {
117 Branch(Int64Equal(numArgs, IntPtr(2)), &callThis2, &callThis3); // 2: args2
118 Bind(&callThis2);
119 {
120 GateRef arg0 = GetCallArg0();
121 GateRef arg1 = GetCallArg1();
122 result = CallBuiltinRuntime(glue,
123 { nativeCode, glue, runtimeCallInfoArgs, func, newTarget, thisValue, arg0, arg1 });
124 Jump(&exit);
125 }
126 Bind(&callThis3);
127 {
128 GateRef arg0 = GetCallArg0();
129 GateRef arg1 = GetCallArg1();
130 GateRef arg2 = GetCallArg2();
131 result = CallBuiltinRuntime(glue,
132 { nativeCode, glue, runtimeCallInfoArgs, func, newTarget, thisValue, arg0, arg1, arg2 });
133 Jump(&exit);
134 }
135 }
136 }
137
138 Bind(&exit);
139 auto ret = *result;
140 env->SubCfgExit();
141 return ret;
142 }
143
DECLARE_BUILTINS(CharCodeAt)144 DECLARE_BUILTINS(CharCodeAt)
145 {
146 auto env = GetEnvironment();
147 DEFVARIABLE(res, VariableType::JS_ANY(), DoubleToTaggedDoublePtr(Double(base::NAN_VALUE)));
148 DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
149
150 Label objNotUndefinedAndNull(env);
151 Label isString(env);
152 Label slowPath(env);
153 Label next(env);
154 Label posTagNotUndefined(env);
155 Label posTagIsInt(env);
156 Label posTagNotInt(env);
157 Label posNotGreaterLen(env);
158 Label posNotLessZero(env);
159 Label exit(env);
160 Label posTagIsDouble(env);
161 Label thisIsHeapobject(env);
162
163 Branch(TaggedIsUndefinedOrNull(thisValue), &slowPath, &objNotUndefinedAndNull);
164 Bind(&objNotUndefinedAndNull);
165 {
166 Branch(TaggedIsHeapObject(thisValue), &thisIsHeapobject, &slowPath);
167 Bind(&thisIsHeapobject);
168 Branch(IsString(thisValue), &isString, &slowPath);
169 Bind(&isString);
170 {
171 GateRef thisLen = GetLengthFromString(thisValue);
172 Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &posTagNotUndefined);
173 Bind(&posTagNotUndefined);
174 {
175 GateRef posTag = GetCallArg0();
176 Branch(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
177 Bind(&posTagIsInt);
178 pos = GetInt32OfTInt(posTag);
179 Jump(&next);
180 Bind(&posTagNotInt);
181 Branch(TaggedIsDouble(posTag), &posTagIsDouble, &slowPath);
182 Bind(&posTagIsDouble);
183 pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
184 Jump(&next);
185 }
186 Bind(&next);
187 {
188 Branch(Int32GreaterThanOrEqual(*pos, thisLen), &exit, &posNotGreaterLen);
189 Bind(&posNotGreaterLen);
190 {
191 Branch(Int32LessThan(*pos, Int32(0)), &exit, &posNotLessZero);
192 Bind(&posNotLessZero);
193 {
194 BuiltinsStringStubBuilder stringBuilder(this);
195 res = IntToTaggedPtr(stringBuilder.StringAt(thisValue, *pos));
196 Jump(&exit);
197 }
198 }
199 }
200 }
201 }
202 Bind(&slowPath);
203 {
204 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
205 Jump(&exit);
206 }
207 Bind(&exit);
208 Return(*res);
209 }
210
DECLARE_BUILTINS(IndexOf)211 DECLARE_BUILTINS(IndexOf)
212 {
213 auto env = GetEnvironment();
214 DEFVARIABLE(res, VariableType::JS_ANY(), IntToTaggedPtr(Int32(-1)));
215 DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
216
217 Label objNotUndefinedAndNull(env);
218 Label isString(env);
219 Label isSearchString(env);
220 Label slowPath(env);
221 Label next(env);
222 Label resPosGreaterZero(env);
223 Label searchTagIsHeapObject(env);
224 Label posTagNotUndefined(env);
225 Label posTagIsInt(env);
226 Label posTagNotInt(env);
227 Label exit(env);
228 Label posTagIsDouble(env);
229 Label nextCount(env);
230 Label posNotLessThanLen(env);
231 Label thisIsHeapobject(env);
232
233 Branch(TaggedIsUndefinedOrNull(thisValue), &slowPath, &objNotUndefinedAndNull);
234 Bind(&objNotUndefinedAndNull);
235 {
236 Branch(TaggedIsHeapObject(thisValue), &thisIsHeapobject, &slowPath);
237 Bind(&thisIsHeapobject);
238 Branch(IsString(thisValue), &isString, &slowPath);
239 Bind(&isString);
240 {
241 GateRef searchTag = GetCallArg0();
242 Branch(TaggedIsHeapObject(searchTag), &searchTagIsHeapObject, &slowPath);
243 Bind(&searchTagIsHeapObject);
244 Branch(IsString(searchTag), &isSearchString, &slowPath);
245 Bind(&isSearchString);
246 {
247 GateRef thisLen = GetLengthFromString(thisValue);
248 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &next, &posTagNotUndefined);
249 Bind(&posTagNotUndefined);
250 {
251 GateRef posTag = GetCallArg1();
252 Branch(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
253 Bind(&posTagIsInt);
254 pos = GetInt32OfTInt(posTag);
255 Jump(&next);
256 Bind(&posTagNotInt);
257 Branch(TaggedIsDouble(posTag), &posTagIsDouble, &slowPath);
258 Bind(&posTagIsDouble);
259 pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
260 Jump(&next);
261 }
262 Bind(&next);
263 {
264 Label posGreaterThanZero(env);
265 Label posNotGreaterThanZero(env);
266 Branch(Int32GreaterThan(*pos, Int32(0)), &posGreaterThanZero, &posNotGreaterThanZero);
267 Bind(&posNotGreaterThanZero);
268 {
269 pos = Int32(0);
270 Jump(&nextCount);
271 }
272 Bind(&posGreaterThanZero);
273 {
274 Branch(Int32LessThanOrEqual(*pos, thisLen), &nextCount, &posNotLessThanLen);
275 Bind(&posNotLessThanLen);
276 {
277 pos = thisLen;
278 Jump(&nextCount);
279 }
280 }
281 Bind(&nextCount);
282 {
283 BuiltinsStringStubBuilder stringBuilder(this);
284 GateRef resPos = stringBuilder.StringIndexOf(thisValue, searchTag, *pos);
285 Branch(Int32GreaterThanOrEqual(resPos, Int32(0)), &resPosGreaterZero, &exit);
286 Bind(&resPosGreaterZero);
287 {
288 Label resPosLessZero(env);
289 Branch(Int32LessThanOrEqual(resPos, thisLen), &resPosLessZero, &exit);
290 Bind(&resPosLessZero);
291 {
292 res = IntToTaggedPtr(resPos);
293 Jump(&exit);
294 }
295 }
296 }
297 }
298 }
299 }
300 }
301 Bind(&slowPath);
302 {
303 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
304 Jump(&exit);
305 }
306 Bind(&exit);
307 Return(*res);
308 }
309
DECLARE_BUILTINS(Substring)310 DECLARE_BUILTINS(Substring)
311 {
312 auto env = GetEnvironment();
313 DEFVARIABLE(res, VariableType::JS_ANY(), IntToTaggedPtr(Int32(-1)));
314 DEFVARIABLE(start, VariableType::INT32(), Int32(0));
315 DEFVARIABLE(end, VariableType::INT32(), Int32(0));
316 DEFVARIABLE(from, VariableType::INT32(), Int32(0));
317 DEFVARIABLE(to, VariableType::INT32(), Int32(0));
318
319 Label objNotUndefinedAndNull(env);
320 Label isString(env);
321 Label isSearchString(env);
322 Label slowPath(env);
323 Label countStart(env);
324 Label endTagIsUndefined(env);
325 Label startNotGreatZero(env);
326 Label countEnd(env);
327 Label endNotGreatZero(env);
328 Label countFrom(env);
329 Label countRes(env);
330 Label startTagNotUndefined(env);
331 Label posTagIsInt(env);
332 Label posTagNotInt(env);
333 Label exit(env);
334 Label posTagIsDouble(env);
335 Label endTagNotUndefined(env);
336 Label endTagIsInt(env);
337 Label endTagNotInt(env);
338 Label endTagIsDouble(env);
339 Label endGreatZero(env);
340 Label endGreatLen(env);
341 Label startGreatZero(env);
342 Label startGreatEnd(env);
343 Label startNotGreatEnd(env);
344 Label thisIsHeapobject(env);
345
346 Branch(TaggedIsUndefinedOrNull(thisValue), &slowPath, &objNotUndefinedAndNull);
347 Bind(&objNotUndefinedAndNull);
348 {
349 Branch(TaggedIsHeapObject(thisValue), &thisIsHeapobject, &slowPath);
350 Bind(&thisIsHeapobject);
351 Branch(IsString(thisValue), &isString, &slowPath);
352 Bind(&isString);
353 {
354 Label next(env);
355 GateRef thisLen = GetLengthFromString(thisValue);
356 Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &startTagNotUndefined);
357 Bind(&startTagNotUndefined);
358 {
359 GateRef startTag = GetCallArg0();
360 Branch(TaggedIsInt(startTag), &posTagIsInt, &posTagNotInt);
361 Bind(&posTagIsInt);
362 start = GetInt32OfTInt(startTag);
363 Jump(&next);
364 Bind(&posTagNotInt);
365 Branch(TaggedIsDouble(startTag), &posTagIsDouble, &slowPath);
366 Bind(&posTagIsDouble);
367 start = DoubleToInt(glue, GetDoubleOfTDouble(startTag));
368 Jump(&next);
369 }
370 Bind(&next);
371 {
372 Branch(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &endTagIsUndefined, &endTagNotUndefined);
373 Bind(&endTagIsUndefined);
374 {
375 end = thisLen;
376 Jump(&countStart);
377 }
378 Bind(&endTagNotUndefined);
379 {
380 GateRef endTag = GetCallArg1();
381 Branch(TaggedIsInt(endTag), &endTagIsInt, &endTagNotInt);
382 Bind(&endTagIsInt);
383 end = GetInt32OfTInt(endTag);
384 Jump(&countStart);
385 Bind(&endTagNotInt);
386 Branch(TaggedIsDouble(endTag), &endTagIsDouble, &slowPath);
387 Bind(&endTagIsDouble);
388 end = DoubleToInt(glue, GetDoubleOfTDouble(endTag));
389 Jump(&countStart);
390 }
391 }
392 Bind(&countStart);
393 {
394 Label startGreatLen(env);
395 Branch(Int32GreaterThan(*start, Int32(0)), &startGreatZero, &startNotGreatZero);
396 Bind(&startNotGreatZero);
397 {
398 start = Int32(0);
399 Jump(&countEnd);
400 }
401 Bind(&startGreatZero);
402 {
403 Branch(Int32GreaterThan(*start, thisLen), &startGreatLen, &countEnd);
404 Bind(&startGreatLen);
405 {
406 start = thisLen;
407 Jump(&countEnd);
408 }
409 }
410 }
411 Bind(&countEnd);
412 {
413 Branch(Int32GreaterThan(*end, Int32(0)), &endGreatZero, &endNotGreatZero);
414 Bind(&endNotGreatZero);
415 {
416 end = Int32(0);
417 Jump(&countFrom);
418 }
419 Bind(&endGreatZero);
420 {
421 Branch(Int32GreaterThan(*end, thisLen), &endGreatLen, &countFrom);
422 Bind(&endGreatLen);
423 {
424 end = thisLen;
425 Jump(&countFrom);
426 }
427 }
428 }
429 Bind(&countFrom);
430 {
431 Branch(Int32GreaterThan(*start, *end), &startGreatEnd, &startNotGreatEnd);
432 Bind(&startGreatEnd);
433 {
434 from = *end;
435 to = *start;
436 Jump(&countRes);
437 }
438 Bind(&startNotGreatEnd);
439 {
440 from = *start;
441 to = *end;
442 Jump(&countRes);
443 }
444 }
445 Bind(&countRes);
446 {
447 BuiltinsStringStubBuilder stringBuilder(this);
448 GateRef len = Int32Sub(*to, *from);
449 Label isUtf8(env);
450 Label isUtf16(env);
451 Branch(IsUtf8String(thisValue), &isUtf8, &isUtf16);
452 Bind(&isUtf8);
453 {
454 res = stringBuilder.FastSubUtf8String(glue, thisValue, *from, len);
455 Jump(&exit);
456 }
457 Bind(&isUtf16);
458 {
459 res = stringBuilder.FastSubUtf16String(glue, thisValue, *from, len);
460 Jump(&exit);
461 }
462 }
463 }
464 }
465
466 Bind(&slowPath);
467 {
468 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
469 Jump(&exit);
470 }
471 Bind(&exit);
472 Return(*res);
473 }
474
DECLARE_BUILTINS(CharAt)475 DECLARE_BUILTINS(CharAt)
476 {
477 auto env = GetEnvironment();
478 DEFVARIABLE(res, VariableType::JS_POINTER(), Hole());
479 DEFVARIABLE(pos, VariableType::INT32(), Int32(0));
480
481 Label objNotUndefinedAndNull(env);
482 Label isString(env);
483 Label slowPath(env);
484 Label next(env);
485 Label posTagNotUndefined(env);
486 Label posTagIsInt(env);
487 Label posTagNotInt(env);
488 Label posNotGreaterLen(env);
489 Label posGreaterLen(env);
490 Label posNotLessZero(env);
491 Label exit(env);
492 Label posTagIsDouble(env);
493 Label thisIsHeapobject(env);
494
495 Branch(TaggedIsUndefinedOrNull(thisValue), &slowPath, &objNotUndefinedAndNull);
496 Bind(&objNotUndefinedAndNull);
497 {
498 Branch(TaggedIsHeapObject(thisValue), &thisIsHeapobject, &slowPath);
499 Bind(&thisIsHeapobject);
500 Branch(IsString(thisValue), &isString, &slowPath);
501 Bind(&isString);
502 {
503 GateRef thisLen = GetLengthFromString(thisValue);
504 Branch(Int64GreaterThanOrEqual(IntPtr(0), numArgs), &next, &posTagNotUndefined);
505 Bind(&posTagNotUndefined);
506 {
507 GateRef posTag = GetCallArg0();
508 Branch(TaggedIsInt(posTag), &posTagIsInt, &posTagNotInt);
509 Bind(&posTagIsInt);
510 pos = GetInt32OfTInt(posTag);
511 Jump(&next);
512 Bind(&posTagNotInt);
513 Branch(TaggedIsDouble(posTag), &posTagIsDouble, &slowPath);
514 Bind(&posTagIsDouble);
515 pos = DoubleToInt(glue, GetDoubleOfTDouble(posTag));
516 Jump(&next);
517 }
518 Bind(&next);
519 {
520 Branch(Int32GreaterThanOrEqual(*pos, thisLen), &posGreaterLen, &posNotGreaterLen);
521 Bind(&posNotGreaterLen);
522 {
523 Branch(Int32LessThan(*pos, Int32(0)), &posGreaterLen, &posNotLessZero);
524 Bind(&posNotLessZero);
525 {
526 BuiltinsStringStubBuilder stringBuilder(this);
527 res = stringBuilder.CreateFromEcmaString(glue, thisValue, *pos);
528 Jump(&exit);
529 }
530 }
531 Bind(&posGreaterLen);
532 {
533 res = GetGlobalConstantValue(
534 VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
535 Jump(&exit);
536 }
537 }
538 }
539 }
540 Bind(&slowPath);
541 {
542 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
543 Jump(&exit);
544 }
545 Bind(&exit);
546 Return(*res);
547 }
548
DECLARE_BUILTINS(VectorForEach)549 DECLARE_BUILTINS(VectorForEach)
550 {
551 auto env = GetEnvironment();
552 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
553
554 Label exit(env);
555 Label slowPath(env);
556
557 ContainersStubBuilder containersBuilder(this);
558 containersBuilder.ContainersCommonFuncCall(glue, thisValue, numArgs, &res, &exit,
559 &slowPath, ContainersType::VECTOR_FOREACH);
560 Bind(&slowPath);
561 {
562 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
563 Jump(&exit);
564 }
565 Bind(&exit);
566 Return(*res);
567 }
568
DECLARE_BUILTINS(VectorReplaceAllElements)569 DECLARE_BUILTINS(VectorReplaceAllElements)
570 {
571 auto env = GetEnvironment();
572 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
573
574 Label exit(env);
575 Label slowPath(env);
576
577 ContainersStubBuilder containersBuilder(this);
578 containersBuilder.ContainersCommonFuncCall(glue, thisValue, numArgs, &res, &exit,
579 &slowPath, ContainersType::VECTOR_REPLACEALLELEMENTS);
580 Bind(&slowPath);
581 {
582 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
583 Jump(&exit);
584 }
585 Bind(&exit);
586 Return(*res);
587 }
588
DECLARE_BUILTINS(StackForEach)589 DECLARE_BUILTINS(StackForEach)
590 {
591 auto env = GetEnvironment();
592 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
593
594 Label exit(env);
595 Label slowPath(env);
596
597 ContainersStubBuilder containersBuilder(this);
598 containersBuilder.ContainersCommonFuncCall(glue, thisValue, numArgs, &res, &exit,
599 &slowPath, ContainersType::STACK_FOREACH);
600 Bind(&slowPath);
601 {
602 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
603 Jump(&exit);
604 }
605 Bind(&exit);
606 Return(*res);
607 }
608
DECLARE_BUILTINS(PlainArrayForEach)609 DECLARE_BUILTINS(PlainArrayForEach)
610 {
611 auto env = GetEnvironment();
612 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
613
614 Label exit(env);
615 Label slowPath(env);
616
617 ContainersStubBuilder containersBuilder(this);
618 containersBuilder.ContainersCommonFuncCall(glue, thisValue, numArgs, &res, &exit,
619 &slowPath, ContainersType::PLAINARRAY_FOREACH);
620 Bind(&slowPath);
621 {
622 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
623 Jump(&exit);
624 }
625 Bind(&exit);
626 Return(*res);
627 }
628
DECLARE_BUILTINS(QueueForEach)629 DECLARE_BUILTINS(QueueForEach)
630 {
631 auto env = GetEnvironment();
632 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
633
634 Label exit(env);
635 Label slowPath(env);
636
637 ContainersStubBuilder containersBuilder(this);
638 containersBuilder.QueueCommonFuncCall(glue, thisValue, numArgs, &res, &exit,
639 &slowPath, ContainersType::QUEUE_FOREACH);
640 Bind(&slowPath);
641 {
642 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
643 Jump(&exit);
644 }
645 Bind(&exit);
646 Return(*res);
647 }
648
DECLARE_BUILTINS(DequeForEach)649 DECLARE_BUILTINS(DequeForEach)
650 {
651 auto env = GetEnvironment();
652 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
653
654 Label exit(env);
655 Label slowPath(env);
656
657 ContainersStubBuilder containersBuilder(this);
658 containersBuilder.DequeCommonFuncCall(glue, thisValue, numArgs, &res, &exit,
659 &slowPath, ContainersType::DEQUE_FOREACH);
660 Bind(&slowPath);
661 {
662 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
663 Jump(&exit);
664 }
665 Bind(&exit);
666 Return(*res);
667 }
668
DECLARE_BUILTINS(LightWeightMapForEach)669 DECLARE_BUILTINS(LightWeightMapForEach)
670 {
671 auto env = GetEnvironment();
672 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
673
674 Label exit(env);
675 Label slowPath(env);
676
677 ContainersStubBuilder containersBuilder(this);
678 containersBuilder.ContainersLightWeightCall(glue, thisValue, numArgs, &res, &exit,
679 &slowPath, ContainersType::LIGHTWEIGHTMAP_FOREACH);
680 Bind(&slowPath);
681 {
682 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
683 Jump(&exit);
684 }
685 Bind(&exit);
686 Return(*res);
687 }
688
DECLARE_BUILTINS(LightWeightSetForEach)689 DECLARE_BUILTINS(LightWeightSetForEach)
690 {
691 auto env = GetEnvironment();
692 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
693
694 Label exit(env);
695 Label slowPath(env);
696
697 ContainersStubBuilder containersBuilder(this);
698 containersBuilder.ContainersLightWeightCall(glue, thisValue, numArgs, &res, &exit,
699 &slowPath, ContainersType::LIGHTWEIGHTSET_FOREACH);
700 Bind(&slowPath);
701 {
702 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
703 Jump(&exit);
704 }
705 Bind(&exit);
706 Return(*res);
707 }
708
DECLARE_BUILTINS(HashMapForEach)709 DECLARE_BUILTINS(HashMapForEach)
710 {
711 auto env = GetEnvironment();
712 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
713
714 Label exit(env);
715 Label slowPath(env);
716
717 ContainersStubBuilder containersBuilder(this);
718 containersBuilder.ContainersHashCall(glue, thisValue, numArgs, &res, &exit,
719 &slowPath, ContainersType::HASHMAP_FOREACH);
720 Bind(&slowPath);
721 {
722 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
723 Jump(&exit);
724 }
725 Bind(&exit);
726 Return(*res);
727 }
728
DECLARE_BUILTINS(HashSetForEach)729 DECLARE_BUILTINS(HashSetForEach)
730 {
731 auto env = GetEnvironment();
732 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
733
734 Label exit(env);
735 Label slowPath(env);
736
737 ContainersStubBuilder containersBuilder(this);
738 containersBuilder.ContainersHashCall(glue, thisValue, numArgs, &res, &exit,
739 &slowPath, ContainersType::HASHSET_FOREACH);
740 Bind(&slowPath);
741 {
742 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
743 Jump(&exit);
744 }
745 Bind(&exit);
746 Return(*res);
747 }
748
DECLARE_BUILTINS(LinkedListForEach)749 DECLARE_BUILTINS(LinkedListForEach)
750 {
751 auto env = GetEnvironment();
752 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
753
754 Label exit(env);
755 Label slowPath(env);
756
757 ContainersStubBuilder containersBuilder(this);
758 containersBuilder.ContainersLinkedListCall(glue, thisValue, numArgs, &res, &exit,
759 &slowPath, ContainersType::LINKEDLIST_FOREACH);
760 Bind(&slowPath);
761 {
762 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
763 Jump(&exit);
764 }
765 Bind(&exit);
766 Return(*res);
767 }
768
DECLARE_BUILTINS(ListForEach)769 DECLARE_BUILTINS(ListForEach)
770 {
771 auto env = GetEnvironment();
772 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
773
774 Label exit(env);
775 Label slowPath(env);
776
777 ContainersStubBuilder containersBuilder(this);
778 containersBuilder.ContainersLinkedListCall(glue, thisValue, numArgs, &res, &exit,
779 &slowPath, ContainersType::LIST_FOREACH);
780 Bind(&slowPath);
781 {
782 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
783 Jump(&exit);
784 }
785 Bind(&exit);
786 Return(*res);
787 }
788
DECLARE_BUILTINS(ArrayListForEach)789 DECLARE_BUILTINS(ArrayListForEach)
790 {
791 auto env = GetEnvironment();
792 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
793
794 Label exit(env);
795 Label slowPath(env);
796
797 ContainersStubBuilder containersBuilder(this);
798 containersBuilder.ContainersCommonFuncCall(glue, thisValue, numArgs, &res, &exit,
799 &slowPath, ContainersType::ARRAYLIST_FOREACH);
800 Bind(&slowPath);
801 {
802 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
803 Jump(&exit);
804 }
805 Bind(&exit);
806 Return(*res);
807 }
808
DECLARE_BUILTINS(ArrayListReplaceAllElements)809 DECLARE_BUILTINS(ArrayListReplaceAllElements)
810 {
811 auto env = GetEnvironment();
812 DEFVARIABLE(res, VariableType::JS_POINTER(), Undefined());
813
814 Label exit(env);
815 Label slowPath(env);
816
817 ContainersStubBuilder containersBuilder(this);
818 containersBuilder.ContainersCommonFuncCall(glue, thisValue, numArgs, &res, &exit,
819 &slowPath, ContainersType::ARRAYLIST_REPLACEALLELEMENTS);
820 Bind(&slowPath);
821 {
822 res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget);
823 Jump(&exit);
824 }
825 Bind(&exit);
826 Return(*res);
827 }
828
DECLARE_BUILTINS(BooleanConstructor)829 DECLARE_BUILTINS(BooleanConstructor)
830 {
831 auto env = GetEnvironment();
832 DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
833
834 Label newTargetIsJSFunction(env);
835 Label slowPath(env);
836 Label exit(env);
837
838 Branch(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath);
839 Bind(&newTargetIsJSFunction);
840 {
841 Label intialHClassIsHClass(env);
842 GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget,
843 IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
844 Branch(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath);
845 Bind(&intialHClassIsHClass);
846 {
847 NewObjectStubBuilder newBuilder(this);
848 newBuilder.SetParameters(glue, 0);
849 Label afterNew(env);
850 newBuilder.NewJSObject(&res, &afterNew, intialHClass);
851 Bind(&afterNew);
852 {
853 GateRef valueOffset = IntPtr(JSPrimitiveRef::VALUE_OFFSET);
854 GateRef value = GetArg(numArgs, IntPtr(0));
855 Store(VariableType::INT64(), glue, *res, valueOffset, FastToBoolean(value));
856 Jump(&exit);
857 }
858 }
859 }
860 Bind(&slowPath);
861 {
862 GateRef argv = GetArgv();
863 res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true);
864 Jump(&exit);
865 }
866 Bind(&exit);
867 Return(*res);
868 }
869
DECLARE_BUILTINS(DateConstructor)870 DECLARE_BUILTINS(DateConstructor)
871 {
872 auto env = GetEnvironment();
873 DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
874
875 Label newTargetIsJSFunction(env);
876 Label slowPath(env);
877 Label exit(env);
878
879 Branch(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath);
880 Bind(&newTargetIsJSFunction);
881 {
882 Label intialHClassIsHClass(env);
883 GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget,
884 IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
885 Branch(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath);
886 Bind(&intialHClassIsHClass);
887 {
888 Label oneArg(env);
889 Label notOneArg(env);
890 Label newJSDate(env);
891 DEFVARIABLE(timeValue, VariableType::FLOAT64(), Double(0));
892 Branch(Int64Equal(numArgs, IntPtr(1)), &oneArg, ¬OneArg);
893 Bind(&oneArg);
894 {
895 Label valueIsNumber(env);
896 GateRef value = GetArgNCheck(IntPtr(0));
897 Branch(TaggedIsNumber(value), &valueIsNumber, &slowPath);
898 Bind(&valueIsNumber);
899 {
900 timeValue = CallNGCRuntime(glue, RTSTUB_ID(TimeClip), {GetDoubleOfTNumber(value)});
901 Jump(&newJSDate);
902 }
903 }
904 Bind(¬OneArg);
905 {
906 Label threeArgs(env);
907 Branch(Int64Equal(numArgs, IntPtr(3)), &threeArgs, &slowPath); // 3: year month day
908 Bind(&threeArgs);
909 {
910 Label numberYearMonthDay(env);
911 GateRef year = GetArgNCheck(IntPtr(0));
912 GateRef month = GetArgNCheck(IntPtr(1));
913 GateRef day = GetArgNCheck(IntPtr(2));
914 Branch(IsNumberYearMonthDay(year, month, day), &numberYearMonthDay, &slowPath);
915 Bind(&numberYearMonthDay);
916 {
917 GateRef y = GetDoubleOfTNumber(year);
918 GateRef m = GetDoubleOfTNumber(month);
919 GateRef d = GetDoubleOfTNumber(day);
920 timeValue = CallNGCRuntime(glue, RTSTUB_ID(SetDateValues), {y, m, d});
921 Jump(&newJSDate);
922 }
923 }
924 }
925 Bind(&newJSDate);
926 {
927 NewObjectStubBuilder newBuilder(this);
928 newBuilder.SetParameters(glue, 0);
929 Label afterNew(env);
930 newBuilder.NewJSObject(&res, &afterNew, intialHClass);
931 Bind(&afterNew);
932 {
933 GateRef timeValueOffset = IntPtr(JSDate::TIME_VALUE_OFFSET);
934 Store(VariableType::JS_NOT_POINTER(), glue, *res, timeValueOffset,
935 DoubleToTaggedDoublePtr(*timeValue));
936 Jump(&exit);
937 }
938 }
939 }
940 }
941 Bind(&slowPath);
942 {
943 GateRef argv = GetArgv();
944 res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true);
945 Jump(&exit);
946 }
947 Bind(&exit);
948 Return(*res);
949 }
950
DECLARE_BUILTINS(ArrayConstructor)951 DECLARE_BUILTINS(ArrayConstructor)
952 {
953 auto env = GetEnvironment();
954 DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
955
956 Label newTargetIsJSFunction(env);
957 Label slowPath(env);
958 Label exit(env);
959
960 Branch(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath);
961 Bind(&newTargetIsJSFunction);
962 {
963 Label fastGetHclass(env);
964 Label intialHClassIsHClass(env);
965 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
966 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset);
967 auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX);
968 Branch(Equal(ChangeTaggedPointerToInt64(arrayFunc), ChangeTaggedPointerToInt64(newTarget)), &fastGetHclass,
969 &slowPath);
970 Bind(&fastGetHclass);
971 GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
972 DEFVARIABLE(arrayLength, VariableType::INT64(), Int64(0));
973 Branch(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath);
974 Bind(&intialHClassIsHClass);
975 {
976 Label noArg(env);
977 Label hasArg(env);
978 Label arrayCreate(env);
979 Branch(Int64Equal(numArgs, IntPtr(0)), &noArg, &hasArg);
980 Bind(&noArg);
981 {
982 Jump(&arrayCreate);
983 }
984 Bind(&hasArg);
985 {
986 Label hasOneArg(env);
987 Branch(Int64Equal(numArgs, IntPtr(1)), &hasOneArg, &slowPath);
988 Bind(&hasOneArg);
989 {
990 Label argIsNumber(env);
991 GateRef arg0 = GetArg(numArgs, IntPtr(0));
992 Branch(TaggedIsNumber(arg0), &argIsNumber, &slowPath);
993 Bind(&argIsNumber);
994 {
995 Label argIsInt(env);
996 Label argIsDouble(env);
997 Branch(TaggedIsInt(arg0), &argIsInt, &argIsDouble);
998 Bind(&argIsInt);
999 {
1000 Label validIntLength(env);
1001 GateRef intLen = GetInt64OfTInt(arg0);
1002 GateRef isGEZero = Int64GreaterThanOrEqual(intLen, Int64(0));
1003 GateRef isLEMaxLen = Int64LessThanOrEqual(intLen, Int64(JSArray::MAX_ARRAY_INDEX));
1004 Branch(BoolAnd(isGEZero, isLEMaxLen), &validIntLength, &slowPath);
1005 Bind(&validIntLength);
1006 {
1007 arrayLength = intLen;
1008 Jump(&arrayCreate);
1009 }
1010 }
1011 Bind(&argIsDouble);
1012 {
1013 Label validDoubleLength(env);
1014 GateRef doubleLength = GetDoubleOfTDouble(arg0);
1015 GateRef doubleToInt = DoubleToInt(glue, doubleLength);
1016 GateRef intToDouble = CastInt64ToFloat64(SExtInt32ToInt64(doubleToInt));
1017 GateRef doubleEqual = DoubleEqual(doubleLength, intToDouble);
1018 GateRef doubleLEMaxLen =
1019 DoubleLessThanOrEqual(doubleLength, Double(JSArray::MAX_ARRAY_INDEX));
1020 Branch(BoolAnd(doubleEqual, doubleLEMaxLen), &validDoubleLength, &slowPath);
1021 Bind(&validDoubleLength);
1022 {
1023 arrayLength = SExtInt32ToInt64(doubleToInt);
1024 Jump(&arrayCreate);
1025 }
1026 }
1027 }
1028 }
1029 }
1030 Bind(&arrayCreate);
1031 {
1032 NewObjectStubBuilder newBuilder(this);
1033 newBuilder.SetParameters(glue, 0);
1034 Label afterNew(env);
1035 newBuilder.NewJSObject(&res, &afterNew, intialHClass);
1036 Bind(&afterNew);
1037 {
1038 GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET);
1039 Store(VariableType::JS_ANY(), glue, *res, lengthOffset, Int64ToTaggedInt(*arrayLength));
1040 GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue,
1041 ConstantIndex::ARRAY_LENGTH_ACCESSOR);
1042 SetPropertyInlinedProps(glue, *res, intialHClass, accessor,
1043 Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX));
1044 SetExtensibleToBitfield(glue, *res, true);
1045 Jump(&exit);
1046 }
1047 }
1048 }
1049 }
1050 Bind(&slowPath);
1051 {
1052 GateRef argv = GetArgv();
1053 res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true);
1054 Jump(&exit);
1055 }
1056
1057 Bind(&exit);
1058 Return(*res);
1059 }
1060 } // namespace panda::ecmascript::kungfu