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_string_stub_builder.h"
17
18 #include "ecmascript/compiler/builtins/builtins_stubs.h"
19 #include "ecmascript/compiler/new_object_stub_builder.h"
20
21 namespace panda::ecmascript::kungfu {
StringAt(GateRef obj,GateRef index)22 GateRef BuiltinsStringStubBuilder::StringAt(GateRef obj, GateRef index)
23 {
24 auto env = GetEnvironment();
25 Label entry(env);
26 env->SubCfgEntry(&entry);
27 DEFVARIABLE(result, VariableType::INT32(), Int32(0));
28
29 Label exit(env);
30 Label isUtf16(env);
31 Label isUtf8(env);
32 Label doIntOp(env);
33 Label leftIsNumber(env);
34 Label rightIsNumber(env);
35 GateRef dataUtf16 = GetNormalStringData(obj);
36 Branch(IsUtf16String(obj), &isUtf16, &isUtf8);
37 Bind(&isUtf16);
38 {
39 result = ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(dataUtf16,
40 PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))))));
41 Jump(&exit);
42 }
43 Bind(&isUtf8);
44 {
45 result = ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(dataUtf16,
46 PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
47 Jump(&exit);
48 }
49 Bind(&exit);
50 auto ret = *result;
51 env->SubCfgExit();
52 return ret;
53 }
54
CreateFromEcmaString(GateRef glue,GateRef obj,GateRef index)55 GateRef BuiltinsStringStubBuilder::CreateFromEcmaString(GateRef glue, GateRef obj, GateRef index)
56 {
57 auto env = GetEnvironment();
58 Label entry(env);
59 env->SubCfgEntry(&entry);
60 DEFVARIABLE(result, VariableType::JS_POINTER(), Hole());
61 DEFVARIABLE(canBeCompressed, VariableType::BOOL(), False());
62 DEFVARIABLE(data, VariableType::INT16(), Int32(0));
63
64 Label exit(env);
65 Label isUtf16(env);
66 Label isUtf8(env);
67 Label allocString(env);
68 GateRef dataUtf = GetNormalStringData(obj);
69 Branch(IsUtf16String(obj), &isUtf16, &isUtf8);
70 Bind(&isUtf16);
71 {
72 GateRef dataAddr = PtrAdd(dataUtf, PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))));
73 data = Load(VariableType::INT16(), dataAddr);
74 canBeCompressed = CanBeCompressed(dataAddr, Int32(1), true);
75 Jump(&allocString);
76 }
77 Bind(&isUtf8);
78 {
79 GateRef dataAddr = PtrAdd(dataUtf, PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))));
80 data = ZExtInt8ToInt16(Load(VariableType::INT8(), dataAddr));
81 canBeCompressed = CanBeCompressed(dataAddr, Int32(1), false);
82 Jump(&allocString);
83 }
84 Bind(&allocString);
85 {
86 Label afterNew(env);
87 Label isUtf8Next(env);
88 Label isUtf16Next(env);
89 NewObjectStubBuilder newBuilder(this);
90 newBuilder.SetParameters(glue, 0);
91 Branch(*canBeCompressed, &isUtf8Next, &isUtf16Next);
92 Bind(&isUtf8Next);
93 {
94 newBuilder.AllocLineStringObject(&result, &afterNew, Int32(1), true);
95 }
96 Bind(&isUtf16Next);
97 {
98 newBuilder.AllocLineStringObject(&result, &afterNew, Int32(1), false);
99 }
100 Bind(&afterNew);
101 {
102 Label isUtf8Copy(env);
103 Label isUtf16Copy(env);
104 GateRef dst = PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET));
105 Branch(*canBeCompressed, &isUtf8Copy, &isUtf16Copy);
106 Bind(&isUtf8Copy);
107 {
108 Store(VariableType::INT8(), glue, dst, IntPtr(0), TruncInt16ToInt8(*data));
109 Jump(&exit);
110 }
111 Bind(&isUtf16Copy);
112 {
113 Store(VariableType::INT16(), glue, dst, IntPtr(0), *data);
114 Jump(&exit);
115 }
116 }
117 }
118 Bind(&exit);
119 auto ret = *result;
120 env->SubCfgExit();
121 return ret;
122 }
123
FastSubString(GateRef glue,GateRef thisValue,GateRef from,GateRef len)124 GateRef BuiltinsStringStubBuilder::FastSubString(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
125 {
126 auto env = GetEnvironment();
127 Label entry(env);
128 env->SubCfgEntry(&entry);
129 DEFVARIABLE(result, VariableType::JS_POINTER(), thisValue);
130
131 Label exit(env);
132 Label lenEqualZero(env);
133 Label lenNotEqualZero(env);
134 Label fromEqualZero(env);
135 Label next(env);
136 Label isUtf8(env);
137 Label isUtf16(env);
138
139 Branch(Int32Equal(len, Int32(0)), &lenEqualZero, &lenNotEqualZero);
140 Bind(&lenEqualZero);
141 {
142 result = GetGlobalConstantValue(
143 VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
144 Jump(&exit);
145 }
146 Bind(&lenNotEqualZero);
147 {
148 Branch(Int32Equal(from, Int32(0)), &fromEqualZero, &next);
149 Bind(&fromEqualZero);
150 {
151 GateRef thisLen = GetLengthFromString(thisValue);
152 Branch(Int32Equal(len, thisLen), &exit, &next);
153 }
154 Bind(&next);
155 {
156 Branch(IsUtf8String(thisValue), &isUtf8, &isUtf16);
157 Bind(&isUtf8);
158 {
159 result = FastSubUtf8String(glue, thisValue, from, len);
160 Jump(&exit);
161 }
162 Bind(&isUtf16);
163 {
164 result = FastSubUtf16String(glue, thisValue, from, len);
165 Jump(&exit);
166 }
167 }
168 }
169 Bind(&exit);
170 auto ret = *result;
171 env->SubCfgExit();
172 return ret;
173 }
174
FastSubUtf8String(GateRef glue,GateRef thisValue,GateRef from,GateRef len)175 GateRef BuiltinsStringStubBuilder::FastSubUtf8String(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
176 {
177 auto env = GetEnvironment();
178 Label entry(env);
179 env->SubCfgEntry(&entry);
180 DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
181 Label exit(env);
182
183 NewObjectStubBuilder newBuilder(this);
184 newBuilder.SetParameters(glue, 0);
185 Label afterNew(env);
186 newBuilder.AllocLineStringObject(&result, &afterNew, len, true);
187 Bind(&afterNew);
188 {
189 GateRef dst = PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET));
190 GateRef source = PtrAdd(GetNormalStringData(thisValue), ZExtInt32ToPtr(from));
191 CopyChars(glue, dst, source, len, IntPtr(sizeof(uint8_t)), VariableType::INT8());
192 Jump(&exit);
193 }
194 Bind(&exit);
195 auto ret = *result;
196 env->SubCfgExit();
197 return ret;
198 }
199
FastSubUtf16String(GateRef glue,GateRef thisValue,GateRef from,GateRef len)200 GateRef BuiltinsStringStubBuilder::FastSubUtf16String(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
201 {
202 auto env = GetEnvironment();
203 Label entry(env);
204 env->SubCfgEntry(&entry);
205 DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
206
207 Label exit(env);
208 Label isUtf16(env);
209 Label isUtf8(env);
210 Label isUtf8Next(env);
211 Label isUtf16Next(env);
212
213 GateRef fromOffset = PtrMul(ZExtInt32ToPtr(from), IntPtr(sizeof(uint16_t) / sizeof(uint8_t)));
214 GateRef source = PtrAdd(GetNormalStringData(thisValue), fromOffset);
215 GateRef canBeCompressed = CanBeCompressed(source, len, true);
216 NewObjectStubBuilder newBuilder(this);
217 newBuilder.SetParameters(glue, 0);
218 Label afterNew(env);
219 Branch(canBeCompressed, &isUtf8, &isUtf16);
220 Bind(&isUtf8);
221 {
222 newBuilder.AllocLineStringObject(&result, &afterNew, len, true);
223 }
224 Bind(&isUtf16);
225 {
226 newBuilder.AllocLineStringObject(&result, &afterNew, len, false);
227 }
228 Bind(&afterNew);
229 {
230 GateRef source1 = PtrAdd(GetNormalStringData(thisValue), fromOffset);
231 GateRef dst = PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET));
232 Branch(canBeCompressed, &isUtf8Next, &isUtf16Next);
233 Bind(&isUtf8Next);
234 {
235 CopyUtf16AsUtf8(glue, source1, dst, len);
236 Jump(&exit);
237 }
238 Bind(&isUtf16Next);
239 {
240 CopyChars(glue, dst, source1, len, IntPtr(sizeof(uint16_t)), VariableType::INT16());
241 Jump(&exit);
242 }
243 }
244 Bind(&exit);
245 auto ret = *result;
246 env->SubCfgExit();
247 return ret;
248 }
249
CopyChars(GateRef glue,GateRef dst,GateRef source,GateRef sourceLength,GateRef size,VariableType type)250 void BuiltinsStringStubBuilder::CopyChars(GateRef glue, GateRef dst, GateRef source,
251 GateRef sourceLength, GateRef size, VariableType type)
252 {
253 auto env = GetEnvironment();
254 Label entry(env);
255 env->SubCfgEntry(&entry);
256 DEFVARIABLE(dstTmp, VariableType::JS_ANY(), dst);
257 DEFVARIABLE(sourceTmp, VariableType::JS_ANY(), source);
258 DEFVARIABLE(len, VariableType::INT32(), sourceLength);
259 Label loopHead(env);
260 Label loopEnd(env);
261 Label next(env);
262 Label exit(env);
263 Jump(&loopHead);
264
265 LoopBegin(&loopHead);
266 {
267 Branch(Int32GreaterThan(*len, Int32(0)), &next, &exit);
268 Bind(&next);
269 {
270 len = Int32Sub(*len, Int32(1));
271 GateRef i = Load(type, *sourceTmp);
272 Store(type, glue, *dstTmp, IntPtr(0), i);
273 Jump(&loopEnd);
274 }
275 }
276 Bind(&loopEnd);
277 sourceTmp = PtrAdd(*sourceTmp, size);
278 dstTmp = PtrAdd(*dstTmp, size);
279 LoopEnd(&loopHead);
280
281 Bind(&exit);
282 env->SubCfgExit();
283 return;
284 }
285
CanBeCompressed(GateRef data,GateRef len,bool isUtf16)286 GateRef BuiltinsStringStubBuilder::CanBeCompressed(GateRef data, GateRef len, bool isUtf16)
287 {
288 auto env = GetEnvironment();
289 Label entry(env);
290 env->SubCfgEntry(&entry);
291 DEFVARIABLE(result, VariableType::BOOL(), True());
292 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
293 Label loopHead(env);
294 Label loopEnd(env);
295 Label nextCount(env);
296 Label isNotASCIICharacter(env);
297 Label exit(env);
298 Jump(&loopHead);
299 LoopBegin(&loopHead);
300 {
301 Branch(Int32LessThan(*i, len), &nextCount, &exit);
302 Bind(&nextCount);
303 {
304 if (isUtf16) {
305 GateRef tmp = Load(VariableType::INT16(), data,
306 PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(uint16_t))));
307 Branch(IsASCIICharacter(ZExtInt16ToInt32(tmp)), &loopEnd, &isNotASCIICharacter);
308 } else {
309 GateRef tmp = Load(VariableType::INT8(), data,
310 PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(uint8_t))));
311 Branch(IsASCIICharacter(ZExtInt8ToInt32(tmp)), &loopEnd, &isNotASCIICharacter);
312 }
313 Bind(&isNotASCIICharacter);
314 {
315 result = False();
316 Jump(&exit);
317 }
318 }
319 }
320 Bind(&loopEnd);
321 i = Int32Add(*i, Int32(1));
322 LoopEnd(&loopHead);
323
324 Bind(&exit);
325 auto ret = *result;
326 env->SubCfgExit();
327 return ret;
328 }
329
CopyUtf16AsUtf8(GateRef glue,GateRef src,GateRef dst,GateRef sourceLength)330 void BuiltinsStringStubBuilder::CopyUtf16AsUtf8(GateRef glue, GateRef src, GateRef dst,
331 GateRef sourceLength)
332 {
333 auto env = GetEnvironment();
334 Label entry(env);
335 env->SubCfgEntry(&entry);
336 DEFVARIABLE(dstTmp, VariableType::JS_ANY(), dst);
337 DEFVARIABLE(sourceTmp, VariableType::JS_ANY(), src);
338 DEFVARIABLE(len, VariableType::INT32(), sourceLength);
339 Label loopHead(env);
340 Label loopEnd(env);
341 Label next(env);
342 Label exit(env);
343 Jump(&loopHead);
344 LoopBegin(&loopHead);
345 {
346 Branch(Int32GreaterThan(*len, Int32(0)), &next, &exit);
347 Bind(&next);
348 {
349 len = Int32Sub(*len, Int32(1));
350 GateRef i = Load(VariableType::INT16(), *sourceTmp);
351 Store(VariableType::INT8(), glue, *dstTmp, IntPtr(0), TruncInt16ToInt8(i));
352 Jump(&loopEnd);
353 }
354 }
355
356 Bind(&loopEnd);
357 sourceTmp = PtrAdd(*sourceTmp, IntPtr(sizeof(uint16_t)));
358 dstTmp = PtrAdd(*dstTmp, IntPtr(sizeof(uint8_t)));
359 LoopEnd(&loopHead);
360
361 Bind(&exit);
362 env->SubCfgExit();
363 return;
364 }
365
GetUtf16Data(GateRef stringData,GateRef index)366 GateRef BuiltinsStringStubBuilder::GetUtf16Data(GateRef stringData, GateRef index)
367 {
368 return ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(stringData,
369 PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))))));
370 }
371
IsASCIICharacter(GateRef data)372 GateRef BuiltinsStringStubBuilder::IsASCIICharacter(GateRef data)
373 {
374 return Int32LessThan(Int32Sub(data, Int32(1)), Int32(base::utf_helper::UTF8_1B_MAX));
375 }
376
GetUtf8Data(GateRef stringData,GateRef index)377 GateRef BuiltinsStringStubBuilder::GetUtf8Data(GateRef stringData, GateRef index)
378 {
379 return ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(stringData,
380 PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
381 }
382
StringIndexOf(GateRef lhsData,bool lhsIsUtf8,GateRef rhsData,bool rhsIsUtf8,GateRef pos,GateRef max,GateRef rhsCount)383 GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhsData, bool lhsIsUtf8, GateRef rhsData, bool rhsIsUtf8,
384 GateRef pos, GateRef max, GateRef rhsCount)
385 {
386 auto env = GetEnvironment();
387 Label entry(env);
388 env->SubCfgEntry(&entry);
389 DEFVARIABLE(i, VariableType::INT32(), pos);
390 DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
391 DEFVARIABLE(j, VariableType::INT32(), Int32(0));
392 DEFVARIABLE(k, VariableType::INT32(), Int32(1));
393 Label exit(env);
394 Label next(env);
395 Label continueFor(env);
396 Label lhsNotEqualFirst(env);
397 Label continueCount(env);
398 Label lessEnd(env);
399 Label equalEnd(env);
400 Label loopHead(env);
401 Label loopEnd(env);
402 Label nextCount(env);
403 Label nextCount1(env);
404 Label nextCount2(env);
405 GateRef first;
406 if (rhsIsUtf8) {
407 first = ZExtInt8ToInt32(Load(VariableType::INT8(), rhsData));
408 } else {
409 first = ZExtInt16ToInt32(Load(VariableType::INT16(), rhsData));
410 }
411 Jump(&loopHead);
412 LoopBegin(&loopHead);
413 Branch(Int32LessThanOrEqual(*i, max), &next, &exit);
414 Bind(&next);
415 {
416 Label loopHead1(env);
417 Label loopEnd1(env);
418 GateRef lhsTemp;
419 if (lhsIsUtf8) {
420 lhsTemp = GetUtf8Data(lhsData, *i);
421 } else {
422 lhsTemp = GetUtf16Data(lhsData, *i);
423 }
424 Branch(Int32NotEqual(lhsTemp, first), &nextCount1, &nextCount);
425 Bind(&nextCount1);
426 {
427 i = Int32Add(*i, Int32(1));
428 Jump(&loopHead1);
429 }
430 LoopBegin(&loopHead1);
431 {
432 Branch(Int32LessThanOrEqual(*i, max), &continueFor, &nextCount);
433 Bind(&continueFor);
434 {
435 GateRef lhsTemp1;
436 if (lhsIsUtf8) {
437 lhsTemp1 = GetUtf8Data(lhsData, *i);
438 } else {
439 lhsTemp1 = GetUtf16Data(lhsData, *i);
440 }
441 Branch(Int32NotEqual(lhsTemp1, first), &lhsNotEqualFirst, &nextCount);
442 Bind(&lhsNotEqualFirst);
443 {
444 i = Int32Add(*i, Int32(1));
445 Jump(&loopEnd1);
446 }
447 }
448 }
449 Bind(&loopEnd1);
450 LoopEnd(&loopHead1);
451 Bind(&nextCount);
452 {
453 Branch(Int32LessThanOrEqual(*i, max), &continueCount, &loopEnd);
454 Bind(&continueCount);
455 {
456 Label loopHead2(env);
457 Label loopEnd2(env);
458 j = Int32Add(*i, Int32(1));
459 GateRef end = Int32Sub(Int32Add(*j, rhsCount), Int32(1));
460 k = Int32(1);
461 Jump(&loopHead2);
462 LoopBegin(&loopHead2);
463 {
464 Branch(Int32LessThan(*j, end), &lessEnd, &nextCount2);
465 Bind(&lessEnd);
466 {
467 GateRef lhsTemp2;
468 if (lhsIsUtf8) {
469 lhsTemp2 = GetUtf8Data(lhsData, *j);
470 } else {
471 lhsTemp2 = GetUtf16Data(lhsData, *j);
472 }
473 GateRef rhsTemp;
474 if (rhsIsUtf8) {
475 rhsTemp = GetUtf8Data(rhsData, *k);
476 } else {
477 rhsTemp = GetUtf16Data(rhsData, *k);
478 }
479 Branch(Int32Equal(lhsTemp2, rhsTemp), &loopEnd2, &nextCount2);
480 }
481 }
482 Bind(&loopEnd2);
483 j = Int32Add(*j, Int32(1));
484 k = Int32Add(*k, Int32(1));
485 LoopEnd(&loopHead2);
486 Bind(&nextCount2);
487 {
488 Branch(Int32Equal(*j, end), &equalEnd, &loopEnd);
489 Bind(&equalEnd);
490 result = *i;
491 Jump(&exit);
492 }
493 }
494 }
495 }
496 Bind(&loopEnd);
497 i = Int32Add(*i, Int32(1));
498 LoopEnd(&loopHead);
499
500 Bind(&exit);
501 auto ret = *result;
502 env->SubCfgExit();
503 return ret;
504 }
505
StringIndexOf(GateRef lhs,GateRef rhs,GateRef pos)506 GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhs, GateRef rhs, GateRef pos)
507 {
508 auto env = GetEnvironment();
509 Label entry(env);
510 env->SubCfgEntry(&entry);
511 DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
512 DEFVARIABLE(posTag, VariableType::INT32(), pos);
513 Label exit(env);
514 Label rhsCountEqualZero(env);
515 Label nextCount(env);
516 Label rhsCountNotEqualZero(env);
517 Label posLessZero(env);
518 Label posNotLessZero(env);
519 Label maxNotLessZero(env);
520 Label rhsIsUtf8(env);
521 Label rhsIsUtf16(env);
522 Label posRMaxNotGreaterLhs(env);
523
524 GateRef lhsCount = GetLengthFromString(lhs);
525 GateRef rhsCount = GetLengthFromString(rhs);
526
527 Branch(Int32GreaterThan(pos, lhsCount), &exit, &nextCount);
528 Bind(&nextCount);
529 {
530 Branch(Int32Equal(rhsCount, Int32(0)), &rhsCountEqualZero, &rhsCountNotEqualZero);
531 Bind(&rhsCountEqualZero);
532 {
533 result = pos;
534 Jump(&exit);
535 }
536 Bind(&rhsCountNotEqualZero);
537 {
538 Branch(Int32LessThan(pos, Int32(0)), &posLessZero, &posNotLessZero);
539 Bind(&posLessZero);
540 {
541 posTag = Int32(0);
542 Jump(&posNotLessZero);
543 }
544 Bind(&posNotLessZero);
545 {
546 GateRef max = Int32Sub(lhsCount, rhsCount);
547 Branch(Int32LessThan(max, Int32(0)), &exit, &maxNotLessZero);
548 Bind(&maxNotLessZero);
549 {
550 GateRef posRMax = Int32Add(*posTag, rhsCount);
551 Branch(Int32GreaterThan(posRMax, lhsCount), &exit, &posRMaxNotGreaterLhs);
552 Bind(&posRMaxNotGreaterLhs);
553 GateRef rhsData = GetNormalStringData(rhs);
554 GateRef lhsData = GetNormalStringData(lhs);
555 Branch(IsUtf8String(rhs), &rhsIsUtf8, &rhsIsUtf16);
556 Bind(&rhsIsUtf8);
557 {
558 Label lhsIsUtf8(env);
559 Label lhsIsUtf16(env);
560 Branch(IsUtf8String(lhs), &lhsIsUtf8, &lhsIsUtf16);
561 Bind(&lhsIsUtf8);
562 {
563 result = StringIndexOf(lhsData, true, rhsData, true, *posTag, max, rhsCount);
564 Jump(&exit);
565 }
566 Bind(&lhsIsUtf16);
567 {
568 result = StringIndexOf(lhsData, false, rhsData, true, *posTag, max, rhsCount);
569 Jump(&exit);
570 }
571 }
572 Bind(&rhsIsUtf16);
573 {
574 Label lhsIsUtf8(env);
575 Label lhsIsUtf16(env);
576 Branch(IsUtf8String(lhs), &lhsIsUtf8, &lhsIsUtf16);
577 Bind(&lhsIsUtf8);
578 {
579 result = StringIndexOf(lhsData, true, rhsData, false, *posTag, max, rhsCount);
580 Jump(&exit);
581 }
582 Bind(&lhsIsUtf16);
583 {
584 result = StringIndexOf(lhsData, false, rhsData, false, *posTag, max, rhsCount);
585 Jump(&exit);
586 }
587 }
588 }
589 }
590 }
591 }
592 Bind(&exit);
593 auto ret = *result;
594 env->SubCfgExit();
595 return ret;
596 }
597 } // namespace panda::ecmascript::kungfu
598