• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #include "ecmascript/compiler/typed_native_inline_lowering.h"
16 #include "ecmascript/compiler/builtins/builtins_array_stub_builder.h"
17 #include "ecmascript/compiler/builtins/builtins_object_stub_builder.h"
18 #include "ecmascript/compiler/circuit_arg_indices.h"
19 #include "ecmascript/compiler/new_object_stub_builder.h"
20 #include "ecmascript/compiler/type_info_accessors.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/interpreter/interpreter-inl.h"
23 #include "ecmascript/jit/jit.h"
24 #include "ecmascript/js_array_iterator.h"
25 #include "ecmascript/js_date.h"
26 #include "ecmascript/js_primitive_ref.h"
27 
28 namespace panda::ecmascript::kungfu {
VisitGate(GateRef gate)29 GateRef TypedNativeInlineLowering::VisitGate(GateRef gate)
30 {
31     auto op = acc_.GetOpCode(gate);
32     switch (op) {
33         case OpCode::MATH_COS:
34             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatCos));
35             break;
36         case OpCode::MATH_COSH:
37             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatCosh));
38             break;
39         case OpCode::MATH_SIN:
40             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatSin));
41             break;
42         case OpCode::MATH_LOG:
43             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatLog));
44             break;
45         case OpCode::MATH_LOG2:
46             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatLog2));
47             break;
48         case OpCode::MATH_LOG10:
49             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatLog10));
50             break;
51         case OpCode::MATH_LOG1P:
52             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatLog1p));
53             break;
54         case OpCode::MATH_EXP:
55             LowerMathExp(gate);
56             break;
57         case OpCode::MATH_EXPM1:
58             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatExpm1));
59             break;
60         case OpCode::MATH_SINH:
61             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatSinh));
62             break;
63         case OpCode::MATH_ASINH:
64             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAsinh));
65             break;
66         case OpCode::MATH_TAN:
67             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatTan));
68             break;
69         case OpCode::MATH_ATAN:
70             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAtan));
71             break;
72         case OpCode::MATH_TANH:
73             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatTanh));
74             break;
75         case OpCode::MATH_ACOS:
76             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAcos));
77             break;
78         case OpCode::MATH_ASIN:
79             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAsin));
80             break;
81         case OpCode::MATH_ATANH:
82             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAtanh));
83             break;
84         case OpCode::MATH_ACOSH:
85             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAcosh));
86             break;
87         case OpCode::MATH_ATAN2:
88             LowerMathAtan2(gate);
89             break;
90         case OpCode::MATH_ABS:
91             LowerAbs(gate);
92             break;
93         case OpCode::MATH_ABS_INT32:
94             LowerIntAbs(gate);
95             break;
96         case OpCode::MATH_ABS_DOUBLE:
97             LowerDoubleAbs(gate);
98             break;
99         case OpCode::MATH_TRUNC:
100             LowerTrunc(gate);
101             break;
102         case OpCode::MATH_POW:
103             LowerMathPow(gate);
104             break;
105         case OpCode::MATH_CBRT:
106             LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatCbrt));
107             break;
108         case OpCode::MATH_SIGN:
109             LowerMathSignInt(gate);
110             break;
111         case OpCode::MATH_SIGN_TAGGED:
112             LowerMathSignTagged(gate);
113             break;
114         case OpCode::MATH_MIN:
115             LowerMinMax<false>(gate);
116             break;
117         case OpCode::MATH_MAX:
118             LowerMinMax<true>(gate);
119             break;
120         case OpCode::MATH_MIN_INT32:
121             LowerIntMinMax<false>(gate);
122             break;
123         case OpCode::MATH_MAX_INT32:
124             LowerIntMinMax<true>(gate);
125             break;
126         case OpCode::MATH_MIN_DOUBLE:
127             LowerDoubleMinMax<false>(gate);
128             break;
129         case OpCode::MATH_MAX_DOUBLE:
130             LowerDoubleMinMax<true>(gate);
131             break;
132         case OpCode::MATH_CLZ32_DOUBLE:
133             LowerClz32Float64(gate);
134             break;
135         case OpCode::MATH_CLZ32_INT32:
136             LowerClz32Int32(gate);
137             break;
138         case OpCode::MATH_SQRT:
139             LowerMathSqrt(gate);
140             break;
141         case OpCode::MATH_ROUND:
142             LowerTaggedRounding(gate);
143             break;
144         case OpCode::MATH_ROUND_DOUBLE:
145         case OpCode::MATH_FROUND:
146             LowerDoubleRounding(gate);
147             break;
148         case OpCode::MATH_CEIL:
149             LowerMathCeilFloor<true>(gate);
150             break;
151         case OpCode::MATH_FLOOR:
152             LowerMathCeilFloor<false>(gate);
153             break;
154         case OpCode::MATH_IMUL:
155             LowerMathImul(gate);
156             break;
157         case OpCode::NEW_NUMBER:
158             LowerNewNumber(gate);
159             break;
160         case OpCode::GLOBAL_IS_FINITE:
161             LowerGlobalIsFinite(gate);
162             break;
163         case OpCode::GLOBAL_IS_NAN:
164             LowerGlobalIsNan(gate);
165             break;
166         case OpCode::DATA_VIEW_GET:
167             LowerDataViewProtoFunc(gate, DataViewProtoFunc::GET);
168             break;
169         case OpCode::DATA_VIEW_SET:
170             LowerDataViewProtoFunc(gate, DataViewProtoFunc::SET);
171             break;
172         case OpCode::ARRAY_BUFFER_IS_VIEW:
173             LowerArrayBufferIsView(gate);
174             break;
175         case OpCode::BIGINT_ASINTN:
176             LowerBigIntAsIntN<false>(gate);
177             break;
178         case OpCode::BIGINT_ASUINTN:
179             LowerBigIntAsIntN<true>(gate);
180             break;
181         case OpCode::NUMBER_IS_FINITE:
182             LowerNumberIsFinite(gate);
183             break;
184         case OpCode::NUMBER_IS_INTEGER:
185         case OpCode::NUMBER_IS_SAFEINTEGER:
186             LowerNumberIsInteger(gate, op);
187             break;
188         case OpCode::NUMBER_IS_NAN:
189             LowerNumberIsNaN(gate);
190             break;
191         case OpCode::NUMBER_PARSE_FLOAT:
192             LowerNumberParseFloat(gate);
193             break;
194         case OpCode::NUMBER_PARSE_INT:
195             LowerNumberParseInt(gate);
196             break;
197         case OpCode::MAP_GET:
198             LowerToCommonStub(gate, CommonStubCSigns::JSMapGet);
199             break;
200         case OpCode::DATE_GET_TIME:
201             LowerDateGetTime(gate);
202             break;
203         case OpCode::MAP_HAS:
204             LowerToCommonStub(gate, CommonStubCSigns::JSMapHas);
205             break;
206         case OpCode::MAP_KEYS:
207             LowerToCommonStub(gate, CommonStubCSigns::JSMapKeys);
208             break;
209         case OpCode::MAP_VALUES:
210             LowerToCommonStub(gate, CommonStubCSigns::JSMapValues);
211             break;
212         case OpCode::MAP_ENTRIES:
213             LowerToCommonStub(gate, CommonStubCSigns::CreateJSMapIterator);
214             break;
215         case OpCode::SET_HAS:
216             LowerToCommonStub(gate, CommonStubCSigns::JSSetHas);
217             break;
218         case OpCode::SET_ADD:
219             LowerToCommonStub(gate, CommonStubCSigns::JSSetAdd);
220             break;
221         case OpCode::DATE_NOW:
222             LowerGeneralWithoutArgs(gate, RTSTUB_ID(CallDateNow));
223             break;
224         case OpCode::TYPED_ARRAY_ENTRIES:
225             LowerTypedArrayIterator(gate, CommonStubCSigns::CreateJSTypedArrayEntries,
226                                     IterationKind::KEY_AND_VALUE);
227             break;
228         case OpCode::TYPED_ARRAY_KEYS:
229             LowerTypedArrayIterator(gate, CommonStubCSigns::CreateJSTypedArrayKeys,
230                                     IterationKind::KEY);
231             break;
232         case OpCode::TYPED_ARRAY_VALUES:
233             LowerTypedArrayIterator(gate, CommonStubCSigns::CreateJSTypedArrayValues,
234                                     IterationKind::VALUE);
235             break;
236         case OpCode::MAP_DELETE:
237             LowerToCommonStub(gate, CommonStubCSigns::JSMapDelete);
238             break;
239         case OpCode::SET_DELETE:
240             LowerToCommonStub(gate, CommonStubCSigns::JSSetDelete);
241             break;
242         case OpCode::SET_VALUES:
243             LowerToCommonStub(gate, CommonStubCSigns::CreateJSSetIterator);
244             break;
245         case OpCode::SET_ENTRIES:
246             LowerToCommonStub(gate, CommonStubCSigns::JSSetEntries);
247             break;
248         case OpCode::BIGINT_CONSTRUCTOR:
249             LowerBigIntConstructor(gate);
250             break;
251         case OpCode::BIGINT_CONSTRUCTOR_INT32:
252             LowerBigIntConstructorInt32<true>(gate);
253             break;
254         case OpCode::BIGINT_CONSTRUCTOR_UINT32:
255             LowerBigIntConstructorInt32<false>(gate);
256             break;
257         case OpCode::STRING_CHAR_CODE_AT:
258             LowerStringCharCodeAt(gate);
259             break;
260         case OpCode::STRING_SUB_STRING:
261             LowerStringSubstring(gate);
262             break;
263         case OpCode::STRING_SUB_STR:
264             LowerStringSubStr(gate);
265             break;
266         case OpCode::STRING_SLICE:
267             LowerStringSlice(gate);
268             break;
269         case OpCode::OBJECT_IS:
270             LowerObjectIs(gate);
271             break;
272         case OpCode::OBJECT_GET_PROTOTYPE_OF:
273             LowerObjectGetPrototypeOf(gate);
274             break;
275         case OpCode::OBJECT_CREATE:
276             LowerObjectCreate(gate);
277             break;
278         case OpCode::OBJECT_IS_PROTOTYPE_OF:
279             LowerObjectIsPrototypeOf(gate);
280             break;
281         case OpCode::OBJECT_HAS_OWN_PROPERTY:
282             LowerObjectHasOwnProperty(gate);
283             break;
284         case OpCode::REFLECT_GET_PROTOTYPE_OF:
285             LowerReflectGetPrototypeOf(gate);
286             break;
287         case OpCode::REFLECT_GET:
288             LowerReflectGet(gate);
289             break;
290         case OpCode::REFLECT_HAS:
291             LowerReflectHas(gate);
292             break;
293         case OpCode::REFLECT_CONSTRUCT:
294             LowerReflectConstruct(gate);
295             break;
296         case OpCode::REFLECT_APPLY:
297             LowerReflectApply(gate);
298             break;
299         case OpCode::FUNCTION_PROTOTYPE_APPLY:
300             LowerFunctionPrototypeApply(gate);
301             break;
302         case OpCode::FUNCTION_PROTOTYPE_BIND:
303             LowerFunctionPrototypeBind(gate);
304             break;
305         case OpCode::FUNCTION_PROTOTYPE_CALL:
306             LowerFunctionPrototypeCall(gate);
307             break;
308         case OpCode::ARRAY_INCLUDES_INDEXOF:
309             LowerArrayIncludesIndexOf(gate);
310             break;
311         case OpCode::ARRAY_ITERATOR_BUILTIN:
312             LowerArrayIteratorBuiltin(gate);
313             break;
314         case OpCode::ARRAY_FOR_EACH:
315             LowerArrayForEach(gate);
316             break;
317         case OpCode::ARRAY_FIND_OR_FINDINDEX:
318             LowerArrayFindOrFindIndex(gate);
319             break;
320         case OpCode::ARRAY_FILTER:
321             LowerArrayFilter(gate);
322             break;
323         case OpCode::ARRAY_MAP:
324             LowerArrayMap(gate);
325             break;
326         case OpCode::ARRAY_SOME:
327             LowerArraySome(gate);
328             break;
329         case OpCode::ARRAY_EVERY:
330             LowerArrayEvery(gate);
331             break;
332         case OpCode::ARRAY_POP:
333             LowerArrayPop(gate);
334             break;
335         case OpCode::ARRAY_PUSH:
336             LowerArrayPush(gate);
337             break;
338         case OpCode::ARRAY_SLICE:
339             LowerArraySlice(gate);
340             break;
341         case OpCode::ARRAY_SORT:
342             LowerArraySort(gate);
343             break;
344         default:
345             break;
346     }
347     return Circuit::NullGate();
348 }
349 
350 template <bool IS_CEIL>
LowerMathCeilFloor(GateRef gate)351 void TypedNativeInlineLowering::LowerMathCeilFloor(GateRef gate)
352 {
353     if (builder_.GetCompilationConfig()->IsAArch64()) {
354         LowerMathCeilFloorWithIntrinsic<IS_CEIL>(gate);
355     } else {
356         LowerMathCeilFloorWithRuntimeCall<IS_CEIL>(gate);
357     }
358 }
359 
360 template <bool IS_CEIL>
LowerMathCeilFloorWithIntrinsic(GateRef gate)361 void TypedNativeInlineLowering::LowerMathCeilFloorWithIntrinsic(GateRef gate)
362 {
363     Environment env(gate, circuit_, &builder_);
364     DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.NanValue());
365     GateRef arg = acc_.GetValueIn(gate, 0);
366 
367     if constexpr (IS_CEIL) {
368         result = builder_.DoubleCeil(arg);
369     } else {
370         result = builder_.DoubleFloor(arg);
371     }
372     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
373 }
374 
375 template <bool IS_CEIL>
LowerMathCeilFloorWithRuntimeCall(GateRef gate)376 void TypedNativeInlineLowering::LowerMathCeilFloorWithRuntimeCall(GateRef gate)
377 {
378     Environment env(gate, circuit_, &builder_);
379     DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.NanValue());
380     GateRef arg = acc_.GetValueIn(gate, 0);
381     GateRef glue = glue_;
382 
383     if constexpr (IS_CEIL) {
384         result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatCeil), Gate::InvalidGateRef, {arg}, gate);
385     } else {
386         result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatFloor), Gate::InvalidGateRef, {arg}, gate);
387     }
388     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
389 }
390 
AllocateArrayIterator(GateRef glue,GateRef self,GateRef iteratorHClass,IterationKind iterationKind)391 GateRef TypedNativeInlineLowering::AllocateArrayIterator(GateRef glue,
392                                                          GateRef self,
393                                                          GateRef iteratorHClass,
394                                                          IterationKind iterationKind)
395 {
396     GateRef emptyArray = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
397     GateRef kind = builder_.Int32(static_cast<int32_t>(iterationKind));
398 
399     builder_.StartAllocate();
400 
401     GateRef iterator = builder_.HeapAlloc(glue, builder_.IntPtr(JSArrayIterator::SIZE),
402         GateType::TaggedValue(), RegionSpaceFlag::IN_YOUNG_SPACE);
403 
404     builder_.StoreHClass(glue, iterator, iteratorHClass, MemoryAttribute::NeedBarrierAndAtomic());
405     builder_.StoreConstOffset(VariableType::INT64(), iterator, JSObject::HASH_OFFSET,
406         builder_.Int64(JSTaggedValue(0).GetRawData()));
407     builder_.StoreConstOffset(VariableType::INT64(), iterator, JSObject::PROPERTIES_OFFSET, emptyArray);
408     builder_.StoreConstOffset(VariableType::INT64(), iterator, JSObject::ELEMENTS_OFFSET, emptyArray);
409 
410     builder_.StoreConstOffset(VariableType::JS_ANY(), iterator, JSArrayIterator::ITERATED_ARRAY_OFFSET, self);
411     builder_.StoreConstOffset(VariableType::INT32(), iterator, JSArrayIterator::NEXT_INDEX_OFFSET, builder_.Int32(0));
412     builder_.StoreConstOffset(VariableType::INT32(), iterator, JSArrayIterator::BIT_FIELD_OFFSET, kind);
413 
414     GateRef result = builder_.FinishAllocate(iterator);
415     builder_.SubCfgExit();
416 
417     return result;
418 }
419 
LowerTypedArrayIterator(GateRef gate,CommonStubCSigns::ID index,IterationKind iterationKind)420 void TypedNativeInlineLowering::LowerTypedArrayIterator(GateRef gate, CommonStubCSigns::ID index,
421                                                         IterationKind iterationKind)
422 {
423     Environment env(gate, circuit_, &builder_);
424 
425     GateRef glue = glue_;
426     GateRef self = acc_.GetValueIn(gate, 0);
427 
428     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
429 
430     Label selfExistsLabel(&env);
431     Label isHeapObjectLabel(&env);
432     Label isTypedArrayLabel(&env);
433     Label selfValidLabel(&env);
434     Label selfInvalidLabel(&env);
435     Label exit(&env);
436 
437     GateRef selfExists = builder_.TaggedIsNotUndefinedAndNullAndHole(self);
438     BRANCH_CIR(selfExists, &selfExistsLabel, &selfInvalidLabel);
439     builder_.Bind(&selfExistsLabel);
440 
441     GateRef isHeapObject = builder_.TaggedIsHeapObject(self, compilationEnv_);
442     BRANCH_CIR(isHeapObject, &isHeapObjectLabel, &selfInvalidLabel);
443     builder_.Bind(&isHeapObjectLabel);
444 
445     GateRef isTypedArray = builder_.IsTypedArray(glue, self);
446     BRANCH_CIR(isTypedArray, &isTypedArrayLabel, &selfInvalidLabel);
447     builder_.Bind(&isTypedArrayLabel);
448 
449     GateRef hasNoConstructor = builder_.BoolNot(builder_.HasConstructor(glue, self));
450     BRANCH_CIR(hasNoConstructor, &selfValidLabel, &selfInvalidLabel);
451     builder_.Bind(&selfValidLabel);
452     {
453         GateRef globalEnv = circuit_->GetGlobalEnvCache();
454         GateRef prototype = builder_.GetGlobalEnvValue(VariableType::JS_POINTER(), glue, globalEnv,
455                                                        GlobalEnv::ARRAY_ITERATOR_PROTOTYPE_INDEX);
456 
457         GateRef iteratorHClass = builder_.GetGlobalConstantValue(ConstantIndex::JS_ARRAY_ITERATOR_CLASS_INDEX);
458         GateRef offset = builder_.IntPtr(JSHClass::PROTOTYPE_OFFSET);
459         builder_.Store(VariableType::JS_POINTER(), glue, iteratorHClass, offset, prototype);
460 
461         result = AllocateArrayIterator(glue, self, iteratorHClass, iterationKind);
462         builder_.Jump(&exit);
463     }
464 
465     builder_.Bind(&selfInvalidLabel);
466     {
467         result = builder_.CallStub(glue, gate, index, { glue, self });
468         builder_.Jump(&exit);
469     }
470     builder_.Bind(&exit);
471     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
472 }
473 
LowerGlobalDoubleIsFinite(GateRef value)474 GateRef TypedNativeInlineLowering::LowerGlobalDoubleIsFinite(GateRef value)
475 {
476     // set the sign bit to 0 by shift left then right.
477     auto temp = builder_.Int64LSL(builder_.CastDoubleToInt64(value), builder_.Int64(1));
478     auto res = builder_.Int64LSR(temp, builder_.Int64(1));
479     auto abs = builder_.CastInt64ToFloat64(res);
480     auto result = builder_.DoubleLessThan(abs, builder_.Double(base::POSITIVE_INFINITY));
481     return result;
482 }
483 
LowerGlobalTNumberIsFinite(GateRef value)484 GateRef TypedNativeInlineLowering::LowerGlobalTNumberIsFinite(GateRef value)
485 {
486     ASSERT(!acc_.GetGateType(value).IsNJSValueType());
487     DEFVALUE(result, (&builder_), VariableType::BOOL(), builder_.Boolean(true));
488 
489     Label isInt(&builder_);
490     Label notInt(&builder_);
491     Label exit(&builder_);
492     builder_.Branch(builder_.TaggedIsInt(value), &isInt, &notInt);
493     builder_.Bind(&isInt);
494     {
495         result = builder_.Boolean(true);
496         builder_.Jump(&exit);
497     }
498     builder_.Bind(&notInt);
499     {
500         result = LowerGlobalDoubleIsFinite(value);
501         builder_.Jump(&exit);
502     }
503     builder_.Bind(&exit);
504     return *result;
505 }
506 
LowerGlobalIsFinite(GateRef gate)507 void TypedNativeInlineLowering::LowerGlobalIsFinite(GateRef gate)
508 {
509     GateRef value = acc_.GetValueIn(gate, 0);
510     Environment env(gate, circuit_, &builder_);
511     GateRef result = LowerGlobalDoubleIsFinite(value);
512 
513     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
514 }
515 
LowerGlobalTNumberIsNan(GateRef value)516 GateRef TypedNativeInlineLowering::LowerGlobalTNumberIsNan(GateRef value)
517 {
518     ASSERT(!acc_.GetGateType(value).IsNJSValueType());
519     DEFVALUE(result, (&builder_), VariableType::BOOL(), builder_.Boolean(false));
520 
521     Label isInt(&builder_);
522     Label notInt(&builder_);
523     Label exit(&builder_);
524     builder_.Branch(builder_.TaggedIsInt(value), &isInt, &notInt);
525     builder_.Bind(&isInt);
526     {
527         result = builder_.Boolean(false);
528         builder_.Jump(&exit);
529     }
530     builder_.Bind(&notInt);
531     {
532         result = builder_.DoubleIsNAN(value);
533         builder_.Jump(&exit);
534     }
535     builder_.Bind(&exit);
536     return *result;
537 }
538 
LowerGlobalIsNan(GateRef gate)539 void TypedNativeInlineLowering::LowerGlobalIsNan(GateRef gate)
540 {
541     GateRef value = acc_.GetValueIn(gate, 0);
542     Environment env(gate, circuit_, &builder_);
543     GateRef result = builder_.DoubleIsNAN(value);
544 
545     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
546 }
547 
LowerMathPow(GateRef gate)548 void TypedNativeInlineLowering::LowerMathPow(GateRef gate)
549 {
550     Environment env(gate, circuit_, &builder_);
551     GateRef base = acc_.GetValueIn(gate, 0);
552     GateRef exp = acc_.GetValueIn(gate, 1);
553     Label exit(&builder_);
554     Label notNan(&builder_);
555 
556     auto nanValue = builder_.NanValue();
557     DEFVALUE(result, (&builder_), VariableType::FLOAT64(), nanValue);
558 
559     const double doubleOne = 1.0;
560     // Base is 1.0, exponent is inf => NaN
561     // Exponent is not finit, if is NaN or is Inf
562     GateRef resultIsNan = LogicOrBuilder(&env)
563         .Or(builder_.DoubleIsNAN(exp))
564         .Or(LogicAndBuilder(&env)
565             .And(builder_.DoubleEqual(builder_.FAbs(base), builder_.Double(doubleOne)))
566             .And(builder_.DoubleIsINF(exp))
567             .Done())
568         .Done();
569 
570     BRANCH_CIR(resultIsNan, &exit, &notNan);
571     builder_.Bind(&notNan);
572     {
573         GateRef glue = glue_;
574         result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatPow), Gate::InvalidGateRef, {base, exp}, gate);
575         builder_.Jump(&exit);
576     }
577 
578     builder_.Bind(&exit);
579     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
580 }
581 
LowerMathExp(GateRef gate)582 void TypedNativeInlineLowering::LowerMathExp(GateRef gate)
583 {
584 #ifdef SUPPORT_LLVM_INTRINSICS_WITH_CALLS
585     Environment env(gate, circuit_, &builder_);
586     constexpr double one = 1.0;
587     GateRef base = builder_.Double(std::exp(one));
588     GateRef power = acc_.GetValueIn(gate, 0U);
589 
590     GateRef exp = builder_.DoubleExp(base, power);
591     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), exp);
592 #else
593     LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatExp));
594 #endif
595 }
596 
LowerMathImul(GateRef gate)597 void TypedNativeInlineLowering::LowerMathImul(GateRef gate)
598 {
599     Environment env(gate, circuit_, &builder_);
600     GateRef val1 = acc_.GetValueIn(gate, 0);
601     GateRef val2 = acc_.GetValueIn(gate, 1);
602     ASSERT(acc_.GetGateType(val1).IsNJSValueType() && acc_.GetGateType(val2).IsNJSValueType());
603 
604     GateRef result = builder_.Int32Mul(val1, val2);
605     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
606 }
607 
LowerGeneralUnaryMath(GateRef gate,RuntimeStubCSigns::ID stubId)608 void TypedNativeInlineLowering::LowerGeneralUnaryMath(GateRef gate, RuntimeStubCSigns::ID stubId)
609 {
610     Environment env(gate, circuit_, &builder_);
611     GateRef value = acc_.GetValueIn(gate, 0);
612     GateRef glue = glue_;
613     GateRef result = builder_.CallNGCRuntime(glue, stubId, Gate::InvalidGateRef, {value}, gate);
614     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
615 }
616 
LowerMathAtan2(GateRef gate)617 void TypedNativeInlineLowering::LowerMathAtan2(GateRef gate)
618 {
619     Environment env(gate, circuit_, &builder_);
620     GateRef y = acc_.GetValueIn(gate, 0);
621     GateRef x = acc_.GetValueIn(gate, 1);
622     GateRef glue = glue_;
623     GateRef result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatAtan2), Gate::InvalidGateRef, {y, x}, gate);
624     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
625 }
626 
627 //  Int abs : The internal representation of an integer is inverse code,
628 //  The absolute value of a negative number can be found by inverting it by adding one.
BuildIntAbs(GateRef value)629 GateRef TypedNativeInlineLowering::BuildIntAbs(GateRef value)
630 {
631     ASSERT(acc_.GetMachineType(value) == MachineType::I32);
632     if (isLiteCG_) {
633         auto temp = builder_.Int32ASR(value, builder_.Int32(JSTaggedValue::INT_SIGN_BIT_OFFSET));
634         auto res = builder_.Int32Xor(value, temp);
635         return builder_.Int32Sub(res, temp);
636     }
637     return builder_.Abs(value);
638 }
639 
640 //  Float abs : A floating-point number is composed of mantissa and exponent.
641 //  The length of mantissa will affect the precision of the number, and its sign will determine the sign of the number.
642 //  The absolute value of a floating-point number can be found by setting mantissa sign bit to 0.
BuildDoubleAbs(GateRef value)643 GateRef TypedNativeInlineLowering::BuildDoubleAbs(GateRef value)
644 {
645     ASSERT(acc_.GetMachineType(value) == MachineType::F64);
646     if (isLiteCG_) {
647         // set the sign bit to 0 by shift left then right.
648         auto temp = builder_.Int64LSL(builder_.CastDoubleToInt64(value), builder_.Int64(1));
649         auto res = builder_.Int64LSR(temp, builder_.Int64(1));
650         return builder_.CastInt64ToFloat64(res);
651     }
652     return builder_.FAbs(value);
653 }
654 
BuildTNumberAbs(GateRef param)655 GateRef TypedNativeInlineLowering::BuildTNumberAbs(GateRef param)
656 {
657     ASSERT(!acc_.GetGateType(param).IsNJSValueType());
658     Label entry(&builder_);
659     builder_.SubCfgEntry(&entry);
660     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
661     Label exit(&builder_);
662     Label isInt(&builder_);
663     Label notInt(&builder_);
664     Label isIntMin(&builder_);
665     Label isResultInt(&builder_);
666     Label intExit(&builder_);
667     BRANCH_CIR(builder_.TaggedIsInt(param), &isInt, &notInt);
668     builder_.Bind(&isInt);
669     {
670         auto value = builder_.GetInt32OfTInt(param);
671         BRANCH_CIR(builder_.Equal(value, builder_.Int32(INT32_MIN)), &isIntMin, &isResultInt);
672         builder_.Bind(&isResultInt);
673         {
674             result = builder_.Int32ToTaggedPtr(BuildIntAbs(value));
675             builder_.Jump(&intExit);
676         }
677         builder_.Bind(&isIntMin);
678         {
679             result = builder_.DoubleToTaggedDoublePtr(builder_.Double(-static_cast<double>(INT_MIN)));
680             builder_.Jump(&intExit);
681         }
682         // Aot compiler fails without jump to intermediate label
683         builder_.Bind(&intExit);
684         builder_.Jump(&exit);
685     }
686     builder_.Bind(&notInt);
687     {
688         auto value = builder_.GetDoubleOfTDouble(param);
689         result = builder_.DoubleToTaggedDoublePtr(BuildDoubleAbs(value));
690         builder_.Jump(&exit);
691     }
692     builder_.Bind(&exit);
693     GateRef res = *result;
694     builder_.SubCfgExit();
695     return res;
696 }
697 
LowerAbs(GateRef gate)698 void TypedNativeInlineLowering::LowerAbs(GateRef gate)
699 {
700     GateRef value = acc_.GetValueIn(gate, 0);
701     Environment env(gate, circuit_, &builder_);
702     GateRef res = BuildTNumberAbs(value);
703     acc_.ReplaceGate(gate, builder_.GetStateDepend(), res);
704 }
705 
BuildRounding(GateRef gate,GateRef value,OpCode op)706 GateRef TypedNativeInlineLowering::BuildRounding(GateRef gate, GateRef value, OpCode op)
707 {
708     if (op == OpCode::MATH_ROUND || op == OpCode::MATH_ROUND_DOUBLE) {
709         Label entry(&builder_);
710         builder_.SubCfgEntry(&entry);
711         const double diff = 0.5;
712         GateRef diffValue = builder_.Double(diff);
713         const double zero = 0.0;
714         Label subOne(&builder_);
715         Label exit(&builder_);
716         Label retCeil(&builder_);
717         Label nonZero(&builder_);
718         DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.Double(zero));
719         // 0 <= x < 0.5, return 0
720         GateRef returnZero = builder_.BitAnd(builder_.DoubleLessThan(value, diffValue),
721             builder_.DoubleGreaterThan(value, builder_.Double(zero)));
722         BRANCH_CIR(returnZero, &exit, &nonZero);
723         builder_.Bind(&nonZero);
724         {
725             GateRef rounded;
726             if (builder_.GetCompilationConfig()->IsAArch64() && !isLiteCG_) {
727                 rounded = builder_.DoubleCeil(value);
728             } else {
729                 GateRef glue = glue_;
730                 rounded = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatCeil), Gate::InvalidGateRef, {value}, gate);
731             }
732             // if ceil(x) - x > 0.5, return ceil(x) - 1
733             // else return ceil(x)
734             BRANCH_CIR(builder_.DoubleGreaterThan(builder_.DoubleSub(rounded, value), diffValue),
735                 &subOne, &retCeil);
736             builder_.Bind(&subOne);
737             {
738                 result = builder_.DoubleSub(rounded, builder_.Double(1U));
739                 builder_.Jump(&exit);
740             }
741             builder_.Bind(&retCeil);
742             result = rounded;
743             builder_.Jump(&exit);
744         }
745         builder_.Bind(&exit);
746         GateRef res = *result;
747         builder_.SubCfgExit();
748         return res;
749     } else if (op == OpCode::MATH_FROUND) {
750         return builder_.ExtFloat32ToDouble(builder_.TruncDoubleToFloat32(value));
751     } else {
752         UNREACHABLE();
753     }
754 }
755 
LowerTaggedRounding(GateRef gate)756 void TypedNativeInlineLowering::LowerTaggedRounding(GateRef gate)
757 {
758     Environment env(gate, circuit_, &builder_);
759 
760     DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.NanValue());
761 
762     GateRef in = acc_.GetValueIn(gate, 0);
763     Label isInt(&builder_);
764     Label isDouble(&builder_);
765     Label exit(&builder_);
766 
767     builder_.Branch(builder_.TaggedIsInt(in), &isInt, &isDouble);
768     builder_.Bind(&isInt);
769     {
770         result = builder_.GetDoubleOfTInt(in);
771         builder_.Jump(&exit);
772     }
773     builder_.Bind(&isDouble);
774     {
775         GateRef value = builder_.GetDoubleOfTDouble(in);
776         result = BuildRounding(gate, value, acc_.GetOpCode(gate));
777         builder_.Jump(&exit);
778     }
779 
780     builder_.Bind(&exit);
781     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
782 }
783 
LowerDoubleRounding(GateRef gate)784 void TypedNativeInlineLowering::LowerDoubleRounding(GateRef gate)
785 {
786     Environment env(gate, circuit_, &builder_);
787     GateRef value = acc_.GetValueIn(gate, 0);
788     GateRef res = BuildRounding(gate, value, acc_.GetOpCode(gate));
789     acc_.ReplaceGate(gate, builder_.GetStateDepend(), res);
790 }
791 
LowerIntAbs(GateRef gate)792 void TypedNativeInlineLowering::LowerIntAbs(GateRef gate)
793 {
794     Environment env(gate, circuit_, &builder_);
795     GateRef value = acc_.GetValueIn(gate, 0);
796     auto frameState = FindFrameState(gate);
797     builder_.DeoptCheck(builder_.NotEqual(value, builder_.Int32(INT32_MIN)), frameState, DeoptType::NOTINT3);
798     GateRef res = BuildIntAbs(value);
799     acc_.ReplaceGate(gate, builder_.GetStateDepend(), res);
800 }
801 
LowerDoubleAbs(GateRef gate)802 void TypedNativeInlineLowering::LowerDoubleAbs(GateRef gate)
803 {
804     GateRef value = acc_.GetValueIn(gate, 0);
805     Environment env(gate, circuit_, &builder_);
806     GateRef res = BuildDoubleAbs(value);
807     acc_.ReplaceGate(gate, builder_.GetStateDepend(), res);
808 }
809 
810 // for min select in1 if int1 < int2, in2 otherwise
811 template<bool IS_MAX>
BuildIntMinMax(GateRef int1,GateRef int2,GateRef in1,GateRef in2)812 GateRef TypedNativeInlineLowering::BuildIntMinMax(GateRef int1, GateRef int2, GateRef in1, GateRef in2)
813 {
814     Label entry(&builder_);
815     builder_.SubCfgEntry(&entry);
816     // int or tagged
817     VariableType type {acc_.GetMachineType(in1), acc_.GetGateType(in1)};
818     DEFVALUE(result, (&builder_), type, (IS_MAX ? in1 : in2));
819     Label left(&builder_);
820     Label exit(&builder_);
821     builder_.Branch(builder_.Int32LessThan(int1, int2), &left, &exit);
822     builder_.Bind(&left);
823     {
824         result = IS_MAX ? in2 : in1;
825         builder_.Jump(&exit);
826     }
827     builder_.Bind(&exit);
828     GateRef res = *result;
829     builder_.SubCfgExit();
830     return res;
831 }
832 
833 template<bool IS_MAX>
BuildIntMinMax(GateRef in1,GateRef in2)834 GateRef TypedNativeInlineLowering::BuildIntMinMax(GateRef in1, GateRef in2)
835 {
836     ASSERT(acc_.GetMachineType(in1) == MachineType::I32);
837     ASSERT(acc_.GetMachineType(in2) == MachineType::I32);
838     if (isLiteCG_) {
839         return BuildIntMinMax<IS_MAX>(in1, in2, in1, in2);
840     }
841     return IS_MAX ? builder_.Int32Max(in1, in2) : builder_.Int32Min(in1, in2);
842 }
843 
844 /* for min select:
845  * NaN if double1 or double2 is NaN
846  * in1 if double1 and double2 are equal and in1 is negative zero
847  * in1 if double1 < double2, in2 otherwise */
848 template<bool IS_MAX>
BuildDoubleMinMax(GateRef double1,GateRef double2,GateRef in1,GateRef in2)849 GateRef TypedNativeInlineLowering::BuildDoubleMinMax(GateRef double1, GateRef double2, GateRef in1, GateRef in2)
850 {
851     Label entry(&builder_);
852     builder_.SubCfgEntry(&entry);
853     GateRef nanValue = builder_.NanValue();
854     if (in1 != double1) { // case when in1 and in2 are tagged
855         nanValue = builder_.DoubleToTaggedDoublePtr(nanValue);
856     }
857     // double or tagged
858     VariableType type {acc_.GetMachineType(in1), acc_.GetGateType(in1)};
859     DEFVALUE(result, (&builder_), type, nanValue);
860     Label left(&builder_);
861     Label rightOrZeroOrNan(&builder_);
862     Label right(&builder_);
863     Label exit(&builder_);
864     Label equal(&builder_);
865     Label equalOrNan(&builder_);
866     builder_.Branch(builder_.DoubleLessThan(double1, double2), &left, &rightOrZeroOrNan);
867     builder_.Bind(&rightOrZeroOrNan);
868     {
869         builder_.Branch(builder_.DoubleGreaterThan(double1, double2), &right, &equalOrNan);
870         builder_.Bind(&equalOrNan);
871         {
872             builder_.Branch(builder_.DoubleEqual(double1, double2), &equal, &exit);
873             builder_.Bind(&equal);
874             {
875                 // Whether to return in1 or in2 matters only in case of 0, -0
876                 const double negZero = -0.0;
877                 GateRef negZeroValue = builder_.CastDoubleToInt64(builder_.Double(negZero));
878                 builder_.Branch(builder_.Equal(builder_.CastDoubleToInt64(double1), negZeroValue), &left, &right);
879             }
880         }
881         builder_.Bind(&right);
882         {
883             result = IS_MAX ? in1 : in2;
884             builder_.Jump(&exit);
885         }
886     }
887     builder_.Bind(&left);
888     {
889         result = IS_MAX ? in2 : in1;
890         builder_.Jump(&exit);
891     }
892     builder_.Bind(&exit);
893     GateRef res = *result;
894     builder_.SubCfgExit();
895     return res;
896 }
897 
898 template<bool IS_MAX>
BuildDoubleMinMax(GateRef in1,GateRef in2)899 GateRef TypedNativeInlineLowering::BuildDoubleMinMax(GateRef in1, GateRef in2)
900 {
901     ASSERT(acc_.GetMachineType(in1) == MachineType::F64);
902     ASSERT(acc_.GetMachineType(in2) == MachineType::F64);
903     if (!isLiteCG_ && builder_.GetCompilationConfig()->IsAArch64()) {
904         return IS_MAX ? builder_.DoubleMax(in1, in2) : builder_.DoubleMin(in1, in2);
905     }
906     return BuildDoubleMinMax<IS_MAX>(in1, in2, in1, in2);
907 }
908 
909 template<bool IS_MAX>
LowerTNumberMinMax(GateRef gate)910 void TypedNativeInlineLowering::LowerTNumberMinMax(GateRef gate)
911 {
912     Environment env(gate, circuit_, &builder_);
913     GateRef in1 = acc_.GetValueIn(gate, 0);
914     GateRef in2 = acc_.GetValueIn(gate, 1);
915     GateRef nanValue = builder_.DoubleToTaggedDoublePtr(builder_.NanValue());
916     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), nanValue);
917     DEFVALUE(double1, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
918     DEFVALUE(double2, (&builder_), VariableType::FLOAT64(), builder_.Double(0));
919 
920     Label isInt1(&builder_);
921     Label isInt2(&builder_);
922     Label isDouble1(&builder_);
923     Label isDouble2(&builder_);
924     Label doubleExit(&builder_);
925     Label exit(&builder_);
926     builder_.Branch(builder_.TaggedIsInt(in1), &isInt1, &isDouble1);
927     {
928         builder_.Bind(&isInt1);
929         GateRef int1 = builder_.GetInt32OfTInt(in1);
930         builder_.Branch(builder_.TaggedIsInt(in2), &isInt2, &isDouble2);
931         {
932             builder_.Bind(&isInt2);
933             GateRef int2 = builder_.GetInt32OfTInt(in2);
934             result = BuildIntMinMax<IS_MAX>(int1, int2, in1, in2);
935             builder_.Jump(&exit);
936         }
937         builder_.Bind(&isDouble2);
938         double1 = builder_.ChangeInt32ToFloat64(int1);
939         double2 = builder_.GetDoubleOfTDouble(in2);
940         builder_.Jump(&doubleExit);
941     }
942     {
943         builder_.Bind(&isDouble1);
944         double1 = builder_.GetDoubleOfTDouble(in1);
945         double2 = builder_.GetDoubleOfTNumber(in2);
946         builder_.Jump(&doubleExit);
947     }
948     builder_.Bind(&doubleExit);
949     result = BuildDoubleMinMax<IS_MAX>(*double1, *double2, in1, in2);
950     builder_.Jump(&exit);
951 
952     builder_.Bind(&exit);
953     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
954 }
955 
956 template<bool IS_MAX>
LowerMathMinMaxWithIntrinsic(GateRef gate)957 void TypedNativeInlineLowering::LowerMathMinMaxWithIntrinsic(GateRef gate)
958 {
959     Environment env(gate, circuit_, &builder_);
960     GateRef in1 = acc_.GetValueIn(gate, 0);
961     GateRef in2 = acc_.GetValueIn(gate, 1);
962     GateRef nanValue = builder_.DoubleToTaggedDoublePtr(builder_.NanValue());
963     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), nanValue);
964 
965     Label intRes(&builder_);
966     Label doubleRes(&builder_);
967     Label exit(&builder_);
968 
969     BRANCH_CIR(LogicAndBuilder(&env).And(builder_.TaggedIsInt(in1)).And(builder_.TaggedIsInt(in2)).Done(),
970         &intRes, &doubleRes);
971     builder_.Bind(&intRes);
972     {
973         GateRef int1 = builder_.GetInt32OfTInt(in1);
974         GateRef int2 = builder_.GetInt32OfTInt(in2);
975         GateRef intRet = BuildIntMinMax<IS_MAX>(int1, int2);
976         result = builder_.Int32ToTaggedPtr(intRet);
977         builder_.Jump(&exit);
978     }
979     builder_.Bind(&doubleRes);
980     {
981         GateRef double1 = builder_.GetDoubleOfTNumber(in1);
982         GateRef double2 = builder_.GetDoubleOfTNumber(in2);
983         // LLVM supports lowering of `minimum/maximum` intrinsics on X86 only since version 17
984         // see https://github.com/llvm/llvm-project/commit/a82d27a9a6853c96f857ba0f514a78cd03bc5c35
985         if (builder_.GetCompilationConfig()->IsAArch64()) {
986             GateRef doubleRet = IS_MAX ? builder_.DoubleMax(double1, double2) : builder_.DoubleMin(double1, double2);
987             result = builder_.DoubleToTaggedDoublePtr(doubleRet);
988         } else {
989             result = BuildDoubleMinMax<IS_MAX>(double1, double2, in1, in2);
990         }
991         builder_.Jump(&exit);
992     }
993     builder_.Bind(&exit);
994     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
995 }
996 
997 template<bool IS_MAX>
LowerMinMax(GateRef gate)998 void TypedNativeInlineLowering::LowerMinMax(GateRef gate)
999 {
1000     if (isLiteCG_) {
1001         LowerTNumberMinMax<IS_MAX>(gate);
1002     } else {
1003         LowerMathMinMaxWithIntrinsic<IS_MAX>(gate);
1004     }
1005 }
1006 
1007 template<bool IS_MAX>
LowerIntMinMax(GateRef gate)1008 void TypedNativeInlineLowering::LowerIntMinMax(GateRef gate)
1009 {
1010     GateRef in1 = acc_.GetValueIn(gate, 0);
1011     GateRef in2 = acc_.GetValueIn(gate, 1);
1012     Environment env(gate, circuit_, &builder_);
1013     GateRef res = BuildIntMinMax<IS_MAX>(in1, in2);
1014     acc_.ReplaceGate(gate, builder_.GetStateDepend(), res);
1015 }
1016 
1017 template<bool IS_MAX>
LowerDoubleMinMax(GateRef gate)1018 void TypedNativeInlineLowering::LowerDoubleMinMax(GateRef gate)
1019 {
1020     GateRef in1 = acc_.GetValueIn(gate, 0);
1021     GateRef in2 = acc_.GetValueIn(gate, 1);
1022     Environment env(gate, circuit_, &builder_);
1023     GateRef res = BuildDoubleMinMax<IS_MAX>(in1, in2);
1024     acc_.ReplaceGate(gate, builder_.GetStateDepend(), res);
1025 }
1026 
FindFrameState(GateRef gate)1027 GateRef TypedNativeInlineLowering::FindFrameState(GateRef gate)
1028 {
1029     while (!acc_.HasFrameState(gate)) {
1030         ASSERT(acc_.GetDependCount(gate) > 0);
1031         gate = acc_.GetDep(gate);
1032     }
1033     return acc_.GetFrameState(gate);
1034 }
1035 
LowerClz32Float64(GateRef gate)1036 void TypedNativeInlineLowering::LowerClz32Float64(GateRef gate)
1037 {
1038     Environment env(gate, circuit_, &builder_);
1039     Label exit(&builder_);
1040     Label isFinit(&builder_);
1041 
1042     GateRef param = acc_.GetValueIn(gate, 0);
1043     const int32_t defaultReturnValue = 32;
1044     DEFVALUE(result, (&builder_), VariableType::INT32(), builder_.Int32(defaultReturnValue));
1045 
1046     // NaN, Inf, -Inf after ToUint32 equal 0, so we in advance know result: Clz32(0) = 32
1047     builder_.Branch(builder_.DoubleIsNanOrInf(param), &exit, &isFinit);
1048     builder_.Bind(&isFinit);
1049     {
1050         auto truncedValue = builder_.TruncInt64ToInt32(builder_.TruncFloatToInt64(param));
1051         result = builder_.CountLeadingZeroes32(truncedValue);
1052         builder_.Jump(&exit);
1053     }
1054 
1055     builder_.Bind(&exit);
1056     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1057 }
1058 
LowerClz32Int32(GateRef gate)1059 void TypedNativeInlineLowering::LowerClz32Int32(GateRef gate)
1060 {
1061     Environment env(gate, circuit_, &builder_);
1062     GateRef param = acc_.GetValueIn(gate, 0);
1063     GateRef result = builder_.CountLeadingZeroes32(param);
1064     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
1065 }
1066 
1067 //  Int trunc(x) : return x
1068 //  Float trunc(x) : return the integer part removing all fractional digits
LowerTrunc(GateRef gate)1069 void TypedNativeInlineLowering::LowerTrunc(GateRef gate)
1070 {
1071     Environment env(gate, circuit_, &builder_);
1072     GateRef param = acc_.GetValueIn(gate, 0);
1073     DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.NanValue());
1074 
1075     Label isInt(&builder_);
1076     Label notInt(&builder_);
1077     Label isDouble(&builder_);
1078     Label exit(&builder_);
1079 
1080     BRANCH_CIR(builder_.TaggedIsInt(param), &isInt, &notInt);
1081     builder_.Bind(&isInt);
1082     {
1083         result = builder_.ChangeInt32ToFloat64(builder_.GetInt32OfTInt(param));
1084         builder_.Jump(&exit);
1085     }
1086     builder_.Bind(&notInt);
1087     {
1088         BRANCH_CIR(builder_.TaggedIsDouble(param), &isDouble, &exit);
1089         builder_.Bind(&isDouble);
1090         {
1091             GateRef input = builder_.GetDoubleOfTDouble(param);
1092             result = builder_.DoubleTrunc(glue_, gate, input);
1093             builder_.Jump(&exit);
1094         }
1095     }
1096     builder_.Bind(&exit);
1097     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1098 }
1099 
LowerMathSqrt(GateRef gate)1100 void TypedNativeInlineLowering::LowerMathSqrt(GateRef gate)
1101 {
1102     Environment env(gate, circuit_, &builder_);
1103     builder_.SetEnvironment(&env);
1104     GateRef param = acc_.GetValueIn(gate, 0);
1105     // 20.2.2.32
1106     // If value is NAN or negative, include -NaN and -Infinity but not -0.0, the result is NaN
1107     // Assembly instruction support NAN and negative
1108     auto ret = builder_.Sqrt(param);
1109     acc_.SetMachineType(ret, MachineType::F64);
1110     acc_.SetGateType(ret, GateType::NJSValue());
1111     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
1112 }
1113 
1114 
AllocateNewNumber(GateRef glue,const CompilationEnv * compilationEnv,CircuitBuilder * builder,GateAccessor acc,GateRef protoOrHclass,GateRef result)1115 GateRef AllocateNewNumber(GateRef glue, const CompilationEnv *compilationEnv, CircuitBuilder *builder, GateAccessor acc,
1116                           GateRef protoOrHclass, GateRef result)
1117 {
1118     Jit::JitLockHolder lock(compilationEnv, "AllocateNewNumber");
1119     JSHandle<JSFunction> numberFunctionCT(compilationEnv->GetGlobalEnv()->GetNumberFunction());
1120     JSTaggedValue protoOrHClassCT = numberFunctionCT->GetProtoOrHClass(compilationEnv->GetJSThread());
1121     JSHClass *numberHClassCT = JSHClass::Cast(protoOrHClassCT.GetTaggedObject());
1122     size_t objectSize = numberHClassCT->GetObjectSize();
1123 
1124     GateRef size = builder->IntPtr(objectSize);
1125 
1126     GateRef emptyArray = builder->GetGlobalConstantValue(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
1127     builder->StartAllocate();
1128     GateRef object = builder->HeapAlloc(glue, size, GateType::TaggedValue(),
1129                                         RegionSpaceFlag::IN_YOUNG_SPACE);
1130     // Initialization:
1131     builder->StoreHClass(glue, object, protoOrHclass, MemoryAttribute::NeedBarrierAndAtomic());
1132     builder->StoreConstOffset(VariableType::INT64(), object, JSObject::HASH_OFFSET,
1133                               builder->Int64(JSTaggedValue(0).GetRawData()));
1134     builder->StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::PROPERTIES_OFFSET, emptyArray,
1135                               MemoryAttribute::NoBarrier());
1136     builder->StoreConstOffset(VariableType::JS_POINTER(), object, JSObject::ELEMENTS_OFFSET, emptyArray,
1137                               MemoryAttribute::NoBarrier());
1138     builder->StoreConstOffset(VariableType::JS_ANY(), object, JSPrimitiveRef::VALUE_OFFSET, result);
1139     auto offset = JSPrimitiveRef::VALUE_OFFSET + JSTaggedValue::TaggedTypeSize();
1140     // Initialize inlined properties:
1141     for (; offset < objectSize; offset += JSTaggedValue::TaggedTypeSize()) {
1142         builder->StoreConstOffset(VariableType::INT64(), object, offset, builder->Undefined());
1143     }
1144     return builder->FinishAllocate(object);
1145 }
1146 
LowerNewNumber(GateRef gate)1147 void TypedNativeInlineLowering::LowerNewNumber(GateRef gate)
1148 {
1149     Environment env(gate, circuit_, &builder_);
1150 
1151     GateRef glue = glue_;
1152     GateRef numberFunction = acc_.GetValueIn(gate, 0);
1153     GateRef param = acc_.GetValueIn(gate, 1);
1154 
1155     GateRef globalEnvNumberFunction = builder_.GetGlobalEnvValue(
1156         VariableType::JS_ANY(), glue, circuit_->GetGlobalEnvCache(), GlobalEnv::NUMBER_FUNCTION_INDEX);
1157     auto builtinIsNumber = builder_.Equal(numberFunction, globalEnvNumberFunction);
1158     builder_.DeoptCheck(builtinIsNumber, FindFrameState(gate), DeoptType::NEWBUILTINCTORFAIL1);
1159 
1160     DEFVALUE(result, (&builder_), VariableType::JS_ANY(),
1161              builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(builder_.Int32(0))));
1162     Label exit(&env);
1163     Label isNumber(&env);
1164     Label notNumber(&env);
1165     BRANCH_CIR(builder_.TaggedIsNumber(param), &isNumber, &notNumber);
1166     builder_.Bind(&isNumber);
1167     {
1168         result = param;
1169         builder_.Jump(&exit);
1170     }
1171     builder_.Bind(&notNumber);
1172     {
1173         builder_.DeoptCheck(builder_.TaggedIsLineUtf8String(glue, param), FindFrameState(gate), DeoptType::NOTSTRING1);
1174         auto length = builder_.GetLengthFromString(param);
1175         builder_.DeoptCheck(builder_.NotEqual(length, builder_.Int32(0)), FindFrameState(gate), DeoptType::NOTINT1);
1176         BuiltinsStringStubBuilder stringStub(builder_.GetCurrentEnvironment(), circuit_->GetGlobalEnvCache());
1177         GateRef dataUtf8 = builder_.PtrAdd(param, builder_.IntPtr(LineString::DATA_OFFSET));
1178         GateRef res = stringStub.StringDataToUint(dataUtf8, length, std::numeric_limits<int32_t>::max());
1179         builder_.DeoptCheck(builder_.NotEqual(res, builder_.Int64(-1)), FindFrameState(gate), DeoptType::NOTINT1);
1180         result = builder_.ToTaggedIntPtr(res);
1181         builder_.Jump(&exit);
1182     }
1183     builder_.Bind(&exit);
1184 
1185     auto protoOrHclass = builder_.LoadConstOffset(VariableType::JS_POINTER(), numberFunction,
1186                                                   JSFunction::PROTO_OR_DYNCLASS_OFFSET);
1187 
1188     GateRef ret = AllocateNewNumber(glue, compilationEnv_, &builder_, acc_, protoOrHclass, *result);
1189 
1190     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
1191 }
1192 
LowerArrayBufferIsView(GateRef gate)1193 void TypedNativeInlineLowering::LowerArrayBufferIsView(GateRef gate)
1194 {
1195     Environment env(gate, circuit_, &builder_);
1196 
1197     GateRef glue = glue_;
1198     GateRef arg = acc_.GetValueIn(gate, 0);
1199     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.TaggedFalse());
1200     Label exit(&builder_);
1201     Label isDataViewOrTypedArray(&builder_);
1202     Label returnTaggedTrue(&builder_);
1203     BRANCH_CIR(builder_.IsEcmaObject(glue, arg), &isDataViewOrTypedArray, &exit);
1204     builder_.Bind(&isDataViewOrTypedArray);
1205     {
1206         BRANCH_CIR(LogicOrBuilder(&env).Or(builder_.CheckJSType(glue, arg, JSType::JS_DATA_VIEW))
1207             .Or(builder_.TaggedObjectIsTypedArray(glue, arg)).Done(),
1208             &returnTaggedTrue, &exit);
1209     }
1210     builder_.Bind(&returnTaggedTrue);
1211     {
1212         result = builder_.TaggedTrue();
1213         builder_.Jump(&exit);
1214     }
1215     builder_.Bind(&exit);
1216     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1217 }
1218 
1219 template <bool IS_UNSIGNED>
LowerBigIntAsIntN(GateRef gate)1220 void TypedNativeInlineLowering::LowerBigIntAsIntN(GateRef gate)
1221 {
1222     Environment env(gate, circuit_, &builder_);
1223     Label hasException(&builder_);
1224     Label exit(&builder_);
1225     Label returnBigInt(&builder_);
1226     Label notZeroBigInt(&builder_);
1227     Label commonCase(&builder_);
1228 #if BIGINT_CONSTRUCTOR_IMPLEMENTED // NOTE: add fastpath after BigInt constructor implementing
1229     Label zeroBits(&builder_);
1230     Label notZeroBits(&builder_);
1231 #endif // BIGINT_CONSTRUCTOR_IMPLEMENTED
1232 
1233     GateRef glue = glue_;
1234     GateRef bits = acc_.GetValueIn(gate, 0);
1235     GateRef bigint = acc_.GetValueIn(gate, 1);
1236     GateRef frameState = acc_.GetValueIn(gate, 2);
1237     GateRef bitness = builder_.GetDoubleOfTDouble(bits);
1238     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1239 
1240     // Deoptimization if bitness is negative or more than safe number
1241     GateRef safeNumber = builder_.Double(SAFE_NUMBER);
1242     GateRef positiveCheck = builder_.DoubleGreaterThanOrEqual(bitness, builder_.Double(0));
1243     GateRef safeCheck = builder_.DoubleLessThanOrEqual(bitness, safeNumber);
1244     builder_.DeoptCheck(positiveCheck, frameState, DeoptType::RANGE_ERROR);
1245     builder_.DeoptCheck(safeCheck, frameState, DeoptType::RANGE_ERROR);
1246     builder_.DeoptCheck(builder_.TaggedIsBigInt(glue, bigint), frameState, DeoptType::NOT_BIG_INT);
1247 
1248     // Return bigint(0), if bits == 0
1249 #if BIGINT_CONSTRUCTOR_IMPLEMENTED // NOTE: add fastpath after BigInt constructor implementing
1250     BRANCH_CIR(builder_.DoubleEqual(bitness, builder_.Double(0)), &zeroBits, &notZeroBits);
1251     builder_.Bind(&zeroBits);
1252     {
1253         result = builder_.BigIntConstructor(0);
1254         builder_.Jump(&exit);
1255     }
1256     builder_.Bind(&notZeroBits);
1257 #endif // BIGINT_CONSTRUCTOR_IMPLEMENTED
1258 
1259     // Return bigint, if bigint == 0
1260     GateRef isZeroBigInt = LogicAndBuilder(&env)
1261         .And(builder_.Int32Equal(builder_.LoadWithoutBarrier(VariableType::INT32(), bigint,
1262             builder_.IntPtr(BigInt::LENGTH_OFFSET)), builder_.Int32(1)))
1263         .And(builder_.Int32Equal(builder_.LoadWithoutBarrier(VariableType::INT32(), bigint,
1264             builder_.IntPtr(BigInt::DATA_OFFSET)), builder_.Int32(0)))
1265         .Done();
1266     BRANCH_CIR(isZeroBigInt, &returnBigInt, &notZeroBigInt);
1267 
1268     // Return bigint, if bits >= max_value
1269     builder_.Bind(&notZeroBigInt);
1270     GateRef maxLengthBits = builder_.Double(static_cast<double>(BigInt::kMaxLengthBits));
1271     BRANCH_CIR(builder_.DoubleGreaterThanOrEqual(bitness, maxLengthBits), &returnBigInt, &commonCase);
1272     builder_.Bind(&returnBigInt);
1273     {
1274         result = bigint;
1275         builder_.Jump(&exit);
1276     }
1277 
1278     // Common case
1279     builder_.Bind(&commonCase);
1280     if constexpr (IS_UNSIGNED) {
1281         result = builder_.CallRuntime(glue, RTSTUB_ID(CallBigIntAsUintN), Gate::InvalidGateRef,
1282                                       {bits, bigint}, gate);
1283     } else {
1284         result = builder_.CallRuntime(glue, RTSTUB_ID(CallBigIntAsIntN), Gate::InvalidGateRef,
1285                                       {bits, bigint}, gate);
1286     }
1287     BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_), &hasException, &exit);
1288     builder_.Bind(&hasException);
1289     {
1290         result = builder_.ExceptionConstant();
1291         builder_.Jump(&exit);
1292     }
1293     builder_.Bind(&exit);
1294     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
1295 }
1296 
LowerDataViewProtoFunc(GateRef gate,DataViewProtoFunc func)1297 void TypedNativeInlineLowering::LowerDataViewProtoFunc(GateRef gate, DataViewProtoFunc func)
1298 {
1299     Environment env(gate, circuit_, &builder_);
1300 
1301     Label isNotDetachedBuffer(&builder_);
1302     Label isNotByteArray(&builder_);
1303     Label getPointFromByteArray(&builder_);
1304     Label getPointFromNotByteArray(&builder_);
1305     Label getValueFromBuffer(&builder_);
1306     Label bufferByteLengthIsZero(&builder_);
1307     Label bufferByteLengthIsNotZero(&builder_);
1308     GateRef glue = glue_;
1309     GateRef thisobj = acc_.GetValueIn(gate, 0);
1310     GateRef requestIndex = acc_.GetValueIn(gate, 1); // 1: requestIndex
1311     GateRef builtinId = Circuit::NullGate();
1312     GateRef isLittleEndian = Circuit::NullGate();
1313     GateRef frameState = Circuit::NullGate();
1314     ASSERT(func == DataViewProtoFunc::GET || func == DataViewProtoFunc::SET);
1315     if (func == DataViewProtoFunc::GET) {
1316         builtinId = acc_.GetValueIn(gate, 2); // 2: builtinId
1317         isLittleEndian = acc_.GetValueIn(gate, 3); // 3: isLittleEndian
1318         frameState = acc_.GetValueIn(gate, 4); // 4: frameState
1319     } else if (func == DataViewProtoFunc::SET) {
1320         builtinId = acc_.GetValueIn(gate, 3); // 3: builtinId
1321         isLittleEndian = acc_.GetValueIn(gate, 4); // 4: isLittleEndian
1322         frameState = acc_.GetValueIn(gate, 5); // 5: frameState
1323     } else {
1324         UNREACHABLE();
1325     }
1326 
1327     GateRef resultfinal = Circuit::NullGate();
1328 
1329     DEFVALUE(dataPointer, (&builder_), VariableType::NATIVE_POINTER(), builder_.IntPtr(0));
1330 
1331     builder_.DeoptCheck(
1332         builder_.Int32GreaterThanOrEqual(requestIndex, builder_.Int32(0)), frameState, DeoptType::INDEXLESSZERO);
1333     GateRef viewedArrayBufferOffset = builder_.IntPtr(JSDataView::VIEW_ARRAY_BUFFER_OFFSET);
1334     GateRef buffer = builder_.Load(VariableType::JS_ANY(), glue, thisobj, viewedArrayBufferOffset);
1335     BRANCH_CIR(builder_.CheckJSType(glue, buffer, JSType::BYTE_ARRAY), &isNotDetachedBuffer, &isNotByteArray);
1336     builder_.Bind(&isNotByteArray);
1337     {
1338         GateRef dataOffset = builder_.IntPtr(JSArrayBuffer::DATA_OFFSET);
1339         GateRef dataSlot = builder_.Load(VariableType::JS_ANY(), glue, buffer, dataOffset);
1340         builder_.DeoptCheck(builder_.TaggedIsNotNull(dataSlot), frameState, DeoptType::ARRAYBUFFERISDETACHED);
1341         builder_.Jump(&isNotDetachedBuffer);
1342     }
1343     builder_.Bind(&isNotDetachedBuffer);
1344     GateRef sizeOffset = builder_.IntPtr(JSDataView::BYTE_LENGTH_OFFSET);
1345     GateRef size = builder_.ZExtInt32ToInt64(builder_.LoadWithoutBarrier(VariableType::INT32(), thisobj, sizeOffset));
1346     GateRef elementSize = BuiltinIdToSize(builtinId);
1347     GateRef totalSize = builder_.Int64Add(builder_.ZExtInt32ToInt64(requestIndex), elementSize);
1348 
1349     builder_.DeoptCheck(
1350         builder_.Int64UnsignedGreaterThanOrEqual(size, totalSize), frameState, DeoptType::TOTALSIZEOVERFLOW);
1351     GateRef byteOffset = builder_.IntPtr(JSDataView::BYTE_OFFSET_OFFSET);
1352     GateRef offset = builder_.LoadWithoutBarrier(VariableType::INT32(), thisobj, byteOffset);
1353     GateRef bufferIndex = builder_.Int32Add(requestIndex, offset);
1354     BRANCH_CIR(builder_.CheckJSType(glue, buffer, JSType::BYTE_ARRAY),
1355                &getPointFromByteArray, &getPointFromNotByteArray);
1356     builder_.Bind(&getPointFromByteArray);
1357     {
1358         dataPointer =
1359             builder_.LoadWithoutBarrier(VariableType::NATIVE_POINTER(), buffer,
1360                                         builder_.IntPtr(ByteArray::DATA_OFFSET));
1361         builder_.Jump(&getValueFromBuffer);
1362     }
1363     builder_.Bind(&getPointFromNotByteArray);
1364     {
1365         GateRef arrayBufferByteLengthOffset = builder_.IntPtr(JSArrayBuffer::BYTE_LENGTH_OFFSET);
1366         GateRef arrayBufferByteLength =
1367             builder_.LoadWithoutBarrier(VariableType::INT32(), buffer, arrayBufferByteLengthOffset);
1368         BRANCH_CIR(builder_.Int32Equal(arrayBufferByteLength, builder_.Int32(0)),
1369                    &bufferByteLengthIsZero,
1370                    &bufferByteLengthIsNotZero);
1371         builder_.Bind(&bufferByteLengthIsZero);
1372         {
1373             dataPointer = builder_.IntPtr(0);
1374             builder_.Jump(&getValueFromBuffer);
1375         }
1376         builder_.Bind(&bufferByteLengthIsNotZero);
1377         {
1378             GateRef bufferDataOffset = builder_.IntPtr(JSArrayBuffer::DATA_OFFSET);
1379             GateRef data = builder_.Load(VariableType::JS_ANY(), glue, buffer, bufferDataOffset);
1380             GateRef externalPointerOffset = builder_.IntPtr(JSNativePointer::POINTER_OFFSET);
1381             GateRef externalPointer =
1382                 builder_.LoadWithoutBarrier(VariableType::NATIVE_POINTER(), data, externalPointerOffset);
1383             dataPointer = externalPointer;
1384             builder_.Jump(&getValueFromBuffer);
1385         }
1386     }
1387     builder_.Bind(&getValueFromBuffer);
1388     ASSERT(func == DataViewProtoFunc::GET || func == DataViewProtoFunc::SET);
1389     if (func == DataViewProtoFunc::GET) {
1390         resultfinal = GetValueFromBuffer(bufferIndex, *dataPointer, isLittleEndian, builtinId);
1391     } else if (func == DataViewProtoFunc::SET) {
1392         GateRef value = acc_.GetValueIn(gate, 2); // 2: value
1393         resultfinal =
1394             SetValueInBuffer(bufferIndex, value, *dataPointer, isLittleEndian, builtinId, glue_);
1395     } else {
1396         UNREACHABLE();
1397     }
1398 
1399     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), resultfinal);
1400 }
1401 
BuiltinIdToSize(GateRef ID)1402 GateRef TypedNativeInlineLowering::BuiltinIdToSize(GateRef ID)
1403 {
1404     auto builtinsID = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(ID));
1405     switch (builtinsID) {
1406         case BuiltinsStubCSigns::ID::DataViewGetInt8:
1407         case BuiltinsStubCSigns::ID::DataViewGetUint8:
1408         case BuiltinsStubCSigns::ID::DataViewSetUint8:
1409         case BuiltinsStubCSigns::ID::DataViewSetInt8:
1410             return builder_.Int64(ElmentSize::BITS_8);
1411         case BuiltinsStubCSigns::ID::DataViewGetInt16:
1412         case BuiltinsStubCSigns::ID::DataViewGetUint16:
1413         case BuiltinsStubCSigns::ID::DataViewSetInt16:
1414         case BuiltinsStubCSigns::ID::DataViewSetUint16:
1415             return builder_.Int64(ElmentSize::BITS_16);
1416         case BuiltinsStubCSigns::ID::DataViewGetUint32:
1417         case BuiltinsStubCSigns::ID::DataViewGetInt32:
1418         case BuiltinsStubCSigns::ID::DataViewGetFloat32:
1419         case BuiltinsStubCSigns::ID::DataViewSetUint32:
1420         case BuiltinsStubCSigns::ID::DataViewSetInt32:
1421         case BuiltinsStubCSigns::ID::DataViewSetFloat32:
1422             return builder_.Int64(ElmentSize::BITS_32);
1423         case BuiltinsStubCSigns::ID::DataViewGetFloat64:
1424         case BuiltinsStubCSigns::ID::DataViewSetFloat64:
1425             return builder_.Int64(ElmentSize::BITS_64);
1426         default:
1427             UNREACHABLE();
1428     }
1429 }
GetValueFromBuffer(GateRef bufferIndex,GateRef dataPointer,GateRef isLittleEndian,GateRef ID)1430 GateRef TypedNativeInlineLowering::GetValueFromBuffer(GateRef bufferIndex,
1431                                                       GateRef dataPointer,
1432                                                       GateRef isLittleEndian,
1433                                                       GateRef ID)
1434 {
1435     Label entry(&builder_);
1436     builder_.SubCfgEntry(&entry);
1437     Label exit(&builder_);
1438     Label littleEndian(&builder_);
1439     Label bigEndian(&builder_);
1440     Label passResult(&builder_);
1441     GateRef finalResult = builder_.NullConstant();
1442     BuiltinsStubCSigns::ID builtinsID = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(ID));
1443     switch (builtinsID) {
1444         case BuiltinsStubCSigns::ID::DataViewGetUint8: {
1445             GateRef uint8Res =
1446                 builder_.LoadWithoutBarrier(VariableType::INT8(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex));
1447             finalResult = builder_.ZExtInt8ToInt32(uint8Res);
1448             builder_.Jump(&exit);
1449             break;
1450         }
1451         case BuiltinsStubCSigns::ID::DataViewGetInt8: {
1452             GateRef int8res =
1453                 builder_.LoadWithoutBarrier(VariableType::INT8(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex));
1454             finalResult = builder_.SExtInt8ToInt32(int8res);
1455             builder_.Jump(&exit);
1456             break;
1457         }
1458         case BuiltinsStubCSigns::ID::DataViewGetUint16: {
1459             DEFVALUE(tempRes, (&builder_), VariableType::INT32(), builder_.Int32(0));
1460             GateRef uint16Res =
1461                 builder_.LoadWithoutBarrier(VariableType::INT16(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex));
1462             BRANCH_CIR(builder_.BoolNot(isLittleEndian), &bigEndian, &littleEndian);
1463             builder_.Bind(&littleEndian);
1464             {
1465                 tempRes = builder_.ZExtInt16ToInt32(uint16Res);
1466                 builder_.Jump(&passResult);
1467             }
1468             builder_.Bind(&bigEndian);
1469             {
1470                 GateRef bigEndianInt16 = builder_.Int16ToBigEndianInt16(uint16Res);
1471                 tempRes = builder_.ZExtInt16ToInt32(bigEndianInt16);
1472                 builder_.Jump(&passResult);
1473             }
1474             builder_.Bind(&passResult);
1475             {
1476                 finalResult = *tempRes;
1477                 builder_.Jump(&exit);
1478             }
1479             break;
1480         }
1481         case BuiltinsStubCSigns::ID::DataViewGetInt16: {
1482             DEFVALUE(tempRes, (&builder_), VariableType::INT32(), builder_.Int32(0));
1483             GateRef int16Res =
1484                 builder_.LoadWithoutBarrier(VariableType::INT16(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex));
1485             BRANCH_CIR(builder_.BoolNot(isLittleEndian), &bigEndian, &littleEndian);
1486             builder_.Bind(&littleEndian);
1487             {
1488                 tempRes = builder_.SExtInt16ToInt32(int16Res);
1489                 builder_.Jump(&passResult);
1490             }
1491             builder_.Bind(&bigEndian);
1492             {
1493                 tempRes = builder_.SExtInt16ToInt32(builder_.Int16ToBigEndianInt16(int16Res));
1494                 builder_.Jump(&passResult);
1495             }
1496             builder_.Bind(&passResult);
1497             {
1498                 finalResult = *tempRes;
1499                 builder_.Jump(&exit);
1500             }
1501             break;
1502         }
1503         case BuiltinsStubCSigns::ID::DataViewGetUint32: {
1504             DEFVALUE(tempRes, (&builder_), VariableType::INT32(), builder_.Int32(0));
1505             GateRef uint32Res =
1506                 builder_.LoadWithoutBarrier(VariableType::INT32(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex));
1507             BRANCH_CIR(builder_.BoolNot(isLittleEndian), &bigEndian, &littleEndian);
1508             builder_.Bind(&littleEndian);
1509             {
1510                 tempRes = uint32Res;
1511                 builder_.Jump(&passResult);
1512             }
1513             builder_.Bind(&bigEndian);
1514             {
1515                 tempRes = builder_.Int32ToBigEndianInt32(uint32Res);
1516                 builder_.Jump(&passResult);
1517             }
1518             builder_.Bind(&passResult);
1519             {
1520                 finalResult = *tempRes;
1521                 builder_.Jump(&exit);
1522             }
1523             break;
1524         }
1525         case BuiltinsStubCSigns::ID::DataViewGetInt32: {
1526             DEFVALUE(tempRes, (&builder_), VariableType::INT32(), builder_.Int32(0));
1527             GateRef int32Res =
1528                 builder_.LoadWithoutBarrier(VariableType::INT32(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex));
1529             BRANCH_CIR(builder_.BoolNot(isLittleEndian), &bigEndian, &littleEndian);
1530             builder_.Bind(&littleEndian);
1531             {
1532                 tempRes = int32Res;
1533                 builder_.Jump(&passResult);
1534             }
1535             builder_.Bind(&bigEndian);
1536             {
1537                 tempRes = builder_.Int32ToBigEndianInt32(int32Res);
1538                 builder_.Jump(&passResult);
1539             }
1540             builder_.Bind(&passResult);
1541             {
1542                 finalResult = *tempRes;
1543                 builder_.Jump(&exit);
1544             }
1545             break;
1546         }
1547         case BuiltinsStubCSigns::ID::DataViewGetFloat32: {
1548             DEFVALUE(tempRes, (&builder_), VariableType::FLOAT64(), builder_.Double(base::NAN_VALUE));
1549             Label notNaN(&builder_);
1550             GateRef int32Res =
1551                 builder_.LoadWithoutBarrier(VariableType::INT32(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex));
1552             BRANCH_CIR(builder_.BoolNot(isLittleEndian), &bigEndian, &littleEndian);
1553             builder_.Bind(&littleEndian);
1554             {
1555                 GateRef float32Res = builder_.CastInt32ToFloat32(int32Res);
1556                 tempRes = builder_.ExtFloat32ToDouble(float32Res);
1557                 builder_.Jump(&passResult);
1558             }
1559             builder_.Bind(&bigEndian);
1560             {
1561                 GateRef bigEndianInt32Res = builder_.Int32ToBigEndianInt32(int32Res);
1562                 GateRef float32Res = builder_.CastInt32ToFloat32(bigEndianInt32Res);
1563                 GateRef doubleRes = builder_.ExtFloat32ToDouble(float32Res);
1564                 BRANCH_CIR(builder_.DoubleIsNAN(doubleRes), &passResult, &notNaN);
1565                 builder_.Bind(&notNaN);
1566                 {
1567                     tempRes = doubleRes;
1568                     builder_.Jump(&passResult);
1569                 }
1570             }
1571             builder_.Bind(&passResult);
1572             {
1573                 finalResult = *tempRes;
1574                 builder_.Jump(&exit);
1575             }
1576             break;
1577         }
1578         case BuiltinsStubCSigns::ID::DataViewGetFloat64: {
1579             GateRef float64Res =
1580                 builder_.LoadWithoutBarrier(VariableType::FLOAT64(), dataPointer,
1581                                             builder_.ZExtInt32ToPtr(bufferIndex));
1582             DEFVALUE(tempRes, (&builder_), VariableType::FLOAT64(), builder_.NanValue());
1583             BRANCH_CIR(builder_.BoolNot(isLittleEndian), &bigEndian, &littleEndian);
1584             builder_.Bind(&bigEndian);
1585             {
1586                 GateRef int64Res = builder_.CastDoubleToInt64(float64Res);
1587                 GateRef bigEndianInt64Res = builder_.Int64ToBigEndianInt64(int64Res);
1588                 GateRef bigEndianDoubleRes = builder_.CastInt64ToFloat64(bigEndianInt64Res);
1589                 Label bigEndianResNotImpure(&builder_);
1590                 BRANCH_CIR(builder_.DoubleIsImpureNaN(bigEndianDoubleRes), &passResult, &bigEndianResNotImpure);
1591                 builder_.Bind(&bigEndianResNotImpure);
1592                 {
1593                     tempRes = bigEndianDoubleRes;
1594                     builder_.Jump(&passResult);
1595                 }
1596             }
1597             builder_.Bind(&littleEndian);
1598             {
1599                 Label resNotImpure(&builder_);
1600                 BRANCH_CIR(builder_.DoubleIsImpureNaN(float64Res), &passResult, &resNotImpure);
1601                 builder_.Bind(&resNotImpure);
1602                 {
1603                     tempRes = float64Res;
1604                     builder_.Jump(&passResult);
1605                 }
1606             }
1607             builder_.Bind(&passResult);
1608             {
1609                 finalResult = *tempRes;
1610                 builder_.Jump(&exit);
1611             }
1612             break;
1613         }
1614         default:
1615             UNREACHABLE();
1616     }
1617     builder_.Bind(&exit);
1618     builder_.SubCfgExit();
1619     return finalResult;
1620 }
1621 
SetValueInBuffer(GateRef bufferIndex,GateRef value,GateRef dataPointer,GateRef isLittleEndian,GateRef ID,GateRef glue)1622 GateRef TypedNativeInlineLowering::SetValueInBuffer(
1623     GateRef bufferIndex, GateRef value, GateRef dataPointer, GateRef isLittleEndian, GateRef ID, GateRef glue)
1624 {
1625     Label entry(&builder_);
1626     builder_.SubCfgEntry(&entry);
1627     Label exit(&builder_);
1628 
1629     Label littleEndian(&builder_);
1630     Label bigEndian(&builder_);
1631     Label passResult(&builder_);
1632     GateRef offset = builder_.ZExtInt32ToPtr(bufferIndex);
1633     Label startStore(&builder_);
1634     Label getInt64Value(&builder_);
1635     DEFVALUE(int64Value, (&builder_), VariableType::INT64(), builder_.Int64(0));
1636     BRANCH_CIR(builder_.DoubleIsNanOrInf(value), &startStore, &getInt64Value);
1637     builder_.Bind(&getInt64Value);
1638     {
1639         int64Value = builder_.TruncFloatToInt64(value);
1640         builder_.Jump(&startStore);
1641     }
1642     builder_.Bind(&startStore);
1643     BuiltinsStubCSigns::ID builtinsID = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(ID));
1644 
1645     switch (builtinsID) {
1646         case BuiltinsStubCSigns::ID::DataViewSetUint8:
1647         case BuiltinsStubCSigns::ID::DataViewSetInt8: {
1648             GateRef int32Value = builder_.TruncInt64ToInt32(*int64Value);
1649             builder_.Store(VariableType::INT8(), glue, dataPointer, offset, builder_.TruncInt32ToInt8(int32Value));
1650             builder_.Jump(&exit);
1651             break;
1652         }
1653         case BuiltinsStubCSigns::ID::DataViewSetUint16:
1654         case BuiltinsStubCSigns::ID::DataViewSetInt16: {
1655             BRANCH_CIR(isLittleEndian, &littleEndian, &bigEndian);
1656             builder_.Bind(&littleEndian);
1657             {
1658                 builder_.Store(
1659                     VariableType::INT16(), glue, dataPointer, offset, builder_.TruncInt64ToInt16(*int64Value));
1660                 builder_.Jump(&exit);
1661             }
1662             builder_.Bind(&bigEndian);
1663             {
1664                 GateRef int16Value = builder_.TruncInt64ToInt16(*int64Value);
1665                 GateRef bigEndianInt16 = builder_.Int16ToBigEndianInt16(int16Value);
1666                 builder_.Store(VariableType::INT16(), glue, dataPointer, offset, bigEndianInt16);
1667                 builder_.Jump(&exit);
1668             }
1669             break;
1670         }
1671         case BuiltinsStubCSigns::ID::DataViewSetFloat32: {
1672             GateRef float32Value = builder_.TruncDoubleToFloat32(value);
1673             BRANCH_CIR(isLittleEndian, &littleEndian, &bigEndian);
1674             builder_.Bind(&littleEndian);
1675             {
1676                 builder_.Store(VariableType::FLOAT32(), glue, dataPointer, offset, float32Value);
1677                 builder_.Jump(&exit);
1678             }
1679             builder_.Bind(&bigEndian);
1680             {
1681                 GateRef int32Value = builder_.CastFloat32ToInt32(float32Value);
1682                 GateRef bigEndianInt32Value = builder_.Int32ToBigEndianInt32(int32Value);
1683                 GateRef bigEndianFloat32Value = builder_.CastInt32ToFloat32(bigEndianInt32Value);
1684                 builder_.Store(VariableType::FLOAT32(), glue, dataPointer, offset, bigEndianFloat32Value);
1685                 builder_.Jump(&exit);
1686             }
1687             break;
1688         }
1689         case BuiltinsStubCSigns::ID::DataViewSetInt32:
1690         case BuiltinsStubCSigns::ID::DataViewSetUint32: {
1691             BRANCH_CIR(isLittleEndian, &littleEndian, &bigEndian);
1692             builder_.Bind(&littleEndian);
1693             {
1694                 builder_.Store(
1695                     VariableType::INT32(), glue, dataPointer, offset, builder_.TruncInt64ToInt32(*int64Value));
1696                 builder_.Jump(&exit);
1697             }
1698             builder_.Bind(&bigEndian);
1699             {
1700                 GateRef int32Value = builder_.TruncInt64ToInt32(*int64Value);
1701                 GateRef bigEndianInt32 = builder_.Int32ToBigEndianInt32(int32Value);
1702                 builder_.Store(VariableType::INT32(), glue, dataPointer, offset, bigEndianInt32);
1703                 builder_.Jump(&exit);
1704             }
1705             break;
1706         }
1707         case BuiltinsStubCSigns::ID::DataViewSetFloat64: {
1708             BRANCH_CIR(isLittleEndian, &littleEndian, &bigEndian);
1709             builder_.Bind(&littleEndian);
1710             {
1711                 builder_.Store(VariableType::FLOAT64(), glue, dataPointer, offset, value);
1712                 builder_.Jump(&exit);
1713             }
1714             builder_.Bind(&bigEndian);
1715             {
1716                 GateRef int64bitsValue = builder_.CastDoubleToInt64(value);
1717                 GateRef bigEndianInt64Value = builder_.Int64ToBigEndianInt64(int64bitsValue);
1718                 GateRef float64Value = builder_.CastInt64ToFloat64(bigEndianInt64Value);
1719                 builder_.Store(VariableType::INT64(), glue, dataPointer, offset, float64Value);
1720                 builder_.Jump(&exit);
1721             }
1722             break;
1723         }
1724         default:
1725             UNREACHABLE();
1726     }
1727     builder_.Bind(&exit);
1728     builder_.SubCfgExit();
1729     return builder_.UndefineConstant();
1730 }
1731 
BuildMathSignDouble(Variable * resVarPtr,CircuitBuilder * builder,GateRef param,std::vector<Label> * labelsForFloatCase)1732 static void BuildMathSignDouble(Variable *resVarPtr, CircuitBuilder *builder, GateRef param,
1733                                 std::vector<Label> *labelsForFloatCase)
1734 {
1735     auto &taggedRes = *resVarPtr;
1736     auto &labelsForFloatCaseRef = *labelsForFloatCase;
1737     auto labelsIdx = 0;
1738     Label *isNan = &labelsForFloatCaseRef.at(labelsIdx++);
1739     Label *notNan = &labelsForFloatCaseRef.at(labelsIdx++);
1740     Label *exitNan = &labelsForFloatCaseRef.at(labelsIdx++);
1741 
1742     auto value = builder->GetDoubleOfTDouble(param);
1743     builder->Branch(builder->DoubleIsNAN(value), isNan, notNan);
1744     builder->Bind(isNan);
1745     {
1746         taggedRes = builder->DoubleToTaggedDoublePtr(builder->NanValue());
1747         builder->Jump(exitNan);
1748     }
1749     builder->Bind(notNan);
1750     {
1751         Label *isZero = &labelsForFloatCaseRef.at(labelsIdx++);
1752         Label *notZero = &labelsForFloatCaseRef.at(labelsIdx++);
1753         Label *exitZero = &labelsForFloatCaseRef.at(labelsIdx++);
1754 
1755         builder->Branch(builder->DoubleEqual(value, builder->Double(0)), isZero, notZero);
1756         builder->Bind(isZero);
1757         {
1758             taggedRes = param;
1759             builder->Jump(exitZero);
1760         }
1761         builder->Bind(notZero);
1762         {
1763             Label *isNegative = &labelsForFloatCaseRef.at(labelsIdx++);
1764             Label *notNegative = &labelsForFloatCaseRef.at(labelsIdx++);
1765             Label *exitNegative = &labelsForFloatCaseRef.at(labelsIdx);
1766 
1767             builder->Branch(builder->DoubleLessThan(value, builder->Double(0)), isNegative, notNegative);
1768             builder->Bind(isNegative);
1769             {
1770                 taggedRes = builder->Int32ToTaggedPtr(builder->Int32(-1));
1771                 builder->Jump(exitNegative);
1772             }
1773             builder->Bind(notNegative);
1774             {
1775                 taggedRes = builder->Int32ToTaggedPtr(builder->Int32(1));
1776                 builder->Jump(exitNegative);
1777             }
1778             builder->Bind(exitNegative);
1779             builder->Jump(exitZero);
1780         }
1781         builder->Bind(exitZero);
1782         builder->Jump(exitNan);
1783     }
1784     builder->Bind(exitNan);
1785 }
1786 
BuildMathSignInt(CircuitBuilder * builder,GateRef input)1787 static GateRef BuildMathSignInt(CircuitBuilder *builder, GateRef input)
1788 {
1789     auto nz = builder->BooleanToInt32(builder->Int32NotEqual(input, builder->Int32(0)));
1790     auto valueShifted = builder->Int32ASR(input, builder->Int32(JSTaggedValue::INT_SIGN_BIT_OFFSET));
1791     return builder->Int32Or(valueShifted, nz);
1792 }
1793 
LowerMathSignInt(GateRef gate)1794 void TypedNativeInlineLowering::LowerMathSignInt(GateRef gate)
1795 {
1796     Environment env(gate, circuit_, &builder_);
1797     GateRef param = acc_.GetValueIn(gate, 0);
1798 
1799     auto res = BuildMathSignInt(&builder_, param);
1800 
1801     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), res);
1802 }
1803 
LowerMathSignTagged(GateRef gate)1804 void TypedNativeInlineLowering::LowerMathSignTagged(GateRef gate)
1805 {
1806     Environment env(gate, circuit_, &builder_);
1807     Label exit(&builder_);
1808     GateRef param = acc_.GetValueIn(gate, 0);
1809     DEFVALUE(taggedRes, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
1810 
1811     std::vector<Label> labelsForFloatCase;
1812     constexpr auto FLOAT_CASE_LABELS_COUNT = 9;
1813     labelsForFloatCase.reserve(FLOAT_CASE_LABELS_COUNT);
1814     for (auto i = 0; i < FLOAT_CASE_LABELS_COUNT; i++) {
1815         labelsForFloatCase.emplace_back(&builder_);
1816     }
1817 
1818     Label isInt(&builder_);
1819     Label notInt(&builder_);
1820     builder_.Branch(builder_.TaggedIsInt(param), &isInt, &notInt);
1821     builder_.Bind(&isInt);
1822     {
1823         auto value = builder_.GetInt32OfTInt(param);
1824 
1825         auto res = BuildMathSignInt(&builder_, value);
1826 
1827         taggedRes = builder_.Int32ToTaggedPtr(res);
1828         builder_.Jump(&exit);
1829     }
1830     builder_.Bind(&notInt);
1831     {
1832         BuildMathSignDouble(&taggedRes, &builder_, param, &labelsForFloatCase);
1833         builder_.Jump(&exit);
1834     }
1835     builder_.Bind(&exit);
1836     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *taggedRes);
1837 }
1838 
BuildDoubleIsFinite(GateRef value)1839 GateRef TypedNativeInlineLowering::BuildDoubleIsFinite(GateRef value)
1840 {
1841     GateRef diff = builder_.DoubleSub(value, value);
1842     return builder_.DoubleEqual(diff, diff);
1843 }
1844 
LowerNumberIsFinite(GateRef gate)1845 void TypedNativeInlineLowering::LowerNumberIsFinite(GateRef gate)
1846 {
1847     GateRef value = acc_.GetValueIn(gate, 0);
1848     Environment env(gate, circuit_, &builder_);
1849     GateRef result = BuildDoubleIsFinite(value);
1850 
1851     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
1852 }
1853 
BuildTaggedIsInteger(GateRef gate,GateRef value,bool safe)1854 GateRef TypedNativeInlineLowering::BuildTaggedIsInteger(GateRef gate, GateRef value, bool safe)
1855 {
1856     Label exit(&builder_);
1857     Label entry(&builder_);
1858     builder_.SubCfgEntry(&entry);
1859     DEFVALUE(result, (&builder_), VariableType::BOOL(), builder_.False());
1860     Label isInt(&builder_);
1861     Label notIsInt(&builder_);
1862     BRANCH_CIR(builder_.TaggedIsInt(value), &isInt, &notIsInt);
1863     builder_.Bind(&isInt);
1864     {
1865         result = builder_.True();
1866         builder_.Jump(&exit);
1867     }
1868     builder_.Bind(&notIsInt);
1869 
1870     Label isFinite(&builder_);
1871     GateRef doubleVal = builder_.GetDoubleOfTDouble(value);
1872     BRANCH_CIR(BuildDoubleIsFinite(doubleVal), &isFinite, &exit);
1873     builder_.Bind(&isFinite);
1874     {
1875         GateRef doubleTrunc = builder_.DoubleTrunc(glue_, gate, doubleVal);
1876         result = builder_.Equal(doubleVal, doubleTrunc);
1877         if (safe) {
1878             GateRef resultVal = *result;
1879             result = LogicAndBuilder(builder_.GetCurrentEnvironment())
1880                 .And(resultVal)
1881                 .And(builder_.DoubleLessThanOrEqual(builder_.FAbs(doubleTrunc),
1882                                                     builder_.Double(base::MAX_SAFE_INTEGER)))
1883                 .Done();
1884         }
1885         builder_.Jump(&exit);
1886     }
1887 
1888     builder_.Bind(&exit);
1889     GateRef res = *result;
1890     builder_.SubCfgExit();
1891     return res;
1892 }
1893 
LowerNumberIsInteger(GateRef gate,OpCode op)1894 void TypedNativeInlineLowering::LowerNumberIsInteger(GateRef gate, OpCode op)
1895 {
1896     ASSERT(op == OpCode::NUMBER_IS_INTEGER || op == OpCode::NUMBER_IS_SAFEINTEGER);
1897     GateRef value = acc_.GetValueIn(gate, 0);
1898     Environment env(gate, circuit_, &builder_);
1899     GateRef result = BuildTaggedIsInteger(gate, value, op == OpCode::NUMBER_IS_SAFEINTEGER);
1900 
1901     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
1902 }
1903 
LowerNumberIsNaN(GateRef gate)1904 void TypedNativeInlineLowering::LowerNumberIsNaN(GateRef gate)
1905 {
1906     GateRef value = acc_.GetValueIn(gate, 0);
1907     Environment env(gate, circuit_, &builder_);
1908     GateRef result = builder_.DoubleIsNAN(value);
1909 
1910     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
1911 }
1912 
LowerNumberParseInt(GateRef gate)1913 void TypedNativeInlineLowering::LowerNumberParseInt(GateRef gate)
1914 {
1915     Environment env(gate, circuit_, &builder_);
1916 
1917     Label exit(&builder_);
1918     Label slowPath(&builder_);
1919     Label msgIsString(&builder_);
1920     Label radixIsSpecial(&builder_);
1921     Label radixIsSpecialInt(&builder_);
1922 
1923     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
1924     DEFVALUE(radix, (&builder_), VariableType::INT32(), builder_.Int32(0));
1925     GateRef msg = acc_.GetValueIn(gate, 0);
1926     GateRef arg2 = acc_.GetValueIn(gate, 1);
1927     GateRef glue = glue_;
1928 
1929     builder_.Branch(builder_.TaggedIsString(glue, msg), &msgIsString, &slowPath);
1930 
1931     builder_.Bind(&msgIsString);
1932     {
1933         builder_.Branch(builder_.TaggedIsUndefined(arg2), &radixIsSpecialInt, &radixIsSpecial);
1934         builder_.Bind(&radixIsSpecial);
1935         {
1936             Label radixIsInt(&builder_);
1937             builder_.Branch(builder_.TaggedIsInt(arg2), &radixIsInt, &slowPath);
1938             builder_.Bind(&radixIsInt);
1939             {
1940                 radix = builder_.GetInt32OfTInt(arg2);
1941                 builder_.Jump(&radixIsSpecialInt);
1942             }
1943         }
1944         builder_.Bind(&radixIsSpecialInt);
1945         {
1946             result = builder_.CallNGCRuntime(glue, RTSTUB_ID(StringToNumber), Gate::InvalidGateRef,
1947                 { glue, msg, *radix }, gate);
1948             builder_.Jump(&exit);
1949         }
1950     }
1951     builder_.Bind(&slowPath);
1952     {
1953         // this may return exception
1954         result = builder_.CallRuntime(glue, RTSTUB_ID(ParseInt), Gate::InvalidGateRef, {msg, arg2}, gate);
1955         builder_.Jump(&exit);
1956     }
1957 
1958     builder_.Bind(&exit);
1959     ReplaceGateWithPendingException(
1960         gate, glue_, builder_.GetState(), builder_.GetDepend(), *result);
1961 }
1962 
CheckAndConvertToUInt(GateRef glue,GateRef msg,Label * notIntegerStr,Label * nonZeroLength)1963 GateRef TypedNativeInlineLowering::CheckAndConvertToUInt(GateRef glue, GateRef msg, Label* notIntegerStr,
1964                                                          Label* nonZeroLength)
1965 {
1966     auto length = builder_.GetLengthFromString(msg);
1967     BRANCH_CIR(builder_.Equal(length, builder_.Int32(0)), notIntegerStr, nonZeroLength);
1968     builder_.Bind(nonZeroLength);
1969     BuiltinsStringStubBuilder stringStub(builder_.GetCurrentEnvironment(), circuit_->GetGlobalEnvCache());
1970     GateRef dataUtf8 = builder_.PtrAdd(msg, builder_.IntPtr(LineString::DATA_OFFSET));
1971     return stringStub.StringDataToUint(dataUtf8, length, std::numeric_limits<int32_t>::max());
1972 }
1973 
LowerNumberParseFloat(GateRef gate)1974 void TypedNativeInlineLowering::LowerNumberParseFloat(GateRef gate)
1975 {
1976     Environment env(gate, circuit_, &builder_);
1977 
1978     DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.HoleConstant());
1979     Label exit(&builder_);
1980 
1981     Label definedMsg(&builder_);
1982     Label undefinedMsg(&builder_);
1983     GateRef msg = acc_.GetValueIn(gate, 0);
1984     builder_.Branch(builder_.BoolNot(builder_.TaggedIsUndefined(msg)), &definedMsg, &undefinedMsg);
1985     builder_.Bind(&definedMsg);
1986     {
1987         auto frameState = acc_.GetFrameState(gate);
1988         GateRef glue = glue_;
1989         builder_.DeoptCheck(builder_.TaggedIsString(glue, msg), frameState, DeoptType::NOTSTRING1);
1990         Label notIntegerStr(&builder_);
1991         Label exitIntegerStr(&builder_);
1992         Label isLineUtf8String(&builder_);
1993         BRANCH_CIR(builder_.TaggedIsLineUtf8String(glue, msg), &isLineUtf8String, &notIntegerStr);
1994         builder_.Bind(&isLineUtf8String);
1995         {
1996             Label isInteger(&builder_);
1997             Label nonZeroLength(&builder_);
1998             GateRef res = CheckAndConvertToUInt(glue, msg, &notIntegerStr, &nonZeroLength);
1999             BRANCH_CIR(builder_.Int64NotEqual(res, builder_.Int64(-1)), &isInteger, &notIntegerStr);
2000             builder_.Bind(&isInteger);
2001             {
2002                 result = builder_.ChangeInt32ToFloat64(builder_.TruncInt64ToInt32(res));
2003                 builder_.Jump(&exitIntegerStr);
2004             }
2005         }
2006         builder_.Bind(&notIntegerStr);
2007         {
2008             auto taggedDouble = builder_.CallNGCRuntime(glue, RTSTUB_ID(NumberHelperStringToDouble),
2009                                                         Gate::InvalidGateRef, { glue, msg }, gate);
2010             result = builder_.GetDoubleOfTDouble(taggedDouble);
2011             builder_.Jump(&exitIntegerStr);
2012         }
2013         builder_.Bind(&exitIntegerStr);
2014         builder_.Jump(&exit);
2015     }
2016     builder_.Bind(&undefinedMsg);
2017     {
2018         result = builder_.Double(base::NAN_VALUE);
2019         builder_.Jump(&exit);
2020     }
2021     builder_.Bind(&exit);
2022     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2023 }
2024 
LowerToCommonStub(GateRef gate,CommonStubCSigns::ID id)2025 void TypedNativeInlineLowering::LowerToCommonStub(GateRef gate, CommonStubCSigns::ID id)
2026 {
2027     Environment env(gate, circuit_, &builder_);
2028     GateRef glue = glue_;
2029     std::vector<GateRef> args {glue};
2030     size_t numIn = acc_.GetNumValueIn(gate);
2031     for (size_t idx = 0; idx < numIn; idx++) {
2032         args.emplace_back(acc_.GetValueIn(gate, idx));
2033     }
2034     // for gloabalEnv
2035     args.emplace_back(circuit_->GetGlobalEnvCache());
2036     GateRef ret = builder_.CallStub(glue, gate, id, args);
2037     acc_.ReplaceGate(gate, builder_.GetStateDepend(), ret);
2038 }
2039 
LowerDateGetTime(GateRef gate)2040 void TypedNativeInlineLowering::LowerDateGetTime(GateRef gate)
2041 {
2042     Environment env(gate, circuit_, &builder_);
2043     GateRef obj = acc_.GetValueIn(gate, 0);
2044     GateRef glue = glue_;
2045     GateRef dateValueOffset = builder_.IntPtr(JSDate::TIME_VALUE_OFFSET);
2046     GateRef result = builder_.Load(VariableType::JS_ANY(), glue, obj, dateValueOffset);
2047     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
2048 }
2049 
LowerGeneralWithoutArgs(GateRef gate,RuntimeStubCSigns::ID stubId)2050 void TypedNativeInlineLowering::LowerGeneralWithoutArgs(GateRef gate, RuntimeStubCSigns::ID stubId)
2051 {
2052     Environment env(gate, circuit_, &builder_);
2053     GateRef glue = glue_;
2054     GateRef result = builder_.CallNGCRuntime(glue, stubId, Gate::InvalidGateRef, {glue}, gate);
2055     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
2056 }
2057 
LowerBigIntConstructor(GateRef gate)2058 void TypedNativeInlineLowering::LowerBigIntConstructor(GateRef gate)
2059 {
2060     Environment env(gate, circuit_, &builder_);
2061     Label hasException(&builder_);
2062     Label exit(&builder_);
2063     GateRef value = acc_.GetValueIn(gate, 0);
2064     GateRef glue = glue_;
2065     auto result = builder_.CallRuntime(glue, RTSTUB_ID(BigIntConstructor), Gate::InvalidGateRef, {value}, gate);
2066     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
2067 }
2068 
2069 template <bool IS_SIGNED>
LowerBigIntConstructorInt32(GateRef gate)2070 void TypedNativeInlineLowering::LowerBigIntConstructorInt32(GateRef gate)
2071 {
2072     Environment env(gate, circuit_, &builder_);
2073     GateRef value = acc_.GetValueIn(gate, 0);
2074     size_t length = 1;
2075     size_t size = AlignUp(BigInt::ComputeSize(length), static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
2076     GateRef sizeGate = builder_.IntPtr(size);
2077     GateRef hclass = builder_.GetGlobalConstantValue(ConstantIndex::BIGINT_CLASS_INDEX);
2078     GateRef sign = builder_.Int32(0);
2079     if constexpr (IS_SIGNED) {
2080         sign = builder_.Int32LSR(value, builder_.Int32(JSTaggedValue::INT_SIGN_BIT_OFFSET));
2081         auto temp = builder_.Int32ASR(value, builder_.Int32(JSTaggedValue::INT_SIGN_BIT_OFFSET));
2082         value = builder_.Int32Sub(builder_.Int32Xor(value, temp), temp);
2083     }
2084 
2085     // looks like code from StartAllocate to FinishAllocate must be linear
2086     builder_.StartAllocate();
2087     GateRef object = builder_.HeapAlloc(glue_, sizeGate, GateType::TaggedValue(),
2088                                         RegionSpaceFlag::IN_SHARED_NON_MOVABLE);
2089     // initialization
2090     GateRef glue = glue_;
2091     builder_.StoreHClass(glue, object, hclass, MemoryAttribute::NeedBarrierAndAtomic());
2092     builder_.StoreConstOffset(VariableType::INT32(), object, BigInt::LENGTH_OFFSET, builder_.Int32(length));
2093     builder_.StoreConstOffset(VariableType::INT32(), object, BigInt::BIT_FIELD_OFFSET, sign);
2094     builder_.StoreConstOffset(VariableType::INT32(), object, BigInt::DATA_OFFSET, value);
2095     GateRef ret = builder_.FinishAllocate(object);
2096 
2097     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret);
2098 }
2099 
BuildTaggedPointerOverflowInt32(GateRef value)2100 GateRef TypedNativeInlineLowering::BuildTaggedPointerOverflowInt32(GateRef value)
2101 {
2102     GateRef intValue = builder_.ChangeFloat64ToInt32(
2103         builder_.CastInt64ToFloat64(builder_.ChangeTaggedPointerToInt64(value)));
2104     return builder_.BitOr(builder_.Int32LessThanOrEqual(intValue, builder_.Int32(INT32_MIN)),
2105                           builder_.Int32GreaterThanOrEqual(intValue, builder_.Int32(INT32_MAX)));
2106 }
2107 
LowerStringCharCodeAt(GateRef gate)2108 void TypedNativeInlineLowering::LowerStringCharCodeAt(GateRef gate)
2109 {
2110     Environment env(gate, circuit_, &builder_);
2111 
2112     GateRef thisValue = acc_.GetValueIn(gate, 0); // 0: first argument
2113     GateRef pos = acc_.GetValueIn(gate, 1); // 1: second argument
2114     GateRef glue = glue_;
2115     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2116     Label posIsValid(&builder_);
2117     Label posNotValid(&builder_);
2118     Label exit(&builder_);
2119 
2120     GateRef strLen = builder_.GetLengthFromString(thisValue);
2121     BRANCH_CIR(builder_.Int32UnsignedLessThan(pos, strLen), &posIsValid, &posNotValid);
2122     builder_.Bind(&posIsValid);
2123     {
2124         BuiltinsStringStubBuilder stringBuilder(builder_.GetCurrentEnvironment(), circuit_->GetGlobalEnvCache());
2125         result = stringBuilder.FastStringCharCodeAt(glue, thisValue, pos);
2126         builder_.Jump(&exit);
2127     }
2128     builder_.Bind(&posNotValid);
2129     {
2130         result = builder_.DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE));
2131         builder_.Jump(&exit);
2132     }
2133     builder_.Bind(&exit);
2134     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result);
2135 }
2136 
LowerStringSubstring(GateRef gate)2137 void TypedNativeInlineLowering::LowerStringSubstring(GateRef gate)
2138 {
2139     Environment env(gate, circuit_, &builder_);
2140 
2141     GateRef thisValue = acc_.GetValueIn(gate, 0); // 0: the first parameter
2142     GateRef startTag = acc_.GetValueIn(gate, 1); // 1: the second parameter
2143     GateRef endTag = acc_.GetValueIn(gate, 2); // 2: the third parameter
2144     GateRef glue = glue_;
2145     DEFVALUE(result, (&builder_), VariableType::JS_POINTER(), builder_.Int32ToTaggedPtr(builder_.Int32(-1)));
2146     DEFVALUE(start, (&builder_), VariableType::INT32(), builder_.Int32(0));
2147     DEFVALUE(end, (&builder_), VariableType::INT32(), builder_.Int32(0));
2148     DEFVALUE(from, (&builder_), VariableType::INT32(), builder_.Int32(0));
2149     DEFVALUE(to, (&builder_), VariableType::INT32(), builder_.Int32(0));
2150     Label next(&builder_);
2151     Label countStart(&builder_);
2152     Label startTagIsInt(&builder_);
2153     Label startTagNotInt(&builder_);
2154     Label endTagIsInt(&builder_);
2155     Label endTagNotInt(&builder_);
2156     GateRef length = builder_.GetLengthFromString(thisValue);
2157 
2158     if (acc_.GetMachineType(startTag) == MachineType::I64) {
2159         BRANCH_CIR(builder_.TaggedIsInt(startTag), &startTagIsInt, &startTagNotInt);
2160         builder_.Bind(&startTagIsInt);
2161         start = builder_.GetInt32OfTInt(startTag);
2162         builder_.Jump(&next);
2163         builder_.Bind(&startTagNotInt);
2164         {
2165             start = builder_.SaturateTruncDoubleToInt32(glue, builder_.GetDoubleOfTDouble(startTag));
2166             builder_.Jump(&next);
2167         }
2168     } else {
2169         start = NumberToInt32(startTag);
2170         builder_.Jump(&next);
2171     }
2172     builder_.Bind(&next);
2173     {
2174         if (acc_.GetMachineType(endTag) == MachineType::I64) {
2175             BRANCH_CIR(builder_.TaggedIsInt(endTag), &endTagIsInt, &endTagNotInt);
2176             builder_.Bind(&endTagIsInt);
2177             end = builder_.GetInt32OfTInt(endTag);
2178             builder_.Jump(&countStart);
2179             builder_.Bind(&endTagNotInt);
2180             {
2181                 end = builder_.SaturateTruncDoubleToInt32(glue, builder_.GetDoubleOfTDouble(endTag));
2182                 builder_.Jump(&countStart);
2183             }
2184         } else {
2185             end = NumberToInt32(endTag);
2186             builder_.Jump(&countStart);
2187         }
2188     }
2189     builder_.Bind(&countStart);
2190     GateRef zero = builder_.Int32(0);
2191     GateRef finalStart = BuildIntMinMax<false>(BuildIntMinMax<true>(*start, zero), length);
2192     GateRef finalEnd = BuildIntMinMax<false>(BuildIntMinMax<true>(*end, zero), length);
2193     from = BuildIntMinMax<false>(finalStart, finalEnd);
2194     to = BuildIntMinMax<true>(finalStart, finalEnd);
2195     const CallSignature *cs = BuiltinsStubCSigns::Get(BuiltinsStubCSigns::ID::StringSubstring);
2196     BuiltinsStringStubBuilder stringBuilder(const_cast<CallSignature *>(cs), &env, circuit_->GetGlobalEnvCache());
2197     GateRef len = builder_.Int32Sub(*to, *from);
2198     result = stringBuilder.GetSubString(glue, thisValue, *from, len);
2199     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2200 }
2201 
LowerStringSubStr(GateRef gate)2202 void TypedNativeInlineLowering::LowerStringSubStr(GateRef gate)
2203 {
2204     Environment env(gate, circuit_, &builder_);
2205 
2206     GateRef thisValue = acc_.GetValueIn(gate, 0); // 0: the first parameter
2207     GateRef intStart = acc_.GetValueIn(gate, 1); // 1: the second parameter
2208     GateRef lengthTag = acc_.GetValueIn(gate, 2); // 2: the third parameter
2209     GateRef glue = glue_;
2210     DEFVALUE(result, (&builder_), VariableType::JS_POINTER(), builder_.Undefined());
2211     DEFVALUE(start, (&builder_), VariableType::INT32(), builder_.Int32(0));
2212     DEFVALUE(end, (&builder_), VariableType::INT32(), builder_.Int32(0));
2213     DEFVALUE(resultLength, (&builder_), VariableType::INT32(), builder_.Int32(0));
2214     Label exit(&builder_);
2215     Label next(&builder_);
2216     Label intStartIsInt(&builder_);
2217     Label intStartNotInt(&builder_);
2218     Label lengthTagIsInt(&builder_);
2219     Label lengthTagNotInt(&builder_);
2220     Label startLessZero(&builder_);
2221     Label countStart(&builder_);
2222     Label countResultLength(&builder_);
2223     Label countResult(&builder_);
2224     GateRef length = builder_.GetLengthFromString(thisValue);
2225 
2226     if (acc_.GetMachineType(intStart) == MachineType::I64) {
2227         BRANCH_CIR(builder_.TaggedIsInt(intStart), &intStartIsInt, &intStartNotInt);
2228         builder_.Bind(&intStartIsInt);
2229         start = builder_.GetInt32OfTInt(intStart);
2230         builder_.Jump(&next);
2231         builder_.Bind(&intStartNotInt);
2232         {
2233             start = builder_.SaturateTruncDoubleToInt32(glue, builder_.GetDoubleOfTDouble(intStart));
2234             builder_.Jump(&next);
2235         }
2236     } else {
2237         start = NumberToInt32(intStart);
2238         builder_.Jump(&next);
2239     }
2240     builder_.Bind(&next);
2241     {
2242         if (acc_.GetMachineType(lengthTag) == MachineType::I64) {
2243             BRANCH_CIR(builder_.TaggedIsInt(lengthTag), &lengthTagIsInt, &lengthTagNotInt);
2244             builder_.Bind(&lengthTagIsInt);
2245             end = builder_.GetInt32OfTInt(lengthTag);
2246             builder_.Jump(&countStart);
2247             builder_.Bind(&lengthTagNotInt);
2248             {
2249                 end = builder_.SaturateTruncDoubleToInt32(glue, builder_.GetDoubleOfTDouble(lengthTag));
2250                 builder_.Jump(&countStart);
2251             }
2252         } else {
2253             end = NumberToInt32(lengthTag);
2254             builder_.Jump(&countStart);
2255         }
2256     }
2257     builder_.Bind(&countStart);
2258     GateRef zero = builder_.Int32(0);
2259     BRANCH_CIR(builder_.Int32LessThan(*start, zero), &startLessZero, &countResultLength);
2260     builder_.Bind(&startLessZero);
2261     {
2262         GateRef tempStart = *start;
2263         start = BuildIntMinMax<true>(builder_.Int32Add(length, tempStart), zero);
2264         builder_.Jump(&countResultLength);
2265     }
2266     builder_.Bind(&countResultLength);
2267     {
2268         resultLength = BuildIntMinMax<false>(BuildIntMinMax<true>(*end, zero), builder_.Int32Sub(length, *start));
2269         builder_.Jump(&countResult);
2270     }
2271     builder_.Bind(&countResult);
2272     {
2273         Label resLenLessOrEqualZero(&builder_);
2274         Label resLenNotLessOrEqualZero(&builder_);
2275         builder_.Branch(builder_.Int32LessThanOrEqual(*resultLength, zero),
2276             &resLenLessOrEqualZero, &resLenNotLessOrEqualZero);
2277         builder_.Bind(&resLenLessOrEqualZero);
2278         {
2279             result = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
2280             builder_.Jump(&exit);
2281         }
2282         builder_.Bind(&resLenNotLessOrEqualZero);
2283         {
2284             const CallSignature *cs = BuiltinsStubCSigns::Get(BuiltinsStubCSigns::ID::StringSubStr);
2285             BuiltinsStringStubBuilder stringBuilder(const_cast<CallSignature *>(cs), &env,
2286                                                     circuit_->GetGlobalEnvCache());
2287             result = stringBuilder.GetFastSubString(glue, thisValue, *start, *resultLength);
2288             builder_.Jump(&exit);
2289         }
2290     }
2291     builder_.Bind(&exit);
2292     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2293 }
2294 
LowerStringSlice(GateRef gate)2295 void TypedNativeInlineLowering::LowerStringSlice(GateRef gate)
2296 {
2297     Environment env(gate, circuit_, &builder_);
2298 
2299     GateRef thisValue = acc_.GetValueIn(gate, 0); // 0: the first parameter
2300     GateRef startTag = acc_.GetValueIn(gate, 1); // 1: the second parameter
2301     GateRef endTag = acc_.GetValueIn(gate, 2); // 2: the third parameter
2302     GateRef glue = glue_;
2303     DEFVALUE(result, (&builder_), VariableType::JS_POINTER(), builder_.Undefined());
2304     DEFVALUE(start, (&builder_), VariableType::INT32(), builder_.Int32(0));
2305     DEFVALUE(end, (&builder_), VariableType::INT32(), builder_.Int32(0));
2306     DEFVALUE(from, (&builder_), VariableType::INT32(), builder_.Int32(0));
2307     DEFVALUE(to, (&builder_), VariableType::INT32(), builder_.Int32(0));
2308     Label exit(&builder_);
2309     Label next(&builder_);
2310     Label startTagIsInt(&builder_);
2311     Label startTagNotInt(&builder_);
2312     Label endTagIsInt(&builder_);
2313     Label endTagNotInt(&builder_);
2314     Label countStart(&builder_);
2315     Label countRes(&builder_);
2316     Label getTo(&builder_);
2317     Label startLessThanZero(&builder_);
2318     Label startNotLessThanZero(&builder_);
2319     GateRef length = builder_.GetLengthFromString(thisValue);
2320 
2321     if (acc_.GetMachineType(startTag) == MachineType::I64) {
2322         BRANCH_CIR(builder_.TaggedIsInt(startTag), &startTagIsInt, &startTagNotInt);
2323         builder_.Bind(&startTagIsInt);
2324         start = builder_.GetInt32OfTInt(startTag);
2325         builder_.Jump(&next);
2326         builder_.Bind(&startTagNotInt);
2327         {
2328             start = builder_.SaturateTruncDoubleToInt32(glue, builder_.GetDoubleOfTDouble(startTag));
2329             builder_.Jump(&next);
2330         }
2331     } else {
2332         start = NumberToInt32(startTag);
2333         builder_.Jump(&next);
2334     }
2335     builder_.Bind(&next);
2336     {
2337         if (acc_.GetMachineType(endTag) == MachineType::I64) {
2338             BRANCH_CIR(builder_.TaggedIsInt(endTag), &endTagIsInt, &endTagNotInt);
2339             builder_.Bind(&endTagIsInt);
2340             end = builder_.GetInt32OfTInt(endTag);
2341             builder_.Jump(&countStart);
2342             builder_.Bind(&endTagNotInt);
2343             end = builder_.SaturateTruncDoubleToInt32(glue, builder_.GetDoubleOfTDouble(endTag));
2344             builder_.Jump(&countStart);
2345         } else {
2346             end = NumberToInt32(endTag);
2347             builder_.Jump(&countStart);
2348         }
2349     }
2350     builder_.Bind(&countStart);
2351     GateRef zero = builder_.Int32(0);
2352     BRANCH_CIR(builder_.Int32LessThan(*start, zero), &startLessThanZero, &startNotLessThanZero);
2353     builder_.Bind(&startLessThanZero);
2354     {
2355         from = BuildIntMinMax<true>(builder_.Int32Add(length, *start), zero);
2356         builder_.Jump(&getTo);
2357     }
2358     builder_.Bind(&startNotLessThanZero);
2359     {
2360         from = BuildIntMinMax<false>(length, *start);
2361         builder_.Jump(&getTo);
2362     }
2363     builder_.Bind(&getTo);
2364     {
2365         Label endLessThanZero(&builder_);
2366         Label endNotLessThanZero(&builder_);
2367         BRANCH_CIR(builder_.Int32LessThan(*end, zero), &endLessThanZero, &endNotLessThanZero);
2368         builder_.Bind(&endLessThanZero);
2369         {
2370             to = BuildIntMinMax<true>(builder_.Int32Add(length, *end), zero);
2371             builder_.Jump(&countRes);
2372         }
2373         builder_.Bind(&endNotLessThanZero);
2374         {
2375             to = BuildIntMinMax<false>(length, *end);
2376             builder_.Jump(&countRes);
2377         }
2378         builder_.Bind(&countRes);
2379         {
2380             Label fromLessThanTo(&builder_);
2381             Label fromNotLessThanTo(&builder_);
2382             BRANCH_CIR(builder_.Int32LessThan(*from, *to), &fromLessThanTo, &fromNotLessThanTo);
2383             builder_.Bind(&fromLessThanTo);
2384             {
2385                 const CallSignature *cs = BuiltinsStubCSigns::Get(BuiltinsStubCSigns::ID::StringSlice);
2386                 BuiltinsStringStubBuilder stringBuilder(const_cast<CallSignature *>(cs), &env,
2387                                                         circuit_->GetGlobalEnvCache());
2388                 GateRef len = builder_.Int32Sub(*to, *from);
2389                 result = stringBuilder.GetSubString(glue, thisValue, *from, len);
2390                 builder_.Jump(&exit);
2391             }
2392             builder_.Bind(&fromNotLessThanTo);
2393             {
2394                 result = builder_.GetGlobalConstantValue(ConstantIndex::EMPTY_STRING_OBJECT_INDEX);
2395                 builder_.Jump(&exit);
2396             }
2397         }
2398     }
2399     builder_.Bind(&exit);
2400     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2401 }
2402 
NumberToInt32(GateRef gate)2403 GateRef TypedNativeInlineLowering::NumberToInt32(GateRef gate)
2404 {
2405     auto machineType = acc_.GetMachineType(gate);
2406     switch (machineType) {
2407         case MachineType::I32:
2408             return gate;
2409         case MachineType::F64:
2410             if (isLiteCG_) {
2411                 return builder_.ChangeFloat64ToInt32(gate);
2412             } else {
2413                 GateRef glue = glue_;
2414                 return builder_.SaturateTruncDoubleToInt32(glue, gate);
2415             }
2416         case MachineType::I1:
2417             return builder_.ZExtInt1ToInt32(gate);
2418         default:
2419             LOG_COMPILER(ERROR) << "Not Number Type";
2420             break;
2421     }
2422     return Circuit::NullGate();
2423 }
2424 
LowerObjectIs(GateRef gate)2425 void TypedNativeInlineLowering::LowerObjectIs(GateRef gate)
2426 {
2427     Environment env(gate, circuit_, &builder_);
2428     GateRef left = acc_.GetValueIn(gate, 0);
2429     GateRef right = acc_.GetValueIn(gate, 1);
2430     GateRef result = Circuit::NullGate();
2431 
2432     if (left == right) {
2433         result = builder_.TaggedTrue();
2434     } else if (TypeInfoAccessor::IsTrustedNotSameType(compilationEnv_, circuit_, chunk_, acc_, left, right)) {
2435         result = builder_.TaggedFalse();
2436     } else {
2437         GateRef glue = glue_;
2438         GateRef boolRet = builder_.CallStub(glue, gate, CommonStubCSigns::SameValue,
2439                                             {glue, left, right, circuit_->GetGlobalEnvCache()});
2440         result = builder_.BooleanToTaggedBooleanPtr(boolRet);
2441     }
2442 
2443     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
2444 }
2445 
LowerObjectGetPrototypeOf(GateRef gate)2446 void TypedNativeInlineLowering::LowerObjectGetPrototypeOf(GateRef gate)
2447 {
2448     Environment env(gate, circuit_, &builder_);
2449     GateRef glue = glue_;
2450     GateRef value = acc_.GetValueIn(gate, 0);
2451     GateRef result = Circuit::NullGate();
2452 
2453     GateRef globalEnv = circuit_->GetGlobalEnvCache();
2454     // fast handle some primitive types
2455     if (TypeInfoAccessor::IsTrustedBooleanOrNumberOrStringType(compilationEnv_, circuit_, chunk_, acc_, value)) {
2456         size_t index = -1;
2457         if (TypeInfoAccessor::IsTrustedBooleanType(acc_, value)) {
2458             index = GlobalEnv::BOOLEAN_PROTOTYPE_INDEX;
2459         } else if (TypeInfoAccessor::IsTrustedNumberType(acc_, value)) {
2460             index = GlobalEnv::NUMBER_PROTOTYPE_INDEX;
2461         } else {
2462             ASSERT(TypeInfoAccessor::IsTrustedStringType(compilationEnv_, circuit_, chunk_, acc_, value));
2463             index = GlobalEnv::STRING_PROTOTYPE_INDEX;
2464         }
2465         result = builder_.GetGlobalEnvValue(VariableType::JS_ANY(), glue, globalEnv, index);
2466     } else {
2467         GateRef object = builder_.ToObject(glue, globalEnv, value);
2468         result = builder_.GetPrototype(glue, object);
2469     }
2470 
2471     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
2472 }
2473 
LowerObjectCreate(GateRef gate)2474 void TypedNativeInlineLowering::LowerObjectCreate(GateRef gate)
2475 {
2476     Environment env(gate, circuit_, &builder_);
2477     GateRef glue = glue_;
2478     GateRef proto = acc_.GetValueIn(gate, 0);
2479     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2480 
2481     Label exception(&builder_);
2482     Label create(&builder_);
2483     Label exit(&builder_);
2484     GateRef protoCheck = LogicAndBuilder(&env)
2485         .And(builder_.BoolNot(builder_.IsEcmaObject(glue, proto)))
2486         .And(builder_.BoolNot(builder_.TaggedIsNull(proto)))
2487         .Done();
2488     protoCheck = LogicOrBuilder(&env).Or(protoCheck).Or(builder_.TaggedIsSharedObj(glue, proto)).Done();
2489     BRANCH_CIR(protoCheck,  &exception, &create);
2490     builder_.Bind(&exception);
2491     {
2492         GateRef taggedId = builder_.Int32(GET_MESSAGE_STRING_ID(CanNotConvertNotValidObject));
2493         builder_.CallRuntime(glue, RTSTUB_ID(ThrowTypeError), Gate::InvalidGateRef,
2494                              { builder_.Int32ToTaggedInt(taggedId) }, gate);
2495         result = builder_.ExceptionConstant();
2496         builder_.Jump(&exit);
2497     }
2498     builder_.Bind(&create);
2499     {
2500         result = builder_.OrdinaryNewJSObjectCreate(glue, proto);
2501         builder_.Jump(&exit);
2502     }
2503     builder_.Bind(&exit);
2504     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2505 }
2506 
LowerObjectIsPrototypeOf(GateRef gate)2507 void TypedNativeInlineLowering::LowerObjectIsPrototypeOf(GateRef gate)
2508 {
2509     Environment env(gate, circuit_, &builder_);
2510     GateRef glue = glue_;
2511     GateRef thisValue = acc_.GetValueIn(gate, 0);
2512     GateRef value = acc_.GetValueIn(gate, 1);
2513     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.TaggedFalse());
2514 
2515     // 1. If Type(V) is not Object, return false.
2516     Label ecmaObject(&builder_);
2517     Label returnFalse(&builder_);
2518     Label returnException(&builder_);
2519     Label exit(&builder_);
2520     BRANCH_CIR(builder_.IsEcmaObject(glue, value), &ecmaObject, &returnFalse);
2521     builder_.Bind(&ecmaObject);
2522     {
2523         // 2. Let O be ? ToObject(this value).
2524         GateRef obj = builder_.ToObject(glue, circuit_->GetGlobalEnvCache(), thisValue);
2525         Label noPendingException(&builder_);
2526         BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_), &returnException, &noPendingException);
2527         builder_.Bind(&noPendingException);
2528         {
2529             // 3. Repeat,
2530             //    a. Set V to ? V.[[GetPrototypeOf]]().
2531             //    b. If V is null, return false.
2532             //    c. If SameValue(O, V) is true, return true.
2533             DEFVALUE(proto, (&builder_), VariableType::JS_ANY(), value);
2534             Label loopHead(&builder_);
2535             Label loopEnd(&builder_);
2536             Label loopExit(&builder_);
2537             Label compare(&builder_);
2538             builder_.Jump(&loopHead);
2539             builder_.LoopBegin(&loopHead);
2540             {
2541                 BRANCH_CIR(builder_.TaggedIsNotNull(*proto), &compare, &loopExit);
2542                 builder_.Bind(&compare);
2543                 {
2544                     proto = builder_.GetPrototype(glue, *proto);
2545                     Label noPendingException1(&builder_);
2546                     BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_),
2547                                &returnException, &noPendingException1);
2548                     builder_.Bind(&noPendingException1);
2549                     {
2550                         Label sameValue(&builder_);
2551                         GateRef same = builder_.CallStub(glue, gate, CommonStubCSigns::SameValue,
2552                                                          {glue, obj, *proto, circuit_->GetGlobalEnvCache()});
2553                         BRANCH_CIR(same, &sameValue, &loopEnd);
2554                         builder_.Bind(&sameValue);
2555                         {
2556                             result = builder_.TaggedTrue();
2557                             builder_.Jump(&exit);
2558                         }
2559                     }
2560                 }
2561             }
2562             builder_.Bind(&loopEnd);
2563             builder_.LoopEnd(&loopHead);
2564             builder_.Bind(&loopExit);
2565             {
2566                 builder_.Jump(&exit);
2567             }
2568         }
2569     }
2570     builder_.Bind(&returnFalse);
2571     {
2572         result = builder_.TaggedFalse();
2573         builder_.Jump(&exit);
2574     }
2575     builder_.Bind(&returnException);
2576     {
2577         result = builder_.ExceptionConstant();
2578         builder_.Jump(&exit);
2579     }
2580     builder_.Bind(&exit);
2581     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2582 }
2583 
LowerObjectHasOwnProperty(GateRef gate)2584 void TypedNativeInlineLowering::LowerObjectHasOwnProperty(GateRef gate)
2585 {
2586     Environment env(gate, circuit_, &builder_);
2587     GateRef glue = glue_;
2588     GateRef thisValue = acc_.GetValueIn(gate, 0);
2589     GateRef key = acc_.GetValueIn(gate, 1);
2590     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.TaggedFalse());
2591     Label callRuntime(&builder_);
2592     Label exit(&builder_);
2593     BuiltinsObjectStubBuilder objectStubBuilder(&env, glue, circuit_->GetGlobalEnvCache());
2594     objectStubBuilder.HasOwnProperty(&result, &exit, &callRuntime, thisValue, key, gate);
2595     builder_.Bind(&callRuntime);
2596     {
2597         result = builder_.CallRuntime(glue, RTSTUB_ID(ObjectPrototypeHasOwnProperty), Gate::InvalidGateRef,
2598                                       { thisValue, key }, gate);
2599         builder_.Jump(&exit);
2600     }
2601     builder_.Bind(&exit);
2602     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2603 }
2604 
LowerReflectGetPrototypeOf(GateRef gate)2605 void TypedNativeInlineLowering::LowerReflectGetPrototypeOf(GateRef gate)
2606 {
2607     Environment env(gate, circuit_, &builder_);
2608     GateRef glue = glue_;
2609     GateRef value = acc_.GetValueIn(gate, 0);
2610     GateRef result = builder_.GetPrototype(glue, value);  // Do not ToObject
2611     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
2612 }
2613 
LowerReflectGet(GateRef gate)2614 void TypedNativeInlineLowering::LowerReflectGet(GateRef gate)
2615 {
2616     Environment env(gate, circuit_, &builder_);
2617     GateRef glue = glue_;
2618     GateRef target = acc_.GetValueIn(gate, 0);
2619     GateRef key = acc_.GetValueIn(gate, 1);  // key is trusted string
2620     Label isEcmaObject(&builder_);
2621     Label notEcmaObject(&builder_);
2622     Label exit(&builder_);
2623     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
2624     // 1. If Type(target) is not Object, throw a TypeError exception.
2625     BRANCH_CIR(builder_.IsEcmaObject(glue, target), &isEcmaObject, &notEcmaObject);
2626     builder_.Bind(&isEcmaObject);
2627     {
2628         result = builder_.CallStub(glue, gate, CommonStubCSigns::DeprecatedGetPropertyByName,  // no ic
2629                                    {glue, target, key, circuit_->GetGlobalEnvCache()});
2630         builder_.Jump(&exit);
2631     }
2632     builder_.Bind(&notEcmaObject);
2633     {
2634         GateRef taggedId = builder_.Int32(GET_MESSAGE_STRING_ID(TargetTypeNotObject));
2635         builder_.CallRuntime(glue, RTSTUB_ID(ThrowTypeError), Gate::InvalidGateRef,
2636                              { builder_.Int32ToTaggedInt(taggedId) }, gate);
2637         result = builder_.ExceptionConstant();
2638         builder_.Jump(&exit);
2639     }
2640     builder_.Bind(&exit);
2641     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2642 }
2643 
LowerReflectHas(GateRef gate)2644 void TypedNativeInlineLowering::LowerReflectHas(GateRef gate)
2645 {
2646     Environment env(gate, circuit_, &builder_);
2647     GateRef glue = glue_;
2648     GateRef target = acc_.GetValueIn(gate, 0);
2649     GateRef key = acc_.GetValueIn(gate, 1);
2650     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.TaggedFalse());
2651     Label afterHasOwn(&builder_);
2652     Label callRuntime(&builder_);
2653     Label exit(&builder_);
2654     BuiltinsObjectStubBuilder objectStubBuilder(&env, glue, circuit_->GetGlobalEnvCache());
2655     objectStubBuilder.HasOwnProperty(&result, &afterHasOwn, &callRuntime, target, key, gate);
2656     builder_.Bind(&afterHasOwn);
2657     {
2658         BRANCH_CIR(builder_.TaggedIsTrue(*result), &exit, &callRuntime);
2659     }
2660     builder_.Bind(&callRuntime);
2661     {
2662         result = builder_.CallRuntime(glue, RTSTUB_ID(ReflectHas), Gate::InvalidGateRef, { target, key }, gate);
2663         builder_.Jump(&exit);
2664     }
2665     builder_.Bind(&exit);
2666     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2667 }
2668 
LowerReflectConstruct(GateRef gate)2669 void TypedNativeInlineLowering::LowerReflectConstruct(GateRef gate)
2670 {
2671     Environment env(gate, circuit_, &builder_);
2672     GateRef glue = glue_;
2673     GateRef target = acc_.GetValueIn(gate, 0);
2674     GateRef thisObj = builder_.CallStub(glue, gate, CommonStubCSigns::NewThisObjectChecked, { glue, target });
2675     Label callCtor(&builder_);
2676     Label callRuntime(&builder_);
2677     Label exit(&builder_);
2678     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
2679     BRANCH_CIR(builder_.TaggedIsHole(thisObj), &callRuntime, &callCtor);
2680     builder_.Bind(&callCtor);
2681     {
2682         std::vector<GateRef> args { glue, builder_.Int64(NUM_MANDATORY_JSFUNC_ARGS), builder_.IntPtr(0),
2683                                     target, target, thisObj };
2684         result = builder_.Construct(gate, args);
2685         builder_.Jump(&exit);
2686     }
2687     builder_.Bind(&callRuntime);
2688     {
2689         result = builder_.CallRuntime(glue, RTSTUB_ID(ReflectConstruct), Gate::InvalidGateRef, { target }, gate);
2690         builder_.Jump(&exit);
2691     }
2692     builder_.Bind(&exit);
2693     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
2694 }
2695 
LowerReflectApply(GateRef gate)2696 void TypedNativeInlineLowering::LowerReflectApply(GateRef gate)
2697 {
2698     Environment env(gate, circuit_, &builder_);
2699     GateRef glue = glue_;
2700     GateRef target = acc_.GetValueIn(gate, 0);
2701     GateRef thisValue = acc_.GetValueIn(gate, 1);
2702     GateRef argumentsList = acc_.GetValueIn(gate, 2);
2703     GateRef result = builder_.CallRuntime(glue, RTSTUB_ID(ReflectApply), Gate::InvalidGateRef,
2704                                           { target, thisValue, argumentsList }, gate);
2705     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
2706 }
2707 
LowerFunctionPrototypeApply(GateRef gate)2708 void TypedNativeInlineLowering::LowerFunctionPrototypeApply(GateRef gate)
2709 {
2710     Environment env(gate, circuit_, &builder_);
2711     GateRef glue = glue_;
2712     GateRef thisFunc = acc_.GetValueIn(gate, 0);
2713     GateRef thisArg = acc_.GetValueIn(gate, 1);
2714     GateRef argArray = acc_.GetValueIn(gate, 2);
2715     GateRef result = builder_.CallRuntime(glue, RTSTUB_ID(FunctionPrototypeApply), Gate::InvalidGateRef,
2716                                           { thisFunc, thisArg, argArray }, gate);
2717     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
2718 }
2719 
LowerFunctionPrototypeBind(GateRef gate)2720 void TypedNativeInlineLowering::LowerFunctionPrototypeBind(GateRef gate)
2721 {
2722     Environment env(gate, circuit_, &builder_);
2723     GateRef glue = glue_;
2724     GateRef target = acc_.GetValueIn(gate, 0);
2725     GateRef thisArg = acc_.GetValueIn(gate, 1);
2726     GateRef result = builder_.CallRuntime(glue, RTSTUB_ID(FunctionPrototypeBind), Gate::InvalidGateRef,
2727                                           { target, thisArg }, gate);
2728     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
2729 }
2730 
LowerFunctionPrototypeCall(GateRef gate)2731 void TypedNativeInlineLowering::LowerFunctionPrototypeCall(GateRef gate)
2732 {
2733     Environment env(gate, circuit_, &builder_);
2734     std::vector<GateRef> args = acc_.GetValueIns(gate);
2735     GateRef result = builder_.CallRuntime(glue_, RTSTUB_ID(FunctionPrototypeCall), Gate::InvalidGateRef, args, gate);
2736     acc_.ReplaceGate(gate, builder_.GetStateDepend(), result);
2737 }
2738 
LowerArrayIncludesIndexOf(GateRef gate)2739 void TypedNativeInlineLowering::LowerArrayIncludesIndexOf(GateRef gate)
2740 {
2741     Environment env(gate, circuit_, &builder_);
2742     Label exit(&builder_);
2743     GateRef glue = glue_;
2744     BuiltinsArrayStubBuilder stubBuilder(&env, circuit_->GetGlobalEnvCache());
2745 
2746     using Indices = CircuitArgIndices::ArrayIncludesIndexOf;
2747     GateRef elements = acc_.GetValueIn(gate, Indices::ELEMENTS);
2748     GateRef target = acc_.GetValueIn(gate, Indices::TARGET);
2749     GateRef fromIndex = acc_.GetValueIn(gate, Indices::FROM_INDEX);
2750     GateRef len = acc_.GetValueIn(gate, Indices::LENGTH);
2751     GateRef callIDRef = acc_.GetValueIn(gate, Indices::CALL_ID);
2752     GateRef kindRef = acc_.GetValueIn(gate, Indices::ARRAY_KIND);
2753 
2754     ElementsKind kind = static_cast<ElementsKind>(acc_.GetConstantValue(kindRef));
2755     BuiltinsStubCSigns::ID callID = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(callIDRef));
2756     auto options = stubBuilder.MakeIndexOfOptions(callID, false);
2757     Variable res = stubBuilder.MakeResultVariableDefaultNotFound(options);
2758 
2759     Label arrayIsNotEmpty(&builder_);
2760     Label searchRangeIsNotEmpty(&builder_);
2761     BRANCH_CIR_UNLIKELY(builder_.Int32Equal(builder_.Int32(0), len), &exit, &arrayIsNotEmpty);
2762     builder_.Bind(&arrayIsNotEmpty);
2763     if (options.reversedOrder) {
2764         BRANCH_CIR_UNLIKELY(builder_.Int64LessThan(fromIndex, builder_.Int64(0)), &exit, &searchRangeIsNotEmpty);
2765     } else {
2766         GateRef exitCond = builder_.Int64GreaterThanOrEqual(fromIndex, builder_.ZExtInt32ToInt64(len));
2767         BRANCH_CIR_UNLIKELY(exitCond, &exit, &searchRangeIsNotEmpty)
2768     }
2769 
2770     builder_.Bind(&searchRangeIsNotEmpty);
2771     // todo: Branches for mutant tagged array (with raw int32 or raw double values)?
2772     Label undefinedBranch(&builder_);
2773     Label targetIsNotUndefined(&builder_);
2774     BRANCH_CIR_UNLIKELY(builder_.TaggedIsUndefined(target), &undefinedBranch, &targetIsNotUndefined);
2775     builder_.Bind(&undefinedBranch);
2776     res = stubBuilder.IndexOfTaggedUndefined(glue, elements, fromIndex, len, options);
2777     builder_.Jump(&exit);
2778 
2779     builder_.Bind(&targetIsNotUndefined);
2780     switch (kind) {
2781         case ElementsKind::INT:
2782         case ElementsKind::HOLE_INT:
2783             res = stubBuilder.IndexOfTaggedIntElements(glue, elements, target, fromIndex, len, options);
2784             break;
2785         case ElementsKind::NUMBER:
2786         case ElementsKind::HOLE_NUMBER:
2787             res = stubBuilder.IndexOfTaggedNumber(glue, elements, target, fromIndex, len, options, false);
2788             break;
2789         case ElementsKind::STRING:
2790             using StringElementsCondition = BuiltinsArrayStubBuilder::StringElementsCondition;
2791             res = stubBuilder.IndexOfStringElements(glue, elements, target, fromIndex, len, options,
2792                 StringElementsCondition::MUST_BE_STRING);
2793             break;
2794         case ElementsKind::HOLE_STRING:
2795             res = stubBuilder.IndexOfStringElements(glue, elements, target, fromIndex, len, options,
2796                 StringElementsCondition::MAY_BE_HOLE);
2797             break;
2798         case ElementsKind::OBJECT:
2799         case ElementsKind::HOLE_OBJECT:
2800             res = stubBuilder.IndexOfBigIntOrObjectElements(glue, elements, target, fromIndex, len, options);
2801             break;
2802         default:
2803             res = stubBuilder.IndexOfGeneric(glue, elements, target, fromIndex, len, options);
2804             break;
2805     }
2806     builder_.Jump(&exit);
2807 
2808     builder_.Bind(&exit);
2809     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *res);
2810 }
2811 
LowerArrayIteratorBuiltin(GateRef gate)2812 void TypedNativeInlineLowering::LowerArrayIteratorBuiltin(GateRef gate)
2813 {
2814     Environment env(gate, circuit_, &builder_);
2815     GateRef thisArray = acc_.GetValueIn(gate, 0);
2816     GateRef callIDRef = acc_.GetValueIn(gate, 1);
2817     BuiltinsStubCSigns::ID callID = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(callIDRef));
2818     IterationKind iterationKind = GetArrayIterKindFromBuilin(callID);
2819 
2820     GateRef glue = glue_;
2821     GateRef globalEnv = circuit_->GetGlobalEnvCache();
2822     GateRef prototype = builder_.GetGlobalEnvValue(
2823         VariableType::JS_POINTER(), glue, globalEnv, GlobalEnv::ARRAY_ITERATOR_PROTOTYPE_INDEX);
2824 
2825     GateRef iteratorHClass = builder_.GetGlobalConstantValue(ConstantIndex::JS_ARRAY_ITERATOR_CLASS_INDEX);
2826     GateRef offset = builder_.IntPtr(JSHClass::PROTOTYPE_OFFSET);
2827     builder_.Store(VariableType::JS_POINTER(), glue, iteratorHClass, offset, prototype);
2828 
2829     GateRef result = AllocateArrayIterator(glue, thisArray, iteratorHClass, iterationKind);
2830     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result);
2831 }
2832 
GetArrayIterKindFromBuilin(BuiltinsStubCSigns::ID callID)2833 IterationKind TypedNativeInlineLowering::GetArrayIterKindFromBuilin(BuiltinsStubCSigns::ID callID)
2834 {
2835     switch (callID) {
2836         case BuiltinsStubCSigns::ID::ArrayEntries:
2837             return IterationKind::KEY_AND_VALUE;
2838         case BuiltinsStubCSigns::ID::ArrayKeys:
2839             return IterationKind::KEY;
2840         case BuiltinsStubCSigns::ID::ArrayValues:
2841             return IterationKind::VALUE;
2842         default:
2843             UNREACHABLE();
2844     }
2845 }
2846 
ReplaceGateWithPendingException(GateRef gate,GateRef glue,GateRef state,GateRef depend,GateRef value)2847 void TypedNativeInlineLowering::ReplaceGateWithPendingException(
2848     GateRef gate, GateRef glue, GateRef state, GateRef depend, GateRef value)
2849 {
2850     GateRef condition = builder_.HasPendingException(glue, compilationEnv_);
2851     auto ifBranch = builder_.Branch(state, condition, 1, BranchWeight::DEOPT_WEIGHT, "checkException");
2852     GateRef ifTrue = builder_.IfTrue(ifBranch);
2853     GateRef ifFalse = builder_.IfFalse(ifBranch);
2854     GateRef eDepend = builder_.DependRelay(ifTrue, depend);
2855     GateRef sDepend = builder_.DependRelay(ifFalse, depend);
2856     StateDepend success(ifFalse, sDepend);
2857     StateDepend exception(ifTrue, eDepend);
2858     acc_.ReplaceHirWithIfBranch(gate, success, exception, value);
2859 }
2860 
LowerArrayForEach(GateRef gate)2861 void TypedNativeInlineLowering::LowerArrayForEach(GateRef gate)
2862 {
2863     Environment env(gate, circuit_, &builder_);
2864     GateRef thisValue = acc_.GetValueIn(gate, 0);
2865     GateRef callBackFn = acc_.GetValueIn(gate, 1);
2866     GateRef usingThis = acc_.GetValueIn(gate, 2);
2867     GateRef glue = glue_;
2868     GateRef length = builder_.GetLengthOfJSArray(thisValue);
2869     Label loopHead(&builder_);
2870     Label loopEnd(&builder_);
2871     Label exit(&builder_);
2872     Label noPendingException(&builder_);
2873     Label merge(&builder_);
2874     DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
2875     DEFVALUE(propKey, (&builder_), VariableType::JS_ANY(), builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(*i)));
2876     DEFVALUE(value, (&builder_), VariableType::JS_ANY(), builder_.Hole());
2877     BRANCH_CIR(builder_.Int32LessThan(*i, length), &loopHead, &exit);
2878     builder_.LoopBegin(&loopHead);
2879     {
2880         GateRef element = builder_.LoadConstOffset(VariableType::JS_POINTER(), thisValue, JSObject::ELEMENTS_OFFSET);
2881         value = builder_.GetValueFromTaggedArray(glue, element, *i);
2882         GateRef nativeCall = builder_.CallInternal(gate,
2883                                                    {glue,
2884                                                     builder_.Int64(6),
2885                                                     builder_.IntPtr(0),
2886                                                     callBackFn,
2887                                                     builder_.Undefined(),
2888                                                     usingThis,
2889                                                     *value,
2890                                                     *propKey,
2891                                                     thisValue},
2892                                                    acc_.TryGetPcOffset(gate));
2893         builder_.SetDepend(nativeCall);
2894         BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_), &exit, &noPendingException);
2895         builder_.Bind(&noPendingException);
2896         {
2897             i = builder_.Int32Add(*i, builder_.Int32(1));
2898             propKey = builder_.ToTaggedIntPtr(builder_.SExtInt32ToInt64(*i));
2899             BRANCH_CIR(builder_.Int32LessThan(*i, length), &loopEnd, &exit);
2900         }
2901     }
2902     builder_.Bind(&loopEnd);
2903     builder_.LoopEnd(&loopHead);
2904 
2905     builder_.Bind(&exit);
2906     ReplaceGateWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), builder_.UndefineConstant());
2907 }
2908 
LowerArrayFindOrFindIndex(GateRef gate)2909 void TypedNativeInlineLowering::LowerArrayFindOrFindIndex(GateRef gate)
2910 {
2911     Environment env(gate, circuit_, &builder_);
2912     GateRef glue = glue_;
2913     BuiltinsArrayStubBuilder arrayBuilder(&env, circuit_->GetGlobalEnvCache());
2914     GateRef thisValue = acc_.GetValueIn(gate, 0);
2915     GateRef callBackFn = acc_.GetValueIn(gate, 1);
2916     GateRef usingThis = acc_.GetValueIn(gate, 2);
2917     GateRef builtinFunc = acc_.GetValueIn(gate, 3);
2918     auto builtinsID = static_cast<BuiltinsStubCSigns::ID>(acc_.GetConstantValue(builtinFunc));
2919     GateRef length = builder_.GetLengthOfJSArray(thisValue);
2920     Label loopHead(&builder_);
2921     Label loopEnd(&builder_);
2922     Label exit(&builder_);
2923     Label noFindElement(&builder_);
2924     Label findElement(&builder_);
2925     Label returnNotFind(&builder_);
2926     Label returnFind(&builder_);
2927     Label quit(&builder_);
2928     Label noPendingException(&builder_);
2929     DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
2930     DEFVALUE(value, (&builder_), VariableType::JS_ANY(), builder_.Hole());
2931     DEFVALUE(res, (&builder_), VariableType::INT32(), builder_.Int32(-1));
2932     DEFVALUE(findRes, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
2933     BRANCH_CIR(builder_.Int32LessThan(*i, length), &loopHead, &exit);
2934     builder_.LoopBegin(&loopHead);
2935     {
2936         GateRef element = builder_.LoadConstOffset(VariableType::JS_POINTER(), thisValue, JSObject::ELEMENTS_OFFSET);
2937         value = builder_.GetValueFromTaggedArray(glue, element, *i);
2938         GateRef nativeCall = builder_.CallInternal(gate,
2939                                                    {glue,
2940                                                     builder_.Int64(6),
2941                                                     builder_.IntPtr(0),
2942                                                     callBackFn,
2943                                                     builder_.Undefined(),
2944                                                     usingThis,
2945                                                     *value,
2946                                                     builder_.Int32ToTaggedPtr(*i),
2947                                                     thisValue},
2948                                                    acc_.TryGetPcOffset(gate));
2949         builder_.SetDepend(nativeCall);
2950         BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_), &exit, &noPendingException);
2951         builder_.Bind(&noPendingException);
2952         {
2953             BRANCH_CIR(builder_.TaggedIsTrue(builder_.FastToBoolean(glue, nativeCall)), &findElement, &noFindElement);
2954             builder_.Bind(&noFindElement);
2955             {
2956                 i = builder_.Int32Add(*i, builder_.Int32(1));
2957                 BRANCH_CIR(builder_.Int32LessThan(*i, length), &loopEnd, &exit);
2958             }
2959         }
2960     }
2961     builder_.Bind(&loopEnd);
2962     builder_.LoopEnd(&loopHead);
2963 
2964     builder_.Bind(&findElement);
2965     {
2966         res = *i;
2967         findRes = *value;
2968         builder_.Jump(&exit);
2969     }
2970     builder_.Bind(&exit);
2971     if (builtinsID == BuiltinsStubCSigns::ID::ArrayFind) {
2972         ReplaceGateWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *findRes);
2973     } else {
2974         ReplaceGateWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *res);
2975     }
2976 }
2977 
LowerArrayFilter(GateRef gate)2978 void TypedNativeInlineLowering::LowerArrayFilter(GateRef gate)
2979 {
2980     Environment env(gate, circuit_, &builder_);
2981     GateRef glue = glue_;
2982     BuiltinsArrayStubBuilder builtinsArrayStubBuilder(&env, circuit_->GetGlobalEnvCache());
2983     auto pcOffset = acc_.TryGetPcOffset(gate);
2984     GateRef thisValue = acc_.GetValueIn(gate, 0);
2985     GateRef callBackFn = acc_.GetValueIn(gate, 1);
2986     GateRef usingThis = acc_.GetValueIn(gate, 2);
2987     GateRef frameState = acc_.GetValueIn(gate, 3);
2988     GateRef length = builder_.SExtInt32ToInt64(builder_.GetLengthOfJSArray(thisValue));
2989     GateRef lengthOffset = builder_.IntPtr(JSArray::LENGTH_OFFSET);
2990 
2991     Label lengthIsZero(&builder_);
2992     Label lengthNotZero(&builder_);
2993     Label notHole(&builder_);
2994     Label loopHead(&builder_);
2995     Label loopEnd(&builder_);
2996     Label afterLoop(&builder_);
2997     Label returnTrue(&builder_);
2998     Label exit(&builder_);
2999     Label needTrim(&builder_);
3000     Label quit(&builder_);
3001     Label noPendingException(&builder_);
3002     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
3003     DEFVALUE(i, (&builder_), VariableType::INT64(), builder_.Int64(0));
3004     DEFVALUE(toIndex, (&builder_), VariableType::INT64(), builder_.Int64(0));
3005     DEFVALUE(propKey, (&builder_), VariableType::JS_ANY(), builder_.ToTaggedIntPtr(*i));
3006     DEFVALUE(kValue, (&builder_), VariableType::JS_ANY(), builder_.Hole());
3007     BRANCH_CIR(builder_.Int64Equal(length, builder_.Int64(0)), &lengthIsZero, &lengthNotZero)
3008     builder_.Bind(&lengthIsZero);
3009     {
3010         NewObjectStubBuilder newBuilder(&env, circuit_->GetGlobalEnvCache());
3011         result = newBuilder.CreateEmptyArray(glue);
3012         builder_.Jump(&quit);
3013     }
3014     builder_.Bind(&lengthNotZero);
3015     builder_.DeoptCheck(builder_.Int64LessThanOrEqual(length, builder_.Int64(JSObject::MAX_GAP)),
3016                         frameState,
3017                         DeoptType::ARRAYLENGTHOVERMAX);
3018     GateRef newArray = builtinsArrayStubBuilder.NewArray(glue, length);
3019     GateRef newArrayEles = builder_.GetElementsArray(glue, newArray);
3020     builder_.Jump(&loopHead);
3021     builder_.LoopBegin(&loopHead);
3022     {
3023         kValue = builtinsArrayStubBuilder.GetTaggedValueWithElementsKind(glue, thisValue, *i);
3024         GateRef callJs = builder_.CallInternal(gate,
3025                                                {glue,
3026                                                 builder_.Int64(6),
3027                                                 builder_.IntPtr(0),
3028                                                 callBackFn,
3029                                                 builder_.Undefined(),
3030                                                 usingThis,
3031                                                 *kValue,
3032                                                 *propKey,
3033                                                 thisValue},
3034                                                pcOffset);
3035         builder_.SetDepend(callJs);
3036         BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_), &quit, &noPendingException);
3037         builder_.Bind(&noPendingException);
3038         {
3039             BRANCH_CIR(builder_.TaggedIsTrue(builder_.FastToBoolean(glue, callJs)), &returnTrue, &afterLoop);
3040             builder_.Bind(&returnTrue);
3041             {
3042                 builtinsArrayStubBuilder.SetValueWithElementsKind(
3043                     glue,
3044                     newArray,
3045                     *kValue,
3046                     *toIndex,
3047                     builder_.Boolean(true),
3048                     builder_.Int32(Elements::ToUint(ElementsKind::NONE)));
3049                 toIndex = builder_.Int64Add(*toIndex, builder_.Int64(1));
3050                 builder_.Jump(&afterLoop);
3051             }
3052         }
3053         builder_.Bind(&afterLoop);
3054         {
3055             i = builder_.Int64Add(*i, builder_.Int64(1));
3056             propKey = builder_.ToTaggedIntPtr(*i);
3057             BRANCH_CIR(builder_.Int64LessThan(*i, length), &loopEnd, &exit);
3058         }
3059     }
3060     builder_.Bind(&loopEnd);
3061     builder_.LoopEnd(&loopHead);
3062 
3063     builder_.Bind(&exit);
3064     result = newArray;
3065 
3066     BRANCH_CIR(builder_.Int64LessThan(*toIndex, length), &needTrim, &quit);
3067     builder_.Bind(&needTrim);
3068     {
3069         GateRef trim = builder_.CallNGCRuntime(
3070             glue, RTSTUB_ID(ArrayTrim), Gate::InvalidGateRef, {glue, newArrayEles, *toIndex}, Circuit::NullGate());
3071         builder_.SetDepend(trim);
3072         builder_.Store(VariableType::INT32(), glue, newArray, lengthOffset, builder_.TruncInt64ToInt32(*toIndex));
3073         builder_.Jump(&quit);
3074     }
3075     builder_.Bind(&quit);
3076     ReplaceGateWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *result);
3077 }
3078 
LowerArrayMap(GateRef gate)3079 void TypedNativeInlineLowering::LowerArrayMap(GateRef gate)
3080 {
3081     Environment env(gate, circuit_, &builder_);
3082     GateRef glue = glue_;
3083     BuiltinsArrayStubBuilder builtinsArrayStubBuilder(&env, circuit_->GetGlobalEnvCache());
3084     auto pcOffset = acc_.TryGetPcOffset(gate);
3085     GateRef thisValue = acc_.GetValueIn(gate, 0);
3086     GateRef callBackFn = acc_.GetValueIn(gate, 1);
3087     GateRef usingThis = acc_.GetValueIn(gate, 2);
3088     GateRef frameState = acc_.GetValueIn(gate, 3);
3089     GateRef length = builder_.SExtInt32ToInt64(builder_.GetLengthOfJSArray(thisValue));
3090 
3091     Label lengthIsZero(&builder_);
3092     Label lengthNotZero(&builder_);
3093     Label notHole(&builder_);
3094     Label loopHead(&builder_);
3095     Label loopEnd(&builder_);
3096     Label returnTrue(&builder_);
3097     Label exit(&builder_);
3098     Label needTrim(&builder_);
3099     Label finish(&builder_);
3100     Label noPendingException(&builder_);
3101     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
3102     DEFVALUE(i, (&builder_), VariableType::INT64(), builder_.Int64(0));
3103     DEFVALUE(toIndex, (&builder_), VariableType::INT64(), builder_.Int64(0));
3104     DEFVALUE(propKey, (&builder_), VariableType::JS_ANY(), builder_.ToTaggedIntPtr(*i));
3105     DEFVALUE(kValue, (&builder_), VariableType::JS_ANY(), builder_.Hole());
3106     BRANCH_CIR(builder_.Int64Equal(length, builder_.Int64(0)), &lengthIsZero, &lengthNotZero)
3107     builder_.Bind(&lengthIsZero);
3108     {
3109         NewObjectStubBuilder newBuilder(&env, circuit_->GetGlobalEnvCache());
3110         result = newBuilder.CreateEmptyArray(glue);
3111         builder_.Jump(&exit);
3112     }
3113     builder_.Bind(&lengthNotZero);
3114     builder_.DeoptCheck(builder_.Int64LessThanOrEqual(length, builder_.Int64(JSObject::MAX_GAP)),
3115                         frameState,
3116                         DeoptType::ARRAYLENGTHOVERMAX);
3117     GateRef newArray = builtinsArrayStubBuilder.NewArray(glue, length);
3118     builder_.Jump(&loopHead);
3119     builder_.LoopBegin(&loopHead);
3120     {
3121         kValue = builtinsArrayStubBuilder.GetTaggedValueWithElementsKind(glue, thisValue, *i);
3122         GateRef callJs = builder_.CallInternal(gate,
3123                                                {glue,
3124                                                 builder_.Int64(6),
3125                                                 builder_.IntPtr(0),
3126                                                 callBackFn,
3127                                                 builder_.Undefined(),
3128                                                 usingThis,
3129                                                 *kValue,
3130                                                 *propKey,
3131                                                 thisValue},
3132                                                pcOffset);
3133         builder_.SetDepend(callJs);
3134         BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_), &exit, &noPendingException);
3135         builder_.Bind(&noPendingException);
3136         {
3137             builtinsArrayStubBuilder.SetValueWithElementsKind(
3138                 glue,
3139                 newArray,
3140                 callJs,
3141                 *toIndex,
3142                 builder_.Boolean(true),
3143                 builder_.Int32(Elements::ToUint(ElementsKind::NONE)));
3144             toIndex = builder_.Int64Add(*toIndex, builder_.Int64(1));
3145 
3146             i = builder_.Int64Add(*i, builder_.Int64(1));
3147             propKey = builder_.ToTaggedIntPtr(*i);
3148             BRANCH_CIR(builder_.Int64LessThan(*i, length), &loopEnd, &finish);
3149         }
3150     }
3151     builder_.Bind(&loopEnd);
3152     builder_.LoopEnd(&loopHead);
3153 
3154     builder_.Bind(&finish);
3155     {
3156         result = newArray;
3157         builder_.Jump(&exit);
3158     }
3159     builder_.Bind(&exit);
3160     ReplaceGateWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *result);
3161 }
3162 
LowerArraySome(GateRef gate)3163 void TypedNativeInlineLowering::LowerArraySome(GateRef gate)
3164 {
3165     Environment env(gate, circuit_, &builder_);
3166     GateRef glue = glue_;
3167     BuiltinsArrayStubBuilder builtinsArrayStubBuilder(&env, circuit_->GetGlobalEnvCache());
3168     auto pcOffset = acc_.TryGetPcOffset(gate);
3169     GateRef thisValue = acc_.GetValueIn(gate, 0);
3170     GateRef callBackFn = acc_.GetValueIn(gate, 1);
3171     GateRef usingThis = acc_.GetValueIn(gate, 2);
3172     GateRef length = builder_.SExtInt32ToInt64(builder_.GetLengthOfJSArray(thisValue));
3173 
3174     Label lengthIsZero(&builder_);
3175     Label lengthNotZero(&builder_);
3176     Label notHole(&builder_);
3177     Label loopHead(&builder_);
3178     Label loopEnd(&builder_);
3179     Label afterLoop(&builder_);
3180     Label exit(&builder_);
3181     Label findElement(&builder_);
3182     Label noPendingException(&builder_);
3183     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.TaggedFalse());
3184     DEFVALUE(i, (&builder_), VariableType::INT64(), builder_.Int64(0));
3185     DEFVALUE(propKey, (&builder_), VariableType::JS_ANY(), builder_.ToTaggedIntPtr(*i));
3186     DEFVALUE(kValue, (&builder_), VariableType::JS_ANY(), builder_.Hole());
3187     BRANCH_CIR(builder_.Int64Equal(length, builder_.Int64(0)), &lengthIsZero, &lengthNotZero)
3188     builder_.Bind(&lengthIsZero);
3189     {
3190         builder_.Jump(&exit);
3191     }
3192     builder_.Bind(&lengthNotZero);
3193     builder_.Jump(&loopHead);
3194     builder_.LoopBegin(&loopHead);
3195     kValue = builtinsArrayStubBuilder.GetTaggedValueWithElementsKind(glue, thisValue, *i);
3196     {
3197         GateRef callJs = builder_.CallInternal(gate,
3198                                                {glue,
3199                                                 builder_.Int64(6),
3200                                                 builder_.IntPtr(0),
3201                                                 callBackFn,
3202                                                 builder_.Undefined(),
3203                                                 usingThis,
3204                                                 *kValue,
3205                                                 *propKey,
3206                                                 thisValue},
3207                                                pcOffset);
3208         builder_.SetDepend(callJs);
3209         BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_), &exit, &noPendingException);
3210         builder_.Bind(&noPendingException);
3211         {
3212             BRANCH_CIR(builder_.TaggedIsTrue(builder_.FastToBoolean(glue, callJs)), &findElement, &afterLoop);
3213             builder_.Bind(&afterLoop);
3214             {
3215                 i = builder_.Int64Add(*i, builder_.Int64(1));
3216                 propKey = builder_.ToTaggedIntPtr(*i);
3217                 BRANCH_CIR(builder_.Int64LessThan(*i, length), &loopEnd, &exit);
3218             }
3219         }
3220     }
3221     builder_.Bind(&loopEnd);
3222     builder_.LoopEnd(&loopHead);
3223 
3224     builder_.Bind(&findElement);
3225     {
3226         result = builder_.TaggedTrue();
3227         builder_.Jump(&exit);
3228     }
3229     builder_.Bind(&exit);
3230     ReplaceGateWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *result);
3231 }
3232 
LowerArrayEvery(GateRef gate)3233 void TypedNativeInlineLowering::LowerArrayEvery(GateRef gate)
3234 {
3235     Environment env(gate, circuit_, &builder_);
3236     GateRef glue = glue_;
3237     BuiltinsArrayStubBuilder builtinsArrayStubBuilder(&env, circuit_->GetGlobalEnvCache());
3238     auto pcOffset = acc_.TryGetPcOffset(gate);
3239     GateRef thisValue = acc_.GetValueIn(gate, 0);
3240     GateRef callBackFn = acc_.GetValueIn(gate, 1);
3241     GateRef usingThis = acc_.GetValueIn(gate, 2);
3242     GateRef length = builder_.SExtInt32ToInt64(builder_.GetLengthOfJSArray(thisValue));
3243 
3244     Label lengthIsZero(&builder_);
3245     Label lengthNotZero(&builder_);
3246     Label notHole(&builder_);
3247     Label loopHead(&builder_);
3248     Label loopEnd(&builder_);
3249     Label afterLoop(&builder_);
3250     Label exit(&builder_);
3251     Label callResultNotTrue(&builder_);
3252     Label noPendingException(&builder_);
3253     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.TaggedTrue());
3254     DEFVALUE(i, (&builder_), VariableType::INT64(), builder_.Int64(0));
3255     DEFVALUE(propKey, (&builder_), VariableType::JS_ANY(), builder_.ToTaggedIntPtr(*i));
3256     DEFVALUE(kValue, (&builder_), VariableType::JS_ANY(), builder_.Hole());
3257     BRANCH_CIR(builder_.Int64Equal(length, builder_.Int64(0)), &lengthIsZero, &lengthNotZero)
3258     builder_.Bind(&lengthIsZero);
3259     {
3260         builder_.Jump(&exit);
3261     }
3262     builder_.Bind(&lengthNotZero);
3263     builder_.Jump(&loopHead);
3264     builder_.LoopBegin(&loopHead);
3265     kValue = builtinsArrayStubBuilder.GetTaggedValueWithElementsKind(glue, thisValue, *i);
3266     {
3267         GateRef callJs = builder_.CallInternal(gate,
3268                                                {glue,
3269                                                 builder_.Int64(6),
3270                                                 builder_.IntPtr(0),
3271                                                 callBackFn,
3272                                                 builder_.Undefined(),
3273                                                 usingThis,
3274                                                 *kValue,
3275                                                 *propKey,
3276                                                 thisValue},
3277                                                pcOffset);
3278         builder_.SetDepend(callJs);
3279         BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_), &exit, &noPendingException);
3280         builder_.Bind(&noPendingException);
3281         {
3282             BRANCH_CIR(builder_.TaggedIsFalse(builder_.FastToBoolean(glue, callJs)), &callResultNotTrue, &afterLoop);
3283             builder_.Bind(&afterLoop);
3284             {
3285                 i = builder_.Int64Add(*i, builder_.Int64(1));
3286                 propKey = builder_.ToTaggedIntPtr(*i);
3287                 BRANCH_CIR(builder_.Int64LessThan(*i, length), &loopEnd, &exit);
3288             }
3289         }
3290     }
3291     builder_.Bind(&loopEnd);
3292     builder_.LoopEnd(&loopHead);
3293 
3294     builder_.Bind(&callResultNotTrue);
3295     {
3296         result = builder_.TaggedFalse();
3297         builder_.Jump(&exit);
3298     }
3299     builder_.Bind(&exit);
3300     ReplaceGateWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *result);
3301 }
3302 
LowerArrayPop(GateRef gate)3303 void TypedNativeInlineLowering::LowerArrayPop(GateRef gate)
3304 {
3305     Environment env(gate, circuit_, &builder_);
3306     Label arraylengthNotZero(&builder_);
3307     Label exit(&builder_);
3308     Label isCOWArray(&builder_);
3309     Label getElements(&builder_);
3310     Label indexLessCapacity(&builder_);
3311     Label slowGetElement(&builder_);
3312     Label setArrayLength(&builder_);
3313     Label checkTrim(&builder_);
3314     Label needTrim(&builder_);
3315     Label noTrim(&builder_);
3316     Label isHole(&builder_);
3317     GateRef thisValue = acc_.GetValueIn(gate, 0);
3318     GateRef glue = glue_;
3319     builder_.DeoptCheck(
3320         builder_.IsStableArrayLengthWriteable(glue, thisValue), acc_.GetValueIn(gate, 1),
3321         DeoptType::ARRAYLENGTHNOTWRITABLE);
3322     GateRef arrayLength = builder_.GetLengthOfJSArray(thisValue);
3323     DEFVALUE(ret, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
3324     BRANCH_CIR(builder_.Int32Equal(arrayLength, builder_.Int32(0)), &exit, &arraylengthNotZero);
3325     builder_.Bind(&arraylengthNotZero);
3326     {
3327         GateRef needCOW = builder_.IsJsCOWArray(glue, thisValue, compilationEnv_);
3328         BRANCH_CIR(needCOW, &isCOWArray, &getElements);
3329         builder_.Bind(&isCOWArray);
3330         {
3331             builder_.CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), builder_.GetDepend(), {thisValue}, glue);
3332             builder_.Jump(&getElements);
3333         }
3334     }
3335     builder_.Bind(&getElements);
3336     {
3337         GateRef elements = builder_.GetElementsArray(glue, thisValue);
3338         GateRef capacity = builder_.GetLengthOfTaggedArray(elements);
3339         GateRef index = builder_.Int32Sub(arrayLength, builder_.Int32(1));
3340         BRANCH_CIR(builder_.Int32LessThan(index, capacity), &indexLessCapacity, &setArrayLength);
3341         builder_.Bind(&indexLessCapacity);
3342         {
3343             GateRef result = builder_.GetValueFromTaggedArray(glue, elements, index);
3344             BRANCH_CIR(builder_.TaggedIsHole(result), &slowGetElement, &checkTrim);
3345             builder_.Bind(&checkTrim);
3346             {
3347                 ret = result;
3348                 GateRef unused = builder_.Int32Sub(capacity, index);
3349                 BRANCH_CIR(
3350                     builder_.Int32GreaterThan(unused, builder_.Int32(TaggedArray::MAX_END_UNUSED)), &needTrim, &noTrim);
3351             }
3352             builder_.Bind(&slowGetElement);
3353             {
3354                 Label hasException(&builder_);
3355                 Label notHasException(&builder_);
3356                 GateRef element = builder_.CallStub(glue, gate, CommonStubCSigns::GetPropertyByIndex,
3357                                                     {glue, thisValue, index, circuit_->GetGlobalEnvCache()});
3358                 BRANCH_CIR(builder_.HasPendingException(glue, compilationEnv_), &hasException, &notHasException);
3359                 builder_.Bind(&hasException);
3360                 {
3361                     ret = builder_.ExceptionConstant();
3362                     builder_.Jump(&exit);
3363                 }
3364                 builder_.Bind(&notHasException);
3365                 {
3366                     ret = element;
3367                     builder_.Jump(&setArrayLength);
3368                 }
3369             }
3370         }
3371         builder_.Bind(&needTrim);
3372         {
3373             builder_.CallNGCRuntime(glue,
3374                                     RTSTUB_ID(ArrayTrim),
3375                                     builder_.GetDepend(),
3376                                     {glue, elements, builder_.ZExtInt32ToInt64(index)},
3377                                     Circuit::NullGate());
3378             builder_.Jump(&setArrayLength);
3379         }
3380         builder_.Bind(&noTrim);
3381         {
3382             builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue, elements, index, builder_.HoleConstant());
3383             builder_.Jump(&setArrayLength);
3384         }
3385         builder_.Bind(&setArrayLength);
3386         {
3387             GateRef lengthOffset = builder_.IntPtr(JSArray::LENGTH_OFFSET);
3388             builder_.Store(VariableType::INT32(), glue, thisValue, lengthOffset, index);
3389             builder_.Jump(&exit);
3390         }
3391     }
3392     builder_.Bind(&exit);
3393     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *ret);
3394 }
3395 
LowerArrayPush(GateRef gate)3396 void TypedNativeInlineLowering::LowerArrayPush(GateRef gate)
3397 {
3398     Environment env(gate, circuit_, &builder_);
3399     Label grow(&builder_);
3400     Label setValue(&builder_);
3401     Label setLength(&builder_);
3402     Label exit(&builder_);
3403     GateRef glue = glue_;
3404     BuiltinsArrayStubBuilder arrayBuilder(&env, circuit_->GetGlobalEnvCache());
3405     GateRef thisValue = acc_.GetValueIn(gate, 0);
3406     GateRef value = acc_.GetValueIn(gate, 1);
3407     GateRef oldLength = builder_.GetLengthOfJSArray(thisValue);
3408     DEFVALUE(ret, (&builder_), VariableType::JS_ANY(), builder_.Int32ToTaggedPtr(thisValue));
3409     DEFVALUE(elements, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
3410     GateRef newLength = builder_.Int32Add(oldLength, builder_.Int32(1));
3411     elements = builder_.GetElementsArray(glue, thisValue);
3412     GateRef capacity = builder_.GetLengthOfTaggedArray(*elements);
3413     BRANCH_CIR(builder_.Int32GreaterThan(newLength, capacity), &grow, &setValue);
3414     builder_.Bind(&grow);
3415     {
3416         elements = builder_.CallStub(glue, gate, CommonStubCSigns::GrowElementsCapacity,
3417             {glue, thisValue, circuit_->GetGlobalEnvCache(), newLength});
3418         builder_.Jump(&setValue);
3419     }
3420     builder_.Bind(&setValue);
3421     {
3422         arrayBuilder.FastSetValueWithElementsKind(glue, thisValue, *elements, value, oldLength, ElementsKind::NONE);
3423         builder_.Jump(&setLength);
3424     }
3425     builder_.Bind(&setLength);
3426     {
3427         arrayBuilder.SetArrayLength(glue, thisValue, newLength);
3428         ret = arrayBuilder.IntToTaggedPtr(newLength);
3429         builder_.Jump(&exit);
3430     }
3431     builder_.Bind(&exit);
3432     ReplaceGateWithPendingException(gate, glue, builder_.GetState(), builder_.GetDepend(), *ret);
3433 }
3434 
LowerArraySlice(GateRef gate)3435 void TypedNativeInlineLowering::LowerArraySlice(GateRef gate)
3436 {
3437     Environment env(gate, circuit_, &builder_);
3438     Label exit(&builder_);
3439     Label checkIndexDone(&builder_);
3440     Label sliceCountIsZero(&builder_);
3441     Label sliceCountIsNotZero(&builder_);
3442     Label inThisEles(&builder_);
3443     Label outThisEles(&builder_);
3444 
3445     Label indexInRange(&builder_);
3446     Label setElementToNewArray(&builder_);
3447 
3448     GateRef thisArray = acc_.GetValueIn(gate, 0);
3449     GateRef startHandler = acc_.GetValueIn(gate, 1);
3450     GateRef endHandler = acc_.GetValueIn(gate, 2);
3451     GateRef frameState = acc_.GetValueIn(gate, 3);
3452     GateRef length = builder_.GetLengthOfJSArray(thisArray);
3453     GateRef glue = glue_;
3454     DEFVALUE(start, (&builder_), VariableType::INT32(), builder_.Int32(0));
3455     DEFVALUE(end, (&builder_), VariableType::INT32(), length);
3456     DEFVALUE(res, (&builder_), VariableType::JS_ANY(), builder_.UndefineConstant());
3457 
3458     CheckAndCalcuSliceIndex(length, startHandler, endHandler, &exit, &checkIndexDone, &res, &start, &end);
3459     builder_.Bind(&checkIndexDone);
3460     GateRef sliceCount = builder_.Int32Sub(*end, *start);
3461     builder_.Branch(builder_.Int32Equal(sliceCount, builder_.Int32(0)), &sliceCountIsZero, &sliceCountIsNotZero);
3462     builder_.Bind(&sliceCountIsZero);
3463     {
3464         NewObjectStubBuilder newObject(&env, circuit_->GetGlobalEnvCache());
3465         res = newObject.CreateEmptyArray(glue);
3466         builder_.Jump(&exit);
3467     }
3468     builder_.Bind(&sliceCountIsNotZero);
3469     builder_.DeoptCheck(builder_.Int32LessThanOrEqual(sliceCount, builder_.Int32(JSObject::MAX_GAP)),
3470                         frameState,
3471                         DeoptType::ARRAYLENGTHOVERMAX);
3472     BuiltinsArrayStubBuilder arrayBuilder(&env, circuit_->GetGlobalEnvCache());
3473     GateRef newArray = arrayBuilder.NewArray(glue, sliceCount);
3474     GateRef newArrayElements = builder_.GetElementsArray(glue, newArray);
3475     GateRef thisElements = builder_.GetElementsArray(glue, thisArray);
3476     GateRef thisElementsLen = builder_.GetLengthOfTaggedArray(thisElements);
3477     BRANCH_CIR(
3478         builder_.Int32GreaterThan(thisElementsLen, builder_.Int32Add(*start, sliceCount)), &inThisEles, &outThisEles);
3479     builder_.Bind(&inThisEles);
3480     {
3481         Label loopHead(&builder_);
3482         Label loopEnd(&builder_);
3483         Label copyElement(&builder_);
3484         Label loopExit(&builder_);
3485         Label afterLoop(&builder_);
3486         DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
3487         builder_.Jump(&loopHead);
3488         builder_.LoopBegin(&loopHead);
3489         {
3490             BRANCH_CIR(builder_.Int32LessThan(*i, sliceCount), &copyElement, &loopExit);
3491             builder_.Bind(&copyElement);
3492             {
3493                 GateRef copyPosition = builder_.Int32Add(*start, *i);
3494                 GateRef ele = builder_.GetValueFromTaggedArray(glue, thisElements, copyPosition);
3495                 builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayElements, *i, ele);
3496                 builder_.Jump(&afterLoop);
3497             }
3498         }
3499         builder_.Bind(&afterLoop);
3500         {
3501             i = builder_.Int32Add(*i, builder_.Int32(1));
3502             builder_.Jump(&loopEnd);
3503         }
3504         builder_.Bind(&loopEnd);
3505         builder_.LoopEnd(&loopHead);
3506         builder_.Bind(&loopExit);
3507         {
3508             res = newArray;
3509             builder_.Jump(&exit);
3510         }
3511     }
3512     builder_.Bind(&outThisEles);
3513     {
3514         Label loopHead(&builder_);
3515         Label loopEnd(&builder_);
3516         Label copyElement(&builder_);
3517         Label loopExit(&builder_);
3518         Label afterLoop(&builder_);
3519         DEFVALUE(i, (&builder_), VariableType::INT32(), builder_.Int32(0));
3520         builder_.Jump(&loopHead);
3521         builder_.LoopBegin(&loopHead);
3522         {
3523             BRANCH_CIR(builder_.Int32LessThan(*i, sliceCount), &copyElement, &loopExit);
3524             builder_.Bind(&copyElement);
3525             {
3526                 GateRef copyPosition = builder_.Int32Add(*i, *start);
3527                 DEFVALUE(element, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant());
3528                 BRANCH_CIR(
3529                     builder_.Int32GreaterThan(thisElementsLen, copyPosition), &indexInRange, &setElementToNewArray);
3530                 builder_.Bind(&indexInRange);
3531                 {
3532                     element = builder_.GetValueFromTaggedArray(glue, thisElements, copyPosition);
3533                     builder_.Jump(&setElementToNewArray);
3534                 }
3535                 builder_.Bind(&setElementToNewArray);
3536                 {
3537                     builder_.SetValueToTaggedArray(VariableType::JS_ANY(), glue, newArrayElements, *i, *element);
3538                     builder_.Jump(&afterLoop);
3539                 }
3540             }
3541             builder_.Bind(&afterLoop);
3542             {
3543                 i = builder_.Int32Add(*i, builder_.Int32(1));
3544                 builder_.Jump(&loopEnd);
3545             }
3546             builder_.Bind(&loopEnd);
3547             builder_.LoopEnd(&loopHead);
3548             builder_.Bind(&loopExit);
3549             {
3550                 res = newArray;
3551                 builder_.Jump(&exit);
3552             }
3553         }
3554     }
3555     builder_.Bind(&exit);
3556     acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *res);
3557 }
3558 
CheckAndCalcuSliceIndex(GateRef length,GateRef startHandler,GateRef endHandler,Label * exit,Label * checkIndexDone,Variable * res,Variable * start,Variable * end)3559 void TypedNativeInlineLowering::CheckAndCalcuSliceIndex(GateRef length,
3560                                                         GateRef startHandler,
3561                                                         GateRef endHandler,
3562                                                         Label* exit,
3563                                                         Label* checkIndexDone,
3564                                                         Variable* res,
3565                                                         Variable* start,
3566                                                         Variable* end)
3567 {
3568     Label startUseZero(&builder_);
3569     Label startNotUndef(&builder_);
3570     Label returnEmptyArray(&builder_);
3571     Label startGreaterOrEqualZero(&builder_);
3572     Label startLessZero(&builder_);
3573     Label startLessLength(&builder_);
3574     Label startCheckDone(&builder_);
3575     Label startCalcu(&builder_);
3576     Label endUseLength(&builder_);
3577     Label endNotUndef(&builder_);
3578     Label endLessZero(&builder_);
3579     Label endGreaterZero(&builder_);
3580     Label endUseMixed(&builder_);
3581     Label endUseZero(&builder_);
3582     Label checkEndLessStart(&builder_);
3583     Label endUseHandler(&builder_);
3584     BRANCH_CIR(builder_.TaggedIsUndefined(startHandler), &startUseZero, &startNotUndef);
3585     builder_.Bind(&startNotUndef);
3586     {
3587         GateRef tempStart = builder_.GetInt32OfTInt(startHandler);
3588         BRANCH_CIR(builder_.Int32LessThan(tempStart, builder_.Int32(0)), &startLessZero, &startGreaterOrEqualZero);
3589         builder_.Bind(&startGreaterOrEqualZero);
3590         {
3591             BRANCH_CIR(builder_.Int32GreaterThanOrEqual(tempStart, length), &returnEmptyArray, &startLessLength);
3592             builder_.Bind(&startLessLength);
3593             {
3594                 start->WriteVariable(tempStart);
3595                 builder_.Jump(&startCheckDone);
3596             }
3597         }
3598         builder_.Bind(&startLessZero);
3599         {
3600             GateRef negativeLength = builder_.Int32Sub(builder_.Int32(0), length);
3601             BRANCH_CIR(builder_.Int32LessThan(tempStart, negativeLength), &startUseZero, &startCalcu);
3602             builder_.Bind(&startCalcu);
3603             {
3604                 start->WriteVariable(builder_.Int32Add(tempStart, length));
3605                 builder_.Jump(&startCheckDone);
3606             }
3607         }
3608         builder_.Bind(&startUseZero);
3609         {
3610             start->WriteVariable(builder_.Int32(0));
3611             builder_.Jump(&startCheckDone);
3612         }
3613     }
3614     builder_.Bind(&startCheckDone);
3615     {
3616         BRANCH_CIR(builder_.TaggedIsUndefined(endHandler), &endUseLength, &endNotUndef);
3617         builder_.Bind(&endNotUndef);
3618         {
3619             GateRef tempEnd = builder_.GetInt32OfTInt(endHandler);
3620             BRANCH_CIR(builder_.Int32LessThan(tempEnd, builder_.Int32(0)), &endLessZero, &endGreaterZero);
3621             builder_.Bind(&endLessZero);
3622             {
3623                 GateRef endMixed = builder_.Int32Add(tempEnd, length);
3624                 BRANCH_CIR(builder_.Int32LessThan(endMixed, builder_.Int32(0)), &endUseZero, &endUseMixed);
3625                 builder_.Bind(&endUseMixed);
3626                 {
3627                     end->WriteVariable(endMixed);
3628                     builder_.Jump(&checkEndLessStart);
3629                 }
3630                 builder_.Bind(&endUseZero);
3631                 {
3632                     end->WriteVariable(builder_.Int32(0));
3633                     builder_.Jump(&checkEndLessStart);
3634                 }
3635             }
3636             builder_.Bind(&endGreaterZero);
3637             {
3638                 BRANCH_CIR(builder_.Int32GreaterThanOrEqual(tempEnd, length), &endUseLength, &endUseHandler);
3639                 builder_.Bind(&endUseHandler);
3640                 {
3641                     end->WriteVariable(tempEnd);
3642                     builder_.Jump(&checkEndLessStart);
3643                 }
3644             }
3645         }
3646         builder_.Bind(&endUseLength);
3647         {
3648             end->WriteVariable(length);
3649             builder_.Jump(&checkEndLessStart);
3650         }
3651         builder_.Bind(&checkEndLessStart);
3652         {
3653             BRANCH_CIR(builder_.Int32GreaterThan(start->ReadVariable(), end->ReadVariable()),
3654                        &returnEmptyArray,
3655                        checkIndexDone);
3656         }
3657     }
3658     builder_.Bind(&returnEmptyArray);
3659     {
3660         NewObjectStubBuilder newBuilder(builder_.GetCurrentEnvironment(), circuit_->GetGlobalEnvCache());
3661         res->WriteVariable(newBuilder.CreateEmptyArray(glue_));
3662         builder_.Jump(exit);
3663     }
3664 }
3665 
LowerArraySort(GateRef gate)3666 void TypedNativeInlineLowering::LowerArraySort(GateRef gate)
3667 {
3668     Environment env(gate, circuit_, &builder_);
3669     GateRef glue = glue_;
3670     GateRef thisValue = acc_.GetValueIn(gate, 0);
3671     GateRef callBackFn = acc_.GetValueIn(gate, 1);
3672     BuiltinsArrayStubBuilder arrayStubBuilder(&env, circuit_->GetGlobalEnvCache());
3673     DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.Undefined());
3674     Label slowPath(&env);
3675     Label exit(&env);
3676     arrayStubBuilder.SortAfterArgs(glue, thisValue, callBackFn, &result, &exit, &slowPath, gate);
3677     builder_.Bind(&slowPath);
3678     {
3679         result.WriteVariable(builder_.CallRuntime(glue, RTSTUB_ID(ArraySort),
3680                                                   Gate::InvalidGateRef, { thisValue }, gate));
3681         builder_.Jump(&exit);
3682     }
3683     builder_.Bind(&exit);
3684     acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result);
3685 }
3686 }
3687