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