1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jit/TypePolicy.h"
9 #include "jit/JitAllocPolicy.h"
10 #include "jit/MIR-wasm.h"
12 #include "jit/MIRGraph.h"
13 #include "js/ScalarType.h" // js::Scalar::Type
16 using namespace js::jit
;
18 static void EnsureOperandNotFloat32(TempAllocator
& alloc
, MInstruction
* def
,
20 MDefinition
* in
= def
->getOperand(op
);
21 if (in
->type() == MIRType::Float32
) {
22 MToDouble
* replace
= MToDouble::New(alloc
, in
);
23 def
->block()->insertBefore(def
, replace
);
24 if (def
->isRecoveredOnBailout()) {
25 replace
->setRecoveredOnBailout();
27 def
->replaceOperand(op
, replace
);
32 [[nodiscard
]] static bool ConvertOperand(TempAllocator
& alloc
,
33 MInstruction
* def
, unsigned op
,
35 MDefinition
* in
= def
->getOperand(op
);
36 if (in
->type() == expected
) {
40 auto* replace
= T::New(alloc
, in
);
41 def
->block()->insertBefore(def
, replace
);
42 def
->replaceOperand(op
, replace
);
44 return replace
->typePolicy()->adjustInputs(alloc
, replace
);
47 static void SetTypePolicyBailoutKind(MInstruction
* newIns
,
48 MInstruction
* forIns
) {
49 // Infallible ToFloat32 or ToDouble doesn't bail out.
50 if ((newIns
->isToFloat32() || newIns
->isToDouble()) && !newIns
->isGuard()) {
54 // Ensure we're not introducing TypePolicy bailouts for transpiled CacheIR
55 // instructions. Unbox operations and other guards should have been inserted
58 // This avoids a performance cliff because frequent TypePolicy bailouts will
59 // disable Warp compilation instead of invalidating the script.
61 MOZ_ASSERT(forIns
->bailoutKind() != BailoutKind::TranspiledCacheIR
);
63 newIns
->setBailoutKind(BailoutKind::TypePolicy
);
66 [[nodiscard
]] static bool UnboxOperand(TempAllocator
& alloc
, MInstruction
* def
,
67 unsigned op
, MIRType expected
) {
68 MDefinition
* in
= def
->getOperand(op
);
69 if (in
->type() == expected
) {
73 auto* replace
= MUnbox::New(alloc
, in
, expected
, MUnbox::Fallible
);
74 SetTypePolicyBailoutKind(replace
, def
);
75 def
->block()->insertBefore(def
, replace
);
76 def
->replaceOperand(op
, replace
);
78 return replace
->typePolicy()->adjustInputs(alloc
, replace
);
81 MDefinition
* js::jit::AlwaysBoxAt(TempAllocator
& alloc
, MInstruction
* at
,
82 MDefinition
* operand
) {
83 MDefinition
* boxedOperand
= operand
;
84 // Replace Float32 by double
85 if (operand
->type() == MIRType::Float32
) {
86 MInstruction
* replace
= MToDouble::New(alloc
, operand
);
87 at
->block()->insertBefore(at
, replace
);
88 boxedOperand
= replace
;
90 MBox
* box
= MBox::New(alloc
, boxedOperand
);
91 at
->block()->insertBefore(at
, box
);
95 static MDefinition
* BoxAt(TempAllocator
& alloc
, MInstruction
* at
,
96 MDefinition
* operand
) {
97 if (operand
->isUnbox()) {
98 return operand
->toUnbox()->input();
100 return AlwaysBoxAt(alloc
, at
, operand
);
103 bool BoxInputsPolicy::staticAdjustInputs(TempAllocator
& alloc
,
105 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
106 MDefinition
* in
= ins
->getOperand(i
);
107 if (in
->type() == MIRType::Value
) {
110 ins
->replaceOperand(i
, BoxAt(alloc
, ins
, in
));
115 bool ArithPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
116 MOZ_ASSERT(IsNumberType(ins
->type()));
117 MOZ_ASSERT(ins
->type() == MIRType::Double
|| ins
->type() == MIRType::Int32
||
118 ins
->type() == MIRType::Float32
);
120 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
121 MDefinition
* in
= ins
->getOperand(i
);
122 if (in
->type() == ins
->type()) {
126 MInstruction
* replace
;
128 if (ins
->type() == MIRType::Double
) {
129 replace
= MToDouble::New(alloc
, in
);
130 } else if (ins
->type() == MIRType::Float32
) {
131 replace
= MToFloat32::New(alloc
, in
);
133 replace
= MToNumberInt32::New(alloc
, in
);
136 SetTypePolicyBailoutKind(replace
, ins
);
137 ins
->block()->insertBefore(ins
, replace
);
138 ins
->replaceOperand(i
, replace
);
140 if (!replace
->typePolicy()->adjustInputs(alloc
, replace
)) {
148 bool BigIntArithPolicy::adjustInputs(TempAllocator
& alloc
,
149 MInstruction
* ins
) const {
150 MOZ_ASSERT(ins
->type() == MIRType::BigInt
);
152 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
153 if (!ConvertOperand
<MToBigInt
>(alloc
, ins
, i
, MIRType::BigInt
)) {
161 bool AllDoublePolicy::staticAdjustInputs(TempAllocator
& alloc
,
163 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
164 MDefinition
* in
= ins
->getOperand(i
);
165 if (in
->type() == MIRType::Double
) {
169 if (!alloc
.ensureBallast()) {
172 MInstruction
* replace
= MToDouble::New(alloc
, in
);
174 ins
->block()->insertBefore(ins
, replace
);
175 ins
->replaceOperand(i
, replace
);
177 if (!replace
->typePolicy()->adjustInputs(alloc
, replace
)) {
185 bool ComparePolicy::adjustInputs(TempAllocator
& alloc
,
186 MInstruction
* def
) const {
187 auto convertOperand
= [&](size_t index
, MIRType expected
) {
188 MDefinition
* operand
= def
->getOperand(index
);
189 if (operand
->type() == expected
) {
192 MInstruction
* replace
= nullptr;
194 case MIRType::Double
:
195 replace
= MToDouble::New(alloc
, operand
);
198 replace
= MToNumberInt32::New(alloc
, operand
);
200 case MIRType::Float32
:
201 replace
= MToFloat32::New(alloc
, operand
);
203 case MIRType::String
:
205 MUnbox::New(alloc
, operand
, MIRType::String
, MUnbox::Fallible
);
207 case MIRType::Symbol
:
209 MUnbox::New(alloc
, operand
, MIRType::Symbol
, MUnbox::Fallible
);
211 case MIRType::Object
:
213 MUnbox::New(alloc
, operand
, MIRType::Object
, MUnbox::Fallible
);
215 case MIRType::BigInt
:
217 MUnbox::New(alloc
, operand
, MIRType::BigInt
, MUnbox::Fallible
);
220 MOZ_CRASH("Unsupported MIRType");
222 replace
->setBailoutKind(BailoutKind::TypePolicy
);
223 def
->block()->insertBefore(def
, replace
);
224 def
->replaceOperand(index
, replace
);
225 return replace
->typePolicy()->adjustInputs(alloc
, replace
);
228 MOZ_ASSERT(def
->isCompare());
229 MCompare
* compare
= def
->toCompare();
230 switch (compare
->compareType()) {
231 case MCompare::Compare_Undefined
:
232 case MCompare::Compare_Null
:
233 MOZ_ASSERT(compare
->rhs()->type() == MIRType::Undefined
||
234 compare
->rhs()->type() == MIRType::Null
);
235 // IF the operand is float32, we must convert it to a double.
236 if (compare
->lhs()->type() == MIRType::Float32
) {
237 MInstruction
* replace
= MToDouble::New(alloc
, compare
->lhs());
238 def
->block()->insertBefore(def
, replace
);
239 def
->replaceOperand(0, replace
);
240 return replace
->typePolicy()->adjustInputs(alloc
, replace
);
242 // GVN and lowering handle all other types.
244 case MCompare::Compare_Int32
:
245 return convertOperand(0, MIRType::Int32
) &&
246 convertOperand(1, MIRType::Int32
);
247 case MCompare::Compare_IntPtr
:
248 case MCompare::Compare_UIntPtr
:
249 MOZ_ASSERT(compare
->lhs()->type() == MIRType::IntPtr
);
250 MOZ_ASSERT(compare
->rhs()->type() == MIRType::IntPtr
);
252 case MCompare::Compare_Double
:
253 return convertOperand(0, MIRType::Double
) &&
254 convertOperand(1, MIRType::Double
);
255 case MCompare::Compare_Float32
:
256 return convertOperand(0, MIRType::Float32
) &&
257 convertOperand(1, MIRType::Float32
);
258 case MCompare::Compare_String
:
259 return convertOperand(0, MIRType::String
) &&
260 convertOperand(1, MIRType::String
);
261 case MCompare::Compare_Symbol
:
262 return convertOperand(0, MIRType::Symbol
) &&
263 convertOperand(1, MIRType::Symbol
);
264 case MCompare::Compare_Object
:
265 return convertOperand(0, MIRType::Object
) &&
266 convertOperand(1, MIRType::Object
);
267 case MCompare::Compare_BigInt
:
268 return convertOperand(0, MIRType::BigInt
) &&
269 convertOperand(1, MIRType::BigInt
);
270 case MCompare::Compare_BigInt_Int32
:
271 return convertOperand(0, MIRType::BigInt
) &&
272 convertOperand(1, MIRType::Int32
);
273 case MCompare::Compare_BigInt_Double
:
274 return convertOperand(0, MIRType::BigInt
) &&
275 convertOperand(1, MIRType::Double
);
276 case MCompare::Compare_BigInt_String
:
277 return convertOperand(0, MIRType::BigInt
) &&
278 convertOperand(1, MIRType::String
);
280 MOZ_CRASH("Unexpected compare type");
286 bool TestPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
287 MDefinition
* op
= ins
->getOperand(0);
288 switch (op
->type()) {
291 case MIRType::Undefined
:
292 case MIRType::Boolean
:
294 case MIRType::Double
:
295 case MIRType::Float32
:
296 case MIRType::Symbol
:
297 case MIRType::BigInt
:
298 case MIRType::Object
:
301 case MIRType::String
: {
302 MStringLength
* length
= MStringLength::New(alloc
, op
);
303 ins
->block()->insertBefore(ins
, length
);
304 ins
->replaceOperand(0, length
);
309 MOZ_ASSERT(IsMagicType(op
->type()));
310 ins
->replaceOperand(0, BoxAt(alloc
, ins
, op
));
316 bool BitwisePolicy::adjustInputs(TempAllocator
& alloc
,
317 MInstruction
* ins
) const {
318 MOZ_ASSERT(ins
->type() == MIRType::Int32
|| ins
->type() == MIRType::Double
);
320 // This policy works for both unary and binary bitwise operations.
321 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
322 if (!ConvertOperand
<MTruncateToInt32
>(alloc
, ins
, i
, MIRType::Int32
)) {
330 bool PowPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
331 MOZ_ASSERT(ins
->type() == MIRType::Int32
|| ins
->type() == MIRType::Double
);
333 if (ins
->type() == MIRType::Int32
) {
334 // Both operands must be int32.
335 return UnboxedInt32Policy
<0>::staticAdjustInputs(alloc
, ins
) &&
336 UnboxedInt32Policy
<1>::staticAdjustInputs(alloc
, ins
);
339 // Otherwise, input must be a double.
340 if (!DoublePolicy
<0>::staticAdjustInputs(alloc
, ins
)) {
344 // Power may be an int32 or a double. Integers receive a faster path.
345 MDefinition
* power
= ins
->toPow()->power();
346 if (power
->isToDouble()) {
347 MDefinition
* input
= power
->toToDouble()->input();
348 if (input
->type() == MIRType::Int32
) {
349 power
->setImplicitlyUsedUnchecked();
350 ins
->replaceOperand(1, input
);
354 return DoublePolicy
<1>::staticAdjustInputs(alloc
, ins
);
357 bool SignPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
358 MOZ_ASSERT(ins
->isSign());
359 MIRType specialization
= ins
->typePolicySpecialization();
361 // MSign is specialized for int32 input types.
362 if (specialization
== MIRType::Int32
) {
363 return UnboxedInt32Policy
<0>::staticAdjustInputs(alloc
, ins
);
366 // Otherwise convert input to double.
367 MOZ_ASSERT(IsFloatingPointType(specialization
));
368 return DoublePolicy
<0>::staticAdjustInputs(alloc
, ins
);
371 template <unsigned Op
>
372 bool SymbolPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
374 return UnboxOperand(alloc
, ins
, Op
, MIRType::Symbol
);
377 template bool SymbolPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
380 template <unsigned Op
>
381 bool BooleanPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
383 return UnboxOperand(alloc
, ins
, Op
, MIRType::Boolean
);
386 template bool BooleanPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
389 template <unsigned Op
>
390 bool StringPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
392 return UnboxOperand(alloc
, ins
, Op
, MIRType::String
);
395 template bool StringPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
397 template bool StringPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
399 template bool StringPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
402 template <unsigned Op
>
403 bool ConvertToStringPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
405 MDefinition
* in
= ins
->getOperand(Op
);
406 if (in
->type() == MIRType::String
) {
411 MToString::New(alloc
, in
, MToString::SideEffectHandling::Bailout
);
412 ins
->block()->insertBefore(ins
, replace
);
413 ins
->replaceOperand(Op
, replace
);
415 return ToStringPolicy::staticAdjustInputs(alloc
, replace
);
418 template bool ConvertToStringPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
420 template bool ConvertToStringPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
422 template bool ConvertToStringPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
425 template <unsigned Op
>
426 bool BigIntPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
428 return UnboxOperand(alloc
, ins
, Op
, MIRType::BigInt
);
431 template bool BigIntPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
433 template bool BigIntPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
436 template <unsigned Op
>
437 bool UnboxedInt32Policy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
439 return UnboxOperand(alloc
, def
, Op
, MIRType::Int32
);
442 template bool UnboxedInt32Policy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
444 template bool UnboxedInt32Policy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
446 template bool UnboxedInt32Policy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
448 template bool UnboxedInt32Policy
<3>::staticAdjustInputs(TempAllocator
& alloc
,
451 template <unsigned Op
>
452 bool Int32OrIntPtrPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
454 MDefinition
* in
= def
->getOperand(Op
);
455 if (in
->type() == MIRType::IntPtr
) {
459 return UnboxedInt32Policy
<Op
>::staticAdjustInputs(alloc
, def
);
462 template bool Int32OrIntPtrPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
464 template bool Int32OrIntPtrPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
467 template <unsigned Op
>
468 bool IntPtrPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
470 // We don't (yet) support converting other types to IntPtr.
471 MOZ_ASSERT(def
->getOperand(Op
)->type() == MIRType::IntPtr
);
475 template bool IntPtrPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
478 template <unsigned Op
>
479 bool ConvertToInt32Policy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
481 return ConvertOperand
<MToNumberInt32
>(alloc
, def
, Op
, MIRType::Int32
);
484 template bool ConvertToInt32Policy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
487 template <unsigned Op
>
488 bool TruncateToInt32OrToInt64Policy
<Op
>::staticAdjustInputs(
489 TempAllocator
& alloc
, MInstruction
* def
) {
490 MOZ_ASSERT(def
->isCompareExchangeTypedArrayElement() ||
491 def
->isAtomicExchangeTypedArrayElement() ||
492 def
->isAtomicTypedArrayElementBinop());
495 if (def
->isCompareExchangeTypedArrayElement()) {
496 type
= def
->toCompareExchangeTypedArrayElement()->arrayType();
497 } else if (def
->isAtomicExchangeTypedArrayElement()) {
498 type
= def
->toAtomicExchangeTypedArrayElement()->arrayType();
500 type
= def
->toAtomicTypedArrayElementBinop()->arrayType();
503 if (Scalar::isBigIntType(type
)) {
504 return ConvertOperand
<MToInt64
>(alloc
, def
, Op
, MIRType::Int64
);
506 return ConvertOperand
<MTruncateToInt32
>(alloc
, def
, Op
, MIRType::Int32
);
509 template bool TruncateToInt32OrToInt64Policy
<2>::staticAdjustInputs(
510 TempAllocator
& alloc
, MInstruction
* def
);
511 template bool TruncateToInt32OrToInt64Policy
<3>::staticAdjustInputs(
512 TempAllocator
& alloc
, MInstruction
* def
);
514 template <unsigned Op
>
515 bool DoublePolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
517 return ConvertOperand
<MToDouble
>(alloc
, def
, Op
, MIRType::Double
);
520 template bool DoublePolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
522 template bool DoublePolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
525 template <unsigned Op
>
526 bool Float32Policy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
528 return ConvertOperand
<MToFloat32
>(alloc
, def
, Op
, MIRType::Float32
);
531 template bool Float32Policy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
533 template bool Float32Policy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
535 template bool Float32Policy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
538 template <unsigned Op
>
539 bool FloatingPointPolicy
<Op
>::adjustInputs(TempAllocator
& alloc
,
540 MInstruction
* def
) const {
541 MIRType policyType
= def
->typePolicySpecialization();
542 if (policyType
== MIRType::Double
) {
543 return DoublePolicy
<Op
>::staticAdjustInputs(alloc
, def
);
545 return Float32Policy
<Op
>::staticAdjustInputs(alloc
, def
);
548 template bool FloatingPointPolicy
<0>::adjustInputs(TempAllocator
& alloc
,
549 MInstruction
* def
) const;
551 template <unsigned Op
>
552 bool NoFloatPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
554 EnsureOperandNotFloat32(alloc
, def
, Op
);
558 template bool NoFloatPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
560 template bool NoFloatPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
562 template bool NoFloatPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
564 template bool NoFloatPolicy
<3>::staticAdjustInputs(TempAllocator
& alloc
,
567 template <unsigned FirstOp
>
568 bool NoFloatPolicyAfter
<FirstOp
>::staticAdjustInputs(TempAllocator
& alloc
,
570 for (size_t op
= FirstOp
, e
= def
->numOperands(); op
< e
; op
++) {
571 EnsureOperandNotFloat32(alloc
, def
, op
);
576 template bool NoFloatPolicyAfter
<0>::staticAdjustInputs(TempAllocator
& alloc
,
578 template bool NoFloatPolicyAfter
<1>::staticAdjustInputs(TempAllocator
& alloc
,
580 template bool NoFloatPolicyAfter
<2>::staticAdjustInputs(TempAllocator
& alloc
,
583 template <unsigned Op
>
584 bool BoxPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
586 MDefinition
* in
= ins
->getOperand(Op
);
587 if (in
->type() == MIRType::Value
) {
591 ins
->replaceOperand(Op
, BoxAt(alloc
, ins
, in
));
595 template bool BoxPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
597 template bool BoxPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
599 template bool BoxPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
602 template <unsigned Op
, MIRType Type
>
603 bool BoxExceptPolicy
<Op
, Type
>::staticAdjustInputs(TempAllocator
& alloc
,
605 MDefinition
* in
= ins
->getOperand(Op
);
606 if (in
->type() == Type
) {
609 return BoxPolicy
<Op
>::staticAdjustInputs(alloc
, ins
);
612 template bool BoxExceptPolicy
<0, MIRType::Object
>::staticAdjustInputs(
613 TempAllocator
& alloc
, MInstruction
* ins
);
615 template <unsigned Op
>
616 bool CacheIdPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
618 MDefinition
* in
= ins
->getOperand(Op
);
619 switch (in
->type()) {
621 case MIRType::String
:
622 case MIRType::Symbol
:
625 return BoxPolicy
<Op
>::staticAdjustInputs(alloc
, ins
);
629 template bool CacheIdPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
631 template bool CacheIdPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
634 bool ToDoublePolicy::staticAdjustInputs(TempAllocator
& alloc
,
636 MOZ_ASSERT(ins
->isToDouble() || ins
->isToFloat32() || ins
->isToFloat16());
638 MDefinition
* in
= ins
->getOperand(0);
639 switch (in
->type()) {
641 case MIRType::Float32
:
642 case MIRType::Double
:
645 case MIRType::Undefined
:
646 case MIRType::Boolean
:
647 // No need for boxing for these types.
649 case MIRType::Object
:
650 case MIRType::String
:
651 case MIRType::Symbol
:
652 case MIRType::BigInt
:
653 // Objects might be effectful. Symbols and BigInts give TypeError.
659 in
= BoxAt(alloc
, ins
, in
);
660 ins
->replaceOperand(0, in
);
664 bool ToInt32Policy::staticAdjustInputs(TempAllocator
& alloc
,
666 MOZ_ASSERT(ins
->isToNumberInt32() || ins
->isTruncateToInt32());
668 IntConversionInputKind conversion
= IntConversionInputKind::Any
;
669 if (ins
->isToNumberInt32()) {
670 conversion
= ins
->toToNumberInt32()->conversion();
673 MDefinition
* in
= ins
->getOperand(0);
674 switch (in
->type()) {
676 case MIRType::Float32
:
677 case MIRType::Double
:
679 // No need for boxing for these types.
681 case MIRType::Undefined
:
682 // No need for boxing when truncating.
683 if (ins
->isTruncateToInt32()) {
688 // No need for boxing, when we will convert.
689 if (conversion
== IntConversionInputKind::Any
) {
693 case MIRType::Boolean
:
694 // No need for boxing, when we will convert.
695 if (conversion
== IntConversionInputKind::Any
) {
699 case MIRType::Object
:
700 case MIRType::String
:
701 case MIRType::Symbol
:
702 case MIRType::BigInt
:
703 // Objects might be effectful. Symbols and BigInts give TypeError.
709 in
= BoxAt(alloc
, ins
, in
);
710 ins
->replaceOperand(0, in
);
714 bool ToBigIntPolicy::staticAdjustInputs(TempAllocator
& alloc
,
716 MOZ_ASSERT(ins
->isToBigInt());
718 MDefinition
* in
= ins
->getOperand(0);
719 switch (in
->type()) {
720 case MIRType::BigInt
:
722 // No need for boxing for these types.
725 // Any other types need to be boxed.
729 in
= BoxAt(alloc
, ins
, in
);
730 ins
->replaceOperand(0, in
);
734 bool ToStringPolicy::staticAdjustInputs(TempAllocator
& alloc
,
736 MOZ_ASSERT(ins
->isToString());
738 MIRType type
= ins
->getOperand(0)->type();
739 if (type
== MIRType::Object
|| type
== MIRType::Symbol
||
740 type
== MIRType::BigInt
) {
741 ins
->replaceOperand(0, BoxAt(alloc
, ins
, ins
->getOperand(0)));
745 // TODO remove the following line once 966957 has landed
746 EnsureOperandNotFloat32(alloc
, ins
, 0);
751 bool ToInt64Policy::staticAdjustInputs(TempAllocator
& alloc
,
753 MOZ_ASSERT(ins
->isToInt64());
755 MDefinition
* input
= ins
->getOperand(0);
756 MIRType type
= input
->type();
759 case MIRType::BigInt
: {
760 auto* replace
= MTruncateBigIntToInt64::New(alloc
, input
);
761 ins
->block()->insertBefore(ins
, replace
);
762 ins
->replaceOperand(0, replace
);
765 // No need for boxing for these types, because they are handled specially
766 // when this instruction is lowered to LIR.
767 case MIRType::Boolean
:
768 case MIRType::String
:
773 ins
->replaceOperand(0, BoxAt(alloc
, ins
, ins
->getOperand(0)));
780 template <unsigned Op
>
781 bool ObjectPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
783 MOZ_ASSERT(ins
->getOperand(Op
)->type() != MIRType::Slots
);
784 MOZ_ASSERT(ins
->getOperand(Op
)->type() != MIRType::Elements
);
786 return UnboxOperand(alloc
, ins
, Op
, MIRType::Object
);
789 template bool ObjectPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
791 template bool ObjectPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
793 template bool ObjectPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
795 template bool ObjectPolicy
<3>::staticAdjustInputs(TempAllocator
& alloc
,
798 bool CallPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
801 call
= ins
->toCall();
803 call
= ins
->toCallClassHook();
806 MDefinition
* func
= call
->getCallee();
807 if (func
->type() != MIRType::Object
) {
808 MInstruction
* unbox
=
809 MUnbox::New(alloc
, func
, MIRType::Object
, MUnbox::Fallible
);
810 SetTypePolicyBailoutKind(unbox
, call
);
811 call
->block()->insertBefore(call
, unbox
);
812 call
->replaceCallee(unbox
);
814 if (!unbox
->typePolicy()->adjustInputs(alloc
, unbox
)) {
819 for (uint32_t i
= 0; i
< call
->numStackArgs(); i
++) {
820 if (!alloc
.ensureBallast()) {
823 EnsureOperandNotFloat32(alloc
, call
, MCallBase::IndexOfStackArg(i
));
829 bool MegamorphicSetElementPolicy::adjustInputs(TempAllocator
& alloc
,
830 MInstruction
* ins
) const {
831 // The first operand should be an object.
832 if (!SingleObjectPolicy::staticAdjustInputs(alloc
, ins
)) {
836 // Box the index and value operands.
837 for (size_t i
= 1, e
= ins
->numOperands(); i
< e
; i
++) {
838 MDefinition
* in
= ins
->getOperand(i
);
839 if (in
->type() == MIRType::Value
) {
842 ins
->replaceOperand(i
, BoxAt(alloc
, ins
, in
));
847 bool StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator
& alloc
,
849 Scalar::Type writeType
,
852 if (Scalar::isBigIntType(writeType
)) {
853 return ConvertOperand
<MToInt64
>(alloc
, ins
, valueOperand
, MIRType::Int64
);
856 MDefinition
* curValue
= value
;
857 // First, ensure the value is int32, boolean, double or Value.
858 // The conversion is based on TypedArrayObjectTemplate::setElementTail.
859 switch (value
->type()) {
861 case MIRType::Double
:
862 case MIRType::Float32
:
863 case MIRType::Boolean
:
867 value
->setImplicitlyUsedUnchecked();
868 value
= MConstant::New(alloc
, Int32Value(0));
869 ins
->block()->insertBefore(ins
, value
->toInstruction());
871 case MIRType::Undefined
:
872 value
->setImplicitlyUsedUnchecked();
873 value
= MConstant::New(alloc
, JS::NaNValue());
874 ins
->block()->insertBefore(ins
, value
->toInstruction());
876 case MIRType::Object
:
877 case MIRType::String
:
878 case MIRType::Symbol
:
879 case MIRType::BigInt
:
880 value
= BoxAt(alloc
, ins
, value
);
883 MOZ_CRASH("Unexpected type");
886 if (value
!= curValue
) {
887 ins
->replaceOperand(valueOperand
, value
);
892 value
->type() == MIRType::Int32
|| value
->type() == MIRType::Boolean
||
893 value
->type() == MIRType::Double
|| value
->type() == MIRType::Float32
||
894 value
->type() == MIRType::Value
);
903 if (value
->type() != MIRType::Int32
) {
904 value
= MTruncateToInt32::New(alloc
, value
);
905 ins
->block()->insertBefore(ins
, value
->toInstruction());
908 case Scalar::Uint8Clamped
:
909 // The transpiler should have inserted MClampToUint8.
910 MOZ_ASSERT(value
->type() == MIRType::Int32
);
912 case Scalar::Float16
:
913 value
= MToFloat16::New(alloc
, value
);
914 ins
->block()->insertBefore(ins
, value
->toInstruction());
916 case Scalar::Float32
:
917 if (value
->type() != MIRType::Float32
) {
918 value
= MToFloat32::New(alloc
, value
);
919 ins
->block()->insertBefore(ins
, value
->toInstruction());
922 case Scalar::Float64
:
923 if (value
->type() != MIRType::Double
) {
924 value
= MToDouble::New(alloc
, value
);
925 ins
->block()->insertBefore(ins
, value
->toInstruction());
929 MOZ_CRASH("Invalid array type");
932 if (value
!= curValue
) {
933 ins
->replaceOperand(valueOperand
, value
);
939 bool StoreUnboxedScalarPolicy::adjustInputs(TempAllocator
& alloc
,
940 MInstruction
* ins
) const {
941 MStoreUnboxedScalar
* store
= ins
->toStoreUnboxedScalar();
942 MOZ_ASSERT(store
->elements()->type() == MIRType::Elements
);
943 MOZ_ASSERT(store
->index()->type() == MIRType::IntPtr
);
945 return adjustValueInput(alloc
, store
, store
->writeType(), store
->value(), 2);
948 bool StoreDataViewElementPolicy::adjustInputs(TempAllocator
& alloc
,
949 MInstruction
* ins
) const {
950 auto* store
= ins
->toStoreDataViewElement();
951 MOZ_ASSERT(store
->elements()->type() == MIRType::Elements
);
952 MOZ_ASSERT(store
->index()->type() == MIRType::IntPtr
);
953 MOZ_ASSERT(store
->littleEndian()->type() == MIRType::Boolean
);
955 return StoreUnboxedScalarPolicy::adjustValueInput(
956 alloc
, ins
, store
->writeType(), store
->value(), 2);
959 bool StoreTypedArrayHolePolicy::adjustInputs(TempAllocator
& alloc
,
960 MInstruction
* ins
) const {
961 MStoreTypedArrayElementHole
* store
= ins
->toStoreTypedArrayElementHole();
962 MOZ_ASSERT(store
->elements()->type() == MIRType::Elements
);
963 MOZ_ASSERT(store
->index()->type() == MIRType::IntPtr
);
964 MOZ_ASSERT(store
->length()->type() == MIRType::IntPtr
);
966 return StoreUnboxedScalarPolicy::adjustValueInput(
967 alloc
, ins
, store
->arrayType(), store
->value(), 3);
970 bool ClampPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
971 MDefinition
* in
= ins
->toClampToUint8()->input();
973 switch (in
->type()) {
975 case MIRType::Double
:
979 ins
->replaceOperand(0, BoxAt(alloc
, ins
, in
));
986 // Lists of all TypePolicy specializations which are used by MIR Instructions.
987 #define TYPE_POLICY_LIST(_) \
990 _(BigIntArithPolicy) \
994 _(MegamorphicSetElementPolicy) \
999 _(StoreDataViewElementPolicy) \
1000 _(StoreTypedArrayHolePolicy) \
1001 _(StoreUnboxedScalarPolicy) \
1009 #define TEMPLATE_TYPE_POLICY_LIST(_) \
1010 _(BigIntPolicy<0>) \
1011 _(BooleanPolicy<0>) \
1012 _(BoxExceptPolicy<0, MIRType::Object>) \
1014 _(ConvertToInt32Policy<0>) \
1015 _(ConvertToStringPolicy<0>) \
1016 _(ConvertToStringPolicy<2>) \
1017 _(DoublePolicy<0>) \
1018 _(FloatingPointPolicy<0>) \
1019 _(UnboxedInt32Policy<0>) \
1020 _(UnboxedInt32Policy<1>) \
1021 _(IntPtrPolicy<0>) \
1022 _(TruncateToInt32OrToInt64Policy<2>) \
1023 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, BoxPolicy<2>>) \
1024 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \
1025 IF_EXPLICIT_RESOURCE_MANAGEMENT( \
1026 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2>, \
1027 BooleanPolicy<3>>)) \
1028 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>) \
1029 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy<2>>) \
1030 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>>) \
1031 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1032 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<2>>) \
1033 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, UnboxedInt32Policy<2>>) \
1034 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2>>) \
1035 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2>>) \
1036 _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1037 _(MixPolicy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2>>) \
1038 _(MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2>>) \
1039 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, UnboxedInt32Policy<2>>) \
1040 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>, \
1042 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>, \
1043 UnboxedInt32Policy<3>>) \
1044 _(MixPolicy<TruncateToInt32OrToInt64Policy<2>, \
1045 TruncateToInt32OrToInt64Policy<3>>) \
1046 _(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>) \
1047 _(MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, \
1048 CacheIdPolicy<2>>) \
1049 _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1>>) \
1050 _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>>) \
1051 _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>>) \
1052 _(MixPolicy<DoublePolicy<0>, DoublePolicy<1>>) \
1053 _(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>>) \
1054 _(MixPolicy<Int32OrIntPtrPolicy<0>, Int32OrIntPtrPolicy<1>>) \
1055 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>) \
1056 _(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>) \
1057 _(MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1>>) \
1058 _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1>>) \
1059 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>>) \
1060 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<2>>) \
1061 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1>>) \
1062 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2>>) \
1063 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3>>) \
1064 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicyAfter<1>>) \
1065 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>>) \
1066 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>>) \
1067 _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2>>) \
1068 _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0>>) \
1069 _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>>) \
1070 _(MixPolicy<StringPolicy<0>, StringPolicy<1>>) \
1071 _(MixPolicy<BoxPolicy<0>, BoxPolicy<1>>) \
1072 _(MixPolicy<BoxPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \
1073 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<2>, ObjectPolicy<3>>) \
1074 _(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, ObjectPolicy<1>>) \
1075 _(MixPolicy<UnboxedInt32Policy<0>, BigIntPolicy<1>>) \
1076 _(MixPolicy<UnboxedInt32Policy<0>, NoFloatPolicyAfter<1>>) \
1077 _(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>, \
1078 NoFloatPolicyAfter<2>>) \
1079 _(NoFloatPolicy<0>) \
1080 _(NoFloatPolicy<1>) \
1081 _(NoFloatPolicy<2>) \
1082 _(NoFloatPolicyAfter<0>) \
1083 _(NoFloatPolicyAfter<1>) \
1084 _(NoFloatPolicyAfter<2>) \
1085 _(ObjectPolicy<0>) \
1086 _(ObjectPolicy<1>) \
1087 _(ObjectPolicy<3>) \
1088 _(StringPolicy<0>) \
1094 // Define for all used TypePolicy specialization, the definition for
1095 // |TypePolicy::Data::thisTypePolicy|. This function returns one constant
1096 // instance of the TypePolicy which is shared among all MIR Instructions of the
1099 // This Macro use __VA_ARGS__ to account for commas of template parameters.
1100 #define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...) \
1101 const TypePolicy* __VA_ARGS__::Data::thisTypePolicy() { \
1102 static constexpr __VA_ARGS__ singletonType; \
1103 return &singletonType; \
1106 TYPE_POLICY_LIST(DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
)
1107 TEMPLATE_TYPE_POLICY_LIST(template <> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
)
1108 #undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
1115 // For extra-good measure in case an unqualified use is ever introduced. (The
1116 // main use in the macro below is explicitly qualified so as not to consult
1117 // this scope and find this function.)
1118 inline TypePolicy
* thisTypePolicy() = delete;
1120 static MIRType
thisTypeSpecialization() {
1121 MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization.");
1126 // For each MIR Instruction, this macro define the |typePolicy| method which is
1127 // using the |thisTypePolicy| method. The |thisTypePolicy| method is either a
1128 // member of the MIR Instruction, such as with MGetElementCache, a member
1129 // inherited from the TypePolicy::Data structure, or a member inherited from
1130 // NoTypePolicy if the MIR instruction has no type policy.
1131 #define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op) \
1132 const TypePolicy* js::jit::M##op::typePolicy() { \
1133 return M##op::thisTypePolicy(); \
1136 MIRType js::jit::M##op::typePolicySpecialization() { \
1137 return thisTypeSpecialization(); \
1140 MIR_OPCODE_LIST(DEFINE_MIR_TYPEPOLICY_MEMBERS_
)
1141 #undef DEFINE_MIR_TYPEPOLICY_MEMBERS_