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"
11 #include "jit/MIRGraph.h"
12 #include "js/ScalarType.h" // js::Scalar::Type
15 using namespace js::jit
;
17 static void EnsureOperandNotFloat32(TempAllocator
& alloc
, MInstruction
* def
,
19 MDefinition
* in
= def
->getOperand(op
);
20 if (in
->type() == MIRType::Float32
) {
21 MToDouble
* replace
= MToDouble::New(alloc
, in
);
22 def
->block()->insertBefore(def
, replace
);
23 if (def
->isRecoveredOnBailout()) {
24 replace
->setRecoveredOnBailout();
26 def
->replaceOperand(op
, replace
);
31 [[nodiscard
]] static bool ConvertOperand(TempAllocator
& alloc
,
32 MInstruction
* def
, unsigned op
,
34 MDefinition
* in
= def
->getOperand(op
);
35 if (in
->type() == expected
) {
39 auto* replace
= T::New(alloc
, in
);
40 def
->block()->insertBefore(def
, replace
);
41 def
->replaceOperand(op
, replace
);
43 return replace
->typePolicy()->adjustInputs(alloc
, replace
);
46 static void SetTypePolicyBailoutKind(MInstruction
* newIns
,
47 MInstruction
* forIns
) {
48 // Infallible ToFloat32 or ToDouble doesn't bail out.
49 if ((newIns
->isToFloat32() || newIns
->isToDouble()) && !newIns
->isGuard()) {
53 // Ensure we're not introducing TypePolicy bailouts for transpiled CacheIR
54 // instructions. Unbox operations and other guards should have been inserted
57 // This avoids a performance cliff because frequent TypePolicy bailouts will
58 // disable Warp compilation instead of invalidating the script.
60 MOZ_ASSERT(forIns
->bailoutKind() != BailoutKind::TranspiledCacheIR
);
62 newIns
->setBailoutKind(BailoutKind::TypePolicy
);
65 [[nodiscard
]] static bool UnboxOperand(TempAllocator
& alloc
, MInstruction
* def
,
66 unsigned op
, MIRType expected
) {
67 MDefinition
* in
= def
->getOperand(op
);
68 if (in
->type() == expected
) {
72 auto* replace
= MUnbox::New(alloc
, in
, expected
, MUnbox::Fallible
);
73 SetTypePolicyBailoutKind(replace
, def
);
74 def
->block()->insertBefore(def
, replace
);
75 def
->replaceOperand(op
, replace
);
77 return replace
->typePolicy()->adjustInputs(alloc
, replace
);
80 MDefinition
* js::jit::AlwaysBoxAt(TempAllocator
& alloc
, MInstruction
* at
,
81 MDefinition
* operand
) {
82 MDefinition
* boxedOperand
= operand
;
83 // Replace Float32 by double
84 if (operand
->type() == MIRType::Float32
) {
85 MInstruction
* replace
= MToDouble::New(alloc
, operand
);
86 at
->block()->insertBefore(at
, replace
);
87 boxedOperand
= replace
;
89 MBox
* box
= MBox::New(alloc
, boxedOperand
);
90 at
->block()->insertBefore(at
, box
);
94 static MDefinition
* BoxAt(TempAllocator
& alloc
, MInstruction
* at
,
95 MDefinition
* operand
) {
96 if (operand
->isUnbox()) {
97 return operand
->toUnbox()->input();
99 return AlwaysBoxAt(alloc
, at
, operand
);
102 bool BoxInputsPolicy::staticAdjustInputs(TempAllocator
& alloc
,
104 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
105 MDefinition
* in
= ins
->getOperand(i
);
106 if (in
->type() == MIRType::Value
) {
109 ins
->replaceOperand(i
, BoxAt(alloc
, ins
, in
));
114 bool ArithPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
115 MOZ_ASSERT(IsNumberType(ins
->type()));
116 MOZ_ASSERT(ins
->type() == MIRType::Double
|| ins
->type() == MIRType::Int32
||
117 ins
->type() == MIRType::Float32
);
119 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
120 MDefinition
* in
= ins
->getOperand(i
);
121 if (in
->type() == ins
->type()) {
125 MInstruction
* replace
;
127 if (ins
->type() == MIRType::Double
) {
128 replace
= MToDouble::New(alloc
, in
);
129 } else if (ins
->type() == MIRType::Float32
) {
130 replace
= MToFloat32::New(alloc
, in
);
132 replace
= MToNumberInt32::New(alloc
, in
);
135 SetTypePolicyBailoutKind(replace
, ins
);
136 ins
->block()->insertBefore(ins
, replace
);
137 ins
->replaceOperand(i
, replace
);
139 if (!replace
->typePolicy()->adjustInputs(alloc
, replace
)) {
147 bool BigIntArithPolicy::adjustInputs(TempAllocator
& alloc
,
148 MInstruction
* ins
) const {
149 MOZ_ASSERT(ins
->type() == MIRType::BigInt
);
151 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
152 if (!ConvertOperand
<MToBigInt
>(alloc
, ins
, i
, MIRType::BigInt
)) {
160 bool AllDoublePolicy::staticAdjustInputs(TempAllocator
& alloc
,
162 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
163 MDefinition
* in
= ins
->getOperand(i
);
164 if (in
->type() == MIRType::Double
) {
168 if (!alloc
.ensureBallast()) {
171 MInstruction
* replace
= MToDouble::New(alloc
, in
);
173 ins
->block()->insertBefore(ins
, replace
);
174 ins
->replaceOperand(i
, replace
);
176 if (!replace
->typePolicy()->adjustInputs(alloc
, replace
)) {
184 bool ComparePolicy::adjustInputs(TempAllocator
& alloc
,
185 MInstruction
* def
) const {
186 MOZ_ASSERT(def
->isCompare());
187 MCompare
* compare
= def
->toCompare();
189 // Convert Float32 operands to doubles
190 for (size_t i
= 0; i
< 2; i
++) {
191 MDefinition
* in
= def
->getOperand(i
);
192 if (in
->type() == MIRType::Float32
) {
193 MInstruction
* replace
= MToDouble::New(alloc
, in
);
194 def
->block()->insertBefore(def
, replace
);
195 def
->replaceOperand(i
, replace
);
199 auto replaceOperand
= [&](size_t index
, auto* replace
) {
200 def
->block()->insertBefore(def
, replace
);
201 def
->replaceOperand(index
, replace
);
202 return replace
->typePolicy()->adjustInputs(alloc
, replace
);
205 if (compare
->compareType() == MCompare::Compare_Undefined
||
206 compare
->compareType() == MCompare::Compare_Null
) {
207 // Nothing to do for undefined and null, lowering handles all types.
211 if (compare
->compareType() == MCompare::Compare_UIntPtr
) {
212 MOZ_ASSERT(compare
->lhs()->type() == MIRType::IntPtr
);
213 MOZ_ASSERT(compare
->rhs()->type() == MIRType::IntPtr
);
217 // Compare_BigInt_Int32 specialization is done for "BigInt <cmp> Int32".
218 // Compare_BigInt_Double specialization is done for "BigInt <cmp> Double".
219 // Compare_BigInt_String specialization is done for "BigInt <cmp> String".
220 if (compare
->compareType() == MCompare::Compare_BigInt_Int32
||
221 compare
->compareType() == MCompare::Compare_BigInt_Double
||
222 compare
->compareType() == MCompare::Compare_BigInt_String
) {
223 if (MDefinition
* in
= def
->getOperand(0); in
->type() != MIRType::BigInt
) {
225 MUnbox::New(alloc
, in
, MIRType::BigInt
, MUnbox::Infallible
);
226 if (!replaceOperand(0, replace
)) {
231 MDefinition
* in
= def
->getOperand(1);
233 MInstruction
* replace
= nullptr;
234 if (compare
->compareType() == MCompare::Compare_BigInt_Int32
) {
235 if (in
->type() != MIRType::Int32
) {
236 replace
= MToNumberInt32::New(
237 alloc
, in
, IntConversionInputKind::NumbersOrBoolsOnly
);
239 } else if (compare
->compareType() == MCompare::Compare_BigInt_Double
) {
240 if (in
->type() != MIRType::Double
) {
241 replace
= MToDouble::New(alloc
, in
, MToFPInstruction::NumbersOnly
);
244 MOZ_ASSERT(compare
->compareType() == MCompare::Compare_BigInt_String
);
245 if (in
->type() != MIRType::String
) {
246 replace
= MUnbox::New(alloc
, in
, MIRType::String
, MUnbox::Infallible
);
251 if (!replaceOperand(1, replace
)) {
259 // Convert all inputs to the right input type
260 MIRType type
= compare
->inputType();
261 MOZ_ASSERT(type
== MIRType::Int32
|| type
== MIRType::Double
||
262 type
== MIRType::Float32
|| type
== MIRType::Object
||
263 type
== MIRType::String
|| type
== MIRType::Symbol
||
264 type
== MIRType::BigInt
);
265 for (size_t i
= 0; i
< 2; i
++) {
266 MDefinition
* in
= def
->getOperand(i
);
267 if (in
->type() == type
) {
271 MInstruction
* replace
;
274 case MIRType::Double
:
275 replace
= MToDouble::New(alloc
, in
, MToFPInstruction::NumbersOnly
);
277 case MIRType::Float32
:
278 replace
= MToFloat32::New(alloc
, in
, MToFPInstruction::NumbersOnly
);
280 case MIRType::Int32
: {
281 IntConversionInputKind convert
= IntConversionInputKind::NumbersOnly
;
282 replace
= MToNumberInt32::New(alloc
, in
, convert
);
285 case MIRType::Object
:
286 replace
= MUnbox::New(alloc
, in
, MIRType::Object
, MUnbox::Infallible
);
288 case MIRType::String
:
289 replace
= MUnbox::New(alloc
, in
, MIRType::String
, MUnbox::Infallible
);
291 case MIRType::Symbol
:
292 replace
= MUnbox::New(alloc
, in
, MIRType::Symbol
, MUnbox::Infallible
);
294 case MIRType::BigInt
:
295 replace
= MUnbox::New(alloc
, in
, MIRType::BigInt
, MUnbox::Infallible
);
298 MOZ_CRASH("Unknown compare specialization");
301 if (!replaceOperand(i
, replace
)) {
309 bool TestPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
310 MDefinition
* op
= ins
->getOperand(0);
311 switch (op
->type()) {
314 case MIRType::Undefined
:
315 case MIRType::Boolean
:
317 case MIRType::Double
:
318 case MIRType::Float32
:
319 case MIRType::Symbol
:
320 case MIRType::BigInt
:
321 case MIRType::Object
:
324 case MIRType::String
: {
325 MStringLength
* length
= MStringLength::New(alloc
, op
);
326 ins
->block()->insertBefore(ins
, length
);
327 ins
->replaceOperand(0, length
);
332 MOZ_ASSERT(IsMagicType(op
->type()));
333 ins
->replaceOperand(0, BoxAt(alloc
, ins
, op
));
339 bool BitwisePolicy::adjustInputs(TempAllocator
& alloc
,
340 MInstruction
* ins
) const {
341 MOZ_ASSERT(ins
->type() == MIRType::Int32
|| ins
->type() == MIRType::Double
);
343 // This policy works for both unary and binary bitwise operations.
344 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
345 if (!ConvertOperand
<MTruncateToInt32
>(alloc
, ins
, i
, MIRType::Int32
)) {
353 bool PowPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
354 MOZ_ASSERT(ins
->type() == MIRType::Int32
|| ins
->type() == MIRType::Double
);
356 if (ins
->type() == MIRType::Int32
) {
357 // Both operands must be int32.
358 return UnboxedInt32Policy
<0>::staticAdjustInputs(alloc
, ins
) &&
359 UnboxedInt32Policy
<1>::staticAdjustInputs(alloc
, ins
);
362 // Otherwise, input must be a double.
363 if (!DoublePolicy
<0>::staticAdjustInputs(alloc
, ins
)) {
367 // Power may be an int32 or a double. Integers receive a faster path.
368 MDefinition
* power
= ins
->toPow()->power();
369 if (power
->isToDouble()) {
370 MDefinition
* input
= power
->toToDouble()->input();
371 if (input
->type() == MIRType::Int32
) {
372 ins
->replaceOperand(1, input
);
376 return DoublePolicy
<1>::staticAdjustInputs(alloc
, ins
);
379 bool SignPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
380 MOZ_ASSERT(ins
->isSign());
381 MIRType specialization
= ins
->typePolicySpecialization();
383 // MSign is specialized for int32 input types.
384 if (specialization
== MIRType::Int32
) {
385 return UnboxedInt32Policy
<0>::staticAdjustInputs(alloc
, ins
);
388 // Otherwise convert input to double.
389 MOZ_ASSERT(IsFloatingPointType(specialization
));
390 return DoublePolicy
<0>::staticAdjustInputs(alloc
, ins
);
393 template <unsigned Op
>
394 bool SymbolPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
396 return UnboxOperand(alloc
, ins
, Op
, MIRType::Symbol
);
399 template bool SymbolPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
402 template <unsigned Op
>
403 bool BooleanPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
405 return UnboxOperand(alloc
, ins
, Op
, MIRType::Boolean
);
408 template bool BooleanPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
411 template <unsigned Op
>
412 bool StringPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
414 return UnboxOperand(alloc
, ins
, Op
, MIRType::String
);
417 template bool StringPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
419 template bool StringPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
421 template bool StringPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
424 template <unsigned Op
>
425 bool ConvertToStringPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
427 MDefinition
* in
= ins
->getOperand(Op
);
428 if (in
->type() == MIRType::String
) {
433 MToString::New(alloc
, in
, MToString::SideEffectHandling::Bailout
);
434 ins
->block()->insertBefore(ins
, replace
);
435 ins
->replaceOperand(Op
, replace
);
437 return ToStringPolicy::staticAdjustInputs(alloc
, replace
);
440 template bool ConvertToStringPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
442 template bool ConvertToStringPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
444 template bool ConvertToStringPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
447 template <unsigned Op
>
448 bool BigIntPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
450 return UnboxOperand(alloc
, ins
, Op
, MIRType::BigInt
);
453 template bool BigIntPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
455 template bool BigIntPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
458 template <unsigned Op
>
459 bool UnboxedInt32Policy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
461 return UnboxOperand(alloc
, def
, Op
, MIRType::Int32
);
464 template bool UnboxedInt32Policy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
466 template bool UnboxedInt32Policy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
468 template bool UnboxedInt32Policy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
470 template bool UnboxedInt32Policy
<3>::staticAdjustInputs(TempAllocator
& alloc
,
473 template <unsigned Op
>
474 bool Int32OrIntPtrPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
476 MDefinition
* in
= def
->getOperand(Op
);
477 if (in
->type() == MIRType::IntPtr
) {
481 return UnboxedInt32Policy
<Op
>::staticAdjustInputs(alloc
, def
);
484 template bool Int32OrIntPtrPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
486 template bool Int32OrIntPtrPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
489 template <unsigned Op
>
490 bool ConvertToInt32Policy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
492 return ConvertOperand
<MToNumberInt32
>(alloc
, def
, Op
, MIRType::Int32
);
495 template bool ConvertToInt32Policy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
498 template <unsigned Op
>
499 bool TruncateToInt32OrToBigIntPolicy
<Op
>::staticAdjustInputs(
500 TempAllocator
& alloc
, MInstruction
* def
) {
501 MOZ_ASSERT(def
->isCompareExchangeTypedArrayElement() ||
502 def
->isAtomicExchangeTypedArrayElement() ||
503 def
->isAtomicTypedArrayElementBinop());
506 if (def
->isCompareExchangeTypedArrayElement()) {
507 type
= def
->toCompareExchangeTypedArrayElement()->arrayType();
508 } else if (def
->isAtomicExchangeTypedArrayElement()) {
509 type
= def
->toAtomicExchangeTypedArrayElement()->arrayType();
511 type
= def
->toAtomicTypedArrayElementBinop()->arrayType();
514 if (Scalar::isBigIntType(type
)) {
515 return ConvertOperand
<MToBigInt
>(alloc
, def
, Op
, MIRType::BigInt
);
517 return ConvertOperand
<MTruncateToInt32
>(alloc
, def
, Op
, MIRType::Int32
);
520 template bool TruncateToInt32OrToBigIntPolicy
<2>::staticAdjustInputs(
521 TempAllocator
& alloc
, MInstruction
* def
);
522 template bool TruncateToInt32OrToBigIntPolicy
<3>::staticAdjustInputs(
523 TempAllocator
& alloc
, MInstruction
* def
);
525 template <unsigned Op
>
526 bool DoublePolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
528 return ConvertOperand
<MToDouble
>(alloc
, def
, Op
, MIRType::Double
);
531 template bool DoublePolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
533 template bool DoublePolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
536 template <unsigned Op
>
537 bool Float32Policy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
539 return ConvertOperand
<MToFloat32
>(alloc
, def
, Op
, MIRType::Float32
);
542 template bool Float32Policy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
544 template bool Float32Policy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
546 template bool Float32Policy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
549 template <unsigned Op
>
550 bool FloatingPointPolicy
<Op
>::adjustInputs(TempAllocator
& alloc
,
551 MInstruction
* def
) const {
552 MIRType policyType
= def
->typePolicySpecialization();
553 if (policyType
== MIRType::Double
) {
554 return DoublePolicy
<Op
>::staticAdjustInputs(alloc
, def
);
556 return Float32Policy
<Op
>::staticAdjustInputs(alloc
, def
);
559 template bool FloatingPointPolicy
<0>::adjustInputs(TempAllocator
& alloc
,
560 MInstruction
* def
) const;
562 template <unsigned Op
>
563 bool NoFloatPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
565 EnsureOperandNotFloat32(alloc
, def
, Op
);
569 template bool NoFloatPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
571 template bool NoFloatPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
573 template bool NoFloatPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
575 template bool NoFloatPolicy
<3>::staticAdjustInputs(TempAllocator
& alloc
,
578 template <unsigned FirstOp
>
579 bool NoFloatPolicyAfter
<FirstOp
>::staticAdjustInputs(TempAllocator
& alloc
,
581 for (size_t op
= FirstOp
, e
= def
->numOperands(); op
< e
; op
++) {
582 EnsureOperandNotFloat32(alloc
, def
, op
);
587 template bool NoFloatPolicyAfter
<0>::staticAdjustInputs(TempAllocator
& alloc
,
589 template bool NoFloatPolicyAfter
<1>::staticAdjustInputs(TempAllocator
& alloc
,
591 template bool NoFloatPolicyAfter
<2>::staticAdjustInputs(TempAllocator
& alloc
,
594 template <unsigned Op
>
595 bool BoxPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
597 MDefinition
* in
= ins
->getOperand(Op
);
598 if (in
->type() == MIRType::Value
) {
602 ins
->replaceOperand(Op
, BoxAt(alloc
, ins
, in
));
606 template bool BoxPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
608 template bool BoxPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
610 template bool BoxPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
613 template <unsigned Op
, MIRType Type
>
614 bool BoxExceptPolicy
<Op
, Type
>::staticAdjustInputs(TempAllocator
& alloc
,
616 MDefinition
* in
= ins
->getOperand(Op
);
617 if (in
->type() == Type
) {
620 return BoxPolicy
<Op
>::staticAdjustInputs(alloc
, ins
);
623 template bool BoxExceptPolicy
<0, MIRType::Object
>::staticAdjustInputs(
624 TempAllocator
& alloc
, MInstruction
* ins
);
626 template <unsigned Op
>
627 bool CacheIdPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
629 MDefinition
* in
= ins
->getOperand(Op
);
630 switch (in
->type()) {
632 case MIRType::String
:
633 case MIRType::Symbol
:
636 return BoxPolicy
<Op
>::staticAdjustInputs(alloc
, ins
);
640 template bool CacheIdPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
642 template bool CacheIdPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
645 bool ToDoublePolicy::staticAdjustInputs(TempAllocator
& alloc
,
647 MOZ_ASSERT(ins
->isToDouble() || ins
->isToFloat32());
649 MDefinition
* in
= ins
->getOperand(0);
650 MToFPInstruction::ConversionKind conversion
;
651 if (ins
->isToDouble()) {
652 conversion
= ins
->toToDouble()->conversion();
654 conversion
= ins
->toToFloat32()->conversion();
657 switch (in
->type()) {
659 case MIRType::Float32
:
660 case MIRType::Double
:
662 // No need for boxing for these types.
665 // No need for boxing, when we will convert.
666 if (conversion
== MToFPInstruction::NonStringPrimitives
) {
670 case MIRType::Undefined
:
671 case MIRType::Boolean
:
672 // No need for boxing, when we will convert.
673 if (conversion
== MToFPInstruction::NonStringPrimitives
) {
677 case MIRType::Object
:
678 case MIRType::String
:
679 case MIRType::Symbol
:
680 case MIRType::BigInt
:
681 // Objects might be effectful. Symbols and BigInts give TypeError.
687 in
= BoxAt(alloc
, ins
, in
);
688 ins
->replaceOperand(0, in
);
692 bool ToInt32Policy::staticAdjustInputs(TempAllocator
& alloc
,
694 MOZ_ASSERT(ins
->isToNumberInt32() || ins
->isTruncateToInt32());
696 IntConversionInputKind conversion
= IntConversionInputKind::Any
;
697 if (ins
->isToNumberInt32()) {
698 conversion
= ins
->toToNumberInt32()->conversion();
701 MDefinition
* in
= ins
->getOperand(0);
702 switch (in
->type()) {
704 case MIRType::Float32
:
705 case MIRType::Double
:
707 // No need for boxing for these types.
709 case MIRType::Undefined
:
710 // No need for boxing when truncating.
711 if (ins
->isTruncateToInt32()) {
716 // No need for boxing, when we will convert.
717 if (conversion
== IntConversionInputKind::Any
) {
721 case MIRType::Boolean
:
722 // No need for boxing, when we will convert.
723 if (conversion
== IntConversionInputKind::Any
) {
726 if (conversion
== IntConversionInputKind::NumbersOrBoolsOnly
) {
730 case MIRType::Object
:
731 case MIRType::String
:
732 case MIRType::Symbol
:
733 case MIRType::BigInt
:
734 // Objects might be effectful. Symbols and BigInts give TypeError.
740 in
= BoxAt(alloc
, ins
, in
);
741 ins
->replaceOperand(0, in
);
745 bool ToBigIntPolicy::staticAdjustInputs(TempAllocator
& alloc
,
747 MOZ_ASSERT(ins
->isToBigInt());
749 MDefinition
* in
= ins
->getOperand(0);
750 switch (in
->type()) {
751 case MIRType::BigInt
:
753 // No need for boxing for these types.
756 // Any other types need to be boxed.
760 in
= BoxAt(alloc
, ins
, in
);
761 ins
->replaceOperand(0, in
);
765 bool ToStringPolicy::staticAdjustInputs(TempAllocator
& alloc
,
767 MOZ_ASSERT(ins
->isToString());
769 MIRType type
= ins
->getOperand(0)->type();
770 if (type
== MIRType::Object
|| type
== MIRType::Symbol
||
771 type
== MIRType::BigInt
) {
772 ins
->replaceOperand(0, BoxAt(alloc
, ins
, ins
->getOperand(0)));
776 // TODO remove the following line once 966957 has landed
777 EnsureOperandNotFloat32(alloc
, ins
, 0);
782 bool ToInt64Policy::staticAdjustInputs(TempAllocator
& alloc
,
784 MOZ_ASSERT(ins
->isToInt64());
786 MDefinition
* input
= ins
->getOperand(0);
787 MIRType type
= input
->type();
790 case MIRType::BigInt
: {
791 auto* replace
= MTruncateBigIntToInt64::New(alloc
, input
);
792 ins
->block()->insertBefore(ins
, replace
);
793 ins
->replaceOperand(0, replace
);
796 // No need for boxing for these types, because they are handled specially
797 // when this instruction is lowered to LIR.
798 case MIRType::Boolean
:
799 case MIRType::String
:
804 ins
->replaceOperand(0, BoxAt(alloc
, ins
, ins
->getOperand(0)));
811 template <unsigned Op
>
812 bool ObjectPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
814 MOZ_ASSERT(ins
->getOperand(Op
)->type() != MIRType::Slots
);
815 MOZ_ASSERT(ins
->getOperand(Op
)->type() != MIRType::Elements
);
817 return UnboxOperand(alloc
, ins
, Op
, MIRType::Object
);
820 template bool ObjectPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
822 template bool ObjectPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
824 template bool ObjectPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
826 template bool ObjectPolicy
<3>::staticAdjustInputs(TempAllocator
& alloc
,
829 bool CallPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
832 call
= ins
->toCall();
834 call
= ins
->toCallClassHook();
837 MDefinition
* func
= call
->getCallee();
838 if (func
->type() != MIRType::Object
) {
839 MInstruction
* unbox
=
840 MUnbox::New(alloc
, func
, MIRType::Object
, MUnbox::Fallible
);
841 SetTypePolicyBailoutKind(unbox
, call
);
842 call
->block()->insertBefore(call
, unbox
);
843 call
->replaceCallee(unbox
);
845 if (!unbox
->typePolicy()->adjustInputs(alloc
, unbox
)) {
850 for (uint32_t i
= 0; i
< call
->numStackArgs(); i
++) {
851 if (!alloc
.ensureBallast()) {
854 EnsureOperandNotFloat32(alloc
, call
, MCallBase::IndexOfStackArg(i
));
860 bool MegamorphicSetElementPolicy::adjustInputs(TempAllocator
& alloc
,
861 MInstruction
* ins
) const {
862 // The first operand should be an object.
863 if (!SingleObjectPolicy::staticAdjustInputs(alloc
, ins
)) {
867 // Box the index and value operands.
868 for (size_t i
= 1, e
= ins
->numOperands(); i
< e
; i
++) {
869 MDefinition
* in
= ins
->getOperand(i
);
870 if (in
->type() == MIRType::Value
) {
873 ins
->replaceOperand(i
, BoxAt(alloc
, ins
, in
));
878 bool StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator
& alloc
,
880 Scalar::Type writeType
,
883 if (Scalar::isBigIntType(writeType
)) {
884 if (value
->type() == MIRType::BigInt
) {
888 auto* replace
= MToBigInt::New(alloc
, value
);
889 ins
->block()->insertBefore(ins
, replace
);
890 ins
->replaceOperand(valueOperand
, replace
);
892 return replace
->typePolicy()->adjustInputs(alloc
, replace
);
895 MDefinition
* curValue
= value
;
896 // First, ensure the value is int32, boolean, double or Value.
897 // The conversion is based on TypedArrayObjectTemplate::setElementTail.
898 switch (value
->type()) {
900 case MIRType::Double
:
901 case MIRType::Float32
:
902 case MIRType::Boolean
:
906 value
->setImplicitlyUsedUnchecked();
907 value
= MConstant::New(alloc
, Int32Value(0));
908 ins
->block()->insertBefore(ins
, value
->toInstruction());
910 case MIRType::Undefined
:
911 value
->setImplicitlyUsedUnchecked();
912 value
= MConstant::New(alloc
, JS::NaNValue());
913 ins
->block()->insertBefore(ins
, value
->toInstruction());
915 case MIRType::Object
:
916 case MIRType::String
:
917 case MIRType::Symbol
:
918 case MIRType::BigInt
:
919 value
= BoxAt(alloc
, ins
, value
);
922 MOZ_CRASH("Unexpected type");
925 if (value
!= curValue
) {
926 ins
->replaceOperand(valueOperand
, value
);
931 value
->type() == MIRType::Int32
|| value
->type() == MIRType::Boolean
||
932 value
->type() == MIRType::Double
|| value
->type() == MIRType::Float32
||
933 value
->type() == MIRType::Value
);
942 if (value
->type() != MIRType::Int32
) {
943 value
= MTruncateToInt32::New(alloc
, value
);
944 ins
->block()->insertBefore(ins
, value
->toInstruction());
947 case Scalar::Uint8Clamped
:
948 // The transpiler should have inserted MClampToUint8.
949 MOZ_ASSERT(value
->type() == MIRType::Int32
);
951 case Scalar::Float32
:
952 if (value
->type() != MIRType::Float32
) {
953 value
= MToFloat32::New(alloc
, value
);
954 ins
->block()->insertBefore(ins
, value
->toInstruction());
957 case Scalar::Float64
:
958 if (value
->type() != MIRType::Double
) {
959 value
= MToDouble::New(alloc
, value
);
960 ins
->block()->insertBefore(ins
, value
->toInstruction());
964 MOZ_CRASH("Invalid array type");
967 if (value
!= curValue
) {
968 ins
->replaceOperand(valueOperand
, value
);
974 bool StoreUnboxedScalarPolicy::adjustInputs(TempAllocator
& alloc
,
975 MInstruction
* ins
) const {
976 MStoreUnboxedScalar
* store
= ins
->toStoreUnboxedScalar();
977 MOZ_ASSERT(store
->elements()->type() == MIRType::Elements
);
978 MOZ_ASSERT(store
->index()->type() == MIRType::IntPtr
);
980 return adjustValueInput(alloc
, store
, store
->writeType(), store
->value(), 2);
983 bool StoreDataViewElementPolicy::adjustInputs(TempAllocator
& alloc
,
984 MInstruction
* ins
) const {
985 auto* store
= ins
->toStoreDataViewElement();
986 MOZ_ASSERT(store
->elements()->type() == MIRType::Elements
);
987 MOZ_ASSERT(store
->index()->type() == MIRType::IntPtr
);
988 MOZ_ASSERT(store
->littleEndian()->type() == MIRType::Boolean
);
990 return StoreUnboxedScalarPolicy::adjustValueInput(
991 alloc
, ins
, store
->writeType(), store
->value(), 2);
994 bool StoreTypedArrayHolePolicy::adjustInputs(TempAllocator
& alloc
,
995 MInstruction
* ins
) const {
996 MStoreTypedArrayElementHole
* store
= ins
->toStoreTypedArrayElementHole();
997 MOZ_ASSERT(store
->elements()->type() == MIRType::Elements
);
998 MOZ_ASSERT(store
->index()->type() == MIRType::IntPtr
);
999 MOZ_ASSERT(store
->length()->type() == MIRType::IntPtr
);
1001 return StoreUnboxedScalarPolicy::adjustValueInput(
1002 alloc
, ins
, store
->arrayType(), store
->value(), 3);
1005 bool ClampPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
1006 MDefinition
* in
= ins
->toClampToUint8()->input();
1008 switch (in
->type()) {
1009 case MIRType::Int32
:
1010 case MIRType::Double
:
1011 case MIRType::Value
:
1014 ins
->replaceOperand(0, BoxAt(alloc
, ins
, in
));
1021 // Lists of all TypePolicy specializations which are used by MIR Instructions.
1022 #define TYPE_POLICY_LIST(_) \
1023 _(AllDoublePolicy) \
1025 _(BigIntArithPolicy) \
1027 _(BoxInputsPolicy) \
1029 _(MegamorphicSetElementPolicy) \
1034 _(StoreDataViewElementPolicy) \
1035 _(StoreTypedArrayHolePolicy) \
1036 _(StoreUnboxedScalarPolicy) \
1044 #define TEMPLATE_TYPE_POLICY_LIST(_) \
1045 _(BigIntPolicy<0>) \
1046 _(BooleanPolicy<0>) \
1047 _(BoxExceptPolicy<0, MIRType::Object>) \
1049 _(ConvertToInt32Policy<0>) \
1050 _(ConvertToStringPolicy<0>) \
1051 _(ConvertToStringPolicy<2>) \
1052 _(DoublePolicy<0>) \
1053 _(FloatingPointPolicy<0>) \
1054 _(UnboxedInt32Policy<0>) \
1055 _(UnboxedInt32Policy<1>) \
1056 _(TruncateToInt32OrToBigIntPolicy<2>) \
1057 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, BoxPolicy<2>>) \
1058 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \
1059 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>) \
1060 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy<2>>) \
1061 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>>) \
1062 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1063 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<2>>) \
1064 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, UnboxedInt32Policy<2>>) \
1065 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2>>) \
1066 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2>>) \
1067 _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1068 _(MixPolicy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2>>) \
1069 _(MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2>>) \
1070 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, UnboxedInt32Policy<2>>) \
1071 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>, \
1073 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>, \
1074 UnboxedInt32Policy<3>>) \
1075 _(MixPolicy<TruncateToInt32OrToBigIntPolicy<2>, \
1076 TruncateToInt32OrToBigIntPolicy<3>>) \
1077 _(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>) \
1078 _(MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, \
1079 CacheIdPolicy<2>>) \
1080 _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1>>) \
1081 _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>>) \
1082 _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>>) \
1083 _(MixPolicy<DoublePolicy<0>, DoublePolicy<1>>) \
1084 _(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>>) \
1085 _(MixPolicy<Int32OrIntPtrPolicy<0>, Int32OrIntPtrPolicy<1>>) \
1086 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>) \
1087 _(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>) \
1088 _(MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1>>) \
1089 _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1>>) \
1090 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>>) \
1091 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<2>>) \
1092 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1>>) \
1093 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2>>) \
1094 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3>>) \
1095 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicyAfter<1>>) \
1096 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>>) \
1097 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>>) \
1098 _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2>>) \
1099 _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0>>) \
1100 _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>>) \
1101 _(MixPolicy<StringPolicy<0>, StringPolicy<1>>) \
1102 _(MixPolicy<BoxPolicy<0>, BoxPolicy<1>>) \
1103 _(MixPolicy<BoxPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \
1104 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<2>, ObjectPolicy<3>>) \
1105 _(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, ObjectPolicy<1>>) \
1106 _(MixPolicy<UnboxedInt32Policy<0>, BigIntPolicy<1>>) \
1107 _(MixPolicy<UnboxedInt32Policy<0>, NoFloatPolicyAfter<1>>) \
1108 _(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>, \
1109 NoFloatPolicyAfter<2>>) \
1110 _(NoFloatPolicy<0>) \
1111 _(NoFloatPolicy<1>) \
1112 _(NoFloatPolicy<2>) \
1113 _(NoFloatPolicyAfter<0>) \
1114 _(NoFloatPolicyAfter<1>) \
1115 _(NoFloatPolicyAfter<2>) \
1116 _(ObjectPolicy<0>) \
1117 _(ObjectPolicy<1>) \
1118 _(ObjectPolicy<3>) \
1119 _(StringPolicy<0>) \
1125 // Define for all used TypePolicy specialization, the definition for
1126 // |TypePolicy::Data::thisTypePolicy|. This function returns one constant
1127 // instance of the TypePolicy which is shared among all MIR Instructions of the
1130 // This Macro use __VA_ARGS__ to account for commas of template parameters.
1131 #define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...) \
1132 const TypePolicy* __VA_ARGS__::Data::thisTypePolicy() { \
1133 static constexpr __VA_ARGS__ singletonType; \
1134 return &singletonType; \
1137 TYPE_POLICY_LIST(DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
)
1138 TEMPLATE_TYPE_POLICY_LIST(template <> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
)
1139 #undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
1146 // For extra-good measure in case an unqualified use is ever introduced. (The
1147 // main use in the macro below is explicitly qualified so as not to consult
1148 // this scope and find this function.)
1149 inline TypePolicy
* thisTypePolicy() = delete;
1151 static MIRType
thisTypeSpecialization() {
1152 MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization.");
1157 // For each MIR Instruction, this macro define the |typePolicy| method which is
1158 // using the |thisTypePolicy| method. The |thisTypePolicy| method is either a
1159 // member of the MIR Instruction, such as with MGetElementCache, a member
1160 // inherited from the TypePolicy::Data structure, or a member inherited from
1161 // NoTypePolicy if the MIR instruction has no type policy.
1162 #define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op) \
1163 const TypePolicy* js::jit::M##op::typePolicy() { \
1164 return M##op::thisTypePolicy(); \
1167 MIRType js::jit::M##op::typePolicySpecialization() { \
1168 return thisTypeSpecialization(); \
1171 MIR_OPCODE_LIST(DEFINE_MIR_TYPEPOLICY_MEMBERS_
)
1172 #undef DEFINE_MIR_TYPEPOLICY_MEMBERS_