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