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, ¬NumberBranch);
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(¬NumberBranch);
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, ¬Number);
493 builder_.Bind(&isNumber);
494 {
495 result = param;
496 builder_.Jump(&exit);
497 }
498 builder_.Bind(¬Number);
499 {
500 Label isString(env);
501 Label notString(env);
502 BRANCH_CIR(builder_.TaggedIsString(param), &isString, ¬String);
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, ¬String);
511 builder_.Bind(&isInteger);
512 {
513 result = IntToTaggedIntPtr(builder_.GetRawHashFromString(param));
514 builder_.Jump(&exit);
515 }
516 }
517 builder_.Bind(¬String);
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