• 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_lowering.h"
17 
18 #include "ecmascript/global_env.h"
19 
20 namespace panda::ecmascript::kungfu {
LowerTypedCallBuitin(GateRef gate)21 void BuiltinLowering::LowerTypedCallBuitin(GateRef gate)
22 {
23     Environment env(gate, circuit_, &builder_);
24     auto valuesIn = acc_.GetNumValueIn(gate);
25     auto idGate = acc_.GetValueIn(gate, valuesIn - 1);
26     auto id = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(idGate));
27     switch (id) {
28         case BUILTINS_STUB_ID(ABS):
29             LowerTypedAbs(gate);
30             break;
31         case BUILTINS_STUB_ID(FLOOR):
32         case BUILTINS_STUB_ID(COS):
33         case BUILTINS_STUB_ID(SIN):
34         case BUILTINS_STUB_ID(ACOS):
35         case BUILTINS_STUB_ID(ATAN):
36             LowerTypedTrigonometric(gate, id);
37             break;
38         case BUILTINS_STUB_ID(LocaleCompare):
39             LowerTypedLocaleCompare(gate);
40             break;
41         case BUILTINS_STUB_ID(SORT):
42             LowerTypedArraySort(gate);
43             break;
44         case BUILTINS_STUB_ID(STRINGIFY):
45             LowerTypedStringify(gate);
46             break;
47         case BUILTINS_STUB_ID(MAP_PROTO_ITERATOR):
48         case BUILTINS_STUB_ID(SET_PROTO_ITERATOR):
49         case BUILTINS_STUB_ID(STRING_PROTO_ITERATOR):
50         case BUILTINS_STUB_ID(ARRAY_PROTO_ITERATOR):
51         case BUILTINS_STUB_ID(TYPED_ARRAY_PROTO_ITERATOR):
52             LowerBuiltinIterator(gate, id);
53             break;
54         case BUILTINS_STUB_ID(MAP_ITERATOR_PROTO_NEXT):
55         case BUILTINS_STUB_ID(SET_ITERATOR_PROTO_NEXT):
56         case BUILTINS_STUB_ID(STRING_ITERATOR_PROTO_NEXT):
57         case BUILTINS_STUB_ID(ARRAY_ITERATOR_PROTO_NEXT):
58             LowerIteratorNext(gate, id);
59             break;
60         case BUILTINS_STUB_ID(NumberConstructor):
61             LowerNumberConstructor(gate);
62             break;
63         default:
64             break;
65     }
66 }
67 
LowerTypedTrigonometric(GateRef gate,BuiltinsStubCSigns::ID id)68 void BuiltinLowering::LowerTypedTrigonometric(GateRef gate, BuiltinsStubCSigns::ID id)
69 {
70     auto ret = TypedTrigonometric(gate, id);
71     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
72 }
73 
TypedTrigonometric(GateRef gate,BuiltinsStubCSigns::ID id)74 GateRef BuiltinLowering::TypedTrigonometric(GateRef gate, BuiltinsStubCSigns::ID id)
75 {
76     auto env = builder_.GetCurrentEnvironment();
77     Label entry(&builder_);
78     env->SubCfgEntry(&entry);
79 
80     Label numberBranch(&builder_);
81     Label notNumberBranch(&builder_);
82     Label exit(&builder_);
83 
84     GateRef para1 = acc_.GetValueIn(gate, 0);
85     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
86 
87     builder_.Branch(builder_.TaggedIsNumber(para1), &numberBranch, &notNumberBranch);
88     builder_.Bind(&numberBranch);
89     {
90         GateRef value = builder_.GetDoubleOfTNumber(para1);
91         Label IsNan(&builder_);
92         Label NotNan(&builder_);
93         GateRef condition = builder_.DoubleIsNAN(value);
94         builder_.Branch(condition, &IsNan, &NotNan);
95         builder_.Bind(&NotNan);
96         {
97             GateRef glue = acc_.GetGlueFromArgList();
98             int index = RTSTUB_ID(FloatCos);
99             switch (id) {
100                 case BUILTINS_STUB_ID(FLOOR):
101                     index = RTSTUB_ID(FloatFloor);
102                     break;
103                 case BUILTINS_STUB_ID(ACOS):
104                     index = RTSTUB_ID(FloatACos);
105                     break;
106                 case BUILTINS_STUB_ID(ATAN):
107                     index = RTSTUB_ID(FloatATan);
108                     break;
109                 case BUILTINS_STUB_ID(COS):
110                     index = RTSTUB_ID(FloatCos);
111                     break;
112                 case BUILTINS_STUB_ID(SIN):
113                     index = RTSTUB_ID(FloatSin);
114                     break;
115                 default:
116                     LOG_ECMA(FATAL) << "this branch is unreachable";
117                     UNREACHABLE();
118             }
119             result = builder_.CallNGCRuntime(glue, index, Gate::InvalidGateRef, {value}, gate);
120             builder_.Jump(&exit);
121         }
122         builder_.Bind(&IsNan);
123         {
124             result = builder_.DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
125             builder_.Jump(&exit);
126         }
127     }
128     builder_.Bind(&notNumberBranch);
129     {
130         builder_.Jump(&exit);
131     }
132 
133     builder_.Bind(&exit);
134     auto ret = *result;
135     env->SubCfgExit();
136     return ret;
137 }
138 
LowerTypedSqrt(GateRef gate)139 void BuiltinLowering::LowerTypedSqrt(GateRef gate)
140 {
141     Environment env(gate, circuit_, &builder_);
142     GateRef param = acc_.GetValueIn(gate, 0);
143     // 20.2.2.32
144     // If value is NAN or negative, include -NaN and -Infinity but not -0.0, the result is NaN
145     // Assembly instruction support NAN and negative
146     auto ret = builder_.Sqrt(param);
147     acc_.SetMachineType(ret, MachineType::F64);
148     acc_.SetGateType(ret, GateType::NJSValue());
149     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
150 }
151 
LowerTypedAbs(GateRef gate)152 void BuiltinLowering::LowerTypedAbs(GateRef gate)
153 {
154     auto ret = TypedAbs(gate);
155     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
156 }
157 
IntToTaggedIntPtr(GateRef x)158 GateRef BuiltinLowering::IntToTaggedIntPtr(GateRef x)
159 {
160     GateRef val = builder_.SExtInt32ToInt64(x);
161     return builder_.ToTaggedIntPtr(val);
162 }
163 
164 //  Int abs : The internal representation of an integer is inverse code,
165 //  The absolute value of a negative number can be found by inverting it by adding one.
166 
167 //  Float abs : A floating-point number is composed of mantissa and exponent.
168 //  The length of mantissa will affect the precision of the number, and its sign will determine the sign of the number.
169 //  The absolute value of a floating-point number can be found by setting mantissa sign bit to 0.
TypedAbs(GateRef gate)170 GateRef BuiltinLowering::TypedAbs(GateRef gate)
171 {
172     auto env = builder_.GetCurrentEnvironment();
173     Label entry(&builder_);
174     env->SubCfgEntry(&entry);
175 
176     Label exit(&builder_);
177     GateRef para1 = acc_.GetValueIn(gate, 0);
178     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
179 
180     Label isInt(&builder_);
181     Label notInt(&builder_);
182     builder_.Branch(builder_.TaggedIsInt(para1), &isInt, &notInt);
183     builder_.Bind(&isInt);
184     {
185         auto value = builder_.GetInt32OfTInt(para1);
186         auto temp = builder_.Int32ASR(value, builder_.Int32(JSTaggedValue::INT_SIGN_BIT_OFFSET));
187         auto res = builder_.Int32Xor(value, temp);
188         result = IntToTaggedIntPtr(builder_.Int32Sub(res, temp));
189         builder_.Jump(&exit);
190     }
191     builder_.Bind(&notInt);
192     {
193         auto value = builder_.GetDoubleOfTDouble(para1);
194         // set the sign bit to 0 by shift left then right.
195         auto temp = builder_.Int64LSL(builder_.CastDoubleToInt64(value), builder_.Int64(1));
196         auto res = builder_.Int64LSR(temp, builder_.Int64(1));
197         result = builder_.DoubleToTaggedDoublePtr(builder_.CastInt64ToFloat64(res));
198         builder_.Jump(&exit);
199     }
200     builder_.Bind(&exit);
201     auto ret = *result;
202     env->SubCfgExit();
203     return ret;
204 }
205 
LowerCallRuntime(GateRef glue,GateRef gate,int index,const std::vector<GateRef> & args,bool useLabel)206 GateRef BuiltinLowering::LowerCallRuntime(GateRef glue, GateRef gate, int index, const std::vector<GateRef> &args,
207                                           bool useLabel)
208 {
209     const std::string name = RuntimeStubCSigns::GetRTName(index);
210     if (useLabel) {
211         GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, gate, name.c_str());
212         return result;
213     } else {
214         const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
215         GateRef target = builder_.IntPtr(index);
216         GateRef result = builder_.Call(cs, glue, target, builder_.GetDepend(), args, gate, name.c_str());
217         return result;
218     }
219 }
220 
ReplaceHirWithValue(GateRef hirGate,GateRef value,bool noThrow)221 void BuiltinLowering::ReplaceHirWithValue(GateRef hirGate, GateRef value, bool noThrow)
222 {
223     if (!noThrow) {
224         GateRef state = builder_.GetState();
225         // copy depend-wire of hirGate to value
226         GateRef depend = builder_.GetDepend();
227         // exception value
228         GateRef exceptionVal = builder_.ExceptionConstant();
229         // compare with trampolines result
230         GateRef equal = builder_.Equal(value, exceptionVal);
231         auto ifBranch = builder_.Branch(state, equal);
232 
233         GateRef ifTrue = builder_.IfTrue(ifBranch);
234         GateRef ifFalse = builder_.IfFalse(ifBranch);
235         GateRef eDepend = builder_.DependRelay(ifTrue, depend);
236         GateRef sDepend = builder_.DependRelay(ifFalse, depend);
237         StateDepend success(ifFalse, sDepend);
238         StateDepend exception(ifTrue, eDepend);
239         acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
240     } else {
241         acc_.ReplaceHirDirectly(hirGate, builder_.GetStateDepend(), value);
242     }
243 }
244 
LowerTypedLocaleCompare(GateRef gate)245 void BuiltinLowering::LowerTypedLocaleCompare(GateRef gate)
246 {
247     GateRef glue = acc_.GetGlueFromArgList();
248     uint32_t index = 0;
249     GateRef thisObj = acc_.GetValueIn(gate, index++);
250     GateRef a0 = acc_.GetValueIn(gate, index++);
251     GateRef a1 = acc_.GetValueIn(gate, index++);
252     GateRef a2 = acc_.GetValueIn(gate, index++);
253 
254     std::vector<GateRef> args;
255     args.reserve(index);
256     args.emplace_back(thisObj);
257     args.emplace_back(a0);
258     args.emplace_back(a1);
259     args.emplace_back(a2);
260     GateRef result = LowerCallRuntime(glue, gate, RTSTUB_ID(LocaleCompare), args);
261     ReplaceHirWithValue(gate, result);
262 }
263 
LowerTypedArraySort(GateRef gate)264 void BuiltinLowering::LowerTypedArraySort(GateRef gate)
265 {
266     GateRef glue = acc_.GetGlueFromArgList();
267     GateRef thisObj = acc_.GetValueIn(gate, 0);
268     GateRef result = LowerCallRuntime(glue, gate, RTSTUB_ID(ArraySort), { thisObj });
269     ReplaceHirWithValue(gate, result);
270 }
271 
LowerCallTargetCheck(Environment * env,GateRef gate)272 GateRef BuiltinLowering::LowerCallTargetCheck(Environment *env, GateRef gate)
273 {
274     builder_.SetEnvironment(env);
275     GateRef idGate = acc_.GetValueIn(gate, 1);
276     BuiltinsStubCSigns::ID id = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(idGate));
277     switch (id) {
278         case BuiltinsStubCSigns::ID::MAP_PROTO_ITERATOR:
279         case BuiltinsStubCSigns::ID::SET_PROTO_ITERATOR:
280         case BuiltinsStubCSigns::ID::STRING_PROTO_ITERATOR:
281         case BuiltinsStubCSigns::ID::ARRAY_PROTO_ITERATOR:
282         case BuiltinsStubCSigns::ID::TYPED_ARRAY_PROTO_ITERATOR: {
283             return LowerCallTargetCheckWithDetector(gate, id);
284         }
285         case BuiltinsStubCSigns::ID::NumberConstructor: {
286             return LowerCallTargetCheckWithGlobalEnv(gate, id);
287         }
288         default: {
289             return LowerCallTargetCheckDefault(gate, id);
290         }
291     }
292 }
293 
LowerCallTargetCheckDefault(GateRef gate,BuiltinsStubCSigns::ID id)294 GateRef BuiltinLowering::LowerCallTargetCheckDefault(GateRef gate, BuiltinsStubCSigns::ID id)
295 {
296     GateRef constantFunction = builder_.GetGlobalConstantValue(GET_TYPED_CONSTANT_INDEX(id));
297     GateRef function = acc_.GetValueIn(gate, 0); // 0: function
298     return builder_.Equal(function, constantFunction);
299 }
300 
LowerCallTargetCheckWithGlobalEnv(GateRef gate,BuiltinsStubCSigns::ID id)301 GateRef BuiltinLowering::LowerCallTargetCheckWithGlobalEnv(GateRef gate, BuiltinsStubCSigns::ID id)
302 {
303     GateRef glueGlobalEnv = builder_.GetGlobalEnv();
304     GateRef globalFunction =
305         builder_.GetGlobalEnvObj(glueGlobalEnv, GET_TYPED_GLOBAL_ENV_INDEX(id));
306     GateRef target = acc_.GetValueIn(gate, 0); // 0:target
307     return builder_.Equal(target, globalFunction);
308 }
309 
LowerCallTargetCheckWithDetector(GateRef gate,BuiltinsStubCSigns::ID id)310 GateRef BuiltinLowering::LowerCallTargetCheckWithDetector(GateRef gate, BuiltinsStubCSigns::ID id)
311 {
312     JSType expectType = JSType::INVALID;
313     uint8_t detectorIndex = 0;
314     switch (id) {
315         case BuiltinsStubCSigns::ID::MAP_PROTO_ITERATOR: {
316             expectType = JSType::JS_MAP;
317             detectorIndex = GlobalEnv::MAP_ITERATOR_DETECTOR_INDEX;
318             break;
319         }
320         case BuiltinsStubCSigns::ID::SET_PROTO_ITERATOR: {
321             expectType = JSType::JS_SET;
322             detectorIndex = GlobalEnv::SET_ITERATOR_DETECTOR_INDEX;
323             break;
324         }
325         case BuiltinsStubCSigns::ID::STRING_PROTO_ITERATOR: {
326             expectType = JSType::STRING_FIRST;
327             detectorIndex = GlobalEnv::STRING_ITERATOR_DETECTOR_INDEX;
328             break;
329         }
330         case BuiltinsStubCSigns::ID::ARRAY_PROTO_ITERATOR: {
331             expectType = JSType::JS_ARRAY;
332             detectorIndex = GlobalEnv::ARRAY_ITERATOR_DETECTOR_INDEX;
333             break;
334         }
335         case BuiltinsStubCSigns::ID::TYPED_ARRAY_PROTO_ITERATOR: {
336             expectType = JSType::JS_TYPED_ARRAY_FIRST;
337             detectorIndex = GlobalEnv::TYPED_ARRAY_ITERATOR_DETECTOR_INDEX;
338             break;
339         }
340         default: {
341             LOG_COMPILER(FATAL) << "this branch is unreachable";
342             UNREACHABLE();
343         }
344     }
345     GateRef obj = acc_.GetValueIn(gate, 2);  // 2: iterator obj
346     GateRef check1 =  builder_.BoolAnd(
347         builder_.TaggedIsHeapObjectOp(obj), builder_.IsSpecificObjectType(obj, expectType));
348     GateRef glueGlobalEnv = builder_.GetGlobalEnv();
349     GateRef markerCell = builder_.GetGlobalEnvObj(glueGlobalEnv, detectorIndex);
350     GateRef check2 = builder_.BoolAnd(check1, builder_.IsMarkerCellValid(markerCell));
351     return check2;
352 }
353 
CheckPara(GateRef gate,GateRef funcCheck)354 GateRef BuiltinLowering::CheckPara(GateRef gate, GateRef funcCheck)
355 {
356     GateRef idGate = acc_.GetValueIn(gate, 1);
357     BuiltinsStubCSigns::ID id = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(idGate));
358     switch (id) {
359         case BuiltinsStubCSigns::ID::COS:
360         case BuiltinsStubCSigns::ID::SIN:
361         case BuiltinsStubCSigns::ID::ACOS:
362         case BuiltinsStubCSigns::ID::ATAN:
363         case BuiltinsStubCSigns::ID::ABS:
364         case BuiltinsStubCSigns::ID::FLOOR: {
365             GateRef para = acc_.GetValueIn(gate, 2);
366             GateRef paracheck = builder_.TaggedIsNumber(para);
367             return builder_.BoolAnd(paracheck, funcCheck);
368         }
369         case BuiltinsStubCSigns::ID::SQRT:
370             // NumberSpeculativeRetype is checked
371             return funcCheck;
372         case BuiltinsStubCSigns::ID::LocaleCompare:
373         case BuiltinsStubCSigns::ID::SORT:
374         case BuiltinsStubCSigns::ID::STRINGIFY:
375         case BuiltinsStubCSigns::ID::MAP_PROTO_ITERATOR:
376         case BuiltinsStubCSigns::ID::SET_PROTO_ITERATOR:
377         case BuiltinsStubCSigns::ID::STRING_PROTO_ITERATOR:
378         case BuiltinsStubCSigns::ID::ARRAY_PROTO_ITERATOR:
379         case BuiltinsStubCSigns::ID::TYPED_ARRAY_PROTO_ITERATOR:
380         case BuiltinsStubCSigns::ID::MAP_ITERATOR_PROTO_NEXT:
381         case BuiltinsStubCSigns::ID::SET_ITERATOR_PROTO_NEXT:
382         case BuiltinsStubCSigns::ID::STRING_ITERATOR_PROTO_NEXT:
383         case BuiltinsStubCSigns::ID::ARRAY_ITERATOR_PROTO_NEXT:
384         case BuiltinsStubCSigns::ID::NumberConstructor:
385         case BuiltinsStubCSigns::ID::StringFromCharCode:
386             // Don't need check para
387             return funcCheck;
388         default: {
389             LOG_COMPILER(FATAL) << "this branch is unreachable";
390             UNREACHABLE();
391         }
392     }
393 }
394 
LowerTypedStringify(GateRef gate)395 void BuiltinLowering::LowerTypedStringify(GateRef gate)
396 {
397     GateRef glue = acc_.GetGlueFromArgList();
398     GateRef value = acc_.GetValueIn(gate, 0);
399     std::vector<GateRef> args;
400     args.emplace_back(value);
401     GateRef result = LowerCallRuntime(glue, gate, RTSTUB_ID(FastStringify), args);
402     ReplaceHirWithValue(gate, result);
403 }
404 
LowerBuiltinIterator(GateRef gate,BuiltinsStubCSigns::ID id)405 void BuiltinLowering::LowerBuiltinIterator(GateRef gate, BuiltinsStubCSigns::ID id)
406 {
407     GateRef glue = acc_.GetGlueFromArgList();
408     GateRef obj = acc_.GetValueIn(gate, 0);
409     GateRef result = Circuit::NullGate();
410     switch (id) {
411         case BUILTINS_STUB_ID(MAP_PROTO_ITERATOR): {
412             result = builder_.CallStub(glue, gate, CommonStubCSigns::CreateJSMapIterator, { glue, obj });
413             break;
414         }
415         case BUILTINS_STUB_ID(SET_PROTO_ITERATOR): {
416             result = builder_.CallStub(glue, gate, CommonStubCSigns::CreateJSSetIterator, { glue, obj });
417             break;
418         }
419         case BUILTINS_STUB_ID(STRING_PROTO_ITERATOR): {
420             result = LowerCallRuntime(glue, gate, RTSTUB_ID(CreateStringIterator), { obj }, true);
421             break;
422         }
423         case BUILTINS_STUB_ID(ARRAY_PROTO_ITERATOR): {
424             result = LowerCallRuntime(glue, gate, RTSTUB_ID(NewJSArrayIterator), { obj }, true);
425             break;
426         }
427         case BUILTINS_STUB_ID(TYPED_ARRAY_PROTO_ITERATOR): {
428             result = LowerCallRuntime(glue, gate, RTSTUB_ID(NewJSTypedArrayIterator), { obj }, true);
429             break;
430         }
431         default:
432             UNREACHABLE();
433     }
434     ReplaceHirWithValue(gate, result);
435 }
436 
LowerIteratorNext(GateRef gate,BuiltinsStubCSigns::ID id)437 void BuiltinLowering::LowerIteratorNext(GateRef gate, BuiltinsStubCSigns::ID id)
438 {
439     GateRef glue = acc_.GetGlueFromArgList();
440     GateRef thisObj = acc_.GetValueIn(gate, 0);
441     GateRef result = Circuit::NullGate();
442     switch (id) {
443         case BUILTINS_STUB_ID(MAP_ITERATOR_PROTO_NEXT): {
444             result = LowerCallRuntime(glue, gate, RTSTUB_ID(MapIteratorNext), { thisObj }, true);
445             break;
446         }
447         case BUILTINS_STUB_ID(SET_ITERATOR_PROTO_NEXT): {
448             result = LowerCallRuntime(glue, gate, RTSTUB_ID(SetIteratorNext), { thisObj }, true);
449             break;
450         }
451         case BUILTINS_STUB_ID(STRING_ITERATOR_PROTO_NEXT): {
452             result = LowerCallRuntime(glue, gate, RTSTUB_ID(StringIteratorNext), { thisObj }, true);
453             break;
454         }
455         case BUILTINS_STUB_ID(ARRAY_ITERATOR_PROTO_NEXT): {
456             result = LowerCallRuntime(glue, gate, RTSTUB_ID(ArrayIteratorNext), { thisObj }, true);
457             break;
458         }
459         default:
460             UNREACHABLE();
461     }
462     ReplaceHirWithValue(gate, result);
463 }
464 
LowerNumberConstructor(GateRef gate)465 void BuiltinLowering::LowerNumberConstructor(GateRef gate)
466 {
467     auto env = builder_.GetCurrentEnvironment();
468 
469     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), IntToTaggedIntPtr(builder_.Int32(0)));
470     GateRef param = acc_.GetValueIn(gate, 0);
471     Label exit(env);
472     Label isNumber(env);
473     Label notNumber(env);
474     builder_.Branch(builder_.TaggedIsNumber(param), &isNumber, &notNumber);
475     builder_.Bind(&isNumber);
476     {
477         result = param;
478         builder_.Jump(&exit);
479     }
480     builder_.Bind(&notNumber);
481     {
482         Label isString(env);
483         Label notString(env);
484         builder_.Branch(builder_.TaggedIsString(param), &isString, &notString);
485         builder_.Bind(&isString);
486         {
487             Label nonZeroLength(env);
488             auto length = builder_.GetLengthFromString(param);
489             builder_.Branch(builder_.Equal(length, builder_.Int32(0)), &exit, &nonZeroLength);
490             builder_.Bind(&nonZeroLength);
491             Label isInteger(env);
492             builder_.Branch(builder_.IsIntegerString(param), &isInteger, &notString);
493             builder_.Bind(&isInteger);
494             {
495                 result = IntToTaggedIntPtr(builder_.GetRawHashFromString(param));
496                 builder_.Jump(&exit);
497             }
498         }
499         builder_.Bind(&notString);
500         {
501             GateRef glue = acc_.GetGlueFromArgList();
502             result = LowerCallRuntime(glue, gate, RTSTUB_ID(ToNumericConvertBigInt), { param }, true);
503             builder_.Jump(&exit);
504         }
505     }
506     builder_.Bind(&exit);
507     ReplaceHirWithValue(gate, *result);
508 }
509 }  // namespace panda::ecmascript::kungfu
510