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