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, ¬NumberBranch);
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(¬NumberBranch);
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, ¬Int);
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(¬Int);
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, ¬Number);
475 builder_.Bind(&isNumber);
476 {
477 result = param;
478 builder_.Jump(&exit);
479 }
480 builder_.Bind(¬Number);
481 {
482 Label isString(env);
483 Label notString(env);
484 builder_.Branch(builder_.TaggedIsString(param), &isString, ¬String);
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, ¬String);
493 builder_.Bind(&isInteger);
494 {
495 result = IntToTaggedIntPtr(builder_.GetRawHashFromString(param));
496 builder_.Jump(&exit);
497 }
498 }
499 builder_.Bind(¬String);
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