Bug 1867190 - Add prefs for PHC probablities r=glandium
[gecko.git] / js / src / jit / TypePolicy.cpp
blobbf3cb68eea7ed4eedab5c1f7cb981a6bc4580f6c
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.h"
11 #include "jit/MIRGraph.h"
12 #include "js/ScalarType.h" // js::Scalar::Type
14 using namespace js;
15 using namespace js::jit;
17 static void EnsureOperandNotFloat32(TempAllocator& alloc, MInstruction* def,
18 unsigned op) {
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);
30 template <class T>
31 [[nodiscard]] static bool ConvertOperand(TempAllocator& alloc,
32 MInstruction* def, unsigned op,
33 MIRType expected) {
34 MDefinition* in = def->getOperand(op);
35 if (in->type() == expected) {
36 return true;
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()) {
50 return;
53 // Ensure we're not introducing TypePolicy bailouts for transpiled CacheIR
54 // instructions. Unbox operations and other guards should have been inserted
55 // by the transpiler.
57 // This avoids a performance cliff because frequent TypePolicy bailouts will
58 // disable Warp compilation instead of invalidating the script.
59 // See bug 1850305.
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) {
69 return true;
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);
91 return 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,
103 MInstruction* ins) {
104 for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
105 MDefinition* in = ins->getOperand(i);
106 if (in->type() == MIRType::Value) {
107 continue;
109 ins->replaceOperand(i, BoxAt(alloc, ins, in));
111 return true;
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()) {
122 continue;
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);
131 } else {
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)) {
140 return false;
144 return true;
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)) {
153 return false;
157 return true;
160 bool AllDoublePolicy::staticAdjustInputs(TempAllocator& alloc,
161 MInstruction* ins) {
162 for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
163 MDefinition* in = ins->getOperand(i);
164 if (in->type() == MIRType::Double) {
165 continue;
168 if (!alloc.ensureBallast()) {
169 return false;
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)) {
177 return false;
181 return true;
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.
208 return true;
211 if (compare->compareType() == MCompare::Compare_UIntPtr) {
212 MOZ_ASSERT(compare->lhs()->type() == MIRType::IntPtr);
213 MOZ_ASSERT(compare->rhs()->type() == MIRType::IntPtr);
214 return true;
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) {
224 auto* replace =
225 MUnbox::New(alloc, in, MIRType::BigInt, MUnbox::Infallible);
226 if (!replaceOperand(0, replace)) {
227 return false;
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);
243 } else {
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);
250 if (replace) {
251 if (!replaceOperand(1, replace)) {
252 return false;
256 return true;
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) {
268 continue;
271 MInstruction* replace;
273 switch (type) {
274 case MIRType::Double:
275 replace = MToDouble::New(alloc, in, MToFPInstruction::NumbersOnly);
276 break;
277 case MIRType::Float32:
278 replace = MToFloat32::New(alloc, in, MToFPInstruction::NumbersOnly);
279 break;
280 case MIRType::Int32: {
281 IntConversionInputKind convert = IntConversionInputKind::NumbersOnly;
282 replace = MToNumberInt32::New(alloc, in, convert);
283 break;
285 case MIRType::Object:
286 replace = MUnbox::New(alloc, in, MIRType::Object, MUnbox::Infallible);
287 break;
288 case MIRType::String:
289 replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Infallible);
290 break;
291 case MIRType::Symbol:
292 replace = MUnbox::New(alloc, in, MIRType::Symbol, MUnbox::Infallible);
293 break;
294 case MIRType::BigInt:
295 replace = MUnbox::New(alloc, in, MIRType::BigInt, MUnbox::Infallible);
296 break;
297 default:
298 MOZ_CRASH("Unknown compare specialization");
301 if (!replaceOperand(i, replace)) {
302 return false;
306 return true;
309 bool TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
310 MDefinition* op = ins->getOperand(0);
311 switch (op->type()) {
312 case MIRType::Value:
313 case MIRType::Null:
314 case MIRType::Undefined:
315 case MIRType::Boolean:
316 case MIRType::Int32:
317 case MIRType::Double:
318 case MIRType::Float32:
319 case MIRType::Symbol:
320 case MIRType::BigInt:
321 case MIRType::Object:
322 break;
324 case MIRType::String: {
325 MStringLength* length = MStringLength::New(alloc, op);
326 ins->block()->insertBefore(ins, length);
327 ins->replaceOperand(0, length);
328 break;
331 default:
332 MOZ_ASSERT(IsMagicType(op->type()));
333 ins->replaceOperand(0, BoxAt(alloc, ins, op));
334 break;
336 return true;
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)) {
346 return false;
350 return true;
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)) {
364 return false;
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);
373 return true;
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,
395 MInstruction* ins) {
396 return UnboxOperand(alloc, ins, Op, MIRType::Symbol);
399 template bool SymbolPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
400 MInstruction* ins);
402 template <unsigned Op>
403 bool BooleanPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
404 MInstruction* ins) {
405 return UnboxOperand(alloc, ins, Op, MIRType::Boolean);
408 template bool BooleanPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
409 MInstruction* ins);
411 template <unsigned Op>
412 bool StringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
413 MInstruction* ins) {
414 return UnboxOperand(alloc, ins, Op, MIRType::String);
417 template bool StringPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
418 MInstruction* ins);
419 template bool StringPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
420 MInstruction* ins);
421 template bool StringPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
422 MInstruction* ins);
424 template <unsigned Op>
425 bool ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
426 MInstruction* ins) {
427 MDefinition* in = ins->getOperand(Op);
428 if (in->type() == MIRType::String) {
429 return true;
432 MToString* replace =
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,
441 MInstruction* ins);
442 template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
443 MInstruction* ins);
444 template bool ConvertToStringPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
445 MInstruction* ins);
447 template <unsigned Op>
448 bool BigIntPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
449 MInstruction* ins) {
450 return UnboxOperand(alloc, ins, Op, MIRType::BigInt);
453 template bool BigIntPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
454 MInstruction* ins);
455 template bool BigIntPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
456 MInstruction* ins);
458 template <unsigned Op>
459 bool UnboxedInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
460 MInstruction* def) {
461 return UnboxOperand(alloc, def, Op, MIRType::Int32);
464 template bool UnboxedInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
465 MInstruction* def);
466 template bool UnboxedInt32Policy<1>::staticAdjustInputs(TempAllocator& alloc,
467 MInstruction* def);
468 template bool UnboxedInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
469 MInstruction* def);
470 template bool UnboxedInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc,
471 MInstruction* def);
473 template <unsigned Op>
474 bool Int32OrIntPtrPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
475 MInstruction* def) {
476 MDefinition* in = def->getOperand(Op);
477 if (in->type() == MIRType::IntPtr) {
478 return true;
481 return UnboxedInt32Policy<Op>::staticAdjustInputs(alloc, def);
484 template bool Int32OrIntPtrPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
485 MInstruction* def);
486 template bool Int32OrIntPtrPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
487 MInstruction* def);
489 template <unsigned Op>
490 bool ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
491 MInstruction* def) {
492 return ConvertOperand<MToNumberInt32>(alloc, def, Op, MIRType::Int32);
495 template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
496 MInstruction* def);
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());
505 Scalar::Type type;
506 if (def->isCompareExchangeTypedArrayElement()) {
507 type = def->toCompareExchangeTypedArrayElement()->arrayType();
508 } else if (def->isAtomicExchangeTypedArrayElement()) {
509 type = def->toAtomicExchangeTypedArrayElement()->arrayType();
510 } else {
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,
527 MInstruction* def) {
528 return ConvertOperand<MToDouble>(alloc, def, Op, MIRType::Double);
531 template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator& alloc,
532 MInstruction* def);
533 template bool DoublePolicy<1>::staticAdjustInputs(TempAllocator& alloc,
534 MInstruction* def);
536 template <unsigned Op>
537 bool Float32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
538 MInstruction* def) {
539 return ConvertOperand<MToFloat32>(alloc, def, Op, MIRType::Float32);
542 template bool Float32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
543 MInstruction* def);
544 template bool Float32Policy<1>::staticAdjustInputs(TempAllocator& alloc,
545 MInstruction* def);
546 template bool Float32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
547 MInstruction* def);
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,
564 MInstruction* def) {
565 EnsureOperandNotFloat32(alloc, def, Op);
566 return true;
569 template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
570 MInstruction* def);
571 template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
572 MInstruction* def);
573 template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
574 MInstruction* def);
575 template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
576 MInstruction* def);
578 template <unsigned FirstOp>
579 bool NoFloatPolicyAfter<FirstOp>::staticAdjustInputs(TempAllocator& alloc,
580 MInstruction* def) {
581 for (size_t op = FirstOp, e = def->numOperands(); op < e; op++) {
582 EnsureOperandNotFloat32(alloc, def, op);
584 return true;
587 template bool NoFloatPolicyAfter<0>::staticAdjustInputs(TempAllocator& alloc,
588 MInstruction* def);
589 template bool NoFloatPolicyAfter<1>::staticAdjustInputs(TempAllocator& alloc,
590 MInstruction* def);
591 template bool NoFloatPolicyAfter<2>::staticAdjustInputs(TempAllocator& alloc,
592 MInstruction* def);
594 template <unsigned Op>
595 bool BoxPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
596 MInstruction* ins) {
597 MDefinition* in = ins->getOperand(Op);
598 if (in->type() == MIRType::Value) {
599 return true;
602 ins->replaceOperand(Op, BoxAt(alloc, ins, in));
603 return true;
606 template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
607 MInstruction* ins);
608 template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
609 MInstruction* ins);
610 template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
611 MInstruction* ins);
613 template <unsigned Op, MIRType Type>
614 bool BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator& alloc,
615 MInstruction* ins) {
616 MDefinition* in = ins->getOperand(Op);
617 if (in->type() == Type) {
618 return true;
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,
628 MInstruction* ins) {
629 MDefinition* in = ins->getOperand(Op);
630 switch (in->type()) {
631 case MIRType::Int32:
632 case MIRType::String:
633 case MIRType::Symbol:
634 return true;
635 default:
636 return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
640 template bool CacheIdPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
641 MInstruction* ins);
642 template bool CacheIdPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
643 MInstruction* ins);
645 bool ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc,
646 MInstruction* ins) {
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();
653 } else {
654 conversion = ins->toToFloat32()->conversion();
657 switch (in->type()) {
658 case MIRType::Int32:
659 case MIRType::Float32:
660 case MIRType::Double:
661 case MIRType::Value:
662 // No need for boxing for these types.
663 return true;
664 case MIRType::Null:
665 // No need for boxing, when we will convert.
666 if (conversion == MToFPInstruction::NonStringPrimitives) {
667 return true;
669 break;
670 case MIRType::Undefined:
671 case MIRType::Boolean:
672 // No need for boxing, when we will convert.
673 if (conversion == MToFPInstruction::NonStringPrimitives) {
674 return true;
676 break;
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.
682 break;
683 default:
684 break;
687 in = BoxAt(alloc, ins, in);
688 ins->replaceOperand(0, in);
689 return true;
692 bool ToInt32Policy::staticAdjustInputs(TempAllocator& alloc,
693 MInstruction* ins) {
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()) {
703 case MIRType::Int32:
704 case MIRType::Float32:
705 case MIRType::Double:
706 case MIRType::Value:
707 // No need for boxing for these types.
708 return true;
709 case MIRType::Undefined:
710 // No need for boxing when truncating.
711 if (ins->isTruncateToInt32()) {
712 return true;
714 break;
715 case MIRType::Null:
716 // No need for boxing, when we will convert.
717 if (conversion == IntConversionInputKind::Any) {
718 return true;
720 break;
721 case MIRType::Boolean:
722 // No need for boxing, when we will convert.
723 if (conversion == IntConversionInputKind::Any) {
724 return true;
726 if (conversion == IntConversionInputKind::NumbersOrBoolsOnly) {
727 return true;
729 break;
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.
735 break;
736 default:
737 break;
740 in = BoxAt(alloc, ins, in);
741 ins->replaceOperand(0, in);
742 return true;
745 bool ToBigIntPolicy::staticAdjustInputs(TempAllocator& alloc,
746 MInstruction* ins) {
747 MOZ_ASSERT(ins->isToBigInt());
749 MDefinition* in = ins->getOperand(0);
750 switch (in->type()) {
751 case MIRType::BigInt:
752 case MIRType::Value:
753 // No need for boxing for these types.
754 return true;
755 default:
756 // Any other types need to be boxed.
757 break;
760 in = BoxAt(alloc, ins, in);
761 ins->replaceOperand(0, in);
762 return true;
765 bool ToStringPolicy::staticAdjustInputs(TempAllocator& alloc,
766 MInstruction* ins) {
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)));
773 return true;
776 // TODO remove the following line once 966957 has landed
777 EnsureOperandNotFloat32(alloc, ins, 0);
779 return true;
782 bool ToInt64Policy::staticAdjustInputs(TempAllocator& alloc,
783 MInstruction* ins) {
784 MOZ_ASSERT(ins->isToInt64());
786 MDefinition* input = ins->getOperand(0);
787 MIRType type = input->type();
789 switch (type) {
790 case MIRType::BigInt: {
791 auto* replace = MTruncateBigIntToInt64::New(alloc, input);
792 ins->block()->insertBefore(ins, replace);
793 ins->replaceOperand(0, replace);
794 break;
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:
800 case MIRType::Int64:
801 case MIRType::Value:
802 break;
803 default:
804 ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
805 break;
808 return true;
811 template <unsigned Op>
812 bool ObjectPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
813 MInstruction* ins) {
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,
821 MInstruction* ins);
822 template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
823 MInstruction* ins);
824 template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
825 MInstruction* ins);
826 template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
827 MInstruction* ins);
829 bool CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
830 MCallBase* call;
831 if (ins->isCall()) {
832 call = ins->toCall();
833 } else {
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)) {
846 return false;
850 for (uint32_t i = 0; i < call->numStackArgs(); i++) {
851 if (!alloc.ensureBallast()) {
852 return false;
854 EnsureOperandNotFloat32(alloc, call, MCallBase::IndexOfStackArg(i));
857 return true;
860 bool MegamorphicSetElementPolicy::adjustInputs(TempAllocator& alloc,
861 MInstruction* ins) const {
862 // The first operand should be an object.
863 if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins)) {
864 return false;
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) {
871 continue;
873 ins->replaceOperand(i, BoxAt(alloc, ins, in));
875 return true;
878 bool StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc,
879 MInstruction* ins,
880 Scalar::Type writeType,
881 MDefinition* value,
882 int valueOperand) {
883 if (Scalar::isBigIntType(writeType)) {
884 if (value->type() == MIRType::BigInt) {
885 return true;
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()) {
899 case MIRType::Int32:
900 case MIRType::Double:
901 case MIRType::Float32:
902 case MIRType::Boolean:
903 case MIRType::Value:
904 break;
905 case MIRType::Null:
906 value->setImplicitlyUsedUnchecked();
907 value = MConstant::New(alloc, Int32Value(0));
908 ins->block()->insertBefore(ins, value->toInstruction());
909 break;
910 case MIRType::Undefined:
911 value->setImplicitlyUsedUnchecked();
912 value = MConstant::New(alloc, JS::NaNValue());
913 ins->block()->insertBefore(ins, value->toInstruction());
914 break;
915 case MIRType::Object:
916 case MIRType::String:
917 case MIRType::Symbol:
918 case MIRType::BigInt:
919 value = BoxAt(alloc, ins, value);
920 break;
921 default:
922 MOZ_CRASH("Unexpected type");
925 if (value != curValue) {
926 ins->replaceOperand(valueOperand, value);
927 curValue = value;
930 MOZ_ASSERT(
931 value->type() == MIRType::Int32 || value->type() == MIRType::Boolean ||
932 value->type() == MIRType::Double || value->type() == MIRType::Float32 ||
933 value->type() == MIRType::Value);
935 switch (writeType) {
936 case Scalar::Int8:
937 case Scalar::Uint8:
938 case Scalar::Int16:
939 case Scalar::Uint16:
940 case Scalar::Int32:
941 case Scalar::Uint32:
942 if (value->type() != MIRType::Int32) {
943 value = MTruncateToInt32::New(alloc, value);
944 ins->block()->insertBefore(ins, value->toInstruction());
946 break;
947 case Scalar::Uint8Clamped:
948 // The transpiler should have inserted MClampToUint8.
949 MOZ_ASSERT(value->type() == MIRType::Int32);
950 break;
951 case Scalar::Float32:
952 if (value->type() != MIRType::Float32) {
953 value = MToFloat32::New(alloc, value);
954 ins->block()->insertBefore(ins, value->toInstruction());
956 break;
957 case Scalar::Float64:
958 if (value->type() != MIRType::Double) {
959 value = MToDouble::New(alloc, value);
960 ins->block()->insertBefore(ins, value->toInstruction());
962 break;
963 default:
964 MOZ_CRASH("Invalid array type");
967 if (value != curValue) {
968 ins->replaceOperand(valueOperand, value);
971 return true;
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:
1012 break;
1013 default:
1014 ins->replaceOperand(0, BoxAt(alloc, ins, in));
1015 break;
1018 return true;
1021 // Lists of all TypePolicy specializations which are used by MIR Instructions.
1022 #define TYPE_POLICY_LIST(_) \
1023 _(AllDoublePolicy) \
1024 _(ArithPolicy) \
1025 _(BigIntArithPolicy) \
1026 _(BitwisePolicy) \
1027 _(BoxInputsPolicy) \
1028 _(CallPolicy) \
1029 _(MegamorphicSetElementPolicy) \
1030 _(ClampPolicy) \
1031 _(ComparePolicy) \
1032 _(PowPolicy) \
1033 _(SignPolicy) \
1034 _(StoreDataViewElementPolicy) \
1035 _(StoreTypedArrayHolePolicy) \
1036 _(StoreUnboxedScalarPolicy) \
1037 _(TestPolicy) \
1038 _(ToDoublePolicy) \
1039 _(ToInt32Policy) \
1040 _(ToBigIntPolicy) \
1041 _(ToStringPolicy) \
1042 _(ToInt64Policy)
1044 #define TEMPLATE_TYPE_POLICY_LIST(_) \
1045 _(BigIntPolicy<0>) \
1046 _(BooleanPolicy<0>) \
1047 _(BoxExceptPolicy<0, MIRType::Object>) \
1048 _(BoxPolicy<0>) \
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>, \
1072 ObjectPolicy<3>>) \
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>) \
1120 _(SymbolPolicy<0>)
1122 namespace js {
1123 namespace jit {
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
1128 // same type.
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_
1141 } // namespace jit
1142 } // namespace js
1144 namespace {
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.");
1155 } // namespace
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_