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