• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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_number_stub_builder.h"
17 
18 #include "ecmascript/compiler/new_object_stub_builder.h"
19 #include "ecmascript/js_primitive_ref.h"
20 
21 namespace panda::ecmascript::kungfu {
ParseFloat(Variable * result,Label * exit,Label * slowPath)22 void BuiltinsNumberStubBuilder::ParseFloat(Variable *result, Label *exit, Label *slowPath)
23 {
24     auto env = GetEnvironment();
25     Label definedMsg(env);
26     Label undefinedMsg(env);
27     GateRef msg = GetCallArg0(numArgs_);
28     BRANCH(TaggedIsUndefined(msg), &undefinedMsg, &definedMsg);
29     Bind(&undefinedMsg);
30     {
31         *result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
32         Jump(exit);
33     }
34     Bind(&definedMsg);
35     {
36         Label heapObj(env);
37         Label stringObj(env);
38         BRANCH(TaggedIsHeapObject(msg), &heapObj, slowPath);
39         Bind(&heapObj);
40         BRANCH(IsString(glue_, msg), &stringObj, slowPath);
41         Bind(&stringObj);
42         {
43             *result = CallNGCRuntime(glue_, RTSTUB_ID(NumberHelperStringToDouble), { glue_, msg });
44             Jump(exit);
45         }
46     }
47 }
48 
ParseInt(Variable * result,Label * exit,Label * slowPath)49 void BuiltinsNumberStubBuilder::ParseInt(Variable *result, Label *exit, Label *slowPath)
50 {
51     auto env = GetEnvironment();
52     Label msgIsString(env);
53     Label radixIsSpecial(env);
54     Label radixIsSpecialInt(env);
55 
56     DEFVARIABLE(radix, VariableType::INT32(), Int32(0));
57     GateRef msg = GetCallArg0(numArgs_);
58     GateRef arg2 = GetCallArg1(numArgs_);
59     // ToString maybe throw exception.
60     Branch(TaggedIsString(glue_, msg), &msgIsString, slowPath);
61     Bind(&msgIsString);
62     Branch(TaggedIsUndefined(arg2), &radixIsSpecialInt, &radixIsSpecial);
63 
64     Bind(&radixIsSpecial);
65     {
66         Label radixIsInt(env);
67         // ToInt maybe throw exception.
68         Branch(TaggedIsInt(arg2), &radixIsInt, slowPath);
69         Bind(&radixIsInt);
70         {
71             radix = GetInt32OfTInt(arg2);
72             Jump(&radixIsSpecialInt);
73         }
74     }
75     Bind(&radixIsSpecialInt);
76     {
77         *result = CallNGCRuntime(glue_, RTSTUB_ID(StringToNumber), { glue_, msg, *radix });
78         Jump(exit);
79     }
80 }
81 
IsFinite(Variable * result,Label * exit,Label * slowPath)82 void BuiltinsNumberStubBuilder::IsFinite(Variable *result, Label *exit, Label *slowPath)
83 {
84     auto env = GetEnvironment();
85     GateRef number = GetCallArg0(numArgs_);
86 
87     // In this method, we actually don't need slow path.
88     // The following code is for passing the verification phase.
89     Label noSlowPath(env);
90     BRANCH(False(), slowPath, &noSlowPath);
91     Bind(&noSlowPath);
92 
93     Label retTrue(env);
94     Label retFalse(env);
95 
96     Label isNotInt(env);
97     BRANCH(TaggedIsInt(number), &retTrue, &isNotInt);
98     Bind(&isNotInt);
99     {
100         Label isDouble(env);
101         BRANCH(TaggedIsDouble(number), &isDouble, &retFalse);
102         Bind(&isDouble);
103         {
104             GateRef f = GetDoubleOfTDouble(number);
105             BRANCH(DoubleIsNanOrInf(f), &retFalse, &retTrue);
106         }
107     }
108 
109     Bind(&retTrue);
110     {
111         *result = TaggedTrue();
112         Jump(exit);
113     }
114     Bind(&retFalse);
115     {
116         *result = TaggedFalse();
117         Jump(exit);
118     }
119 }
120 
IsNaN(Variable * result,Label * exit,Label * slowPath)121 void BuiltinsNumberStubBuilder::IsNaN(Variable *result, Label *exit, Label *slowPath)
122 {
123     auto env = GetEnvironment();
124     GateRef number = GetCallArg0(numArgs_);
125 
126     // In this method, we actually don't need slow path.
127     // The following code is for passing the verification phase.
128     Label noSlowPath(env);
129     BRANCH(False(), slowPath, &noSlowPath);
130     Bind(&noSlowPath);
131 
132     Label retTrue(env);
133     Label retFalse(env);
134 
135     Label isDouble(env);
136     BRANCH(TaggedIsDouble(number), &isDouble, &retFalse);
137     Bind(&isDouble);
138     BRANCH(DoubleIsNAN(GetDoubleOfTDouble(number)), &retTrue, &retFalse);
139 
140     Bind(&retTrue);
141     {
142         *result = TaggedTrue();
143         Jump(exit);
144     }
145     Bind(&retFalse);
146     {
147         *result = TaggedFalse();
148         Jump(exit);
149     }
150 }
151 
IsInteger(Variable * result,Label * exit,Label * slowPath)152 void BuiltinsNumberStubBuilder::IsInteger(Variable *result, Label *exit, Label *slowPath)
153 {
154     auto env = GetEnvironment();
155     GateRef number = GetCallArg0(numArgs_);
156 
157     // In this method, we actually don't need slow path.
158     // The following code is for passing the verification phase.
159     Label noSlowPath(env);
160     BRANCH(False(), slowPath, &noSlowPath);
161     Bind(&noSlowPath);
162 
163     Label retTrue(env);
164     Label retFalse(env);
165 
166     Label isNotInt(env);
167     BRANCH(TaggedIsInt(number), &retTrue, &isNotInt);
168     Bind(&isNotInt);
169     {
170         Label isDouble(env);
171         BRANCH(TaggedIsDouble(number), &isDouble, &retFalse);
172         Bind(&isDouble);
173         BRANCH(DoubleIsInteger(GetDoubleOfTDouble(number)), &retTrue, &retFalse);
174     }
175 
176     Bind(&retTrue);
177     {
178         *result = TaggedTrue();
179         Jump(exit);
180     }
181     Bind(&retFalse);
182     {
183         *result = TaggedFalse();
184         Jump(exit);
185     }
186 }
187 
IsSafeInteger(Variable * result,Label * exit,Label * slowPath)188 void BuiltinsNumberStubBuilder::IsSafeInteger(Variable *result, Label *exit, Label *slowPath)
189 {
190     auto env = GetEnvironment();
191     GateRef number = GetCallArg0(numArgs_);
192 
193     // In this method, we actually don't need slow path.
194     // The following code is for passing the verification phase.
195     Label noSlowPath(env);
196     BRANCH(False(), slowPath, &noSlowPath);
197     Bind(&noSlowPath);
198 
199     Label retTrue(env);
200     Label retFalse(env);
201 
202     Label isNotInt(env);
203     BRANCH(TaggedIsInt(number), &retTrue, &isNotInt);
204     Bind(&isNotInt);
205     {
206         Label isDouble(env);
207         BRANCH(TaggedIsDouble(number), &isDouble, &retFalse);
208         Bind(&isDouble);
209         {
210             Label isNotNanOrInf(env);
211             GateRef f = GetDoubleOfTDouble(number);
212             BRANCH(DoubleIsNanOrInf(f), &retFalse, &isNotNanOrInf);
213             Bind(&isNotNanOrInf);
214             {
215                 Label checkSafe(env);
216                 GateRef truncated = ChangeInt32ToFloat64(TruncFloatToInt64(f));
217                 BRANCH(DoubleEqual(f, truncated), &checkSafe, &retFalse);
218                 Bind(&checkSafe);
219                 BRANCH(DoubleLessThanOrEqual(DoubleAbs(f), Double(base::MAX_SAFE_INTEGER)), &retTrue, &retFalse);
220             }
221         }
222     }
223 
224     Bind(&retTrue);
225     {
226         *result = TaggedTrue();
227         Jump(exit);
228     }
229     Bind(&retFalse);
230     {
231         *result = TaggedFalse();
232         Jump(exit);
233     }
234 }
235 
GenNumberConstructor(GateRef nativeCode,GateRef func,GateRef newTarget)236 void BuiltinsNumberStubBuilder::GenNumberConstructor(GateRef nativeCode, GateRef func, GateRef newTarget)
237 {
238     auto env = GetEnvironment();
239     DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
240     DEFVARIABLE(numberValue, VariableType::JS_ANY(), IntToTaggedPtr(IntPtr(0)));
241     Label thisCollectionObj(env);
242     Label slowPath(env);
243     Label slowPath1(env);
244     Label exit(env);
245 
246     Label hasArg(env);
247     Label numberCreate(env);
248     Label newTargetIsHeapObject(env);
249     BRANCH(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath);
250     Bind(&newTargetIsHeapObject);
251     BRANCH(Int64GreaterThan(numArgs_, IntPtr(0)), &hasArg, &numberCreate);
252     Bind(&hasArg);
253     {
254         GateRef value = GetArgFromArgv(glue_, Int32(0));
255         Label number(env);
256         BRANCH(TaggedIsNumber(value), &number, &slowPath);
257         Bind(&number);
258         {
259             numberValue = value;
260             res = value;
261             Jump(&numberCreate);
262         }
263     }
264 
265     Bind(&numberCreate);
266     Label newObj(env);
267     Label newTargetIsJSFunction(env);
268     BRANCH(TaggedIsUndefined(newTarget), &exit, &newObj);
269     Bind(&newObj);
270     {
271         BRANCH(IsJSFunction(glue_, newTarget), &newTargetIsJSFunction, &slowPath);
272         Bind(&newTargetIsJSFunction);
273         {
274             Label intialHClassIsHClass(env);
275             GateRef intialHClass = Load(VariableType::JS_ANY(), glue_, newTarget,
276                 IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
277             BRANCH(IsJSHClass(glue_, intialHClass), &intialHClassIsHClass, &slowPath1);
278             Bind(&intialHClassIsHClass);
279             {
280                 NewObjectStubBuilder newBuilder(this);
281                 newBuilder.SetParameters(glue_, 0);
282                 Label afterNew(env);
283                 newBuilder.NewJSObject(&res, &afterNew, intialHClass);
284                 Bind(&afterNew);
285                 {
286                     GateRef valueOffset = IntPtr(JSPrimitiveRef::VALUE_OFFSET);
287                     Store(VariableType::INT64(), glue_, *res, valueOffset, *numberValue);
288                     Jump(&exit);
289                 }
290             }
291             Bind(&slowPath1);
292             {
293                 GateRef argv = GetArgv();
294                 res = CallBuiltinRuntimeWithNewTarget(glue_,
295                     { glue_, nativeCode, func, thisValue_, numArgs_, argv, newTarget });
296                 Jump(&exit);
297             }
298         }
299     }
300 
301     Bind(&slowPath);
302     {
303         GateRef argv = GetArgv();
304         res = CallBuiltinRuntime(glue_, { glue_, nativeCode, func, thisValue_, numArgs_, argv }, true);
305         Jump(&exit);
306     }
307     Bind(&exit);
308     Return(*res);
309 }
310 
ToStringFunc(Variable * result,Label * exit,Label * slowPath)311 void BuiltinsNumberStubBuilder::ToStringFunc(Variable *result, Label *exit, Label *slowPath)
312 {
313     auto env = GetEnvironment();
314     Label definedMsg(env);
315     Label undefinedMsg(env);
316     Label thisIsInt(env);
317     Label msgIsInt(env);
318     BRANCH(TaggedIsInt(thisValue_), &thisIsInt, slowPath);
319     Bind(&thisIsInt);
320     GateRef thisValueInt = GetInt32OfTInt(thisValue_);
321     GateRef msg = GetCallArg0(numArgs_);
322     BRANCH(TaggedIsUndefined(msg), &undefinedMsg, &definedMsg);
323     Bind(&undefinedMsg);
324     {
325         *result = NumberToString(thisValueInt, Int32(10)); // 10: means radix
326         Jump(exit);
327     }
328     Bind(&definedMsg);
329     BRANCH(TaggedIsInt(msg), &msgIsInt, slowPath);
330     Bind(&msgIsInt);
331     {
332         Label throwError(env);
333         Label notThrowError(env);
334         GateRef msgValue = GetInt32OfTInt(msg);
335         GateRef outOfRange = BitOr(Int32LessThan(msgValue, Int32(base::MIN_RADIX)),
336                                    Int32GreaterThan(msgValue, Int32(base::MAX_RADIX)));
337         BRANCH(outOfRange, &throwError, &notThrowError);
338         Bind(&throwError);
339         {
340             GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InvalidRadixLength));
341             CallRuntimeWithGlobalEnv(glue_, GetCurrentGlobalEnv(),
342                 RTSTUB_ID(ThrowRangeError), { IntToTaggedInt(taggedId) });
343             Jump(exit);
344         }
345         Bind(&notThrowError);
346         {
347             *result = NumberToString(thisValueInt, msgValue);
348             Jump(exit);
349         }
350     }
351 }
352 
NumberToString(GateRef number,GateRef radix)353 GateRef BuiltinsNumberStubBuilder::NumberToString(GateRef number, GateRef radix)
354 {
355     auto env = GetEnvironment();
356     Label subentry(env);
357     env->SubCfgEntry(&subentry);
358     DEFVARIABLE(result, VariableType::JS_POINTER(), Hole());
359     DEFVARIABLE(n, VariableType::INT32(), number);
360 
361     Label exit(env);
362     Label numIsNegative(env);
363     Label numNotNegative(env);
364     Label afterFast(env);
365     Label afterNew(env);
366     GateRef isNegative = Int32LessThan(number, Int32(0));
367     BRANCH(isNegative, &numIsNegative, &numNotNegative);
368     Bind(&numIsNegative);
369     {
370         n = Int32Sub(Int32(0), *n);
371         Jump(&afterFast);
372     }
373     Bind(&numNotNegative);
374     {
375         Label thisIsZero(env);
376         Label thisNotZero(env);
377         Label thisIsSingle(env);
378         Label thisNotSingle(env);
379         BRANCH(Int32Equal(number, Int32(0)), &thisIsZero, &thisNotZero);
380         Bind(&thisIsZero);
381         {
382             result = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::ZERO_INDEX);
383             Jump(&exit);
384         }
385         Bind(&thisNotZero);
386         {
387             BRANCH(Int32LessThan(number, radix), &thisIsSingle, &afterFast);
388             Bind(&thisIsSingle);
389             GateRef singleCharTable = GetSingleCharTable(glue_);
390             GateRef index = ToCharCode(number);
391             result = GetValueFromTaggedArray(glue_, singleCharTable, index);
392             Jump(&exit);
393         }
394     }
395     Bind(&afterFast);
396     {
397         DEFVARIABLE(temp, VariableType::INT32(), *n);
398         DEFVARIABLE(length, VariableType::INT32(), Int32(0));
399         Label lenAddOne(env);
400         Label lenNotAddOne(env);
401         BRANCH(isNegative, &lenAddOne, &lenNotAddOne);
402         Bind(&lenAddOne);
403         {
404             length = Int32Add(*length, Int32(1));
405             Jump(&lenNotAddOne);
406         }
407         Bind(&lenNotAddOne);
408         {
409             Label loopHead(env);
410             Label loopEnd(env);
411             Label next(env);
412             Label loopExit(env);
413             Jump(&loopHead);
414             LoopBegin(&loopHead);
415             {
416                 BRANCH(Int32GreaterThan(*temp, Int32(0)), &next, &loopExit);
417                 Bind(&next);
418                 {
419                     temp = Int32Div(*temp, radix);
420                     length = Int32Add(*length, Int32(1));
421                     Jump(&loopEnd);
422                 }
423             }
424             Bind(&loopEnd);
425             LoopEndWithCheckSafePoint(&loopHead, env, glue_);
426             Bind(&loopExit);
427             {
428                 NewObjectStubBuilder newBuilder(this);
429                 newBuilder.SetParameters(glue_, 0);
430                 newBuilder.AllocLineStringObject(&result, &afterNew, *length, true);
431                 Bind(&afterNew);
432                 {
433                     GateRef dst = ChangeTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineString::DATA_OFFSET)));
434                     DEFVARIABLE(cursor, VariableType::INT32(), Int32Sub(*length, Int32(1)));
435                     DEFVARIABLE(digit, VariableType::INT32(), Int32(0));
436                     DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
437                     dstTmp = PtrAdd(*dstTmp, PtrMul(ZExtInt32ToPtr(*cursor), IntPtr(sizeof(uint8_t))));
438                     Label loopHead1(env);
439                     Label loopEnd1(env);
440                     Label next1(env);
441                     Label loopExit1(env);
442                     Jump(&loopHead1);
443                     LoopBegin(&loopHead1);
444                     {
445                         BRANCH(Int32GreaterThan(*n, Int32(0)), &next1, &loopExit1);
446                         Bind(&next1);
447                         {
448                             digit = Int32Mod(*n, radix);
449                             n = Int32Div(*n, radix);
450                             GateRef digitChar = ToCharCode(*digit);
451                             Store(VariableType::INT8(), glue_, *dstTmp, IntPtr(0), TruncInt32ToInt8(digitChar));
452                             cursor = Int32Sub(*cursor, Int32(1));
453                             Jump(&loopEnd1);
454                         }
455                     }
456                     Bind(&loopEnd1);
457                     dstTmp = PtrSub(*dstTmp, IntPtr(sizeof(uint8_t)));
458                     // Work with low level buffers, we can't call GC. Loop is simple, no more 32 iteration.
459                     // Ability using GC at the end of loop require add additional calculate pointer to data of string
460                     // on each iteration.
461                     LoopEnd(&loopHead1);
462                     Bind(&loopExit1);
463                     {
464                         Label strInsertSign(env);
465                         Label strNotInsertSign(env);
466                         BRANCH(isNegative, &strInsertSign, &exit);
467                         Bind(&strInsertSign);
468                         {
469                             dstTmp = PtrSub(*dstTmp, IntPtr(sizeof(uint8_t)));
470                             Store(VariableType::INT8(), glue_, dst, IntPtr(0), Int8(45)); // 45: means '-'
471                             Jump(&exit);
472                         }
473                     }
474                 }
475             }
476         }
477     }
478     Bind(&exit);
479     auto ret = *result;
480     env->SubCfgExit();
481     return ret;
482 }
483 }  // namespace panda::ecmascript::kungfu
484