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