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 = PtrAdd(obj, IntPtr(EcmaString::DATA_OFFSET));
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 = PtrAdd(obj, IntPtr(EcmaString::DATA_OFFSET));
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.AllocStringObject(&result, &afterNew, Int32(1), true);
95 }
96 Bind(&isUtf16Next);
97 {
98 newBuilder.AllocStringObject(&result, &afterNew, Int32(1), false);
99 }
100 Bind(&afterNew);
101 {
102 Label isUtf8Copy(env);
103 Label isUtf16Copy(env);
104 GateRef dst = PtrAdd(*result, IntPtr(EcmaString::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
FastSubUtf8String(GateRef glue,GateRef thisValue,GateRef from,GateRef len)124 GateRef BuiltinsStringStubBuilder::FastSubUtf8String(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(), Undefined());
130
131 Label exit(env);
132 Label lenEqualZero(env);
133 Label lenNotEqualZero(env);
134
135 Branch(Int32Equal(len, Int32(0)), &lenEqualZero, &lenNotEqualZero);
136 Bind(&lenEqualZero);
137 {
138 result = GetGlobalConstantValue(
139 VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
140 Jump(&exit);
141 }
142 Bind(&lenNotEqualZero);
143 {
144 NewObjectStubBuilder newBuilder(this);
145 newBuilder.SetParameters(glue, 0);
146 Label afterNew(env);
147 newBuilder.AllocStringObject(&result, &afterNew, len, true);
148 Bind(&afterNew);
149 {
150 GateRef dst = PtrAdd(*result, IntPtr(EcmaString::DATA_OFFSET));
151 GateRef source = PtrAdd(PtrAdd(thisValue, IntPtr(EcmaString::DATA_OFFSET)), ZExtInt32ToPtr(from));
152 StringCopy(glue, dst, source, len, IntPtr(sizeof(uint8_t)), VariableType::INT8());
153 Jump(&exit);
154 }
155 }
156 Bind(&exit);
157 auto ret = *result;
158 env->SubCfgExit();
159 return ret;
160 }
161
FastSubUtf16String(GateRef glue,GateRef thisValue,GateRef from,GateRef len)162 GateRef BuiltinsStringStubBuilder::FastSubUtf16String(GateRef glue, GateRef thisValue, GateRef from, GateRef len)
163 {
164 auto env = GetEnvironment();
165 Label entry(env);
166 env->SubCfgEntry(&entry);
167 DEFVARIABLE(result, VariableType::JS_POINTER(), Undefined());
168
169 Label exit(env);
170 Label isUtf16(env);
171 Label isUtf8(env);
172 Label isUtf8Next(env);
173 Label isUtf16Next(env);
174 Label lenEqualZero(env);
175 Label lenNotEqualZero(env);
176
177 Branch(Int32Equal(len, Int32(0)), &lenEqualZero, &lenNotEqualZero);
178 Bind(&lenEqualZero);
179 {
180 result = GetGlobalConstantValue(
181 VariableType::JS_POINTER(), glue, ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
182 Jump(&exit);
183 }
184 Bind(&lenNotEqualZero);
185 {
186 GateRef fromOffset = PtrMul(ZExtInt32ToPtr(from), IntPtr(sizeof(uint16_t) / sizeof(uint8_t)));
187 GateRef source = PtrAdd(PtrAdd(thisValue, IntPtr(EcmaString::DATA_OFFSET)), fromOffset);
188 GateRef canBeCompressed = CanBeCompressed(source, len, true);
189 NewObjectStubBuilder newBuilder(this);
190 newBuilder.SetParameters(glue, 0);
191 Label afterNew(env);
192 Branch(canBeCompressed, &isUtf8, &isUtf16);
193 Bind(&isUtf8);
194 {
195 newBuilder.AllocStringObject(&result, &afterNew, len, true);
196 }
197 Bind(&isUtf16);
198 {
199 newBuilder.AllocStringObject(&result, &afterNew, len, false);
200 }
201 Bind(&afterNew);
202 {
203 GateRef source1 = PtrAdd(PtrAdd(thisValue, IntPtr(EcmaString::DATA_OFFSET)), fromOffset);
204 GateRef dst = PtrAdd(*result, IntPtr(EcmaString::DATA_OFFSET));
205 Branch(canBeCompressed, &isUtf8Next, &isUtf16Next);
206 Bind(&isUtf8Next);
207 {
208 CopyUtf16AsUtf8(glue, source1, dst, len);
209 Jump(&exit);
210 }
211 Bind(&isUtf16Next);
212 {
213 StringCopy(glue, dst, source1, len, IntPtr(sizeof(uint16_t)), VariableType::INT16());
214 Jump(&exit);
215 }
216 }
217 }
218 Bind(&exit);
219 auto ret = *result;
220 env->SubCfgExit();
221 return ret;
222 }
223
StringCopy(GateRef glue,GateRef dst,GateRef source,GateRef sourceLength,GateRef size,VariableType type)224 void BuiltinsStringStubBuilder::StringCopy(GateRef glue, GateRef dst, GateRef source,
225 GateRef sourceLength, GateRef size, VariableType type)
226 {
227 auto env = GetEnvironment();
228 Label entry(env);
229 env->SubCfgEntry(&entry);
230 DEFVARIABLE(dstTmp, VariableType::JS_ANY(), dst);
231 DEFVARIABLE(sourceTmp, VariableType::JS_ANY(), source);
232 DEFVARIABLE(len, VariableType::INT32(), sourceLength);
233 Label loopHead(env);
234 Label loopEnd(env);
235 Label next(env);
236 Label exit(env);
237 Jump(&loopHead);
238
239 LoopBegin(&loopHead);
240 {
241 Branch(Int32GreaterThan(*len, Int32(0)), &next, &exit);
242 Bind(&next);
243 {
244 len = Int32Sub(*len, Int32(1));
245 GateRef i = Load(type, *sourceTmp);
246 Store(type, glue, *dstTmp, IntPtr(0), i);
247 Jump(&loopEnd);
248 }
249 }
250 Bind(&loopEnd);
251 sourceTmp = PtrAdd(*sourceTmp, size);
252 dstTmp = PtrAdd(*dstTmp, size);
253 LoopEnd(&loopHead);
254
255 Bind(&exit);
256 env->SubCfgExit();
257 return;
258 }
259
CanBeCompressed(GateRef data,GateRef len,bool isUtf16)260 GateRef BuiltinsStringStubBuilder::CanBeCompressed(GateRef data, GateRef len, bool isUtf16)
261 {
262 auto env = GetEnvironment();
263 Label entry(env);
264 env->SubCfgEntry(&entry);
265 DEFVARIABLE(result, VariableType::BOOL(), True());
266 DEFVARIABLE(i, VariableType::INT32(), Int32(0));
267 Label loopHead(env);
268 Label loopEnd(env);
269 Label nextCount(env);
270 Label isNotASCIICharacter(env);
271 Label exit(env);
272 Jump(&loopHead);
273 LoopBegin(&loopHead);
274 {
275 Branch(Int32LessThan(*i, len), &nextCount, &exit);
276 Bind(&nextCount);
277 {
278 if (isUtf16) {
279 GateRef tmp = Load(VariableType::INT16(), data,
280 PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(uint16_t))));
281 Branch(IsASCIICharacter(ZExtInt16ToInt32(tmp)), &loopEnd, &isNotASCIICharacter);
282 } else {
283 GateRef tmp = Load(VariableType::INT8(), data,
284 PtrMul(ZExtInt32ToPtr(*i), IntPtr(sizeof(uint8_t))));
285 Branch(IsASCIICharacter(ZExtInt8ToInt32(tmp)), &loopEnd, &isNotASCIICharacter);
286 }
287 Bind(&isNotASCIICharacter);
288 {
289 result = False();
290 Jump(&exit);
291 }
292 }
293 }
294 Bind(&loopEnd);
295 i = Int32Add(*i, Int32(1));
296 LoopEnd(&loopHead);
297
298 Bind(&exit);
299 auto ret = *result;
300 env->SubCfgExit();
301 return ret;
302 }
303
CopyUtf16AsUtf8(GateRef glue,GateRef src,GateRef dst,GateRef sourceLength)304 void BuiltinsStringStubBuilder::CopyUtf16AsUtf8(GateRef glue, GateRef src, GateRef dst,
305 GateRef sourceLength)
306 {
307 auto env = GetEnvironment();
308 Label entry(env);
309 env->SubCfgEntry(&entry);
310 DEFVARIABLE(dstTmp, VariableType::JS_ANY(), dst);
311 DEFVARIABLE(sourceTmp, VariableType::JS_ANY(), src);
312 DEFVARIABLE(len, VariableType::INT32(), sourceLength);
313 Label loopHead(env);
314 Label loopEnd(env);
315 Label next(env);
316 Label exit(env);
317 Jump(&loopHead);
318 LoopBegin(&loopHead);
319 {
320 Branch(Int32GreaterThan(*len, Int32(0)), &next, &exit);
321 Bind(&next);
322 {
323 len = Int32Sub(*len, Int32(1));
324 GateRef i = Load(VariableType::INT16(), *sourceTmp);
325 Store(VariableType::INT8(), glue, *dstTmp, IntPtr(0), TruncInt16ToInt8(i));
326 Jump(&loopEnd);
327 }
328 }
329
330 Bind(&loopEnd);
331 sourceTmp = PtrAdd(*sourceTmp, IntPtr(sizeof(uint16_t)));
332 dstTmp = PtrAdd(*dstTmp, IntPtr(sizeof(uint8_t)));
333 LoopEnd(&loopHead);
334
335 Bind(&exit);
336 env->SubCfgExit();
337 return;
338 }
339
GetUtf16Date(GateRef stringData,GateRef index)340 GateRef BuiltinsStringStubBuilder::GetUtf16Date(GateRef stringData, GateRef index)
341 {
342 return ZExtInt16ToInt32(Load(VariableType::INT16(), PtrAdd(stringData,
343 PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint16_t))))));
344 }
345
IsASCIICharacter(GateRef data)346 GateRef BuiltinsStringStubBuilder::IsASCIICharacter(GateRef data)
347 {
348 return Int32LessThan(Int32Sub(data, Int32(1)), Int32(base::utf_helper::UTF8_1B_MAX));
349 }
350
GetUtf8Date(GateRef stringData,GateRef index)351 GateRef BuiltinsStringStubBuilder::GetUtf8Date(GateRef stringData, GateRef index)
352 {
353 return ZExtInt8ToInt32(Load(VariableType::INT8(), PtrAdd(stringData,
354 PtrMul(ZExtInt32ToPtr(index), IntPtr(sizeof(uint8_t))))));
355 }
356
StringIndexOf(GateRef lhsData,bool lhsIsUtf8,GateRef rhsData,bool rhsIsUtf8,GateRef pos,GateRef max,GateRef rhsCount)357 GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhsData, bool lhsIsUtf8, GateRef rhsData, bool rhsIsUtf8,
358 GateRef pos, GateRef max, GateRef rhsCount)
359 {
360 auto env = GetEnvironment();
361 Label entry(env);
362 env->SubCfgEntry(&entry);
363 DEFVARIABLE(i, VariableType::INT32(), pos);
364 DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
365 DEFVARIABLE(j, VariableType::INT32(), Int32(0));
366 DEFVARIABLE(k, VariableType::INT32(), Int32(1));
367 Label exit(env);
368 Label next(env);
369 Label continueFor(env);
370 Label lhsNotEqualFirst(env);
371 Label continueCount(env);
372 Label lessEnd(env);
373 Label equalEnd(env);
374 Label loopHead(env);
375 Label loopEnd(env);
376 Label nextCount(env);
377 Label nextCount1(env);
378 Label nextCount2(env);
379 GateRef first;
380 if (rhsIsUtf8) {
381 first = ZExtInt8ToInt32(Load(VariableType::INT8(), rhsData));
382 } else {
383 first = ZExtInt16ToInt32(Load(VariableType::INT16(), rhsData));
384 }
385 Jump(&loopHead);
386 LoopBegin(&loopHead);
387 Branch(Int32LessThanOrEqual(*i, max), &next, &exit);
388 Bind(&next);
389 {
390 Label loopHead1(env);
391 Label loopEnd1(env);
392 GateRef lhsTemp;
393 if (lhsIsUtf8) {
394 lhsTemp = GetUtf8Date(lhsData, *i);
395 } else {
396 lhsTemp = GetUtf16Date(lhsData, *i);
397 }
398 Branch(Int32NotEqual(lhsTemp, first), &nextCount1, &nextCount);
399 Bind(&nextCount1);
400 {
401 i = Int32Add(*i, Int32(1));
402 Jump(&loopHead1);
403 }
404 LoopBegin(&loopHead1);
405 {
406 Branch(Int32LessThanOrEqual(*i, max), &continueFor, &nextCount);
407 Bind(&continueFor);
408 {
409 GateRef lhsTemp1;
410 if (lhsIsUtf8) {
411 lhsTemp1 = GetUtf8Date(lhsData, *i);
412 } else {
413 lhsTemp1 = GetUtf16Date(lhsData, *i);
414 }
415 Branch(Int32NotEqual(lhsTemp1, first), &lhsNotEqualFirst, &nextCount);
416 Bind(&lhsNotEqualFirst);
417 {
418 i = Int32Add(*i, Int32(1));
419 Jump(&loopEnd1);
420 }
421 }
422 }
423 Bind(&loopEnd1);
424 LoopEnd(&loopHead1);
425 Bind(&nextCount);
426 {
427 Branch(Int32LessThanOrEqual(*i, max), &continueCount, &loopEnd);
428 Bind(&continueCount);
429 {
430 Label loopHead2(env);
431 Label loopEnd2(env);
432 j = Int32Add(*i, Int32(1));
433 GateRef end = Int32Sub(Int32Add(*j, rhsCount), Int32(1));
434 k = Int32(1);
435 Jump(&loopHead2);
436 LoopBegin(&loopHead2);
437 {
438 Branch(Int32LessThan(*j, end), &lessEnd, &nextCount2);
439 Bind(&lessEnd);
440 {
441 GateRef lhsTemp2;
442 if (lhsIsUtf8) {
443 lhsTemp2 = GetUtf8Date(lhsData, *j);
444 } else {
445 lhsTemp2 = GetUtf16Date(lhsData, *j);
446 }
447 GateRef rhsTemp;
448 if (rhsIsUtf8) {
449 rhsTemp = GetUtf8Date(rhsData, *k);
450 } else {
451 rhsTemp = GetUtf16Date(rhsData, *k);
452 }
453 Branch(Int32Equal(lhsTemp2, rhsTemp), &loopEnd2, &nextCount2);
454 }
455 }
456 Bind(&loopEnd2);
457 j = Int32Add(*j, Int32(1));
458 k = Int32Add(*k, Int32(1));
459 LoopEnd(&loopHead2);
460 Bind(&nextCount2);
461 {
462 Branch(Int32Equal(*j, end), &equalEnd, &loopEnd);
463 Bind(&equalEnd);
464 result = *i;
465 Jump(&exit);
466 }
467 }
468 }
469 }
470 Bind(&loopEnd);
471 i = Int32Add(*i, Int32(1));
472 LoopEnd(&loopHead);
473
474 Bind(&exit);
475 auto ret = *result;
476 env->SubCfgExit();
477 return ret;
478 }
479
StringIndexOf(GateRef lhs,GateRef rhs,GateRef pos)480 GateRef BuiltinsStringStubBuilder::StringIndexOf(GateRef lhs, GateRef rhs, GateRef pos)
481 {
482 auto env = GetEnvironment();
483 Label entry(env);
484 env->SubCfgEntry(&entry);
485 DEFVARIABLE(result, VariableType::INT32(), Int32(-1));
486 DEFVARIABLE(posTag, VariableType::INT32(), pos);
487 Label exit(env);
488 Label rhsCountEqualZero(env);
489 Label nextCount(env);
490 Label rhsCountNotEqualZero(env);
491 Label posLessZero(env);
492 Label posNotLessZero(env);
493 Label maxNotLessZero(env);
494 Label rhsIsUtf8(env);
495 Label rhsIsUtf16(env);
496
497 GateRef lhsCount = GetLengthFromString(lhs);
498 GateRef rhsCount = GetLengthFromString(rhs);
499
500 Branch(Int32GreaterThan(pos, lhsCount), &exit, &nextCount);
501 Bind(&nextCount);
502 {
503 Branch(Int32Equal(rhsCount, Int32(0)), &rhsCountEqualZero, &rhsCountNotEqualZero);
504 Bind(&rhsCountEqualZero);
505 {
506 result = pos;
507 Jump(&exit);
508 }
509 Bind(&rhsCountNotEqualZero);
510 {
511 Branch(Int32LessThan(pos, Int32(0)), &posLessZero, &posNotLessZero);
512 Bind(&posLessZero);
513 {
514 posTag = Int32(0);
515 Jump(&posNotLessZero);
516 }
517 Bind(&posNotLessZero);
518 {
519 GateRef max = Int32Sub(lhsCount, rhsCount);
520 Branch(Int32LessThan(max, Int32(0)), &exit, &maxNotLessZero);
521 Bind(&maxNotLessZero);
522 {
523 GateRef rhsData = PtrAdd(rhs, IntPtr(EcmaString::DATA_OFFSET));
524 GateRef lhsData = PtrAdd(lhs, IntPtr(EcmaString::DATA_OFFSET));
525 Branch(IsUtf8String(rhs), &rhsIsUtf8, &rhsIsUtf16);
526 Bind(&rhsIsUtf8);
527 {
528 Label lhsIsUtf8(env);
529 Label lhsIsUtf16(env);
530 Branch(IsUtf8String(lhs), &lhsIsUtf8, &lhsIsUtf16);
531 Bind(&lhsIsUtf8);
532 {
533 result = StringIndexOf(lhsData, true, rhsData, true, *posTag, max, rhsCount);
534 Jump(&exit);
535 }
536 Bind(&lhsIsUtf16);
537 {
538 result = StringIndexOf(lhsData, false, rhsData, true, *posTag, max, rhsCount);
539 Jump(&exit);
540 }
541 }
542 Bind(&rhsIsUtf16);
543 {
544 Label lhsIsUtf8(env);
545 Label lhsIsUtf16(env);
546 Branch(IsUtf8String(lhs), &lhsIsUtf8, &lhsIsUtf16);
547 Bind(&lhsIsUtf8);
548 {
549 result = StringIndexOf(lhsData, true, rhsData, false, *posTag, max, rhsCount);
550 Jump(&exit);
551 }
552 Bind(&lhsIsUtf16);
553 {
554 result = StringIndexOf(lhsData, false, rhsData, false, *posTag, max, rhsCount);
555 Jump(&exit);
556 }
557 }
558 }
559 }
560 }
561 }
562 Bind(&exit);
563 auto ret = *result;
564 env->SubCfgExit();
565 return ret;
566 }
567 } // namespace panda::ecmascript::kungfu
568