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, ¬NumberBranch);
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(¬NumberBranch);
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, ¬Number);
503 builder_.Bind(&isNumber);
504 {
505 result = param;
506 builder_.Jump(&exit);
507 }
508 builder_.Bind(¬Number);
509 {
510 Label isString(env);
511 Label notString(env);
512 BRANCH_CIR(builder_.TaggedIsString(param), &isString, ¬String);
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, ¬String);
521 builder_.Bind(&isInteger);
522 {
523 result = IntToTaggedIntPtr(builder_.GetRawHashFromString(param));
524 builder_.Jump(&exit);
525 }
526 }
527 builder_.Bind(¬String);
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