14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/compiler/builtins/builtins_number_stub_builder.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/builtins/builtins_number.h"
194514f5e3Sopenharmony_ci#include "ecmascript/compiler/new_object_stub_builder.h"
204514f5e3Sopenharmony_ci#include "ecmascript/compiler/stub_builder-inl.h"
214514f5e3Sopenharmony_ci#include "ecmascript/js_arguments.h"
224514f5e3Sopenharmony_ci#include "ecmascript/js_primitive_ref.h"
234514f5e3Sopenharmony_ci#include "ecmascript/tagged_dictionary.h"
244514f5e3Sopenharmony_ci
254514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu {
264514f5e3Sopenharmony_civoid BuiltinsNumberStubBuilder::ParseFloat(Variable *result, Label *exit, Label *slowPath)
274514f5e3Sopenharmony_ci{
284514f5e3Sopenharmony_ci    auto env = GetEnvironment();
294514f5e3Sopenharmony_ci    Label definedMsg(env);
304514f5e3Sopenharmony_ci    Label undefinedMsg(env);
314514f5e3Sopenharmony_ci    GateRef msg = GetCallArg0(numArgs_);
324514f5e3Sopenharmony_ci    BRANCH(TaggedIsUndefined(msg), &undefinedMsg, &definedMsg);
334514f5e3Sopenharmony_ci    Bind(&undefinedMsg);
344514f5e3Sopenharmony_ci    {
354514f5e3Sopenharmony_ci        *result = DoubleToTaggedDoublePtr(Double(base::NAN_VALUE));
364514f5e3Sopenharmony_ci        Jump(exit);
374514f5e3Sopenharmony_ci    }
384514f5e3Sopenharmony_ci    Bind(&definedMsg);
394514f5e3Sopenharmony_ci    {
404514f5e3Sopenharmony_ci        Label heapObj(env);
414514f5e3Sopenharmony_ci        Label stringObj(env);
424514f5e3Sopenharmony_ci        BRANCH(TaggedIsHeapObject(msg), &heapObj, slowPath);
434514f5e3Sopenharmony_ci        Bind(&heapObj);
444514f5e3Sopenharmony_ci        BRANCH(IsString(msg), &stringObj, slowPath);
454514f5e3Sopenharmony_ci        Bind(&stringObj);
464514f5e3Sopenharmony_ci        {
474514f5e3Sopenharmony_ci            *result = CallNGCRuntime(glue_, RTSTUB_ID(NumberHelperStringToDouble), { msg });
484514f5e3Sopenharmony_ci            Jump(exit);
494514f5e3Sopenharmony_ci        }
504514f5e3Sopenharmony_ci    }
514514f5e3Sopenharmony_ci}
524514f5e3Sopenharmony_ci
534514f5e3Sopenharmony_civoid BuiltinsNumberStubBuilder::ParseInt(Variable *result, Label *exit, Label *slowPath)
544514f5e3Sopenharmony_ci{
554514f5e3Sopenharmony_ci    auto env = GetEnvironment();
564514f5e3Sopenharmony_ci    Label msgIsString(env);
574514f5e3Sopenharmony_ci    Label radixIsSpecial(env);
584514f5e3Sopenharmony_ci    Label radixIsSpecialInt(env);
594514f5e3Sopenharmony_ci
604514f5e3Sopenharmony_ci    DEFVARIABLE(radix, VariableType::INT32(), Int32(0));
614514f5e3Sopenharmony_ci    GateRef msg = GetCallArg0(numArgs_);
624514f5e3Sopenharmony_ci    GateRef arg2 = GetCallArg1(numArgs_);
634514f5e3Sopenharmony_ci    // ToString maybe throw exception.
644514f5e3Sopenharmony_ci    Branch(TaggedIsString(msg), &msgIsString, slowPath);
654514f5e3Sopenharmony_ci    Bind(&msgIsString);
664514f5e3Sopenharmony_ci    Branch(TaggedIsUndefined(arg2), &radixIsSpecialInt, &radixIsSpecial);
674514f5e3Sopenharmony_ci
684514f5e3Sopenharmony_ci    Bind(&radixIsSpecial);
694514f5e3Sopenharmony_ci    {
704514f5e3Sopenharmony_ci        Label radixIsInt(env);
714514f5e3Sopenharmony_ci        // ToInt maybe throw exception.
724514f5e3Sopenharmony_ci        Branch(TaggedIsInt(arg2), &radixIsInt, slowPath);
734514f5e3Sopenharmony_ci        Bind(&radixIsInt);
744514f5e3Sopenharmony_ci        {
754514f5e3Sopenharmony_ci            radix = GetInt32OfTInt(arg2);
764514f5e3Sopenharmony_ci            Jump(&radixIsSpecialInt);
774514f5e3Sopenharmony_ci        }
784514f5e3Sopenharmony_ci    }
794514f5e3Sopenharmony_ci    Bind(&radixIsSpecialInt);
804514f5e3Sopenharmony_ci    {
814514f5e3Sopenharmony_ci        *result = CallNGCRuntime(glue_, RTSTUB_ID(StringToNumber), { msg, *radix });
824514f5e3Sopenharmony_ci        Jump(exit);
834514f5e3Sopenharmony_ci    }
844514f5e3Sopenharmony_ci}
854514f5e3Sopenharmony_ci
864514f5e3Sopenharmony_civoid BuiltinsNumberStubBuilder::IsFinite(Variable *result, Label *exit, Label *slowPath)
874514f5e3Sopenharmony_ci{
884514f5e3Sopenharmony_ci    auto env = GetEnvironment();
894514f5e3Sopenharmony_ci    GateRef number = GetCallArg0(numArgs_);
904514f5e3Sopenharmony_ci
914514f5e3Sopenharmony_ci    // In this method, we actually don't need slow path.
924514f5e3Sopenharmony_ci    // The following code is for passing the verification phase.
934514f5e3Sopenharmony_ci    Label noSlowPath(env);
944514f5e3Sopenharmony_ci    BRANCH(False(), slowPath, &noSlowPath);
954514f5e3Sopenharmony_ci    Bind(&noSlowPath);
964514f5e3Sopenharmony_ci
974514f5e3Sopenharmony_ci    Label retTrue(env);
984514f5e3Sopenharmony_ci    Label retFalse(env);
994514f5e3Sopenharmony_ci
1004514f5e3Sopenharmony_ci    Label isNotInt(env);
1014514f5e3Sopenharmony_ci    BRANCH(TaggedIsInt(number), &retTrue, &isNotInt);
1024514f5e3Sopenharmony_ci    Bind(&isNotInt);
1034514f5e3Sopenharmony_ci    {
1044514f5e3Sopenharmony_ci        Label isDouble(env);
1054514f5e3Sopenharmony_ci        BRANCH(TaggedIsDouble(number), &isDouble, &retFalse);
1064514f5e3Sopenharmony_ci        Bind(&isDouble);
1074514f5e3Sopenharmony_ci        {
1084514f5e3Sopenharmony_ci            GateRef f = GetDoubleOfTDouble(number);
1094514f5e3Sopenharmony_ci            BRANCH(DoubleIsNanOrInf(f), &retFalse, &retTrue);
1104514f5e3Sopenharmony_ci        }
1114514f5e3Sopenharmony_ci    }
1124514f5e3Sopenharmony_ci
1134514f5e3Sopenharmony_ci    Bind(&retTrue);
1144514f5e3Sopenharmony_ci    {
1154514f5e3Sopenharmony_ci        *result = TaggedTrue();
1164514f5e3Sopenharmony_ci        Jump(exit);
1174514f5e3Sopenharmony_ci    }
1184514f5e3Sopenharmony_ci    Bind(&retFalse);
1194514f5e3Sopenharmony_ci    {
1204514f5e3Sopenharmony_ci        *result = TaggedFalse();
1214514f5e3Sopenharmony_ci        Jump(exit);
1224514f5e3Sopenharmony_ci    }
1234514f5e3Sopenharmony_ci}
1244514f5e3Sopenharmony_ci
1254514f5e3Sopenharmony_civoid BuiltinsNumberStubBuilder::IsNaN(Variable *result, Label *exit, Label *slowPath)
1264514f5e3Sopenharmony_ci{
1274514f5e3Sopenharmony_ci    auto env = GetEnvironment();
1284514f5e3Sopenharmony_ci    GateRef number = GetCallArg0(numArgs_);
1294514f5e3Sopenharmony_ci
1304514f5e3Sopenharmony_ci    // In this method, we actually don't need slow path.
1314514f5e3Sopenharmony_ci    // The following code is for passing the verification phase.
1324514f5e3Sopenharmony_ci    Label noSlowPath(env);
1334514f5e3Sopenharmony_ci    BRANCH(False(), slowPath, &noSlowPath);
1344514f5e3Sopenharmony_ci    Bind(&noSlowPath);
1354514f5e3Sopenharmony_ci
1364514f5e3Sopenharmony_ci    Label retTrue(env);
1374514f5e3Sopenharmony_ci    Label retFalse(env);
1384514f5e3Sopenharmony_ci
1394514f5e3Sopenharmony_ci    Label isDouble(env);
1404514f5e3Sopenharmony_ci    BRANCH(TaggedIsDouble(number), &isDouble, &retFalse);
1414514f5e3Sopenharmony_ci    Bind(&isDouble);
1424514f5e3Sopenharmony_ci    BRANCH(DoubleIsNAN(GetDoubleOfTDouble(number)), &retTrue, &retFalse);
1434514f5e3Sopenharmony_ci
1444514f5e3Sopenharmony_ci    Bind(&retTrue);
1454514f5e3Sopenharmony_ci    {
1464514f5e3Sopenharmony_ci        *result = TaggedTrue();
1474514f5e3Sopenharmony_ci        Jump(exit);
1484514f5e3Sopenharmony_ci    }
1494514f5e3Sopenharmony_ci    Bind(&retFalse);
1504514f5e3Sopenharmony_ci    {
1514514f5e3Sopenharmony_ci        *result = TaggedFalse();
1524514f5e3Sopenharmony_ci        Jump(exit);
1534514f5e3Sopenharmony_ci    }
1544514f5e3Sopenharmony_ci}
1554514f5e3Sopenharmony_ci
1564514f5e3Sopenharmony_civoid BuiltinsNumberStubBuilder::IsInteger(Variable *result, Label *exit, Label *slowPath)
1574514f5e3Sopenharmony_ci{
1584514f5e3Sopenharmony_ci    auto env = GetEnvironment();
1594514f5e3Sopenharmony_ci    GateRef number = GetCallArg0(numArgs_);
1604514f5e3Sopenharmony_ci
1614514f5e3Sopenharmony_ci    // In this method, we actually don't need slow path.
1624514f5e3Sopenharmony_ci    // The following code is for passing the verification phase.
1634514f5e3Sopenharmony_ci    Label noSlowPath(env);
1644514f5e3Sopenharmony_ci    BRANCH(False(), slowPath, &noSlowPath);
1654514f5e3Sopenharmony_ci    Bind(&noSlowPath);
1664514f5e3Sopenharmony_ci
1674514f5e3Sopenharmony_ci    Label retTrue(env);
1684514f5e3Sopenharmony_ci    Label retFalse(env);
1694514f5e3Sopenharmony_ci
1704514f5e3Sopenharmony_ci    Label isNotInt(env);
1714514f5e3Sopenharmony_ci    BRANCH(TaggedIsInt(number), &retTrue, &isNotInt);
1724514f5e3Sopenharmony_ci    Bind(&isNotInt);
1734514f5e3Sopenharmony_ci    {
1744514f5e3Sopenharmony_ci        Label isDouble(env);
1754514f5e3Sopenharmony_ci        BRANCH(TaggedIsDouble(number), &isDouble, &retFalse);
1764514f5e3Sopenharmony_ci        Bind(&isDouble);
1774514f5e3Sopenharmony_ci        BRANCH(DoubleIsInteger(GetDoubleOfTDouble(number)), &retTrue, &retFalse);
1784514f5e3Sopenharmony_ci    }
1794514f5e3Sopenharmony_ci
1804514f5e3Sopenharmony_ci    Bind(&retTrue);
1814514f5e3Sopenharmony_ci    {
1824514f5e3Sopenharmony_ci        *result = TaggedTrue();
1834514f5e3Sopenharmony_ci        Jump(exit);
1844514f5e3Sopenharmony_ci    }
1854514f5e3Sopenharmony_ci    Bind(&retFalse);
1864514f5e3Sopenharmony_ci    {
1874514f5e3Sopenharmony_ci        *result = TaggedFalse();
1884514f5e3Sopenharmony_ci        Jump(exit);
1894514f5e3Sopenharmony_ci    }
1904514f5e3Sopenharmony_ci}
1914514f5e3Sopenharmony_ci
1924514f5e3Sopenharmony_civoid BuiltinsNumberStubBuilder::IsSafeInteger(Variable *result, Label *exit, Label *slowPath)
1934514f5e3Sopenharmony_ci{
1944514f5e3Sopenharmony_ci    auto env = GetEnvironment();
1954514f5e3Sopenharmony_ci    GateRef number = GetCallArg0(numArgs_);
1964514f5e3Sopenharmony_ci
1974514f5e3Sopenharmony_ci    // In this method, we actually don't need slow path.
1984514f5e3Sopenharmony_ci    // The following code is for passing the verification phase.
1994514f5e3Sopenharmony_ci    Label noSlowPath(env);
2004514f5e3Sopenharmony_ci    BRANCH(False(), slowPath, &noSlowPath);
2014514f5e3Sopenharmony_ci    Bind(&noSlowPath);
2024514f5e3Sopenharmony_ci
2034514f5e3Sopenharmony_ci    Label retTrue(env);
2044514f5e3Sopenharmony_ci    Label retFalse(env);
2054514f5e3Sopenharmony_ci
2064514f5e3Sopenharmony_ci    Label isNotInt(env);
2074514f5e3Sopenharmony_ci    BRANCH(TaggedIsInt(number), &retTrue, &isNotInt);
2084514f5e3Sopenharmony_ci    Bind(&isNotInt);
2094514f5e3Sopenharmony_ci    {
2104514f5e3Sopenharmony_ci        Label isDouble(env);
2114514f5e3Sopenharmony_ci        BRANCH(TaggedIsDouble(number), &isDouble, &retFalse);
2124514f5e3Sopenharmony_ci        Bind(&isDouble);
2134514f5e3Sopenharmony_ci        {
2144514f5e3Sopenharmony_ci            Label isNotNanOrInf(env);
2154514f5e3Sopenharmony_ci            GateRef f = GetDoubleOfTDouble(number);
2164514f5e3Sopenharmony_ci            BRANCH(DoubleIsNanOrInf(f), &retFalse, &isNotNanOrInf);
2174514f5e3Sopenharmony_ci            Bind(&isNotNanOrInf);
2184514f5e3Sopenharmony_ci            {
2194514f5e3Sopenharmony_ci                Label checkSafe(env);
2204514f5e3Sopenharmony_ci                GateRef truncated = ChangeInt32ToFloat64(TruncFloatToInt64(f));
2214514f5e3Sopenharmony_ci                BRANCH(DoubleEqual(f, truncated), &checkSafe, &retFalse);
2224514f5e3Sopenharmony_ci                Bind(&checkSafe);
2234514f5e3Sopenharmony_ci                BRANCH(DoubleLessThanOrEqual(DoubleAbs(f), Double(base::MAX_SAFE_INTEGER)), &retTrue, &retFalse);
2244514f5e3Sopenharmony_ci            }
2254514f5e3Sopenharmony_ci        }
2264514f5e3Sopenharmony_ci    }
2274514f5e3Sopenharmony_ci
2284514f5e3Sopenharmony_ci    Bind(&retTrue);
2294514f5e3Sopenharmony_ci    {
2304514f5e3Sopenharmony_ci        *result = TaggedTrue();
2314514f5e3Sopenharmony_ci        Jump(exit);
2324514f5e3Sopenharmony_ci    }
2334514f5e3Sopenharmony_ci    Bind(&retFalse);
2344514f5e3Sopenharmony_ci    {
2354514f5e3Sopenharmony_ci        *result = TaggedFalse();
2364514f5e3Sopenharmony_ci        Jump(exit);
2374514f5e3Sopenharmony_ci    }
2384514f5e3Sopenharmony_ci}
2394514f5e3Sopenharmony_ci
2404514f5e3Sopenharmony_civoid BuiltinsNumberStubBuilder::GenNumberConstructor(GateRef nativeCode, GateRef func, GateRef newTarget)
2414514f5e3Sopenharmony_ci{
2424514f5e3Sopenharmony_ci    auto env = GetEnvironment();
2434514f5e3Sopenharmony_ci    DEFVARIABLE(res, VariableType::JS_ANY(), Undefined());
2444514f5e3Sopenharmony_ci    DEFVARIABLE(numberValue, VariableType::JS_ANY(), IntToTaggedPtr(IntPtr(0)));
2454514f5e3Sopenharmony_ci    Label thisCollectionObj(env);
2464514f5e3Sopenharmony_ci    Label slowPath(env);
2474514f5e3Sopenharmony_ci    Label slowPath1(env);
2484514f5e3Sopenharmony_ci    Label exit(env);
2494514f5e3Sopenharmony_ci
2504514f5e3Sopenharmony_ci    Label hasArg(env);
2514514f5e3Sopenharmony_ci    Label numberCreate(env);
2524514f5e3Sopenharmony_ci    Label newTargetIsHeapObject(env);
2534514f5e3Sopenharmony_ci    BRANCH(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath);
2544514f5e3Sopenharmony_ci    Bind(&newTargetIsHeapObject);
2554514f5e3Sopenharmony_ci    BRANCH(Int64GreaterThan(numArgs_, IntPtr(0)), &hasArg, &numberCreate);
2564514f5e3Sopenharmony_ci    Bind(&hasArg);
2574514f5e3Sopenharmony_ci    {
2584514f5e3Sopenharmony_ci        GateRef value = GetArgFromArgv(Int32(0));
2594514f5e3Sopenharmony_ci        Label number(env);
2604514f5e3Sopenharmony_ci        BRANCH(TaggedIsNumber(value), &number, &slowPath);
2614514f5e3Sopenharmony_ci        Bind(&number);
2624514f5e3Sopenharmony_ci        {
2634514f5e3Sopenharmony_ci            numberValue = value;
2644514f5e3Sopenharmony_ci            res = value;
2654514f5e3Sopenharmony_ci            Jump(&numberCreate);
2664514f5e3Sopenharmony_ci        }
2674514f5e3Sopenharmony_ci    }
2684514f5e3Sopenharmony_ci
2694514f5e3Sopenharmony_ci    Bind(&numberCreate);
2704514f5e3Sopenharmony_ci    Label newObj(env);
2714514f5e3Sopenharmony_ci    Label newTargetIsJSFunction(env);
2724514f5e3Sopenharmony_ci    BRANCH(TaggedIsUndefined(newTarget), &exit, &newObj);
2734514f5e3Sopenharmony_ci    Bind(&newObj);
2744514f5e3Sopenharmony_ci    {
2754514f5e3Sopenharmony_ci        BRANCH(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath);
2764514f5e3Sopenharmony_ci        Bind(&newTargetIsJSFunction);
2774514f5e3Sopenharmony_ci        {
2784514f5e3Sopenharmony_ci            Label intialHClassIsHClass(env);
2794514f5e3Sopenharmony_ci            GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget,
2804514f5e3Sopenharmony_ci                IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
2814514f5e3Sopenharmony_ci            BRANCH(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath1);
2824514f5e3Sopenharmony_ci            Bind(&intialHClassIsHClass);
2834514f5e3Sopenharmony_ci            {
2844514f5e3Sopenharmony_ci                NewObjectStubBuilder newBuilder(this);
2854514f5e3Sopenharmony_ci                newBuilder.SetParameters(glue_, 0);
2864514f5e3Sopenharmony_ci                Label afterNew(env);
2874514f5e3Sopenharmony_ci                newBuilder.NewJSObject(&res, &afterNew, intialHClass);
2884514f5e3Sopenharmony_ci                Bind(&afterNew);
2894514f5e3Sopenharmony_ci                {
2904514f5e3Sopenharmony_ci                    GateRef valueOffset = IntPtr(JSPrimitiveRef::VALUE_OFFSET);
2914514f5e3Sopenharmony_ci                    Store(VariableType::INT64(), glue_, *res, valueOffset, *numberValue);
2924514f5e3Sopenharmony_ci                    Jump(&exit);
2934514f5e3Sopenharmony_ci                }
2944514f5e3Sopenharmony_ci            }
2954514f5e3Sopenharmony_ci            Bind(&slowPath1);
2964514f5e3Sopenharmony_ci            {
2974514f5e3Sopenharmony_ci                GateRef argv = GetArgv();
2984514f5e3Sopenharmony_ci                res = CallBuiltinRuntimeWithNewTarget(glue_,
2994514f5e3Sopenharmony_ci                    { glue_, nativeCode, func, thisValue_, numArgs_, argv, newTarget });
3004514f5e3Sopenharmony_ci                Jump(&exit);
3014514f5e3Sopenharmony_ci            }
3024514f5e3Sopenharmony_ci        }
3034514f5e3Sopenharmony_ci    }
3044514f5e3Sopenharmony_ci
3054514f5e3Sopenharmony_ci    Bind(&slowPath);
3064514f5e3Sopenharmony_ci    {
3074514f5e3Sopenharmony_ci        GateRef argv = GetArgv();
3084514f5e3Sopenharmony_ci        res = CallBuiltinRuntime(glue_, { glue_, nativeCode, func, thisValue_, numArgs_, argv }, true);
3094514f5e3Sopenharmony_ci        Jump(&exit);
3104514f5e3Sopenharmony_ci    }
3114514f5e3Sopenharmony_ci    Bind(&exit);
3124514f5e3Sopenharmony_ci    Return(*res);
3134514f5e3Sopenharmony_ci}
3144514f5e3Sopenharmony_ci
3154514f5e3Sopenharmony_civoid BuiltinsNumberStubBuilder::ToString(Variable *result, Label *exit, Label *slowPath)
3164514f5e3Sopenharmony_ci{
3174514f5e3Sopenharmony_ci    auto env = GetEnvironment();
3184514f5e3Sopenharmony_ci    Label definedMsg(env);
3194514f5e3Sopenharmony_ci    Label undefinedMsg(env);
3204514f5e3Sopenharmony_ci    Label thisIsInt(env);
3214514f5e3Sopenharmony_ci    Label msgIsInt(env);
3224514f5e3Sopenharmony_ci    BRANCH(TaggedIsInt(thisValue_), &thisIsInt, slowPath);
3234514f5e3Sopenharmony_ci    Bind(&thisIsInt);
3244514f5e3Sopenharmony_ci    GateRef thisValueInt = GetInt32OfTInt(thisValue_);
3254514f5e3Sopenharmony_ci    GateRef msg = GetCallArg0(numArgs_);
3264514f5e3Sopenharmony_ci    BRANCH(TaggedIsUndefined(msg), &undefinedMsg, &definedMsg);
3274514f5e3Sopenharmony_ci    Bind(&undefinedMsg);
3284514f5e3Sopenharmony_ci    {
3294514f5e3Sopenharmony_ci        *result = NumberToString(thisValueInt, Int32(10)); // 10: means radix
3304514f5e3Sopenharmony_ci        Jump(exit);
3314514f5e3Sopenharmony_ci    }
3324514f5e3Sopenharmony_ci    Bind(&definedMsg);
3334514f5e3Sopenharmony_ci    BRANCH(TaggedIsInt(msg), &msgIsInt, slowPath);
3344514f5e3Sopenharmony_ci    Bind(&msgIsInt);
3354514f5e3Sopenharmony_ci    {
3364514f5e3Sopenharmony_ci        Label throwError(env);
3374514f5e3Sopenharmony_ci        Label notThrowError(env);
3384514f5e3Sopenharmony_ci        GateRef msgValue = GetInt32OfTInt(msg);
3394514f5e3Sopenharmony_ci        GateRef outOfRange = BitOr(Int32LessThan(msgValue, Int32(base::MIN_RADIX)),
3404514f5e3Sopenharmony_ci                                   Int32GreaterThan(msgValue, Int32(base::MAX_RADIX)));
3414514f5e3Sopenharmony_ci        BRANCH(outOfRange, &throwError, &notThrowError);
3424514f5e3Sopenharmony_ci        Bind(&throwError);
3434514f5e3Sopenharmony_ci        {
3444514f5e3Sopenharmony_ci            GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(InvalidRadixLength));
3454514f5e3Sopenharmony_ci            CallRuntime(glue_, RTSTUB_ID(ThrowRangeError), { IntToTaggedInt(taggedId) });
3464514f5e3Sopenharmony_ci            Jump(exit);
3474514f5e3Sopenharmony_ci        }
3484514f5e3Sopenharmony_ci        Bind(&notThrowError);
3494514f5e3Sopenharmony_ci        {
3504514f5e3Sopenharmony_ci            *result = NumberToString(thisValueInt, msgValue);
3514514f5e3Sopenharmony_ci            Jump(exit);
3524514f5e3Sopenharmony_ci        }
3534514f5e3Sopenharmony_ci    }
3544514f5e3Sopenharmony_ci}
3554514f5e3Sopenharmony_ci
3564514f5e3Sopenharmony_ciGateRef BuiltinsNumberStubBuilder::NumberToString(GateRef number, GateRef radix)
3574514f5e3Sopenharmony_ci{
3584514f5e3Sopenharmony_ci    auto env = GetEnvironment();
3594514f5e3Sopenharmony_ci    Label subentry(env);
3604514f5e3Sopenharmony_ci    env->SubCfgEntry(&subentry);
3614514f5e3Sopenharmony_ci    DEFVARIABLE(result, VariableType::JS_POINTER(), Hole());
3624514f5e3Sopenharmony_ci    DEFVARIABLE(n, VariableType::INT32(), number);
3634514f5e3Sopenharmony_ci
3644514f5e3Sopenharmony_ci    Label exit(env);
3654514f5e3Sopenharmony_ci    Label numIsNegative(env);
3664514f5e3Sopenharmony_ci    Label numNotNegative(env);
3674514f5e3Sopenharmony_ci    Label afterFast(env);
3684514f5e3Sopenharmony_ci    Label afterNew(env);
3694514f5e3Sopenharmony_ci    GateRef isNegative = Int32LessThan(number, Int32(0));
3704514f5e3Sopenharmony_ci    BRANCH(isNegative, &numIsNegative, &numNotNegative);
3714514f5e3Sopenharmony_ci    Bind(&numIsNegative);
3724514f5e3Sopenharmony_ci    {
3734514f5e3Sopenharmony_ci        n = Int32Sub(Int32(0), *n);
3744514f5e3Sopenharmony_ci        Jump(&afterFast);
3754514f5e3Sopenharmony_ci    }
3764514f5e3Sopenharmony_ci    Bind(&numNotNegative);
3774514f5e3Sopenharmony_ci    {
3784514f5e3Sopenharmony_ci        Label thisIsZero(env);
3794514f5e3Sopenharmony_ci        Label thisNotZero(env);
3804514f5e3Sopenharmony_ci        Label thisIsSingle(env);
3814514f5e3Sopenharmony_ci        Label thisNotSingle(env);
3824514f5e3Sopenharmony_ci        BRANCH(Int32Equal(number, Int32(0)), &thisIsZero, &thisNotZero);
3834514f5e3Sopenharmony_ci        Bind(&thisIsZero);
3844514f5e3Sopenharmony_ci        {
3854514f5e3Sopenharmony_ci            result = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::ZERO_INDEX);
3864514f5e3Sopenharmony_ci            Jump(&exit);
3874514f5e3Sopenharmony_ci        }
3884514f5e3Sopenharmony_ci        Bind(&thisNotZero);
3894514f5e3Sopenharmony_ci        {
3904514f5e3Sopenharmony_ci            BRANCH(Int32LessThan(number, radix), &thisIsSingle, &afterFast);
3914514f5e3Sopenharmony_ci            Bind(&thisIsSingle);
3924514f5e3Sopenharmony_ci            GateRef singleCharTable = GetSingleCharTable(glue_);
3934514f5e3Sopenharmony_ci            GateRef index = ToCharCode(number);
3944514f5e3Sopenharmony_ci            result = GetValueFromTaggedArray(singleCharTable, index);
3954514f5e3Sopenharmony_ci            Jump(&exit);
3964514f5e3Sopenharmony_ci        }
3974514f5e3Sopenharmony_ci    }
3984514f5e3Sopenharmony_ci    Bind(&afterFast);
3994514f5e3Sopenharmony_ci    {
4004514f5e3Sopenharmony_ci        DEFVARIABLE(temp, VariableType::INT32(), *n);
4014514f5e3Sopenharmony_ci        DEFVARIABLE(length, VariableType::INT32(), Int32(0));
4024514f5e3Sopenharmony_ci        Label lenAddOne(env);
4034514f5e3Sopenharmony_ci        Label lenNotAddOne(env);
4044514f5e3Sopenharmony_ci        BRANCH(isNegative, &lenAddOne, &lenNotAddOne);
4054514f5e3Sopenharmony_ci        Bind(&lenAddOne);
4064514f5e3Sopenharmony_ci        {
4074514f5e3Sopenharmony_ci            length = Int32Add(*length, Int32(1));
4084514f5e3Sopenharmony_ci            Jump(&lenNotAddOne);
4094514f5e3Sopenharmony_ci        }
4104514f5e3Sopenharmony_ci        Bind(&lenNotAddOne);
4114514f5e3Sopenharmony_ci        {
4124514f5e3Sopenharmony_ci            Label loopHead(env);
4134514f5e3Sopenharmony_ci            Label loopEnd(env);
4144514f5e3Sopenharmony_ci            Label next(env);
4154514f5e3Sopenharmony_ci            Label loopExit(env);
4164514f5e3Sopenharmony_ci            Jump(&loopHead);
4174514f5e3Sopenharmony_ci            LoopBegin(&loopHead);
4184514f5e3Sopenharmony_ci            {
4194514f5e3Sopenharmony_ci                BRANCH(Int32GreaterThan(*temp, Int32(0)), &next, &loopExit);
4204514f5e3Sopenharmony_ci                Bind(&next);
4214514f5e3Sopenharmony_ci                {
4224514f5e3Sopenharmony_ci                    temp = Int32Div(*temp, radix);
4234514f5e3Sopenharmony_ci                    length = Int32Add(*length, Int32(1));
4244514f5e3Sopenharmony_ci                    Jump(&loopEnd);
4254514f5e3Sopenharmony_ci                }
4264514f5e3Sopenharmony_ci            }
4274514f5e3Sopenharmony_ci            Bind(&loopEnd);
4284514f5e3Sopenharmony_ci            LoopEnd(&loopHead, env, glue_);
4294514f5e3Sopenharmony_ci            Bind(&loopExit);
4304514f5e3Sopenharmony_ci            {
4314514f5e3Sopenharmony_ci                NewObjectStubBuilder newBuilder(this);
4324514f5e3Sopenharmony_ci                newBuilder.SetParameters(glue_, 0);
4334514f5e3Sopenharmony_ci                newBuilder.AllocLineStringObject(&result, &afterNew, *length, true);
4344514f5e3Sopenharmony_ci                Bind(&afterNew);
4354514f5e3Sopenharmony_ci                {
4364514f5e3Sopenharmony_ci                    GateRef dst = ChangeTaggedPointerToInt64(PtrAdd(*result, IntPtr(LineEcmaString::DATA_OFFSET)));
4374514f5e3Sopenharmony_ci                    DEFVARIABLE(cursor, VariableType::INT32(), Int32Sub(*length, Int32(1)));
4384514f5e3Sopenharmony_ci                    DEFVARIABLE(digit, VariableType::INT32(), Int32(0));
4394514f5e3Sopenharmony_ci                    DEFVARIABLE(dstTmp, VariableType::NATIVE_POINTER(), dst);
4404514f5e3Sopenharmony_ci                    dstTmp = PtrAdd(*dstTmp, PtrMul(ZExtInt32ToPtr(*cursor), IntPtr(sizeof(uint8_t))));
4414514f5e3Sopenharmony_ci                    Label loopHead1(env);
4424514f5e3Sopenharmony_ci                    Label loopEnd1(env);
4434514f5e3Sopenharmony_ci                    Label next1(env);
4444514f5e3Sopenharmony_ci                    Label loopExit1(env);
4454514f5e3Sopenharmony_ci                    Jump(&loopHead1);
4464514f5e3Sopenharmony_ci                    LoopBegin(&loopHead1);
4474514f5e3Sopenharmony_ci                    {
4484514f5e3Sopenharmony_ci                        BRANCH(Int32GreaterThan(*n, Int32(0)), &next1, &loopExit1);
4494514f5e3Sopenharmony_ci                        Bind(&next1);
4504514f5e3Sopenharmony_ci                        {
4514514f5e3Sopenharmony_ci                            digit = Int32Mod(*n, radix);
4524514f5e3Sopenharmony_ci                            n = Int32Div(*n, radix);
4534514f5e3Sopenharmony_ci                            GateRef digitChar = ToCharCode(*digit);
4544514f5e3Sopenharmony_ci                            Store(VariableType::INT8(), glue_, *dstTmp, IntPtr(0), TruncInt32ToInt8(digitChar));
4554514f5e3Sopenharmony_ci                            cursor = Int32Sub(*cursor, Int32(1));
4564514f5e3Sopenharmony_ci                            Jump(&loopEnd1);
4574514f5e3Sopenharmony_ci                        }
4584514f5e3Sopenharmony_ci                    }
4594514f5e3Sopenharmony_ci                    Bind(&loopEnd1);
4604514f5e3Sopenharmony_ci                    dstTmp = PtrSub(*dstTmp, IntPtr(sizeof(uint8_t)));
4614514f5e3Sopenharmony_ci                    // Work with low level buffers, we can't call GC. Loop is simple, no more 32 iteration.
4624514f5e3Sopenharmony_ci                    // Ability using GC at the end of loop require add additional calculate pointer to data of string
4634514f5e3Sopenharmony_ci                    // on each iteration.
4644514f5e3Sopenharmony_ci                    LoopEnd(&loopHead1);
4654514f5e3Sopenharmony_ci                    Bind(&loopExit1);
4664514f5e3Sopenharmony_ci                    {
4674514f5e3Sopenharmony_ci                        Label strInsertSign(env);
4684514f5e3Sopenharmony_ci                        Label strNotInsertSign(env);
4694514f5e3Sopenharmony_ci                        BRANCH(isNegative, &strInsertSign, &exit);
4704514f5e3Sopenharmony_ci                        Bind(&strInsertSign);
4714514f5e3Sopenharmony_ci                        {
4724514f5e3Sopenharmony_ci                            dstTmp = PtrSub(*dstTmp, IntPtr(sizeof(uint8_t)));
4734514f5e3Sopenharmony_ci                            Store(VariableType::INT8(), glue_, dst, IntPtr(0), Int8(45)); // 45: means '-'
4744514f5e3Sopenharmony_ci                            Jump(&exit);
4754514f5e3Sopenharmony_ci                        }
4764514f5e3Sopenharmony_ci                    }
4774514f5e3Sopenharmony_ci                }
4784514f5e3Sopenharmony_ci            }
4794514f5e3Sopenharmony_ci        }
4804514f5e3Sopenharmony_ci    }
4814514f5e3Sopenharmony_ci    Bind(&exit);
4824514f5e3Sopenharmony_ci    auto ret = *result;
4834514f5e3Sopenharmony_ci    env->SubCfgExit();
4844514f5e3Sopenharmony_ci    return ret;
4854514f5e3Sopenharmony_ci}
4864514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::kungfu
487