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, ¬NumberBranch);
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(¬NumberBranch);
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, ¬Number);
499 builder_.Bind(&isNumber);
500 {
501 result = param;
502 builder_.Jump(&exit);
503 }
504 builder_.Bind(¬Number);
505 {
506 Label isString(env);
507 Label notString(env);
508 BRANCH_CIR(builder_.TaggedIsString(param), &isString, ¬String);
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, ¬String);
517 builder_.Bind(&isInteger);
518 {
519 result = IntToTaggedIntPtr(builder_.GetRawHashFromString(param));
520 builder_.Jump(&exit);
521 }
522 }
523 builder_.Bind(¬String);
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