• 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 #include "ecmascript/global_env.h"
18 
19 namespace panda::ecmascript::kungfu {
LowerTypedCallBuitin(GateRef gate)20 void BuiltinLowering::LowerTypedCallBuitin(GateRef gate)
21 {
22     Environment env(gate, circuit_, &builder_);
23     auto valuesIn = acc_.GetNumValueIn(gate);
24     ASSERT(valuesIn >= 1);
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(StringLocaleCompare):
29             LowerTypedLocaleCompare(gate);
30             break;
31         case BUILTINS_STUB_ID(ArraySort):
32             LowerTypedArraySort(gate);
33             break;
34         case BUILTINS_STUB_ID(JsonStringify):
35             LowerTypedStringify(gate);
36             break;
37         case BUILTINS_STUB_ID(MapProtoIterator):
38         case BUILTINS_STUB_ID(SetProtoIterator):
39         case BUILTINS_STUB_ID(StringProtoIterator):
40         case BUILTINS_STUB_ID(ArrayProtoIterator):
41         case BUILTINS_STUB_ID(TypeArrayProtoIterator):
42             LowerBuiltinIterator(gate, id);
43             break;
44         case BUILTINS_STUB_ID(MapIteratorProtoNext):
45         case BUILTINS_STUB_ID(SetIteratorProtoNext):
46         case BUILTINS_STUB_ID(StringIteratorProtoNext):
47         case BUILTINS_STUB_ID(ArrayIteratorProtoNext):
48             LowerIteratorNext(gate, id);
49             break;
50         case BUILTINS_STUB_ID(IteratorProtoReturn):
51             LowerIteratorReturn(gate, id);
52             break;
53         case BUILTINS_STUB_ID(NumberConstructor):
54             LowerNumberConstructor(gate);
55             break;
56         default:
57             break;
58     }
59 }
60 
LowerTypedFloor(GateRef gate)61 void BuiltinLowering::LowerTypedFloor(GateRef gate)
62 {
63     auto ret = TypedFloor(gate);
64     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
65 }
66 
TypedLocaleCompare(GateRef glue,GateRef gate,GateRef thisObj,GateRef thatObj)67 GateRef BuiltinLowering::TypedLocaleCompare(GateRef glue, GateRef gate, GateRef thisObj, GateRef thatObj)
68 {
69     auto env = builder_.GetCurrentEnvironment();
70     Label entry(&builder_);
71     env->SubCfgEntry(&entry);
72 
73     Label slowPath(&builder_);
74     Label fastPath(&builder_);
75     Label localeCompareGC(&builder_);
76     Label exit(&builder_);
77     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
78 
79     GateRef isString = builder_.BothAreString(thisObj, thatObj);
80     builder_.Branch(isString, &fastPath, &slowPath);
81     builder_.Bind(&fastPath);
82     {
83         result = builder_.CallRuntime(glue, RTSTUB_ID(LocaleCompareCacheable), Gate::InvalidGateRef,
84             { builder_.Undefined(), thisObj, thatObj }, gate);
85         GateRef status = builder_.TaggedIsUndefined(*result);
86         builder_.Branch(status, &localeCompareGC, &exit, BranchWeight::ONE_WEIGHT, BranchWeight::STRONG_WEIGHT,
87             "TypedLocaleCompare");
88         builder_.Bind(&localeCompareGC);
89         {
90             result = builder_.CallRuntime(glue, RTSTUB_ID(LocaleCompareWithGc), Gate::InvalidGateRef,
91                 { builder_.Undefined(), thisObj, thatObj, builder_.Undefined() }, gate);
92             builder_.Jump(&exit);
93         }
94     }
95     builder_.Bind(&slowPath);
96     {
97         result = LowerCallRuntime(glue, gate, RTSTUB_ID(LocaleCompare),
98             { thisObj, thatObj, builder_.Undefined(), builder_.Undefined()});
99         builder_.Jump(&exit);
100     }
101     builder_.Bind(&exit);
102     auto ret = *result;
103     env->SubCfgExit();
104     return ret;
105 }
106 
TypedFloor(GateRef gate)107 GateRef BuiltinLowering::TypedFloor(GateRef gate)
108 {
109     auto env = builder_.GetCurrentEnvironment();
110     Label entry(&builder_);
111     env->SubCfgEntry(&entry);
112 
113     Label numberBranch(&builder_);
114     Label notNumberBranch(&builder_);
115     Label exit(&builder_);
116 
117     GateRef para1 = acc_.GetValueIn(gate, 0);
118     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
119 
120     BRANCH_CIR(builder_.TaggedIsNumber(para1), &numberBranch, &notNumberBranch);
121     builder_.Bind(&numberBranch);
122     {
123         GateRef value = builder_.GetDoubleOfTNumber(para1);
124         Label IsNan(&builder_);
125         Label NotNan(&builder_);
126         GateRef condition = builder_.DoubleIsNAN(value);
127         BRANCH_CIR(condition, &IsNan, &NotNan);
128         builder_.Bind(&NotNan);
129         {
130             GateRef glue = acc_.GetGlueFromArgList();
131             int index = RTSTUB_ID(FloatFloor);
132             GateRef floor = builder_.CallNGCRuntime(glue, index, Gate::InvalidGateRef, {value}, gate);
133             result = builder_.DoubleToTaggedDoublePtr(floor);
134             builder_.Jump(&exit);
135         }
136         builder_.Bind(&IsNan);
137         {
138             result = builder_.DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
139             builder_.Jump(&exit);
140         }
141     }
142     builder_.Bind(&notNumberBranch);
143     {
144         builder_.Jump(&exit);
145     }
146 
147     builder_.Bind(&exit);
148     auto ret = *result;
149     env->SubCfgExit();
150     return ret;
151 }
152 
IntToTaggedIntPtr(GateRef x)153 GateRef BuiltinLowering::IntToTaggedIntPtr(GateRef x)
154 {
155     GateRef val = builder_.SExtInt32ToInt64(x);
156     return builder_.ToTaggedIntPtr(val);
157 }
158 
LowerCallRuntime(GateRef glue,GateRef gate,int index,const std::vector<GateRef> & args,bool useLabel)159 GateRef BuiltinLowering::LowerCallRuntime(GateRef glue, GateRef gate, int index, const std::vector<GateRef> &args,
160                                           bool useLabel)
161 {
162     const std::string name = RuntimeStubCSigns::GetRTName(index);
163     if (useLabel) {
164         GateRef result = builder_.CallRuntime(glue, index, Gate::InvalidGateRef, args, gate, name.c_str());
165         return result;
166     } else {
167         const CallSignature *cs = RuntimeStubCSigns::Get(RTSTUB_ID(CallRuntime));
168         GateRef target = builder_.IntPtr(index);
169         GateRef result = builder_.Call(cs, glue, target, builder_.GetDepend(), args, gate, name.c_str());
170         return result;
171     }
172 }
173 
ReplaceHirWithValue(GateRef hirGate,GateRef value,bool noThrow)174 void BuiltinLowering::ReplaceHirWithValue(GateRef hirGate, GateRef value, bool noThrow)
175 {
176     if (!noThrow) {
177         GateRef state = builder_.GetState();
178         // copy depend-wire of hirGate to value
179         GateRef depend = builder_.GetDepend();
180         // exception value
181         GateRef exceptionVal = builder_.ExceptionConstant();
182         // compare with trampolines result
183         GateRef equal = builder_.Equal(value, exceptionVal);
184         auto ifBranch = builder_.Branch(state, equal, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
185 
186         GateRef ifTrue = builder_.IfTrue(ifBranch);
187         GateRef ifFalse = builder_.IfFalse(ifBranch);
188         GateRef eDepend = builder_.DependRelay(ifTrue, depend);
189         GateRef sDepend = builder_.DependRelay(ifFalse, depend);
190         StateDepend success(ifFalse, sDepend);
191         StateDepend exception(ifTrue, eDepend);
192         acc_.ReplaceHirWithIfBranch(hirGate, success, exception, value);
193     } else {
194         acc_.ReplaceHirDirectly(hirGate, builder_.GetStateDepend(), value);
195     }
196 }
197 
LowerTypedLocaleCompare(GateRef gate)198 void BuiltinLowering::LowerTypedLocaleCompare(GateRef gate)
199 {
200     GateRef glue = acc_.GetGlueFromArgList();
201 
202     size_t index = 0;
203     GateRef thisObj = acc_.GetValueIn(gate, index++);
204     GateRef thatObj = acc_.GetValueIn(gate, index++);
205 
206     static constexpr size_t NUM_OF_ARGS = 4;
207     ASSERT(acc_.GetNumValueIn(gate) > 0);
208     size_t argsIn = acc_.GetNumValueIn(gate) - 1;
209     GateRef result = Circuit::NullGate();
210     if (argsIn == 2) { // 2: string.localeCompare(string)
211         // If the number of args is two, it must satisfy conditions for cache optimization.
212         // The cache of icu collator if locale is undefined
213         result = TypedLocaleCompare(glue, gate, thisObj, thatObj);
214     } else {
215         // willdo: Implement cache fastpath
216         std::vector<GateRef> args = { thisObj, thatObj };
217         ASSERT(argsIn <= NUM_OF_ARGS);
218         args.reserve(NUM_OF_ARGS);
219         while (index < argsIn) {
220             GateRef arg = acc_.GetValueIn(gate, index++);
221             args.emplace_back(arg);
222         }
223         while (index < NUM_OF_ARGS) {
224             args.emplace_back(builder_.Undefined());
225             index++;
226         }
227         result = LowerCallRuntime(glue, gate, RTSTUB_ID(LocaleCompare), args);
228     }
229     ReplaceHirWithValue(gate, result);
230 }
231 
LowerTypedArraySort(GateRef gate)232 void BuiltinLowering::LowerTypedArraySort(GateRef gate)
233 {
234     GateRef glue = acc_.GetGlueFromArgList();
235     GateRef thisObj = acc_.GetValueIn(gate, 0);
236     GateRef result = LowerCallRuntime(glue, gate, RTSTUB_ID(ArraySort), { thisObj });
237     ReplaceHirWithValue(gate, result);
238 }
239 
LowerCallTargetCheck(Environment * env,GateRef gate)240 GateRef BuiltinLowering::LowerCallTargetCheck(Environment *env, GateRef gate)
241 {
242     builder_.SetEnvironment(env);
243     GateRef idGate = acc_.GetValueIn(gate, 1);
244     BuiltinsStubCSigns::ID id = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(idGate));
245     switch (id) {
246         case BuiltinsStubCSigns::ID::MapProtoIterator:
247         case BuiltinsStubCSigns::ID::SetProtoIterator:
248         case BuiltinsStubCSigns::ID::StringProtoIterator:
249         case BuiltinsStubCSigns::ID::ArrayProtoIterator:
250         case BuiltinsStubCSigns::ID::TypeArrayProtoIterator: {
251             return LowerCallTargetCheckWithDetector(gate, id);
252         }
253         case BuiltinsStubCSigns::ID::DateGetTime:
254         case BuiltinsStubCSigns::ID::MapClear:
255         case BuiltinsStubCSigns::ID::MapDelete:
256         case BuiltinsStubCSigns::ID::MapGet:
257         case BuiltinsStubCSigns::ID::MapHas:
258         case BuiltinsStubCSigns::ID::SetAdd:
259         case BuiltinsStubCSigns::ID::SetClear:
260         case BuiltinsStubCSigns::ID::SetDelete:
261         case BuiltinsStubCSigns::ID::SetHas: {
262             return LowerCallTargetCheckWithObjectType(gate, id);
263         }
264         case BuiltinsStubCSigns::ID::BigIntConstructor:
265         case BuiltinsStubCSigns::ID::NumberConstructor: {
266             return LowerCallTargetCheckWithGlobalEnv(gate, id);
267         }
268         default: {
269             return LowerCallTargetCheckDefault(gate, id);
270         }
271     }
272 }
273 
LowerCallTargetCheckDefault(GateRef gate,BuiltinsStubCSigns::ID id)274 GateRef BuiltinLowering::LowerCallTargetCheckDefault(GateRef gate, BuiltinsStubCSigns::ID id)
275 {
276     GateRef constantFunction = builder_.GetGlobalConstantValue(GET_TYPED_CONSTANT_INDEX(id));
277     GateRef function = acc_.GetValueIn(gate, 0); // 0: function
278     return builder_.Equal(function, constantFunction);
279 }
280 
LowerCallTargetCheckWithGlobalEnv(GateRef gate,BuiltinsStubCSigns::ID id)281 GateRef BuiltinLowering::LowerCallTargetCheckWithGlobalEnv(GateRef gate, BuiltinsStubCSigns::ID id)
282 {
283     GateRef glueGlobalEnv = builder_.GetGlobalEnv();
284     GateRef globalFunction =
285         builder_.GetGlobalEnvObj(glueGlobalEnv, GET_TYPED_GLOBAL_ENV_INDEX(id));
286     GateRef target = acc_.GetValueIn(gate, 0); // 0:target
287     return builder_.Equal(target, globalFunction);
288 }
289 
LowerCallTargetCheckWithDetector(GateRef gate,BuiltinsStubCSigns::ID id)290 GateRef BuiltinLowering::LowerCallTargetCheckWithDetector(GateRef gate, BuiltinsStubCSigns::ID id)
291 {
292     JSType expectType = JSType::INVALID;
293     uint16_t detectorIndex = 0;
294     switch (id) {
295         case BuiltinsStubCSigns::ID::MapProtoIterator: {
296             expectType = JSType::JS_MAP;
297             detectorIndex = GlobalEnv::MAP_ITERATOR_DETECTOR_INDEX;
298             break;
299         }
300         case BuiltinsStubCSigns::ID::SetProtoIterator: {
301             expectType = JSType::JS_SET;
302             detectorIndex = GlobalEnv::SET_ITERATOR_DETECTOR_INDEX;
303             break;
304         }
305         case BuiltinsStubCSigns::ID::StringProtoIterator: {
306             expectType = JSType::STRING_FIRST;
307             detectorIndex = GlobalEnv::STRING_ITERATOR_DETECTOR_INDEX;
308             break;
309         }
310         case BuiltinsStubCSigns::ID::ArrayProtoIterator: {
311             expectType = JSType::JS_ARRAY;
312             detectorIndex = GlobalEnv::ARRAY_ITERATOR_DETECTOR_INDEX;
313             break;
314         }
315         case BuiltinsStubCSigns::ID::TypeArrayProtoIterator: {
316             expectType = JSType::JS_TYPED_ARRAY_FIRST;
317             detectorIndex = GlobalEnv::TYPED_ARRAY_ITERATOR_DETECTOR_INDEX;
318             break;
319         }
320         default: {
321             LOG_COMPILER(FATAL) << "this branch is unreachable";
322             UNREACHABLE();
323         }
324     }
325     GateRef obj = acc_.GetValueIn(gate, 2);  // 2: iterator obj
326     return LogicAndBuilder(builder_.GetCurrentEnvironment())
327         .And(builder_.TaggedIsHeapObjectOp(obj))
328         .And(builder_.IsSpecificObjectType(obj, expectType))
329         .And(builder_.IsMarkerCellValid(builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), detectorIndex)))
330         .Done();
331 }
332 
LowerCallTargetCheckWithObjectType(GateRef gate,BuiltinsStubCSigns::ID id)333 GateRef BuiltinLowering::LowerCallTargetCheckWithObjectType(GateRef gate, BuiltinsStubCSigns::ID id)
334 {
335     JSType expectType = JSType::INVALID;
336     switch (id) {
337         case BuiltinsStubCSigns::ID::MapClear:
338         case BuiltinsStubCSigns::ID::MapDelete:
339         case BuiltinsStubCSigns::ID::MapGet:
340         case BuiltinsStubCSigns::ID::MapHas: {
341             expectType = JSType::JS_MAP;
342             break;
343         }
344         case BuiltinsStubCSigns::ID::SetAdd:
345         case BuiltinsStubCSigns::ID::SetClear:
346         case BuiltinsStubCSigns::ID::SetDelete:
347         case BuiltinsStubCSigns::ID::SetHas: {
348             expectType = JSType::JS_SET;
349             break;
350         }
351         case BuiltinsStubCSigns::ID::DateGetTime: {
352             expectType = JSType::JS_DATE;
353             break;
354         }
355         default: {
356             LOG_COMPILER(FATAL) << "this branch is unreachable";
357             UNREACHABLE();
358         }
359     }
360     GateRef obj = acc_.GetValueIn(gate, 2);  // 2: receiver obj
361     return LogicAndBuilder(builder_.GetCurrentEnvironment())
362         .And(builder_.TaggedIsHeapObjectOp(obj))
363         .And(builder_.IsSpecificObjectType(obj, expectType))
364         .And(LowerCallTargetCheckDefault(gate, id))
365         .Done();
366 }
367 
CheckPara(GateRef gate,GateRef funcCheck)368 GateRef BuiltinLowering::CheckPara(GateRef gate, GateRef funcCheck)
369 {
370     GateRef idGate = acc_.GetValueIn(gate, 1);
371     BuiltinsStubCSigns::ID id = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(idGate));
372     if (IS_TYPED_INLINE_BUILTINS_ID(id)) {
373         // Don't need check param. Param was checked before
374         return funcCheck;
375     }
376     switch (id) {
377         case BuiltinsStubCSigns::ID::StringLocaleCompare:
378         case BuiltinsStubCSigns::ID::ArraySort:
379         case BuiltinsStubCSigns::ID::JsonStringify:
380         case BuiltinsStubCSigns::ID::MapProtoIterator:
381         case BuiltinsStubCSigns::ID::SetProtoIterator:
382         case BuiltinsStubCSigns::ID::StringProtoIterator:
383         case BuiltinsStubCSigns::ID::ArrayProtoIterator:
384         case BuiltinsStubCSigns::ID::TypeArrayProtoIterator:
385         case BuiltinsStubCSigns::ID::MapIteratorProtoNext:
386         case BuiltinsStubCSigns::ID::SetIteratorProtoNext:
387         case BuiltinsStubCSigns::ID::StringIteratorProtoNext:
388         case BuiltinsStubCSigns::ID::ArrayIteratorProtoNext:
389         case BuiltinsStubCSigns::ID::IteratorProtoReturn:
390         case BuiltinsStubCSigns::ID::NumberConstructor:
391         case BuiltinsStubCSigns::ID::TypedArrayEntries:
392         case BuiltinsStubCSigns::ID::TypedArrayKeys:
393         case BuiltinsStubCSigns::ID::TypedArrayValues:
394             // Don't need check para
395             return funcCheck;
396         default: {
397             LOG_COMPILER(FATAL) << "this branch is unreachable";
398             UNREACHABLE();
399         }
400     }
401 }
402 
LowerTypedStringify(GateRef gate)403 void BuiltinLowering::LowerTypedStringify(GateRef gate)
404 {
405     GateRef glue = acc_.GetGlueFromArgList();
406     GateRef value = acc_.GetValueIn(gate, 1);
407     std::vector<GateRef> args;
408     args.emplace_back(value);
409     GateRef result = LowerCallRuntime(glue, gate, RTSTUB_ID(FastStringify), args);
410     ReplaceHirWithValue(gate, result);
411 }
412 
LowerBuiltinIterator(GateRef gate,BuiltinsStubCSigns::ID id)413 void BuiltinLowering::LowerBuiltinIterator(GateRef gate, BuiltinsStubCSigns::ID id)
414 {
415     GateRef glue = acc_.GetGlueFromArgList();
416     GateRef obj = acc_.GetValueIn(gate, 0);
417     GateRef result = Circuit::NullGate();
418     switch (id) {
419         case BUILTINS_STUB_ID(MapProtoIterator): {
420             result = builder_.CallStub(glue, gate, CommonStubCSigns::CreateJSMapIterator, { glue, obj });
421             break;
422         }
423         case BUILTINS_STUB_ID(SetProtoIterator): {
424             result = builder_.CallStub(glue, gate, CommonStubCSigns::CreateJSSetIterator, { glue, obj });
425             break;
426         }
427         case BUILTINS_STUB_ID(StringProtoIterator): {
428             result = LowerCallRuntime(glue, gate, RTSTUB_ID(CreateStringIterator), { obj }, true);
429             break;
430         }
431         case BUILTINS_STUB_ID(ArrayProtoIterator): {
432             result = LowerCallRuntime(glue, gate, RTSTUB_ID(NewJSArrayIterator), { obj }, true);
433             break;
434         }
435         case BUILTINS_STUB_ID(TypeArrayProtoIterator): {
436             result = LowerCallRuntime(glue, gate, RTSTUB_ID(NewJSTypedArrayIterator), { obj }, true);
437             break;
438         }
439         default:
440             UNREACHABLE();
441     }
442     ReplaceHirWithValue(gate, result);
443 }
444 
LowerIteratorNext(GateRef gate,BuiltinsStubCSigns::ID id)445 void BuiltinLowering::LowerIteratorNext(GateRef gate, BuiltinsStubCSigns::ID id)
446 {
447     GateRef glue = acc_.GetGlueFromArgList();
448     GateRef thisObj = acc_.GetValueIn(gate, 0);
449     GateRef result = Circuit::NullGate();
450     switch (id) {
451         case BUILTINS_STUB_ID(MapIteratorProtoNext): {
452             result = LowerCallRuntime(glue, gate, RTSTUB_ID(MapIteratorNext), { thisObj }, true);
453             break;
454         }
455         case BUILTINS_STUB_ID(SetIteratorProtoNext): {
456             result = LowerCallRuntime(glue, gate, RTSTUB_ID(SetIteratorNext), { thisObj }, true);
457             break;
458         }
459         case BUILTINS_STUB_ID(StringIteratorProtoNext): {
460             result = builder_.CallStub(glue, gate, CommonStubCSigns::StringIteratorNext, { glue, thisObj });
461             break;
462         }
463         case BUILTINS_STUB_ID(ArrayIteratorProtoNext): {
464             result = LowerCallRuntime(glue, gate, RTSTUB_ID(ArrayIteratorNext), { thisObj }, true);
465             break;
466         }
467         default:
468             UNREACHABLE();
469     }
470     ReplaceHirWithValue(gate, result);
471 }
472 
LowerIteratorReturn(GateRef gate,BuiltinsStubCSigns::ID id)473 void BuiltinLowering::LowerIteratorReturn(GateRef gate, BuiltinsStubCSigns::ID id)
474 {
475     GateRef glue = acc_.GetGlueFromArgList();
476     GateRef thisObj = acc_.GetValueIn(gate, 0);
477     GateRef result = Circuit::NullGate();
478     switch (id) {
479         case BUILTINS_STUB_ID(IteratorProtoReturn): {
480             result = LowerCallRuntime(glue, gate, RTSTUB_ID(IteratorReturn), { thisObj }, true);
481             break;
482         }
483         default:
484             UNREACHABLE();
485     }
486     ReplaceHirWithValue(gate, result);
487 }
488 
LowerNumberConstructor(GateRef gate)489 void BuiltinLowering::LowerNumberConstructor(GateRef gate)
490 {
491     auto env = builder_.GetCurrentEnvironment();
492 
493     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), IntToTaggedIntPtr(builder_.Int32(0)));
494     GateRef param = acc_.GetValueIn(gate, 0);
495     Label exit(env);
496     Label isNumber(env);
497     Label notNumber(env);
498     BRANCH_CIR(builder_.TaggedIsNumber(param), &isNumber, &notNumber);
499     builder_.Bind(&isNumber);
500     {
501         result = param;
502         builder_.Jump(&exit);
503     }
504     builder_.Bind(&notNumber);
505     {
506         Label isString(env);
507         Label notString(env);
508         BRANCH_CIR(builder_.TaggedIsString(param), &isString, &notString);
509         builder_.Bind(&isString);
510         {
511             Label nonZeroLength(env);
512             auto length = builder_.GetLengthFromString(param);
513             BRANCH_CIR(builder_.Equal(length, builder_.Int32(0)), &exit, &nonZeroLength);
514             builder_.Bind(&nonZeroLength);
515             Label isInteger(env);
516             BRANCH_CIR(builder_.IsIntegerString(param), &isInteger, &notString);
517             builder_.Bind(&isInteger);
518             {
519                 result = IntToTaggedIntPtr(builder_.GetRawHashFromString(param));
520                 builder_.Jump(&exit);
521             }
522         }
523         builder_.Bind(&notString);
524         {
525             GateRef glue = acc_.GetGlueFromArgList();
526             result = LowerCallRuntime(glue, gate, RTSTUB_ID(ToNumericConvertBigInt), { param }, true);
527             builder_.Jump(&exit);
528         }
529     }
530     builder_.Bind(&exit);
531     ReplaceHirWithValue(gate, *result);
532 }
533 }  // namespace panda::ecmascript::kungfu
534