no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / js / src / jit / TypePolicy.cpp
blob8f2c3a253b41e001e7b5f5e6c3dd80c9aafb7d48
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"
11 #include "jit/MIR.h"
12 #include "jit/MIRGraph.h"
13 #include "js/ScalarType.h" // js::Scalar::Type
15 using namespace js;
16 using namespace js::jit;
18 static void EnsureOperandNotFloat32(TempAllocator& alloc, MInstruction* def,
19 unsigned op) {
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);
31 template <class T>
32 [[nodiscard]] static bool ConvertOperand(TempAllocator& alloc,
33 MInstruction* def, unsigned op,
34 MIRType expected) {
35 MDefinition* in = def->getOperand(op);
36 if (in->type() == expected) {
37 return true;
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()) {
51 return;
54 // Ensure we're not introducing TypePolicy bailouts for transpiled CacheIR
55 // instructions. Unbox operations and other guards should have been inserted
56 // by the transpiler.
58 // This avoids a performance cliff because frequent TypePolicy bailouts will
59 // disable Warp compilation instead of invalidating the script.
60 // See bug 1850305.
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) {
70 return true;
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);
92 return 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,
104 MInstruction* ins) {
105 for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
106 MDefinition* in = ins->getOperand(i);
107 if (in->type() == MIRType::Value) {
108 continue;
110 ins->replaceOperand(i, BoxAt(alloc, ins, in));
112 return true;
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()) {
123 continue;
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);
132 } else {
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)) {
141 return false;
145 return true;
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)) {
154 return false;
158 return true;
161 bool AllDoublePolicy::staticAdjustInputs(TempAllocator& alloc,
162 MInstruction* ins) {
163 for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
164 MDefinition* in = ins->getOperand(i);
165 if (in->type() == MIRType::Double) {
166 continue;
169 if (!alloc.ensureBallast()) {
170 return false;
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)) {
178 return false;
182 return true;
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) {
190 return true;
192 MInstruction* replace = nullptr;
193 switch (expected) {
194 case MIRType::Double:
195 replace = MToDouble::New(alloc, operand);
196 break;
197 case MIRType::Int32:
198 replace = MToNumberInt32::New(alloc, operand);
199 break;
200 case MIRType::Float32:
201 replace = MToFloat32::New(alloc, operand);
202 break;
203 case MIRType::String:
204 replace =
205 MUnbox::New(alloc, operand, MIRType::String, MUnbox::Fallible);
206 break;
207 case MIRType::Symbol:
208 replace =
209 MUnbox::New(alloc, operand, MIRType::Symbol, MUnbox::Fallible);
210 break;
211 case MIRType::Object:
212 replace =
213 MUnbox::New(alloc, operand, MIRType::Object, MUnbox::Fallible);
214 break;
215 case MIRType::BigInt:
216 replace =
217 MUnbox::New(alloc, operand, MIRType::BigInt, MUnbox::Fallible);
218 break;
219 default:
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.
243 return true;
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);
250 return true;
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);
278 default:
279 MOZ_CRASH("Unexpected compare type");
282 return true;
285 bool TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
286 MDefinition* op = ins->getOperand(0);
287 switch (op->type()) {
288 case MIRType::Value:
289 case MIRType::Null:
290 case MIRType::Undefined:
291 case MIRType::Boolean:
292 case MIRType::Int32:
293 case MIRType::Double:
294 case MIRType::Float32:
295 case MIRType::Symbol:
296 case MIRType::BigInt:
297 case MIRType::Object:
298 break;
300 case MIRType::String: {
301 MStringLength* length = MStringLength::New(alloc, op);
302 ins->block()->insertBefore(ins, length);
303 ins->replaceOperand(0, length);
304 break;
307 default:
308 MOZ_ASSERT(IsMagicType(op->type()));
309 ins->replaceOperand(0, BoxAt(alloc, ins, op));
310 break;
312 return true;
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)) {
322 return false;
326 return true;
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)) {
340 return false;
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);
350 return true;
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,
372 MInstruction* ins) {
373 return UnboxOperand(alloc, ins, Op, MIRType::Symbol);
376 template bool SymbolPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
377 MInstruction* ins);
379 template <unsigned Op>
380 bool BooleanPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
381 MInstruction* ins) {
382 return UnboxOperand(alloc, ins, Op, MIRType::Boolean);
385 template bool BooleanPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
386 MInstruction* ins);
388 template <unsigned Op>
389 bool StringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
390 MInstruction* ins) {
391 return UnboxOperand(alloc, ins, Op, MIRType::String);
394 template bool StringPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
395 MInstruction* ins);
396 template bool StringPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
397 MInstruction* ins);
398 template bool StringPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
399 MInstruction* ins);
401 template <unsigned Op>
402 bool ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
403 MInstruction* ins) {
404 MDefinition* in = ins->getOperand(Op);
405 if (in->type() == MIRType::String) {
406 return true;
409 MToString* replace =
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,
418 MInstruction* ins);
419 template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
420 MInstruction* ins);
421 template bool ConvertToStringPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
422 MInstruction* ins);
424 template <unsigned Op>
425 bool BigIntPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
426 MInstruction* ins) {
427 return UnboxOperand(alloc, ins, Op, MIRType::BigInt);
430 template bool BigIntPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
431 MInstruction* ins);
432 template bool BigIntPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
433 MInstruction* ins);
435 template <unsigned Op>
436 bool UnboxedInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
437 MInstruction* def) {
438 return UnboxOperand(alloc, def, Op, MIRType::Int32);
441 template bool UnboxedInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
442 MInstruction* def);
443 template bool UnboxedInt32Policy<1>::staticAdjustInputs(TempAllocator& alloc,
444 MInstruction* def);
445 template bool UnboxedInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
446 MInstruction* def);
447 template bool UnboxedInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc,
448 MInstruction* def);
450 template <unsigned Op>
451 bool Int32OrIntPtrPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
452 MInstruction* def) {
453 MDefinition* in = def->getOperand(Op);
454 if (in->type() == MIRType::IntPtr) {
455 return true;
458 return UnboxedInt32Policy<Op>::staticAdjustInputs(alloc, def);
461 template bool Int32OrIntPtrPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
462 MInstruction* def);
463 template bool Int32OrIntPtrPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
464 MInstruction* def);
466 template <unsigned Op>
467 bool ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
468 MInstruction* def) {
469 return ConvertOperand<MToNumberInt32>(alloc, def, Op, MIRType::Int32);
472 template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
473 MInstruction* def);
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());
482 Scalar::Type type;
483 if (def->isCompareExchangeTypedArrayElement()) {
484 type = def->toCompareExchangeTypedArrayElement()->arrayType();
485 } else if (def->isAtomicExchangeTypedArrayElement()) {
486 type = def->toAtomicExchangeTypedArrayElement()->arrayType();
487 } else {
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,
504 MInstruction* def) {
505 return ConvertOperand<MToDouble>(alloc, def, Op, MIRType::Double);
508 template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator& alloc,
509 MInstruction* def);
510 template bool DoublePolicy<1>::staticAdjustInputs(TempAllocator& alloc,
511 MInstruction* def);
513 template <unsigned Op>
514 bool Float32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
515 MInstruction* def) {
516 return ConvertOperand<MToFloat32>(alloc, def, Op, MIRType::Float32);
519 template bool Float32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
520 MInstruction* def);
521 template bool Float32Policy<1>::staticAdjustInputs(TempAllocator& alloc,
522 MInstruction* def);
523 template bool Float32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
524 MInstruction* def);
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,
541 MInstruction* def) {
542 EnsureOperandNotFloat32(alloc, def, Op);
543 return true;
546 template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
547 MInstruction* def);
548 template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
549 MInstruction* def);
550 template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
551 MInstruction* def);
552 template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
553 MInstruction* def);
555 template <unsigned FirstOp>
556 bool NoFloatPolicyAfter<FirstOp>::staticAdjustInputs(TempAllocator& alloc,
557 MInstruction* def) {
558 for (size_t op = FirstOp, e = def->numOperands(); op < e; op++) {
559 EnsureOperandNotFloat32(alloc, def, op);
561 return true;
564 template bool NoFloatPolicyAfter<0>::staticAdjustInputs(TempAllocator& alloc,
565 MInstruction* def);
566 template bool NoFloatPolicyAfter<1>::staticAdjustInputs(TempAllocator& alloc,
567 MInstruction* def);
568 template bool NoFloatPolicyAfter<2>::staticAdjustInputs(TempAllocator& alloc,
569 MInstruction* def);
571 template <unsigned Op>
572 bool BoxPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
573 MInstruction* ins) {
574 MDefinition* in = ins->getOperand(Op);
575 if (in->type() == MIRType::Value) {
576 return true;
579 ins->replaceOperand(Op, BoxAt(alloc, ins, in));
580 return true;
583 template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
584 MInstruction* ins);
585 template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
586 MInstruction* ins);
587 template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
588 MInstruction* ins);
590 template <unsigned Op, MIRType Type>
591 bool BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator& alloc,
592 MInstruction* ins) {
593 MDefinition* in = ins->getOperand(Op);
594 if (in->type() == Type) {
595 return true;
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,
605 MInstruction* ins) {
606 MDefinition* in = ins->getOperand(Op);
607 switch (in->type()) {
608 case MIRType::Int32:
609 case MIRType::String:
610 case MIRType::Symbol:
611 return true;
612 default:
613 return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
617 template bool CacheIdPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
618 MInstruction* ins);
619 template bool CacheIdPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
620 MInstruction* ins);
622 bool ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc,
623 MInstruction* ins) {
624 MOZ_ASSERT(ins->isToDouble() || ins->isToFloat32());
626 MDefinition* in = ins->getOperand(0);
627 switch (in->type()) {
628 case MIRType::Int32:
629 case MIRType::Float32:
630 case MIRType::Double:
631 case MIRType::Value:
632 case MIRType::Null:
633 case MIRType::Undefined:
634 case MIRType::Boolean:
635 // No need for boxing for these types.
636 return true;
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.
642 break;
643 default:
644 break;
647 in = BoxAt(alloc, ins, in);
648 ins->replaceOperand(0, in);
649 return true;
652 bool ToInt32Policy::staticAdjustInputs(TempAllocator& alloc,
653 MInstruction* ins) {
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()) {
663 case MIRType::Int32:
664 case MIRType::Float32:
665 case MIRType::Double:
666 case MIRType::Value:
667 // No need for boxing for these types.
668 return true;
669 case MIRType::Undefined:
670 // No need for boxing when truncating.
671 if (ins->isTruncateToInt32()) {
672 return true;
674 break;
675 case MIRType::Null:
676 // No need for boxing, when we will convert.
677 if (conversion == IntConversionInputKind::Any) {
678 return true;
680 break;
681 case MIRType::Boolean:
682 // No need for boxing, when we will convert.
683 if (conversion == IntConversionInputKind::Any) {
684 return true;
686 break;
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.
692 break;
693 default:
694 break;
697 in = BoxAt(alloc, ins, in);
698 ins->replaceOperand(0, in);
699 return true;
702 bool ToBigIntPolicy::staticAdjustInputs(TempAllocator& alloc,
703 MInstruction* ins) {
704 MOZ_ASSERT(ins->isToBigInt());
706 MDefinition* in = ins->getOperand(0);
707 switch (in->type()) {
708 case MIRType::BigInt:
709 case MIRType::Value:
710 // No need for boxing for these types.
711 return true;
712 default:
713 // Any other types need to be boxed.
714 break;
717 in = BoxAt(alloc, ins, in);
718 ins->replaceOperand(0, in);
719 return true;
722 bool ToStringPolicy::staticAdjustInputs(TempAllocator& alloc,
723 MInstruction* ins) {
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)));
730 return true;
733 // TODO remove the following line once 966957 has landed
734 EnsureOperandNotFloat32(alloc, ins, 0);
736 return true;
739 bool ToInt64Policy::staticAdjustInputs(TempAllocator& alloc,
740 MInstruction* ins) {
741 MOZ_ASSERT(ins->isToInt64());
743 MDefinition* input = ins->getOperand(0);
744 MIRType type = input->type();
746 switch (type) {
747 case MIRType::BigInt: {
748 auto* replace = MTruncateBigIntToInt64::New(alloc, input);
749 ins->block()->insertBefore(ins, replace);
750 ins->replaceOperand(0, replace);
751 break;
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:
757 case MIRType::Int64:
758 case MIRType::Value:
759 break;
760 default:
761 ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
762 break;
765 return true;
768 template <unsigned Op>
769 bool ObjectPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
770 MInstruction* ins) {
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,
778 MInstruction* ins);
779 template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
780 MInstruction* ins);
781 template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
782 MInstruction* ins);
783 template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
784 MInstruction* ins);
786 bool CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) const {
787 MCallBase* call;
788 if (ins->isCall()) {
789 call = ins->toCall();
790 } else {
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)) {
803 return false;
807 for (uint32_t i = 0; i < call->numStackArgs(); i++) {
808 if (!alloc.ensureBallast()) {
809 return false;
811 EnsureOperandNotFloat32(alloc, call, MCallBase::IndexOfStackArg(i));
814 return true;
817 bool MegamorphicSetElementPolicy::adjustInputs(TempAllocator& alloc,
818 MInstruction* ins) const {
819 // The first operand should be an object.
820 if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins)) {
821 return false;
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) {
828 continue;
830 ins->replaceOperand(i, BoxAt(alloc, ins, in));
832 return true;
835 bool StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc,
836 MInstruction* ins,
837 Scalar::Type writeType,
838 MDefinition* value,
839 int valueOperand) {
840 if (Scalar::isBigIntType(writeType)) {
841 if (value->type() == MIRType::BigInt) {
842 return true;
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()) {
856 case MIRType::Int32:
857 case MIRType::Double:
858 case MIRType::Float32:
859 case MIRType::Boolean:
860 case MIRType::Value:
861 break;
862 case MIRType::Null:
863 value->setImplicitlyUsedUnchecked();
864 value = MConstant::New(alloc, Int32Value(0));
865 ins->block()->insertBefore(ins, value->toInstruction());
866 break;
867 case MIRType::Undefined:
868 value->setImplicitlyUsedUnchecked();
869 value = MConstant::New(alloc, JS::NaNValue());
870 ins->block()->insertBefore(ins, value->toInstruction());
871 break;
872 case MIRType::Object:
873 case MIRType::String:
874 case MIRType::Symbol:
875 case MIRType::BigInt:
876 value = BoxAt(alloc, ins, value);
877 break;
878 default:
879 MOZ_CRASH("Unexpected type");
882 if (value != curValue) {
883 ins->replaceOperand(valueOperand, value);
884 curValue = value;
887 MOZ_ASSERT(
888 value->type() == MIRType::Int32 || value->type() == MIRType::Boolean ||
889 value->type() == MIRType::Double || value->type() == MIRType::Float32 ||
890 value->type() == MIRType::Value);
892 switch (writeType) {
893 case Scalar::Int8:
894 case Scalar::Uint8:
895 case Scalar::Int16:
896 case Scalar::Uint16:
897 case Scalar::Int32:
898 case Scalar::Uint32:
899 if (value->type() != MIRType::Int32) {
900 value = MTruncateToInt32::New(alloc, value);
901 ins->block()->insertBefore(ins, value->toInstruction());
903 break;
904 case Scalar::Uint8Clamped:
905 // The transpiler should have inserted MClampToUint8.
906 MOZ_ASSERT(value->type() == MIRType::Int32);
907 break;
908 case Scalar::Float32:
909 if (value->type() != MIRType::Float32) {
910 value = MToFloat32::New(alloc, value);
911 ins->block()->insertBefore(ins, value->toInstruction());
913 break;
914 case Scalar::Float64:
915 if (value->type() != MIRType::Double) {
916 value = MToDouble::New(alloc, value);
917 ins->block()->insertBefore(ins, value->toInstruction());
919 break;
920 default:
921 MOZ_CRASH("Invalid array type");
924 if (value != curValue) {
925 ins->replaceOperand(valueOperand, value);
928 return true;
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()) {
966 case MIRType::Int32:
967 case MIRType::Double:
968 case MIRType::Value:
969 break;
970 default:
971 ins->replaceOperand(0, BoxAt(alloc, ins, in));
972 break;
975 return true;
978 // Lists of all TypePolicy specializations which are used by MIR Instructions.
979 #define TYPE_POLICY_LIST(_) \
980 _(AllDoublePolicy) \
981 _(ArithPolicy) \
982 _(BigIntArithPolicy) \
983 _(BitwisePolicy) \
984 _(BoxInputsPolicy) \
985 _(CallPolicy) \
986 _(MegamorphicSetElementPolicy) \
987 _(ClampPolicy) \
988 _(ComparePolicy) \
989 _(PowPolicy) \
990 _(SignPolicy) \
991 _(StoreDataViewElementPolicy) \
992 _(StoreTypedArrayHolePolicy) \
993 _(StoreUnboxedScalarPolicy) \
994 _(TestPolicy) \
995 _(ToDoublePolicy) \
996 _(ToInt32Policy) \
997 _(ToBigIntPolicy) \
998 _(ToStringPolicy) \
999 _(ToInt64Policy)
1001 #define TEMPLATE_TYPE_POLICY_LIST(_) \
1002 _(BigIntPolicy<0>) \
1003 _(BooleanPolicy<0>) \
1004 _(BoxExceptPolicy<0, MIRType::Object>) \
1005 _(BoxPolicy<0>) \
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>, \
1029 ObjectPolicy<3>>) \
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>) \
1077 _(SymbolPolicy<0>)
1079 namespace js {
1080 namespace jit {
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
1085 // same type.
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_
1098 } // namespace jit
1099 } // namespace js
1101 namespace {
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.");
1112 } // namespace
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_