• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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