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_UIntPtr
:
248 MOZ_ASSERT(compare
->lhs()->type() == MIRType::IntPtr
);
249 MOZ_ASSERT(compare
->rhs()->type() == MIRType::IntPtr
);
251 case MCompare::Compare_Double
:
252 return convertOperand(0, MIRType::Double
) &&
253 convertOperand(1, MIRType::Double
);
254 case MCompare::Compare_Float32
:
255 return convertOperand(0, MIRType::Float32
) &&
256 convertOperand(1, MIRType::Float32
);
257 case MCompare::Compare_String
:
258 return convertOperand(0, MIRType::String
) &&
259 convertOperand(1, MIRType::String
);
260 case MCompare::Compare_Symbol
:
261 return convertOperand(0, MIRType::Symbol
) &&
262 convertOperand(1, MIRType::Symbol
);
263 case MCompare::Compare_Object
:
264 return convertOperand(0, MIRType::Object
) &&
265 convertOperand(1, MIRType::Object
);
266 case MCompare::Compare_BigInt
:
267 return convertOperand(0, MIRType::BigInt
) &&
268 convertOperand(1, MIRType::BigInt
);
269 case MCompare::Compare_BigInt_Int32
:
270 return convertOperand(0, MIRType::BigInt
) &&
271 convertOperand(1, MIRType::Int32
);
272 case MCompare::Compare_BigInt_Double
:
273 return convertOperand(0, MIRType::BigInt
) &&
274 convertOperand(1, MIRType::Double
);
275 case MCompare::Compare_BigInt_String
:
276 return convertOperand(0, MIRType::BigInt
) &&
277 convertOperand(1, MIRType::String
);
279 MOZ_CRASH("Unexpected compare type");
285 bool TestPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
286 MDefinition
* op
= ins
->getOperand(0);
287 switch (op
->type()) {
290 case MIRType::Undefined
:
291 case MIRType::Boolean
:
293 case MIRType::Double
:
294 case MIRType::Float32
:
295 case MIRType::Symbol
:
296 case MIRType::BigInt
:
297 case MIRType::Object
:
300 case MIRType::String
: {
301 MStringLength
* length
= MStringLength::New(alloc
, op
);
302 ins
->block()->insertBefore(ins
, length
);
303 ins
->replaceOperand(0, length
);
308 MOZ_ASSERT(IsMagicType(op
->type()));
309 ins
->replaceOperand(0, BoxAt(alloc
, ins
, op
));
315 bool BitwisePolicy::adjustInputs(TempAllocator
& alloc
,
316 MInstruction
* ins
) const {
317 MOZ_ASSERT(ins
->type() == MIRType::Int32
|| ins
->type() == MIRType::Double
);
319 // This policy works for both unary and binary bitwise operations.
320 for (size_t i
= 0, e
= ins
->numOperands(); i
< e
; i
++) {
321 if (!ConvertOperand
<MTruncateToInt32
>(alloc
, ins
, i
, MIRType::Int32
)) {
329 bool PowPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
330 MOZ_ASSERT(ins
->type() == MIRType::Int32
|| ins
->type() == MIRType::Double
);
332 if (ins
->type() == MIRType::Int32
) {
333 // Both operands must be int32.
334 return UnboxedInt32Policy
<0>::staticAdjustInputs(alloc
, ins
) &&
335 UnboxedInt32Policy
<1>::staticAdjustInputs(alloc
, ins
);
338 // Otherwise, input must be a double.
339 if (!DoublePolicy
<0>::staticAdjustInputs(alloc
, ins
)) {
343 // Power may be an int32 or a double. Integers receive a faster path.
344 MDefinition
* power
= ins
->toPow()->power();
345 if (power
->isToDouble()) {
346 MDefinition
* input
= power
->toToDouble()->input();
347 if (input
->type() == MIRType::Int32
) {
348 power
->setImplicitlyUsedUnchecked();
349 ins
->replaceOperand(1, input
);
353 return DoublePolicy
<1>::staticAdjustInputs(alloc
, ins
);
356 bool SignPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
357 MOZ_ASSERT(ins
->isSign());
358 MIRType specialization
= ins
->typePolicySpecialization();
360 // MSign is specialized for int32 input types.
361 if (specialization
== MIRType::Int32
) {
362 return UnboxedInt32Policy
<0>::staticAdjustInputs(alloc
, ins
);
365 // Otherwise convert input to double.
366 MOZ_ASSERT(IsFloatingPointType(specialization
));
367 return DoublePolicy
<0>::staticAdjustInputs(alloc
, ins
);
370 template <unsigned Op
>
371 bool SymbolPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
373 return UnboxOperand(alloc
, ins
, Op
, MIRType::Symbol
);
376 template bool SymbolPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
379 template <unsigned Op
>
380 bool BooleanPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
382 return UnboxOperand(alloc
, ins
, Op
, MIRType::Boolean
);
385 template bool BooleanPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
388 template <unsigned Op
>
389 bool StringPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
391 return UnboxOperand(alloc
, ins
, Op
, MIRType::String
);
394 template bool StringPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
396 template bool StringPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
398 template bool StringPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
401 template <unsigned Op
>
402 bool ConvertToStringPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
404 MDefinition
* in
= ins
->getOperand(Op
);
405 if (in
->type() == MIRType::String
) {
410 MToString::New(alloc
, in
, MToString::SideEffectHandling::Bailout
);
411 ins
->block()->insertBefore(ins
, replace
);
412 ins
->replaceOperand(Op
, replace
);
414 return ToStringPolicy::staticAdjustInputs(alloc
, replace
);
417 template bool ConvertToStringPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
419 template bool ConvertToStringPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
421 template bool ConvertToStringPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
424 template <unsigned Op
>
425 bool BigIntPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
427 return UnboxOperand(alloc
, ins
, Op
, MIRType::BigInt
);
430 template bool BigIntPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
432 template bool BigIntPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
435 template <unsigned Op
>
436 bool UnboxedInt32Policy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
438 return UnboxOperand(alloc
, def
, Op
, MIRType::Int32
);
441 template bool UnboxedInt32Policy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
443 template bool UnboxedInt32Policy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
445 template bool UnboxedInt32Policy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
447 template bool UnboxedInt32Policy
<3>::staticAdjustInputs(TempAllocator
& alloc
,
450 template <unsigned Op
>
451 bool Int32OrIntPtrPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
453 MDefinition
* in
= def
->getOperand(Op
);
454 if (in
->type() == MIRType::IntPtr
) {
458 return UnboxedInt32Policy
<Op
>::staticAdjustInputs(alloc
, def
);
461 template bool Int32OrIntPtrPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
463 template bool Int32OrIntPtrPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
466 template <unsigned Op
>
467 bool ConvertToInt32Policy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
469 return ConvertOperand
<MToNumberInt32
>(alloc
, def
, Op
, MIRType::Int32
);
472 template bool ConvertToInt32Policy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
475 template <unsigned Op
>
476 bool TruncateToInt32OrToBigIntPolicy
<Op
>::staticAdjustInputs(
477 TempAllocator
& alloc
, MInstruction
* def
) {
478 MOZ_ASSERT(def
->isCompareExchangeTypedArrayElement() ||
479 def
->isAtomicExchangeTypedArrayElement() ||
480 def
->isAtomicTypedArrayElementBinop());
483 if (def
->isCompareExchangeTypedArrayElement()) {
484 type
= def
->toCompareExchangeTypedArrayElement()->arrayType();
485 } else if (def
->isAtomicExchangeTypedArrayElement()) {
486 type
= def
->toAtomicExchangeTypedArrayElement()->arrayType();
488 type
= def
->toAtomicTypedArrayElementBinop()->arrayType();
491 if (Scalar::isBigIntType(type
)) {
492 return ConvertOperand
<MToBigInt
>(alloc
, def
, Op
, MIRType::BigInt
);
494 return ConvertOperand
<MTruncateToInt32
>(alloc
, def
, Op
, MIRType::Int32
);
497 template bool TruncateToInt32OrToBigIntPolicy
<2>::staticAdjustInputs(
498 TempAllocator
& alloc
, MInstruction
* def
);
499 template bool TruncateToInt32OrToBigIntPolicy
<3>::staticAdjustInputs(
500 TempAllocator
& alloc
, MInstruction
* def
);
502 template <unsigned Op
>
503 bool DoublePolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
505 return ConvertOperand
<MToDouble
>(alloc
, def
, Op
, MIRType::Double
);
508 template bool DoublePolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
510 template bool DoublePolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
513 template <unsigned Op
>
514 bool Float32Policy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
516 return ConvertOperand
<MToFloat32
>(alloc
, def
, Op
, MIRType::Float32
);
519 template bool Float32Policy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
521 template bool Float32Policy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
523 template bool Float32Policy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
526 template <unsigned Op
>
527 bool FloatingPointPolicy
<Op
>::adjustInputs(TempAllocator
& alloc
,
528 MInstruction
* def
) const {
529 MIRType policyType
= def
->typePolicySpecialization();
530 if (policyType
== MIRType::Double
) {
531 return DoublePolicy
<Op
>::staticAdjustInputs(alloc
, def
);
533 return Float32Policy
<Op
>::staticAdjustInputs(alloc
, def
);
536 template bool FloatingPointPolicy
<0>::adjustInputs(TempAllocator
& alloc
,
537 MInstruction
* def
) const;
539 template <unsigned Op
>
540 bool NoFloatPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
542 EnsureOperandNotFloat32(alloc
, def
, Op
);
546 template bool NoFloatPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
548 template bool NoFloatPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
550 template bool NoFloatPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
552 template bool NoFloatPolicy
<3>::staticAdjustInputs(TempAllocator
& alloc
,
555 template <unsigned FirstOp
>
556 bool NoFloatPolicyAfter
<FirstOp
>::staticAdjustInputs(TempAllocator
& alloc
,
558 for (size_t op
= FirstOp
, e
= def
->numOperands(); op
< e
; op
++) {
559 EnsureOperandNotFloat32(alloc
, def
, op
);
564 template bool NoFloatPolicyAfter
<0>::staticAdjustInputs(TempAllocator
& alloc
,
566 template bool NoFloatPolicyAfter
<1>::staticAdjustInputs(TempAllocator
& alloc
,
568 template bool NoFloatPolicyAfter
<2>::staticAdjustInputs(TempAllocator
& alloc
,
571 template <unsigned Op
>
572 bool BoxPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
574 MDefinition
* in
= ins
->getOperand(Op
);
575 if (in
->type() == MIRType::Value
) {
579 ins
->replaceOperand(Op
, BoxAt(alloc
, ins
, in
));
583 template bool BoxPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
585 template bool BoxPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
587 template bool BoxPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
590 template <unsigned Op
, MIRType Type
>
591 bool BoxExceptPolicy
<Op
, Type
>::staticAdjustInputs(TempAllocator
& alloc
,
593 MDefinition
* in
= ins
->getOperand(Op
);
594 if (in
->type() == Type
) {
597 return BoxPolicy
<Op
>::staticAdjustInputs(alloc
, ins
);
600 template bool BoxExceptPolicy
<0, MIRType::Object
>::staticAdjustInputs(
601 TempAllocator
& alloc
, MInstruction
* ins
);
603 template <unsigned Op
>
604 bool CacheIdPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
606 MDefinition
* in
= ins
->getOperand(Op
);
607 switch (in
->type()) {
609 case MIRType::String
:
610 case MIRType::Symbol
:
613 return BoxPolicy
<Op
>::staticAdjustInputs(alloc
, ins
);
617 template bool CacheIdPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
619 template bool CacheIdPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
622 bool ToDoublePolicy::staticAdjustInputs(TempAllocator
& alloc
,
624 MOZ_ASSERT(ins
->isToDouble() || ins
->isToFloat32());
626 MDefinition
* in
= ins
->getOperand(0);
627 switch (in
->type()) {
629 case MIRType::Float32
:
630 case MIRType::Double
:
633 case MIRType::Undefined
:
634 case MIRType::Boolean
:
635 // No need for boxing for these types.
637 case MIRType::Object
:
638 case MIRType::String
:
639 case MIRType::Symbol
:
640 case MIRType::BigInt
:
641 // Objects might be effectful. Symbols and BigInts give TypeError.
647 in
= BoxAt(alloc
, ins
, in
);
648 ins
->replaceOperand(0, in
);
652 bool ToInt32Policy::staticAdjustInputs(TempAllocator
& alloc
,
654 MOZ_ASSERT(ins
->isToNumberInt32() || ins
->isTruncateToInt32());
656 IntConversionInputKind conversion
= IntConversionInputKind::Any
;
657 if (ins
->isToNumberInt32()) {
658 conversion
= ins
->toToNumberInt32()->conversion();
661 MDefinition
* in
= ins
->getOperand(0);
662 switch (in
->type()) {
664 case MIRType::Float32
:
665 case MIRType::Double
:
667 // No need for boxing for these types.
669 case MIRType::Undefined
:
670 // No need for boxing when truncating.
671 if (ins
->isTruncateToInt32()) {
676 // No need for boxing, when we will convert.
677 if (conversion
== IntConversionInputKind::Any
) {
681 case MIRType::Boolean
:
682 // No need for boxing, when we will convert.
683 if (conversion
== IntConversionInputKind::Any
) {
687 case MIRType::Object
:
688 case MIRType::String
:
689 case MIRType::Symbol
:
690 case MIRType::BigInt
:
691 // Objects might be effectful. Symbols and BigInts give TypeError.
697 in
= BoxAt(alloc
, ins
, in
);
698 ins
->replaceOperand(0, in
);
702 bool ToBigIntPolicy::staticAdjustInputs(TempAllocator
& alloc
,
704 MOZ_ASSERT(ins
->isToBigInt());
706 MDefinition
* in
= ins
->getOperand(0);
707 switch (in
->type()) {
708 case MIRType::BigInt
:
710 // No need for boxing for these types.
713 // Any other types need to be boxed.
717 in
= BoxAt(alloc
, ins
, in
);
718 ins
->replaceOperand(0, in
);
722 bool ToStringPolicy::staticAdjustInputs(TempAllocator
& alloc
,
724 MOZ_ASSERT(ins
->isToString());
726 MIRType type
= ins
->getOperand(0)->type();
727 if (type
== MIRType::Object
|| type
== MIRType::Symbol
||
728 type
== MIRType::BigInt
) {
729 ins
->replaceOperand(0, BoxAt(alloc
, ins
, ins
->getOperand(0)));
733 // TODO remove the following line once 966957 has landed
734 EnsureOperandNotFloat32(alloc
, ins
, 0);
739 bool ToInt64Policy::staticAdjustInputs(TempAllocator
& alloc
,
741 MOZ_ASSERT(ins
->isToInt64());
743 MDefinition
* input
= ins
->getOperand(0);
744 MIRType type
= input
->type();
747 case MIRType::BigInt
: {
748 auto* replace
= MTruncateBigIntToInt64::New(alloc
, input
);
749 ins
->block()->insertBefore(ins
, replace
);
750 ins
->replaceOperand(0, replace
);
753 // No need for boxing for these types, because they are handled specially
754 // when this instruction is lowered to LIR.
755 case MIRType::Boolean
:
756 case MIRType::String
:
761 ins
->replaceOperand(0, BoxAt(alloc
, ins
, ins
->getOperand(0)));
768 template <unsigned Op
>
769 bool ObjectPolicy
<Op
>::staticAdjustInputs(TempAllocator
& alloc
,
771 MOZ_ASSERT(ins
->getOperand(Op
)->type() != MIRType::Slots
);
772 MOZ_ASSERT(ins
->getOperand(Op
)->type() != MIRType::Elements
);
774 return UnboxOperand(alloc
, ins
, Op
, MIRType::Object
);
777 template bool ObjectPolicy
<0>::staticAdjustInputs(TempAllocator
& alloc
,
779 template bool ObjectPolicy
<1>::staticAdjustInputs(TempAllocator
& alloc
,
781 template bool ObjectPolicy
<2>::staticAdjustInputs(TempAllocator
& alloc
,
783 template bool ObjectPolicy
<3>::staticAdjustInputs(TempAllocator
& alloc
,
786 bool CallPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
789 call
= ins
->toCall();
791 call
= ins
->toCallClassHook();
794 MDefinition
* func
= call
->getCallee();
795 if (func
->type() != MIRType::Object
) {
796 MInstruction
* unbox
=
797 MUnbox::New(alloc
, func
, MIRType::Object
, MUnbox::Fallible
);
798 SetTypePolicyBailoutKind(unbox
, call
);
799 call
->block()->insertBefore(call
, unbox
);
800 call
->replaceCallee(unbox
);
802 if (!unbox
->typePolicy()->adjustInputs(alloc
, unbox
)) {
807 for (uint32_t i
= 0; i
< call
->numStackArgs(); i
++) {
808 if (!alloc
.ensureBallast()) {
811 EnsureOperandNotFloat32(alloc
, call
, MCallBase::IndexOfStackArg(i
));
817 bool MegamorphicSetElementPolicy::adjustInputs(TempAllocator
& alloc
,
818 MInstruction
* ins
) const {
819 // The first operand should be an object.
820 if (!SingleObjectPolicy::staticAdjustInputs(alloc
, ins
)) {
824 // Box the index and value operands.
825 for (size_t i
= 1, e
= ins
->numOperands(); i
< e
; i
++) {
826 MDefinition
* in
= ins
->getOperand(i
);
827 if (in
->type() == MIRType::Value
) {
830 ins
->replaceOperand(i
, BoxAt(alloc
, ins
, in
));
835 bool StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator
& alloc
,
837 Scalar::Type writeType
,
840 if (Scalar::isBigIntType(writeType
)) {
841 if (value
->type() == MIRType::BigInt
) {
845 auto* replace
= MToBigInt::New(alloc
, value
);
846 ins
->block()->insertBefore(ins
, replace
);
847 ins
->replaceOperand(valueOperand
, replace
);
849 return replace
->typePolicy()->adjustInputs(alloc
, replace
);
852 MDefinition
* curValue
= value
;
853 // First, ensure the value is int32, boolean, double or Value.
854 // The conversion is based on TypedArrayObjectTemplate::setElementTail.
855 switch (value
->type()) {
857 case MIRType::Double
:
858 case MIRType::Float32
:
859 case MIRType::Boolean
:
863 value
->setImplicitlyUsedUnchecked();
864 value
= MConstant::New(alloc
, Int32Value(0));
865 ins
->block()->insertBefore(ins
, value
->toInstruction());
867 case MIRType::Undefined
:
868 value
->setImplicitlyUsedUnchecked();
869 value
= MConstant::New(alloc
, JS::NaNValue());
870 ins
->block()->insertBefore(ins
, value
->toInstruction());
872 case MIRType::Object
:
873 case MIRType::String
:
874 case MIRType::Symbol
:
875 case MIRType::BigInt
:
876 value
= BoxAt(alloc
, ins
, value
);
879 MOZ_CRASH("Unexpected type");
882 if (value
!= curValue
) {
883 ins
->replaceOperand(valueOperand
, value
);
888 value
->type() == MIRType::Int32
|| value
->type() == MIRType::Boolean
||
889 value
->type() == MIRType::Double
|| value
->type() == MIRType::Float32
||
890 value
->type() == MIRType::Value
);
899 if (value
->type() != MIRType::Int32
) {
900 value
= MTruncateToInt32::New(alloc
, value
);
901 ins
->block()->insertBefore(ins
, value
->toInstruction());
904 case Scalar::Uint8Clamped
:
905 // The transpiler should have inserted MClampToUint8.
906 MOZ_ASSERT(value
->type() == MIRType::Int32
);
908 case Scalar::Float32
:
909 if (value
->type() != MIRType::Float32
) {
910 value
= MToFloat32::New(alloc
, value
);
911 ins
->block()->insertBefore(ins
, value
->toInstruction());
914 case Scalar::Float64
:
915 if (value
->type() != MIRType::Double
) {
916 value
= MToDouble::New(alloc
, value
);
917 ins
->block()->insertBefore(ins
, value
->toInstruction());
921 MOZ_CRASH("Invalid array type");
924 if (value
!= curValue
) {
925 ins
->replaceOperand(valueOperand
, value
);
931 bool StoreUnboxedScalarPolicy::adjustInputs(TempAllocator
& alloc
,
932 MInstruction
* ins
) const {
933 MStoreUnboxedScalar
* store
= ins
->toStoreUnboxedScalar();
934 MOZ_ASSERT(store
->elements()->type() == MIRType::Elements
);
935 MOZ_ASSERT(store
->index()->type() == MIRType::IntPtr
);
937 return adjustValueInput(alloc
, store
, store
->writeType(), store
->value(), 2);
940 bool StoreDataViewElementPolicy::adjustInputs(TempAllocator
& alloc
,
941 MInstruction
* ins
) const {
942 auto* store
= ins
->toStoreDataViewElement();
943 MOZ_ASSERT(store
->elements()->type() == MIRType::Elements
);
944 MOZ_ASSERT(store
->index()->type() == MIRType::IntPtr
);
945 MOZ_ASSERT(store
->littleEndian()->type() == MIRType::Boolean
);
947 return StoreUnboxedScalarPolicy::adjustValueInput(
948 alloc
, ins
, store
->writeType(), store
->value(), 2);
951 bool StoreTypedArrayHolePolicy::adjustInputs(TempAllocator
& alloc
,
952 MInstruction
* ins
) const {
953 MStoreTypedArrayElementHole
* store
= ins
->toStoreTypedArrayElementHole();
954 MOZ_ASSERT(store
->elements()->type() == MIRType::Elements
);
955 MOZ_ASSERT(store
->index()->type() == MIRType::IntPtr
);
956 MOZ_ASSERT(store
->length()->type() == MIRType::IntPtr
);
958 return StoreUnboxedScalarPolicy::adjustValueInput(
959 alloc
, ins
, store
->arrayType(), store
->value(), 3);
962 bool ClampPolicy::adjustInputs(TempAllocator
& alloc
, MInstruction
* ins
) const {
963 MDefinition
* in
= ins
->toClampToUint8()->input();
965 switch (in
->type()) {
967 case MIRType::Double
:
971 ins
->replaceOperand(0, BoxAt(alloc
, ins
, in
));
978 // Lists of all TypePolicy specializations which are used by MIR Instructions.
979 #define TYPE_POLICY_LIST(_) \
982 _(BigIntArithPolicy) \
986 _(MegamorphicSetElementPolicy) \
991 _(StoreDataViewElementPolicy) \
992 _(StoreTypedArrayHolePolicy) \
993 _(StoreUnboxedScalarPolicy) \
1001 #define TEMPLATE_TYPE_POLICY_LIST(_) \
1002 _(BigIntPolicy<0>) \
1003 _(BooleanPolicy<0>) \
1004 _(BoxExceptPolicy<0, MIRType::Object>) \
1006 _(ConvertToInt32Policy<0>) \
1007 _(ConvertToStringPolicy<0>) \
1008 _(ConvertToStringPolicy<2>) \
1009 _(DoublePolicy<0>) \
1010 _(FloatingPointPolicy<0>) \
1011 _(UnboxedInt32Policy<0>) \
1012 _(UnboxedInt32Policy<1>) \
1013 _(TruncateToInt32OrToBigIntPolicy<2>) \
1014 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, BoxPolicy<2>>) \
1015 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \
1016 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>) \
1017 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, UnboxedInt32Policy<2>>) \
1018 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>>) \
1019 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1020 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<2>>) \
1021 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, UnboxedInt32Policy<2>>) \
1022 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2>>) \
1023 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2>>) \
1024 _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1025 _(MixPolicy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2>>) \
1026 _(MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2>>) \
1027 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, UnboxedInt32Policy<2>>) \
1028 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>, \
1030 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>, \
1031 UnboxedInt32Policy<3>>) \
1032 _(MixPolicy<TruncateToInt32OrToBigIntPolicy<2>, \
1033 TruncateToInt32OrToBigIntPolicy<3>>) \
1034 _(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>) \
1035 _(MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>, \
1036 CacheIdPolicy<2>>) \
1037 _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1>>) \
1038 _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>>) \
1039 _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>>) \
1040 _(MixPolicy<DoublePolicy<0>, DoublePolicy<1>>) \
1041 _(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>>) \
1042 _(MixPolicy<Int32OrIntPtrPolicy<0>, Int32OrIntPtrPolicy<1>>) \
1043 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>) \
1044 _(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>) \
1045 _(MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1>>) \
1046 _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1>>) \
1047 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>>) \
1048 _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<2>>) \
1049 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1>>) \
1050 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2>>) \
1051 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3>>) \
1052 _(MixPolicy<ObjectPolicy<0>, NoFloatPolicyAfter<1>>) \
1053 _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>>) \
1054 _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>>) \
1055 _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2>>) \
1056 _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0>>) \
1057 _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>>) \
1058 _(MixPolicy<StringPolicy<0>, StringPolicy<1>>) \
1059 _(MixPolicy<BoxPolicy<0>, BoxPolicy<1>>) \
1060 _(MixPolicy<BoxPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>) \
1061 _(MixPolicy<ObjectPolicy<0>, BoxPolicy<2>, ObjectPolicy<3>>) \
1062 _(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, ObjectPolicy<1>>) \
1063 _(MixPolicy<UnboxedInt32Policy<0>, BigIntPolicy<1>>) \
1064 _(MixPolicy<UnboxedInt32Policy<0>, NoFloatPolicyAfter<1>>) \
1065 _(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>, \
1066 NoFloatPolicyAfter<2>>) \
1067 _(NoFloatPolicy<0>) \
1068 _(NoFloatPolicy<1>) \
1069 _(NoFloatPolicy<2>) \
1070 _(NoFloatPolicyAfter<0>) \
1071 _(NoFloatPolicyAfter<1>) \
1072 _(NoFloatPolicyAfter<2>) \
1073 _(ObjectPolicy<0>) \
1074 _(ObjectPolicy<1>) \
1075 _(ObjectPolicy<3>) \
1076 _(StringPolicy<0>) \
1082 // Define for all used TypePolicy specialization, the definition for
1083 // |TypePolicy::Data::thisTypePolicy|. This function returns one constant
1084 // instance of the TypePolicy which is shared among all MIR Instructions of the
1087 // This Macro use __VA_ARGS__ to account for commas of template parameters.
1088 #define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...) \
1089 const TypePolicy* __VA_ARGS__::Data::thisTypePolicy() { \
1090 static constexpr __VA_ARGS__ singletonType; \
1091 return &singletonType; \
1094 TYPE_POLICY_LIST(DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
)
1095 TEMPLATE_TYPE_POLICY_LIST(template <> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
)
1096 #undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
1103 // For extra-good measure in case an unqualified use is ever introduced. (The
1104 // main use in the macro below is explicitly qualified so as not to consult
1105 // this scope and find this function.)
1106 inline TypePolicy
* thisTypePolicy() = delete;
1108 static MIRType
thisTypeSpecialization() {
1109 MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization.");
1114 // For each MIR Instruction, this macro define the |typePolicy| method which is
1115 // using the |thisTypePolicy| method. The |thisTypePolicy| method is either a
1116 // member of the MIR Instruction, such as with MGetElementCache, a member
1117 // inherited from the TypePolicy::Data structure, or a member inherited from
1118 // NoTypePolicy if the MIR instruction has no type policy.
1119 #define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op) \
1120 const TypePolicy* js::jit::M##op::typePolicy() { \
1121 return M##op::thisTypePolicy(); \
1124 MIRType js::jit::M##op::typePolicySpecialization() { \
1125 return thisTypeSpecialization(); \
1128 MIR_OPCODE_LIST(DEFINE_MIR_TYPEPOLICY_MEMBERS_
)
1129 #undef DEFINE_MIR_TYPEPOLICY_MEMBERS_