• 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(msg), &stringObj, slowPath);
41         Bind(&stringObj);
42         {
43             *result = CallNGCRuntime(glue_, RTSTUB_ID(NumberHelperStringToDouble), { 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(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), { 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(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(newTarget), &newTargetIsJSFunction, &slowPath);
272         Bind(&newTargetIsJSFunction);
273         {
274             Label intialHClassIsHClass(env);
275             GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget,
276                 IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
277             BRANCH(IsJSHClass(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             CallRuntime(glue_, RTSTUB_ID(ThrowRangeError), { IntToTaggedInt(taggedId) });
342             Jump(exit);
343         }
344         Bind(&notThrowError);
345         {
346             *result = NumberToString(thisValueInt, msgValue);
347             Jump(exit);
348         }
349     }
350 }
351 
NumberToString(GateRef number,GateRef radix)352 GateRef BuiltinsNumberStubBuilder::NumberToString(GateRef number, GateRef radix)
353 {
354     auto env = GetEnvironment();
355     Label subentry(env);
356     env->SubCfgEntry(&subentry);
357     DEFVARIABLE(result, VariableType::JS_POINTER(), Hole());
358     DEFVARIABLE(n, VariableType::INT32(), number);
359 
360     Label exit(env);
361     Label numIsNegative(env);
362     Label numNotNegative(env);
363     Label afterFast(env);
364     Label afterNew(env);
365     GateRef isNegative = Int32LessThan(number, Int32(0));
366     BRANCH(isNegative, &numIsNegative, &numNotNegative);
367     Bind(&numIsNegative);
368     {
369         n = Int32Sub(Int32(0), *n);
370         Jump(&afterFast);
371     }
372     Bind(&numNotNegative);
373     {
374         Label thisIsZero(env);
375         Label thisNotZero(env);
376         Label thisIsSingle(env);
377         Label thisNotSingle(env);
378         BRANCH(Int32Equal(number, Int32(0)), &thisIsZero, &thisNotZero);
379         Bind(&thisIsZero);
380         {
381             result = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::ZERO_INDEX);
382             Jump(&exit);
383         }
384         Bind(&thisNotZero);
385         {
386             BRANCH(Int32LessThan(number, radix), &thisIsSingle, &afterFast);
387             Bind(&thisIsSingle);
388             GateRef singleCharTable = GetSingleCharTable(glue_);
389             GateRef index = ToCharCode(number);
390             result = GetValueFromTaggedArray(singleCharTable, index);
391             Jump(&exit);
392         }
393     }
394     Bind(&afterFast);
395     {
396         DEFVARIABLE(temp, VariableType::INT32(), *n);
397         DEFVARIABLE(length, VariableType::INT32(), Int32(0));
398         Label lenAddOne(env);
399         Label lenNotAddOne(env);
400         BRANCH(isNegative, &lenAddOne, &lenNotAddOne);
401         Bind(&lenAddOne);
402         {
403             length = Int32Add(*length, Int32(1));
404             Jump(&lenNotAddOne);
405         }
406         Bind(&lenNotAddOne);
407         {
408             Label loopHead(env);
409             Label loopEnd(env);
410             Label next(env);
411             Label loopExit(env);
412             Jump(&loopHead);
413             LoopBegin(&loopHead);
414             {
415                 BRANCH(Int32GreaterThan(*temp, Int32(0)), &next, &loopExit);
416                 Bind(&next);
417                 {
418                     temp = Int32Div(*temp, radix);
419                     length = Int32Add(*length, Int32(1));
420                     Jump(&loopEnd);
421                 }
422             }
423             Bind(&loopEnd);
424             LoopEnd(&loopHead, env, glue_);
425             Bind(&loopExit);
426             {
427                 NewObjectStubBuilder newBuilder(this);
428                 newBuilder.SetParameters(glue_, 0);
429                 newBuilder.AllocLineStringObject(&result, &afterNew, *length, true);
430                 Bind(&afterNew);
431                 {
432                     GateRef dst = ChangeTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
433                     DEFVARIABLE(cursor, VariableType::INT32(), Int32Sub(*length, Int32(1)));
434                     DEFVARIABLE(digit, VariableType::INT32(), Int32(0));
435                     DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
436                     dstTmp = PtrAdd(*dstTmp, PtrMul(ZExtInt32ToPtr(*cursor), IntPtr(sizeof(uint8_t))));
437                     Label loopHead1(env);
438                     Label loopEnd1(env);
439                     Label next1(env);
440                     Label loopExit1(env);
441                     Jump(&loopHead1);
442                     LoopBegin(&loopHead1);
443                     {
444                         BRANCH(Int32GreaterThan(*n, Int32(0)), &next1, &loopExit1);
445                         Bind(&next1);
446                         {
447                             digit = Int32Mod(*n, radix);
448                             n = Int32Div(*n, radix);
449                             GateRef digitChar = ToCharCode(*digit);
450                             Store(VariableType::INT8(), glue_, *dstTmp, IntPtr(0), TruncInt32ToInt8(digitChar));
451                             cursor = Int32Sub(*cursor, Int32(1));
452                             Jump(&loopEnd1);
453                         }
454                     }
455                     Bind(&loopEnd1);
456                     dstTmp = PtrSub(*dstTmp, IntPtr(sizeof(uint8_t)));
457                     // Work with low level buffers, we can't call GC. Loop is simple, no more 32 iteration.
458                     // Ability using GC at the end of loop require add additional calculate pointer to data of string
459                     // on each iteration.
460                     LoopEnd(&loopHead1);
461                     Bind(&loopExit1);
462                     {
463                         Label strInsertSign(env);
464                         Label strNotInsertSign(env);
465                         BRANCH(isNegative, &strInsertSign, &exit);
466                         Bind(&strInsertSign);
467                         {
468                             dstTmp = PtrSub(*dstTmp, IntPtr(sizeof(uint8_t)));
469                             Store(VariableType::INT8(), glue_, dst, IntPtr(0), Int8(45)); // 45: means '-'
470                             Jump(&exit);
471                         }
472                     }
473                 }
474             }
475         }
476     }
477     Bind(&exit);
478     auto ret = *result;
479     env->SubCfgExit();
480     return ret;
481 }
482 }  // namespace panda::ecmascript::kungfu
483