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, ¬NumberBranch);
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(¬NumberBranch);
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, ¬Number);
490 builder_.Bind(&isNumber);
491 {
492 result = param;
493 builder_.Jump(&exit);
494 }
495 builder_.Bind(¬Number);
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, ¬LineUtf8String);
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, ¬LineUtf8String);
512 builder_.Bind(&isInteger);
513 {
514 result = IntToTaggedIntPtr(res);
515 builder_.Jump(&exit);
516 }
517 }
518 builder_.Bind(¬LineUtf8String);
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