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