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, ¬Int);
517 builder_.Bind(&isInt);
518 {
519 result = builder_.Boolean(true);
520 builder_.Jump(&exit);
521 }
522 builder_.Bind(¬Int);
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, ¬Int);
549 builder_.Bind(&isInt);
550 {
551 result = builder_.Boolean(false);
552 builder_.Jump(&exit);
553 }
554 builder_.Bind(¬Int);
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, ¬Nan);
595 builder_.Bind(¬Nan);
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, ¬Int);
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(¬Int);
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, ¬Int);
1102 builder_.Bind(&isInt);
1103 {
1104 result = builder_.ChangeInt32ToFloat64(builder_.GetInt32OfTInt(param));
1105 builder_.Jump(&exit);
1106 }
1107 builder_.Bind(¬Int);
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, ¬Number);
1187 builder_.Bind(&isNumber);
1188 {
1189 result = param;
1190 builder_.Jump(&exit);
1191 }
1192 builder_.Bind(¬Number);
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, ¬ZeroBits);
1267 builder_.Bind(&zeroBits);
1268 {
1269 result = builder_.BigIntConstructor(0);
1270 builder_.Jump(&exit);
1271 }
1272 builder_.Bind(¬ZeroBits);
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, ¬ZeroBigInt);
1283
1284 // Return bigint, if bits >= max_value
1285 builder_.Bind(¬ZeroBigInt);
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, ¬NaN);
1566 builder_.Bind(¬NaN);
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, ¬NaN);
1687 builder_.Bind(&isNaN);
1688 {
1689 builder_.Store(VariableType::FLOAT32(), glue, dataPointer, offset, float32Value);
1690 builder_.Jump(&exit);
1691 }
1692 builder_.Bind(¬NaN);
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, ¬NaN);
1733 {
1734 builder_.Bind(&isNaN);
1735 {
1736 builder_.Store(VariableType::FLOAT64(), glue, dataPointer, offset, value);
1737 builder_.Jump(&exit);
1738 }
1739 builder_.Bind(¬NaN);
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, ¬Int);
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(¬Int);
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, ¬IsInt);
1934 builder_.Bind(&isInt);
1935 {
1936 result = builder_.True();
1937 builder_.Jump(&exit);
1938 }
1939 builder_.Bind(¬IsInt);
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, ¬IntegerStr);
2053 builder_.Bind(&isIntegerStr);
2054 {
2055 result = builder_.ChangeInt32ToFloat64(builder_.GetRawHashFromString(msg));
2056 builder_.Jump(&exitIntegerStr);
2057 }
2058 builder_.Bind(¬IntegerStr);
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, ¬EcmaObject);
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(¬EcmaObject);
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), ©Element, &loopExit);
3694 builder_.Bind(©Element);
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), ©Element, &loopExit);
3727 builder_.Bind(©Element);
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