1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
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/. */
6 
7 #include "jit/TypePolicy.h"
8 
9 #include "jit/Lowering.h"
10 #include "jit/MIR.h"
11 #include "jit/MIRGraph.h"
12 
13 #include "jit/shared/Lowering-shared-inl.h"
14 
15 using namespace js;
16 using namespace js::jit;
17 
18 using JS::DoubleNaNValue;
19 
EnsureOperandNotFloat32(TempAllocator & alloc,MInstruction * def,unsigned op)20 static void EnsureOperandNotFloat32(TempAllocator& alloc, MInstruction* def,
21                                     unsigned op) {
22   MDefinition* in = def->getOperand(op);
23   if (in->type() == MIRType::Float32) {
24     MToDouble* replace = MToDouble::New(alloc, in);
25     def->block()->insertBefore(def, replace);
26     if (def->isRecoveredOnBailout()) replace->setRecoveredOnBailout();
27     def->replaceOperand(op, replace);
28   }
29 }
30 
AlwaysBoxAt(TempAllocator & alloc,MInstruction * at,MDefinition * operand)31 MDefinition* js::jit::AlwaysBoxAt(TempAllocator& alloc, MInstruction* at,
32                                   MDefinition* operand) {
33   MDefinition* boxedOperand = operand;
34   // Replace Float32 by double
35   if (operand->type() == MIRType::Float32) {
36     MInstruction* replace = MToDouble::New(alloc, operand);
37     at->block()->insertBefore(at, replace);
38     boxedOperand = replace;
39   }
40   MBox* box = MBox::New(alloc, boxedOperand);
41   at->block()->insertBefore(at, box);
42   return box;
43 }
44 
BoxAt(TempAllocator & alloc,MInstruction * at,MDefinition * operand)45 static MDefinition* BoxAt(TempAllocator& alloc, MInstruction* at,
46                           MDefinition* operand) {
47   if (operand->isUnbox()) return operand->toUnbox()->input();
48   return AlwaysBoxAt(alloc, at, operand);
49 }
50 
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)51 bool BoxInputsPolicy::staticAdjustInputs(TempAllocator& alloc,
52                                          MInstruction* ins) {
53   for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
54     MDefinition* in = ins->getOperand(i);
55     if (in->type() == MIRType::Value) continue;
56     ins->replaceOperand(i, BoxAt(alloc, ins, in));
57   }
58   return true;
59 }
60 
adjustInputs(TempAllocator & alloc,MInstruction * ins)61 bool ArithPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
62   MIRType specialization = ins->typePolicySpecialization();
63   if (specialization == MIRType::None)
64     return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
65 
66   MOZ_ASSERT(ins->type() == MIRType::Double || ins->type() == MIRType::Int32 ||
67              ins->type() == MIRType::Float32);
68 
69   for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
70     MDefinition* in = ins->getOperand(i);
71     if (in->type() == ins->type()) continue;
72 
73     MInstruction* replace;
74 
75     if (ins->type() == MIRType::Double)
76       replace = MToDouble::New(alloc, in);
77     else if (ins->type() == MIRType::Float32)
78       replace = MToFloat32::New(alloc, in);
79     else
80       replace = MToNumberInt32::New(alloc, in);
81 
82     ins->block()->insertBefore(ins, replace);
83     ins->replaceOperand(i, replace);
84 
85     if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false;
86   }
87 
88   return true;
89 }
90 
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)91 bool AllDoublePolicy::staticAdjustInputs(TempAllocator& alloc,
92                                          MInstruction* ins) {
93   for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
94     MDefinition* in = ins->getOperand(i);
95     if (in->type() == MIRType::Double) continue;
96 
97     if (!alloc.ensureBallast()) return false;
98     MInstruction* replace = MToDouble::New(alloc, in);
99 
100     ins->block()->insertBefore(ins, replace);
101     ins->replaceOperand(i, replace);
102 
103     if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false;
104   }
105 
106   return true;
107 }
108 
adjustInputs(TempAllocator & alloc,MInstruction * def)109 bool ComparePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) {
110   MOZ_ASSERT(def->isCompare());
111   MCompare* compare = def->toCompare();
112 
113   // Convert Float32 operands to doubles
114   for (size_t i = 0; i < 2; i++) {
115     MDefinition* in = def->getOperand(i);
116     if (in->type() == MIRType::Float32) {
117       MInstruction* replace = MToDouble::New(alloc, in);
118       def->block()->insertBefore(def, replace);
119       def->replaceOperand(i, replace);
120     }
121   }
122 
123   // Box inputs to get value
124   if (compare->compareType() == MCompare::Compare_Unknown ||
125       compare->compareType() == MCompare::Compare_Bitwise) {
126     return BoxInputsPolicy::staticAdjustInputs(alloc, def);
127   }
128 
129   // Compare_Boolean specialization is done for "Anything === Bool"
130   // If the LHS is boolean, we set the specialization to Compare_Int32.
131   // This matches other comparisons of the form bool === bool and
132   // generated code of Compare_Int32 is more efficient.
133   if (compare->compareType() == MCompare::Compare_Boolean &&
134       def->getOperand(0)->type() == MIRType::Boolean) {
135     compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth);
136   }
137 
138   // Compare_Boolean specialization is done for "Anything === Bool"
139   // As of previous line Anything can't be Boolean
140   if (compare->compareType() == MCompare::Compare_Boolean) {
141     // Unbox rhs that is definitely Boolean
142     MDefinition* rhs = def->getOperand(1);
143     if (rhs->type() != MIRType::Boolean) {
144       MInstruction* unbox =
145           MUnbox::New(alloc, rhs, MIRType::Boolean, MUnbox::Infallible);
146       def->block()->insertBefore(def, unbox);
147       def->replaceOperand(1, unbox);
148       if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) return false;
149     }
150 
151     MOZ_ASSERT(def->getOperand(0)->type() != MIRType::Boolean);
152     MOZ_ASSERT(def->getOperand(1)->type() == MIRType::Boolean);
153     return true;
154   }
155 
156   // Compare_StrictString specialization is done for "Anything === String"
157   // If the LHS is string, we set the specialization to Compare_String.
158   if (compare->compareType() == MCompare::Compare_StrictString &&
159       def->getOperand(0)->type() == MIRType::String) {
160     compare->setCompareType(MCompare::Compare_String);
161   }
162 
163   // Compare_StrictString specialization is done for "Anything === String"
164   // As of previous line Anything can't be String
165   if (compare->compareType() == MCompare::Compare_StrictString) {
166     // Unbox rhs that is definitely String
167     MDefinition* rhs = def->getOperand(1);
168     if (rhs->type() != MIRType::String) {
169       MInstruction* unbox =
170           MUnbox::New(alloc, rhs, MIRType::String, MUnbox::Infallible);
171       def->block()->insertBefore(def, unbox);
172       def->replaceOperand(1, unbox);
173       if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) return false;
174     }
175 
176     MOZ_ASSERT(def->getOperand(0)->type() != MIRType::String);
177     MOZ_ASSERT(def->getOperand(1)->type() == MIRType::String);
178     return true;
179   }
180 
181   if (compare->compareType() == MCompare::Compare_Undefined ||
182       compare->compareType() == MCompare::Compare_Null) {
183     // Nothing to do for undefined and null, lowering handles all types.
184     return true;
185   }
186 
187   // Convert all inputs to the right input type
188   MIRType type = compare->inputType();
189   MOZ_ASSERT(type == MIRType::Int32 || type == MIRType::Double ||
190              type == MIRType::Float32 || type == MIRType::Object ||
191              type == MIRType::String || type == MIRType::Symbol);
192   for (size_t i = 0; i < 2; i++) {
193     MDefinition* in = def->getOperand(i);
194     if (in->type() == type) continue;
195 
196     MInstruction* replace;
197 
198     switch (type) {
199       case MIRType::Double: {
200         MToFPInstruction::ConversionKind convert =
201             MToFPInstruction::NumbersOnly;
202         if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS &&
203             i == 0)
204           convert = MToFPInstruction::NonNullNonStringPrimitives;
205         else if (compare->compareType() ==
206                      MCompare::Compare_DoubleMaybeCoerceRHS &&
207                  i == 1)
208           convert = MToFPInstruction::NonNullNonStringPrimitives;
209         replace = MToDouble::New(alloc, in, convert);
210         break;
211       }
212       case MIRType::Float32: {
213         MToFPInstruction::ConversionKind convert =
214             MToFPInstruction::NumbersOnly;
215         if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS &&
216             i == 0)
217           convert = MToFPInstruction::NonNullNonStringPrimitives;
218         else if (compare->compareType() ==
219                      MCompare::Compare_DoubleMaybeCoerceRHS &&
220                  i == 1)
221           convert = MToFPInstruction::NonNullNonStringPrimitives;
222         replace = MToFloat32::New(alloc, in, convert);
223         break;
224       }
225       case MIRType::Int32: {
226         IntConversionInputKind convert = IntConversionInputKind::NumbersOnly;
227         if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth ||
228             (compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS &&
229              i == 0) ||
230             (compare->compareType() == MCompare::Compare_Int32MaybeCoerceRHS &&
231              i == 1)) {
232           convert = IntConversionInputKind::NumbersOrBoolsOnly;
233         }
234         replace = MToNumberInt32::New(alloc, in, convert);
235         break;
236       }
237       case MIRType::Object:
238         replace = MUnbox::New(alloc, in, MIRType::Object, MUnbox::Infallible);
239         break;
240       case MIRType::String:
241         replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Infallible);
242         break;
243       case MIRType::Symbol:
244         replace = MUnbox::New(alloc, in, MIRType::Symbol, MUnbox::Infallible);
245         break;
246       default:
247         MOZ_CRASH("Unknown compare specialization");
248     }
249 
250     def->block()->insertBefore(def, replace);
251     def->replaceOperand(i, replace);
252 
253     if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false;
254   }
255 
256   return true;
257 }
258 
adjustInputs(TempAllocator & alloc,MInstruction * def)259 bool SameValuePolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) {
260   MOZ_ASSERT(def->isSameValue());
261   MSameValue* sameValue = def->toSameValue();
262   MIRType lhsType = sameValue->lhs()->type();
263   MIRType rhsType = sameValue->rhs()->type();
264 
265   // If both operands are numbers, convert them to doubles.
266   if (IsNumberType(lhsType) && IsNumberType(rhsType))
267     return AllDoublePolicy::staticAdjustInputs(alloc, def);
268 
269   // SameValue(Anything, Double) is specialized, so convert the rhs if it's
270   // not already a double.
271   if (lhsType == MIRType::Value && IsNumberType(rhsType)) {
272     if (rhsType != MIRType::Double) {
273       MInstruction* replace = MToDouble::New(alloc, sameValue->rhs());
274       def->block()->insertBefore(def, replace);
275       def->replaceOperand(1, replace);
276 
277       if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false;
278     }
279 
280     return true;
281   }
282 
283   // Otherwise box both operands.
284   return BoxInputsPolicy::staticAdjustInputs(alloc, def);
285 }
286 
adjustInputs(TempAllocator & alloc,MInstruction * def)287 bool TypeBarrierPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) {
288   MTypeBarrier* ins = def->toTypeBarrier();
289   MIRType inputType = ins->getOperand(0)->type();
290   MIRType outputType = ins->type();
291 
292   // Input and output type are already in accordance.
293   if (inputType == outputType) return true;
294 
295   // Output is a value, currently box the input.
296   if (outputType == MIRType::Value) {
297     // XXX: Possible optimization: decrease resultTypeSet to only include
298     // the inputType. This will remove the need for boxing.
299     MOZ_ASSERT(inputType != MIRType::Value);
300     ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
301     return true;
302   }
303 
304   // Box input if needed.
305   if (inputType != MIRType::Value) {
306     MOZ_ASSERT(ins->alwaysBails());
307     ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
308   }
309 
310   // We can't unbox a value to null/undefined/lazyargs. So keep output
311   // also a value.
312   // Note: Using setResultType shouldn't be done in TypePolicies,
313   //       Here it is fine, since the type barrier has no uses.
314   if (IsNullOrUndefined(outputType) ||
315       outputType == MIRType::MagicOptimizedArguments) {
316     MOZ_ASSERT(!ins->hasDefUses());
317     ins->setResultType(MIRType::Value);
318     return true;
319   }
320 
321   // Unbox / propagate the right type.
322   MUnbox::Mode mode = MUnbox::TypeBarrier;
323   MInstruction* replace =
324       MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode);
325   if (!ins->isMovable()) replace->setNotMovable();
326 
327   ins->block()->insertBefore(ins, replace);
328   ins->replaceOperand(0, replace);
329   if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false;
330 
331   // The TypeBarrier is equivalent to removing branches with unexpected
332   // types.  The unexpected types would have changed Range Analysis
333   // predictions.  As such, we need to prevent destructive optimizations.
334   ins->block()->flagOperandsOfPrunedBranches(replace);
335 
336   return true;
337 }
338 
adjustInputs(TempAllocator & alloc,MInstruction * ins)339 bool TestPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
340   MDefinition* op = ins->getOperand(0);
341   switch (op->type()) {
342     case MIRType::Value:
343     case MIRType::Null:
344     case MIRType::Undefined:
345     case MIRType::Boolean:
346     case MIRType::Int32:
347     case MIRType::Double:
348     case MIRType::Float32:
349     case MIRType::Symbol:
350     case MIRType::Object:
351       break;
352 
353     case MIRType::String: {
354       MStringLength* length = MStringLength::New(alloc, op);
355       ins->block()->insertBefore(ins, length);
356       ins->replaceOperand(0, length);
357       break;
358     }
359 
360     default:
361       ins->replaceOperand(0, BoxAt(alloc, ins, op));
362       break;
363   }
364   return true;
365 }
366 
adjustInputs(TempAllocator & alloc,MInstruction * ins)367 bool BitwisePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
368   MIRType specialization = ins->typePolicySpecialization();
369   if (specialization == MIRType::None)
370     return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
371 
372   MOZ_ASSERT(ins->type() == specialization);
373   MOZ_ASSERT(specialization == MIRType::Int32 ||
374              specialization == MIRType::Double);
375 
376   // This policy works for both unary and binary bitwise operations.
377   for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
378     MDefinition* in = ins->getOperand(i);
379     if (in->type() == MIRType::Int32) continue;
380 
381     MInstruction* replace = MTruncateToInt32::New(alloc, in);
382     ins->block()->insertBefore(ins, replace);
383     ins->replaceOperand(i, replace);
384 
385     if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false;
386   }
387 
388   return true;
389 }
390 
adjustInputs(TempAllocator & alloc,MInstruction * ins)391 bool PowPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
392   MIRType specialization = ins->typePolicySpecialization();
393   MOZ_ASSERT(specialization == MIRType::Int32 ||
394              specialization == MIRType::Double ||
395              specialization == MIRType::None);
396 
397   // Inputs will be boxed if either is non-numeric.
398   if (specialization == MIRType::None)
399     return BoxInputsPolicy::staticAdjustInputs(alloc, ins);
400 
401   // Otherwise, input must be a double.
402   if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins)) return false;
403 
404   // Power may be an int32 or a double. Integers receive a faster path.
405   if (specialization == MIRType::Double)
406     return DoublePolicy<1>::staticAdjustInputs(alloc, ins);
407   return UnboxedInt32Policy<1>::staticAdjustInputs(alloc, ins);
408 }
409 
410 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)411 bool StringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
412                                           MInstruction* ins) {
413   MDefinition* in = ins->getOperand(Op);
414   if (in->type() == MIRType::String) return true;
415 
416   MUnbox* replace = MUnbox::New(alloc, in, MIRType::String, MUnbox::Fallible);
417   ins->block()->insertBefore(ins, replace);
418   ins->replaceOperand(Op, replace);
419 
420   return replace->typePolicy()->adjustInputs(alloc, replace);
421 }
422 
423 template bool StringPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
424                                                   MInstruction* ins);
425 template bool StringPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
426                                                   MInstruction* ins);
427 template bool StringPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
428                                                   MInstruction* ins);
429 
430 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)431 bool ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
432                                                    MInstruction* ins) {
433   MDefinition* in = ins->getOperand(Op);
434   if (in->type() == MIRType::String) return true;
435 
436   MToString* replace = MToString::New(alloc, in);
437   ins->block()->insertBefore(ins, replace);
438   ins->replaceOperand(Op, replace);
439 
440   if (!ToStringPolicy::staticAdjustInputs(alloc, replace)) return false;
441 
442   return true;
443 }
444 
445 template bool ConvertToStringPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
446                                                            MInstruction* ins);
447 template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
448                                                            MInstruction* ins);
449 template bool ConvertToStringPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
450                                                            MInstruction* ins);
451 
452 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * def)453 bool BooleanPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
454                                            MInstruction* def) {
455   MDefinition* in = def->getOperand(Op);
456   if (in->type() == MIRType::Boolean) return true;
457 
458   MUnbox* replace = MUnbox::New(alloc, in, MIRType::Boolean, MUnbox::Fallible);
459   def->block()->insertBefore(def, replace);
460   def->replaceOperand(Op, replace);
461 
462   return replace->typePolicy()->adjustInputs(alloc, replace);
463 }
464 
465 template bool BooleanPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
466                                                    MInstruction* def);
467 
468 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * def)469 bool UnboxedInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
470                                                 MInstruction* def) {
471   MDefinition* in = def->getOperand(Op);
472   if (in->type() == MIRType::Int32) return true;
473 
474   MUnbox* replace = MUnbox::New(alloc, in, MIRType::Int32, MUnbox::Fallible);
475   def->block()->insertBefore(def, replace);
476   def->replaceOperand(Op, replace);
477 
478   return replace->typePolicy()->adjustInputs(alloc, replace);
479 }
480 
481 template bool UnboxedInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
482                                                         MInstruction* def);
483 template bool UnboxedInt32Policy<1>::staticAdjustInputs(TempAllocator& alloc,
484                                                         MInstruction* def);
485 template bool UnboxedInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
486                                                         MInstruction* def);
487 template bool UnboxedInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc,
488                                                         MInstruction* def);
489 
490 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * def)491 bool ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
492                                                   MInstruction* def) {
493   MDefinition* in = def->getOperand(Op);
494   if (in->type() == MIRType::Int32) return true;
495 
496   auto* replace = MToNumberInt32::New(alloc, in);
497   def->block()->insertBefore(def, replace);
498   def->replaceOperand(Op, replace);
499 
500   return replace->typePolicy()->adjustInputs(alloc, replace);
501 }
502 
503 template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
504                                                           MInstruction* def);
505 
506 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * def)507 bool TruncateToInt32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
508                                                    MInstruction* def) {
509   MDefinition* in = def->getOperand(Op);
510   if (in->type() == MIRType::Int32) return true;
511 
512   MTruncateToInt32* replace = MTruncateToInt32::New(alloc, in);
513   def->block()->insertBefore(def, replace);
514   def->replaceOperand(Op, replace);
515 
516   return replace->typePolicy()->adjustInputs(alloc, replace);
517 }
518 
519 template bool TruncateToInt32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
520                                                            MInstruction* def);
521 template bool TruncateToInt32Policy<3>::staticAdjustInputs(TempAllocator& alloc,
522                                                            MInstruction* def);
523 
524 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * def)525 bool DoublePolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
526                                           MInstruction* def) {
527   MDefinition* in = def->getOperand(Op);
528   if (in->type() == MIRType::Double || in->type() == MIRType::SinCosDouble)
529     return true;
530 
531   MToDouble* replace = MToDouble::New(alloc, in);
532   def->block()->insertBefore(def, replace);
533   def->replaceOperand(Op, replace);
534 
535   return replace->typePolicy()->adjustInputs(alloc, replace);
536 }
537 
538 template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator& alloc,
539                                                   MInstruction* def);
540 template bool DoublePolicy<1>::staticAdjustInputs(TempAllocator& alloc,
541                                                   MInstruction* def);
542 
543 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * def)544 bool Float32Policy<Op>::staticAdjustInputs(TempAllocator& alloc,
545                                            MInstruction* def) {
546   MDefinition* in = def->getOperand(Op);
547   if (in->type() == MIRType::Float32) return true;
548 
549   MToFloat32* replace = MToFloat32::New(alloc, in);
550   def->block()->insertBefore(def, replace);
551   def->replaceOperand(Op, replace);
552 
553   return replace->typePolicy()->adjustInputs(alloc, replace);
554 }
555 
556 template bool Float32Policy<0>::staticAdjustInputs(TempAllocator& alloc,
557                                                    MInstruction* def);
558 template bool Float32Policy<1>::staticAdjustInputs(TempAllocator& alloc,
559                                                    MInstruction* def);
560 template bool Float32Policy<2>::staticAdjustInputs(TempAllocator& alloc,
561                                                    MInstruction* def);
562 
563 template <unsigned Op>
adjustInputs(TempAllocator & alloc,MInstruction * def)564 bool FloatingPointPolicy<Op>::adjustInputs(TempAllocator& alloc,
565                                            MInstruction* def) {
566   MIRType policyType = def->typePolicySpecialization();
567   if (policyType == MIRType::Double)
568     return DoublePolicy<Op>::staticAdjustInputs(alloc, def);
569   return Float32Policy<Op>::staticAdjustInputs(alloc, def);
570 }
571 
572 template bool FloatingPointPolicy<0>::adjustInputs(TempAllocator& alloc,
573                                                    MInstruction* def);
574 
575 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * def)576 bool NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
577                                            MInstruction* def) {
578   EnsureOperandNotFloat32(alloc, def, Op);
579   return true;
580 }
581 
582 template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
583                                                    MInstruction* def);
584 template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
585                                                    MInstruction* def);
586 template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
587                                                    MInstruction* def);
588 template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
589                                                    MInstruction* def);
590 
591 template <unsigned FirstOp>
adjustInputs(TempAllocator & alloc,MInstruction * def)592 bool NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator& alloc,
593                                                MInstruction* def) {
594   for (size_t op = FirstOp, e = def->numOperands(); op < e; op++)
595     EnsureOperandNotFloat32(alloc, def, op);
596   return true;
597 }
598 
599 template bool NoFloatPolicyAfter<0>::adjustInputs(TempAllocator& alloc,
600                                                   MInstruction* def);
601 template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator& alloc,
602                                                   MInstruction* def);
603 template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc,
604                                                   MInstruction* def);
605 
606 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)607 bool SimdScalarPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
608                                               MInstruction* ins) {
609   MOZ_ASSERT(IsSimdType(ins->type()));
610   MIRType laneType = SimdTypeToLaneType(ins->type());
611 
612   MDefinition* in = ins->getOperand(Op);
613 
614   // A vector with boolean lanes requires Int32 inputs that have already been
615   // converted to 0/-1.
616   // We can't insert a MIRType::Boolean lane directly - it requires conversion.
617   if (laneType == MIRType::Boolean) {
618     MOZ_ASSERT(in->type() == MIRType::Int32,
619                "Boolean SIMD vector requires Int32 lanes.");
620     return true;
621   }
622 
623   if (in->type() == laneType) return true;
624 
625   MInstruction* replace;
626   if (laneType == MIRType::Int32) {
627     replace = MTruncateToInt32::New(alloc, in);
628   } else {
629     MOZ_ASSERT(laneType == MIRType::Float32);
630     replace = MToFloat32::New(alloc, in);
631   }
632 
633   ins->block()->insertBefore(ins, replace);
634   ins->replaceOperand(Op, replace);
635 
636   return replace->typePolicy()->adjustInputs(alloc, replace);
637 }
638 
639 template bool SimdScalarPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
640                                                       MInstruction* def);
641 template bool SimdScalarPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
642                                                       MInstruction* def);
643 template bool SimdScalarPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
644                                                       MInstruction* def);
645 template bool SimdScalarPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
646                                                       MInstruction* def);
647 
648 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)649 bool BoxPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
650                                        MInstruction* ins) {
651   MDefinition* in = ins->getOperand(Op);
652   if (in->type() == MIRType::Value) return true;
653 
654   ins->replaceOperand(Op, BoxAt(alloc, ins, in));
655   return true;
656 }
657 
658 template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
659                                                MInstruction* ins);
660 template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
661                                                MInstruction* ins);
662 template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
663                                                MInstruction* ins);
664 
665 template <unsigned Op, MIRType Type>
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)666 bool BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator& alloc,
667                                                    MInstruction* ins) {
668   MDefinition* in = ins->getOperand(Op);
669   if (in->type() == Type) return true;
670   return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
671 }
672 
673 template bool BoxExceptPolicy<0, MIRType::Object>::staticAdjustInputs(
674     TempAllocator& alloc, MInstruction* ins);
675 
676 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)677 bool CacheIdPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
678                                            MInstruction* ins) {
679   MDefinition* in = ins->getOperand(Op);
680   switch (in->type()) {
681     case MIRType::Int32:
682     case MIRType::String:
683     case MIRType::Symbol:
684       return true;
685     default:
686       return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
687   }
688 }
689 
690 template bool CacheIdPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
691                                                    MInstruction* ins);
692 template bool CacheIdPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
693                                                    MInstruction* ins);
694 
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)695 bool ToDoublePolicy::staticAdjustInputs(TempAllocator& alloc,
696                                         MInstruction* ins) {
697   MOZ_ASSERT(ins->isToDouble() || ins->isToFloat32());
698 
699   MDefinition* in = ins->getOperand(0);
700   MToFPInstruction::ConversionKind conversion;
701   if (ins->isToDouble())
702     conversion = ins->toToDouble()->conversion();
703   else
704     conversion = ins->toToFloat32()->conversion();
705 
706   switch (in->type()) {
707     case MIRType::Int32:
708     case MIRType::Float32:
709     case MIRType::Double:
710     case MIRType::Value:
711       // No need for boxing for these types.
712       return true;
713     case MIRType::Null:
714       // No need for boxing, when we will convert.
715       if (conversion == MToFPInstruction::NonStringPrimitives) return true;
716       break;
717     case MIRType::Undefined:
718     case MIRType::Boolean:
719       // No need for boxing, when we will convert.
720       if (conversion == MToFPInstruction::NonStringPrimitives) return true;
721       if (conversion == MToFPInstruction::NonNullNonStringPrimitives)
722         return true;
723       break;
724     case MIRType::Object:
725     case MIRType::String:
726     case MIRType::Symbol:
727       // Objects might be effectful. Symbols give TypeError.
728       break;
729     default:
730       break;
731   }
732 
733   in = BoxAt(alloc, ins, in);
734   ins->replaceOperand(0, in);
735   return true;
736 }
737 
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)738 bool ToInt32Policy::staticAdjustInputs(TempAllocator& alloc,
739                                        MInstruction* ins) {
740   MOZ_ASSERT(ins->isToNumberInt32() || ins->isTruncateToInt32());
741 
742   IntConversionInputKind conversion = IntConversionInputKind::Any;
743   if (ins->isToNumberInt32()) conversion = ins->toToNumberInt32()->conversion();
744 
745   MDefinition* in = ins->getOperand(0);
746   switch (in->type()) {
747     case MIRType::Int32:
748     case MIRType::Float32:
749     case MIRType::Double:
750     case MIRType::Value:
751       // No need for boxing for these types.
752       return true;
753     case MIRType::Undefined:
754       // No need for boxing when truncating.
755       if (ins->isTruncateToInt32()) return true;
756       break;
757     case MIRType::Null:
758       // No need for boxing, when we will convert.
759       if (conversion == IntConversionInputKind::Any) return true;
760       break;
761     case MIRType::Boolean:
762       // No need for boxing, when we will convert.
763       if (conversion == IntConversionInputKind::Any) return true;
764       if (conversion == IntConversionInputKind::NumbersOrBoolsOnly) return true;
765       break;
766     case MIRType::Object:
767     case MIRType::String:
768     case MIRType::Symbol:
769       // Objects might be effectful. Symbols give TypeError.
770       break;
771     default:
772       break;
773   }
774 
775   in = BoxAt(alloc, ins, in);
776   ins->replaceOperand(0, in);
777   return true;
778 }
779 
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)780 bool ToStringPolicy::staticAdjustInputs(TempAllocator& alloc,
781                                         MInstruction* ins) {
782   MOZ_ASSERT(ins->isToString());
783 
784   MIRType type = ins->getOperand(0)->type();
785   if (type == MIRType::Object || type == MIRType::Symbol) {
786     ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
787     return true;
788   }
789 
790   // TODO remove the following line once 966957 has landed
791   EnsureOperandNotFloat32(alloc, ins, 0);
792 
793   return true;
794 }
795 
796 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)797 bool ObjectPolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
798                                           MInstruction* ins) {
799   MDefinition* in = ins->getOperand(Op);
800   if (in->type() == MIRType::Object || in->type() == MIRType::Slots ||
801       in->type() == MIRType::Elements) {
802     return true;
803   }
804 
805   MUnbox* replace = MUnbox::New(alloc, in, MIRType::Object, MUnbox::Fallible);
806   ins->block()->insertBefore(ins, replace);
807   ins->replaceOperand(Op, replace);
808 
809   return replace->typePolicy()->adjustInputs(alloc, replace);
810 }
811 
812 template bool ObjectPolicy<0>::staticAdjustInputs(TempAllocator& alloc,
813                                                   MInstruction* ins);
814 template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator& alloc,
815                                                   MInstruction* ins);
816 template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator& alloc,
817                                                   MInstruction* ins);
818 template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator& alloc,
819                                                   MInstruction* ins);
820 
821 template <unsigned Op>
staticAdjustInputs(TempAllocator & alloc,MInstruction * ins)822 bool SimdSameAsReturnedTypePolicy<Op>::staticAdjustInputs(TempAllocator& alloc,
823                                                           MInstruction* ins) {
824   MOZ_ASSERT(ins->type() == ins->getOperand(Op)->type());
825   return true;
826 }
827 
828 template bool SimdSameAsReturnedTypePolicy<0>::staticAdjustInputs(
829     TempAllocator& alloc, MInstruction* ins);
830 template bool SimdSameAsReturnedTypePolicy<1>::staticAdjustInputs(
831     TempAllocator& alloc, MInstruction* ins);
832 
adjustInputs(TempAllocator & alloc,MInstruction * ins)833 bool SimdAllPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
834   for (unsigned i = 0, e = ins->numOperands(); i < e; i++)
835     MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization());
836   return true;
837 }
838 
839 template <unsigned Op>
adjustInputs(TempAllocator & alloc,MInstruction * ins)840 bool SimdPolicy<Op>::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
841   MOZ_ASSERT(ins->typePolicySpecialization() == ins->getOperand(Op)->type());
842   return true;
843 }
844 
845 template bool SimdPolicy<0>::adjustInputs(TempAllocator& alloc,
846                                           MInstruction* ins);
847 
adjustInputs(TempAllocator & alloc,MInstruction * ins)848 bool SimdShufflePolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
849   MSimdGeneralShuffle* s = ins->toSimdGeneralShuffle();
850 
851   for (unsigned i = 0; i < s->numVectors(); i++)
852     MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization());
853 
854   // Next inputs are the lanes, which need to be int32
855   for (unsigned i = 0; i < s->numLanes(); i++) {
856     MDefinition* in = ins->getOperand(s->numVectors() + i);
857     if (in->type() == MIRType::Int32) continue;
858 
859     auto* replace =
860         MToNumberInt32::New(alloc, in, IntConversionInputKind::NumbersOnly);
861     ins->block()->insertBefore(ins, replace);
862     ins->replaceOperand(s->numVectors() + i, replace);
863     if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false;
864   }
865 
866   return true;
867 }
868 
adjustInputs(TempAllocator & alloc,MInstruction * ins)869 bool SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
870   // First input is the mask, which has to be a boolean.
871   MOZ_ASSERT(IsBooleanSimdType(ins->getOperand(0)->type()));
872 
873   // Next inputs are the two vectors of a particular type.
874   for (unsigned i = 1; i < 3; i++)
875     MOZ_ASSERT(ins->getOperand(i)->type() == ins->typePolicySpecialization());
876 
877   return true;
878 }
879 
adjustInputs(TempAllocator & alloc,MInstruction * ins)880 bool CallPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
881   MCall* call = ins->toCall();
882 
883   MDefinition* func = call->getFunction();
884   if (func->type() != MIRType::Object) {
885     MInstruction* unbox =
886         MUnbox::New(alloc, func, MIRType::Object, MUnbox::Fallible);
887     call->block()->insertBefore(call, unbox);
888     call->replaceFunction(unbox);
889 
890     if (!unbox->typePolicy()->adjustInputs(alloc, unbox)) return false;
891   }
892 
893   for (uint32_t i = 0; i < call->numStackArgs(); i++) {
894     if (!alloc.ensureBallast()) return false;
895     EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i));
896   }
897 
898   return true;
899 }
900 
adjustInputs(TempAllocator & alloc,MInstruction * ins)901 bool CallSetElementPolicy::adjustInputs(TempAllocator& alloc,
902                                         MInstruction* ins) {
903   // The first operand should be an object.
904   if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins)) return false;
905 
906   // Box the index and value operands.
907   for (size_t i = 1, e = ins->numOperands(); i < e; i++) {
908     MDefinition* in = ins->getOperand(i);
909     if (in->type() == MIRType::Value) continue;
910     ins->replaceOperand(i, BoxAt(alloc, ins, in));
911   }
912   return true;
913 }
914 
adjustInputs(TempAllocator & alloc,MInstruction * def)915 bool InstanceOfPolicy::adjustInputs(TempAllocator& alloc, MInstruction* def) {
916   // Box first operand if it isn't object
917   if (def->getOperand(0)->type() != MIRType::Object)
918     if (!BoxPolicy<0>::staticAdjustInputs(alloc, def)) return false;
919 
920   return true;
921 }
922 
adjustValueInput(TempAllocator & alloc,MInstruction * ins,Scalar::Type writeType,MDefinition * value,int valueOperand)923 bool StoreUnboxedScalarPolicy::adjustValueInput(TempAllocator& alloc,
924                                                 MInstruction* ins,
925                                                 Scalar::Type writeType,
926                                                 MDefinition* value,
927                                                 int valueOperand) {
928   // Storing a SIMD value requires a valueOperand that has already been
929   // SimdUnboxed. See IonBuilder::inlineSimdStore(()
930   if (Scalar::isSimdType(writeType)) {
931     MOZ_ASSERT(IsSimdType(value->type()));
932     return true;
933   }
934 
935   MDefinition* curValue = value;
936   // First, ensure the value is int32, boolean, double or Value.
937   // The conversion is based on TypedArrayObjectTemplate::setElementTail.
938   switch (value->type()) {
939     case MIRType::Int32:
940     case MIRType::Double:
941     case MIRType::Float32:
942     case MIRType::Boolean:
943     case MIRType::Value:
944       break;
945     case MIRType::Null:
946       value->setImplicitlyUsedUnchecked();
947       value = MConstant::New(alloc, Int32Value(0));
948       ins->block()->insertBefore(ins, value->toInstruction());
949       break;
950     case MIRType::Undefined:
951       value->setImplicitlyUsedUnchecked();
952       value = MConstant::New(alloc, DoubleNaNValue());
953       ins->block()->insertBefore(ins, value->toInstruction());
954       break;
955     case MIRType::Object:
956     case MIRType::String:
957     case MIRType::Symbol:
958       value = BoxAt(alloc, ins, value);
959       break;
960     default:
961       MOZ_CRASH("Unexpected type");
962   }
963 
964   if (value != curValue) {
965     ins->replaceOperand(valueOperand, value);
966     curValue = value;
967   }
968 
969   MOZ_ASSERT(
970       value->type() == MIRType::Int32 || value->type() == MIRType::Boolean ||
971       value->type() == MIRType::Double || value->type() == MIRType::Float32 ||
972       value->type() == MIRType::Value);
973 
974   switch (writeType) {
975     case Scalar::Int8:
976     case Scalar::Uint8:
977     case Scalar::Int16:
978     case Scalar::Uint16:
979     case Scalar::Int32:
980     case Scalar::Uint32:
981       if (value->type() != MIRType::Int32) {
982         value = MTruncateToInt32::New(alloc, value);
983         ins->block()->insertBefore(ins, value->toInstruction());
984       }
985       break;
986     case Scalar::Uint8Clamped:
987       // IonBuilder should have inserted ClampToUint8.
988       MOZ_ASSERT(value->type() == MIRType::Int32);
989       break;
990     case Scalar::Float32:
991       if (value->type() != MIRType::Float32) {
992         value = MToFloat32::New(alloc, value);
993         ins->block()->insertBefore(ins, value->toInstruction());
994       }
995       break;
996     case Scalar::Float64:
997       if (value->type() != MIRType::Double) {
998         value = MToDouble::New(alloc, value);
999         ins->block()->insertBefore(ins, value->toInstruction());
1000       }
1001       break;
1002     default:
1003       MOZ_CRASH("Invalid array type");
1004   }
1005 
1006   if (value != curValue) ins->replaceOperand(valueOperand, value);
1007 
1008   return true;
1009 }
1010 
adjustInputs(TempAllocator & alloc,MInstruction * ins)1011 bool StoreUnboxedScalarPolicy::adjustInputs(TempAllocator& alloc,
1012                                             MInstruction* ins) {
1013   if (!SingleObjectPolicy::staticAdjustInputs(alloc, ins)) return false;
1014 
1015   MStoreUnboxedScalar* store = ins->toStoreUnboxedScalar();
1016   MOZ_ASSERT(IsValidElementsType(store->elements(), store->offsetAdjustment()));
1017   MOZ_ASSERT(store->index()->type() == MIRType::Int32);
1018 
1019   return adjustValueInput(alloc, store, store->writeType(), store->value(), 2);
1020 }
1021 
adjustInputs(TempAllocator & alloc,MInstruction * ins)1022 bool StoreTypedArrayHolePolicy::adjustInputs(TempAllocator& alloc,
1023                                              MInstruction* ins) {
1024   MStoreTypedArrayElementHole* store = ins->toStoreTypedArrayElementHole();
1025   MOZ_ASSERT(store->elements()->type() == MIRType::Elements);
1026   MOZ_ASSERT(store->index()->type() == MIRType::Int32);
1027   MOZ_ASSERT(store->length()->type() == MIRType::Int32);
1028 
1029   return StoreUnboxedScalarPolicy::adjustValueInput(
1030       alloc, ins, store->arrayType(), store->value(), 3);
1031 }
1032 
adjustInputs(TempAllocator & alloc,MInstruction * ins)1033 bool StoreUnboxedObjectOrNullPolicy::adjustInputs(TempAllocator& alloc,
1034                                                   MInstruction* ins) {
1035   if (!ObjectPolicy<0>::staticAdjustInputs(alloc, ins)) return false;
1036 
1037   if (!ObjectPolicy<3>::staticAdjustInputs(alloc, ins)) return false;
1038 
1039   // Change the value input to a ToObjectOrNull instruction if it might be
1040   // a non-null primitive. Insert a post barrier for the instruction's object
1041   // and whatever its new value is, unless the value is definitely null.
1042   MStoreUnboxedObjectOrNull* store = ins->toStoreUnboxedObjectOrNull();
1043 
1044   MOZ_ASSERT(store->typedObj()->type() == MIRType::Object);
1045 
1046   MDefinition* value = store->value();
1047   if (value->type() == MIRType::Object || value->type() == MIRType::Null ||
1048       value->type() == MIRType::ObjectOrNull) {
1049     if (value->type() != MIRType::Null) {
1050       MInstruction* barrier =
1051           MPostWriteBarrier::New(alloc, store->typedObj(), value);
1052       store->block()->insertBefore(store, barrier);
1053     }
1054     return true;
1055   }
1056 
1057   MToObjectOrNull* replace = MToObjectOrNull::New(alloc, value);
1058   store->block()->insertBefore(store, replace);
1059   store->setValue(replace);
1060 
1061   if (!BoxPolicy<0>::staticAdjustInputs(alloc, replace)) return false;
1062 
1063   MInstruction* barrier =
1064       MPostWriteBarrier::New(alloc, store->typedObj(), replace);
1065   store->block()->insertBefore(store, barrier);
1066 
1067   return true;
1068 }
1069 
adjustInputs(TempAllocator & alloc,MInstruction * ins)1070 bool StoreUnboxedStringPolicy::adjustInputs(TempAllocator& alloc,
1071                                             MInstruction* ins) {
1072   if (!ObjectPolicy<0>::staticAdjustInputs(alloc, ins)) return false;
1073 
1074   // Change the value input to a ToString instruction if it might be
1075   // a non-null primitive.
1076   if (!ConvertToStringPolicy<2>::staticAdjustInputs(alloc, ins)) return false;
1077 
1078   if (!ObjectPolicy<3>::staticAdjustInputs(alloc, ins)) return false;
1079 
1080   // Insert a post barrier for the instruction's object and whatever its new
1081   // value is.
1082   MStoreUnboxedString* store = ins->toStoreUnboxedString();
1083 
1084   MOZ_ASSERT(store->typedObj()->type() == MIRType::Object);
1085 
1086   MDefinition* value = store->value();
1087   MOZ_ASSERT(value->type() == MIRType::String);
1088   MInstruction* barrier =
1089       MPostWriteBarrier::New(alloc, store->typedObj(), value);
1090   store->block()->insertBefore(store, barrier);
1091   return true;
1092 }
1093 
adjustInputs(TempAllocator & alloc,MInstruction * ins)1094 bool ClampPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins) {
1095   MDefinition* in = ins->toClampToUint8()->input();
1096 
1097   switch (in->type()) {
1098     case MIRType::Int32:
1099     case MIRType::Double:
1100     case MIRType::Value:
1101       break;
1102     default:
1103       ins->replaceOperand(0, BoxAt(alloc, ins, in));
1104       break;
1105   }
1106 
1107   return true;
1108 }
1109 
adjustInputs(TempAllocator & alloc,MInstruction * ins)1110 bool FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc,
1111                                        MInstruction* ins) {
1112   MOZ_ASSERT(ins->numOperands() == 1);
1113   MIRType inputType = ins->getOperand(0)->type();
1114   MIRType outputType = ins->type();
1115 
1116   // Special case when output is a Float32, but input isn't.
1117   if (outputType == MIRType::Float32 && inputType != MIRType::Float32) {
1118     // Create a MToFloat32 to add between the MFilterTypeSet and
1119     // its uses.
1120     MInstruction* replace = MToFloat32::New(alloc, ins);
1121     ins->justReplaceAllUsesWithExcept(replace);
1122     ins->block()->insertAfter(ins, replace);
1123 
1124     // Reset the type to not MIRType::Float32
1125     // Note: setResultType shouldn't happen in TypePolicies,
1126     //       Here it is fine, since there is just one use we just
1127     //       added ourself. And the resulting type after MToFloat32
1128     //       equals the original type.
1129     ins->setResultType(ins->resultTypeSet()->getKnownMIRType());
1130     outputType = ins->type();
1131 
1132     // Do the type analysis
1133     if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false;
1134 
1135     // Fall through to let the MFilterTypeSet adjust its input based
1136     // on its new type.
1137   }
1138 
1139   // Input and output type are already in accordance.
1140   if (inputType == outputType) return true;
1141 
1142   // Output is a value, box the input.
1143   if (outputType == MIRType::Value) {
1144     MOZ_ASSERT(inputType != MIRType::Value);
1145     ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
1146     return true;
1147   }
1148 
1149   // The outputType should be a subset of the inputType else we are in code
1150   // that has never executed yet. Bail to see the new type (if that hasn't
1151   // happened yet).
1152   if (inputType != MIRType::Value) {
1153     MBail* bail = MBail::New(alloc);
1154     ins->block()->insertBefore(ins, bail);
1155     bail->setDependency(ins->dependency());
1156     ins->setDependency(bail);
1157     ins->replaceOperand(0, BoxAt(alloc, ins, ins->getOperand(0)));
1158   }
1159 
1160   // We can't unbox a value to null/undefined/lazyargs. So keep output
1161   // also a value.
1162   // Note: Using setResultType shouldn't be done in TypePolicies,
1163   //       Here it is fine, since the type barrier has no uses.
1164   if (IsNullOrUndefined(outputType) ||
1165       outputType == MIRType::MagicOptimizedArguments) {
1166     MOZ_ASSERT(!ins->hasDefUses());
1167     ins->setResultType(MIRType::Value);
1168     return true;
1169   }
1170 
1171   // Unbox / propagate the right type.
1172   MUnbox::Mode mode = MUnbox::Infallible;
1173   MInstruction* replace =
1174       MUnbox::New(alloc, ins->getOperand(0), ins->type(), mode);
1175 
1176   ins->block()->insertBefore(ins, replace);
1177   ins->replaceOperand(0, replace);
1178   if (!replace->typePolicy()->adjustInputs(alloc, replace)) return false;
1179 
1180   // Carry over the dependency the MFilterTypeSet had.
1181   replace->setDependency(ins->dependency());
1182 
1183   return true;
1184 }
1185 
1186 // Lists of all TypePolicy specializations which are used by MIR Instructions.
1187 #define TYPE_POLICY_LIST(_)         \
1188   _(ArithPolicy)                    \
1189   _(BitwisePolicy)                  \
1190   _(BoxInputsPolicy)                \
1191   _(CallPolicy)                     \
1192   _(CallSetElementPolicy)           \
1193   _(ClampPolicy)                    \
1194   _(ComparePolicy)                  \
1195   _(FilterTypeSetPolicy)            \
1196   _(InstanceOfPolicy)               \
1197   _(PowPolicy)                      \
1198   _(SameValuePolicy)                \
1199   _(SimdAllPolicy)                  \
1200   _(SimdSelectPolicy)               \
1201   _(SimdShufflePolicy)              \
1202   _(StoreTypedArrayHolePolicy)      \
1203   _(StoreUnboxedScalarPolicy)       \
1204   _(StoreUnboxedObjectOrNullPolicy) \
1205   _(StoreUnboxedStringPolicy)       \
1206   _(TestPolicy)                     \
1207   _(AllDoublePolicy)                \
1208   _(ToDoublePolicy)                 \
1209   _(ToInt32Policy)                  \
1210   _(ToStringPolicy)                 \
1211   _(TypeBarrierPolicy)
1212 
1213 #define TEMPLATE_TYPE_POLICY_LIST(_)                                          \
1214   _(BoxExceptPolicy<0, MIRType::Object>)                                      \
1215   _(BoxPolicy<0>)                                                             \
1216   _(ConvertToInt32Policy<0>)                                                  \
1217   _(ConvertToStringPolicy<0>)                                                 \
1218   _(ConvertToStringPolicy<2>)                                                 \
1219   _(DoublePolicy<0>)                                                          \
1220   _(FloatingPointPolicy<0>)                                                   \
1221   _(UnboxedInt32Policy<0>)                                                    \
1222   _(UnboxedInt32Policy<1>)                                                    \
1223   _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, BoxPolicy<2>>)                \
1224   _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2>>)                   \
1225   _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2>>)                \
1226   _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, BoxPolicy<2>>)          \
1227   _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1228   _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>,                         \
1229               TruncateToInt32Policy<2>>)                                      \
1230   _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, BoxPolicy<2>>)                \
1231   _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, UnboxedInt32Policy<2>>)       \
1232   _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>, ObjectPolicy<2>>)             \
1233   _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>>) \
1234   _(MixPolicy<StringPolicy<0>, ObjectPolicy<1>, StringPolicy<2>>)             \
1235   _(MixPolicy<StringPolicy<0>, StringPolicy<1>, StringPolicy<2>>)             \
1236   _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>, UnboxedInt32Policy<2>>)       \
1237   _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>, UnboxedInt32Policy<2>,  \
1238               UnboxedInt32Policy<3>>)                                         \
1239   _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>,                         \
1240               TruncateToInt32Policy<2>, TruncateToInt32Policy<3>>)            \
1241   _(MixPolicy<ObjectPolicy<0>, CacheIdPolicy<1>, NoFloatPolicy<2>>)           \
1242   _(MixPolicy<SimdScalarPolicy<0>, SimdScalarPolicy<1>, SimdScalarPolicy<2>,  \
1243               SimdScalarPolicy<3>>)                                           \
1244   _(MixPolicy<ObjectPolicy<0>, BoxExceptPolicy<1, MIRType::Object>,           \
1245               CacheIdPolicy<2>>)                                              \
1246   _(MixPolicy<BoxPolicy<0>, ObjectPolicy<1>>)                                 \
1247   _(MixPolicy<ConvertToStringPolicy<0>, ConvertToStringPolicy<1>>)            \
1248   _(MixPolicy<ConvertToStringPolicy<0>, ObjectPolicy<1>>)                     \
1249   _(MixPolicy<DoublePolicy<0>, DoublePolicy<1>>)                              \
1250   _(MixPolicy<UnboxedInt32Policy<0>, UnboxedInt32Policy<1>>)                  \
1251   _(MixPolicy<ObjectPolicy<0>, BoxPolicy<1>>)                                 \
1252   _(MixPolicy<BoxExceptPolicy<0, MIRType::Object>, CacheIdPolicy<1>>)         \
1253   _(MixPolicy<CacheIdPolicy<0>, ObjectPolicy<1>>)                             \
1254   _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<1>>)                     \
1255   _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<1>>)                        \
1256   _(MixPolicy<ObjectPolicy<0>, UnboxedInt32Policy<2>>)                        \
1257   _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<1>>)                             \
1258   _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<2>>)                             \
1259   _(MixPolicy<ObjectPolicy<0>, NoFloatPolicy<3>>)                             \
1260   _(MixPolicy<ObjectPolicy<0>, ObjectPolicy<1>>)                              \
1261   _(MixPolicy<ObjectPolicy<0>, StringPolicy<1>>)                              \
1262   _(MixPolicy<ObjectPolicy<0>, ConvertToStringPolicy<2>>)                     \
1263   _(MixPolicy<ObjectPolicy<1>, ConvertToStringPolicy<0>>)                     \
1264   _(MixPolicy<SimdSameAsReturnedTypePolicy<0>,                                \
1265               SimdSameAsReturnedTypePolicy<1>>)                               \
1266   _(MixPolicy<SimdSameAsReturnedTypePolicy<0>, SimdScalarPolicy<1>>)          \
1267   _(MixPolicy<StringPolicy<0>, UnboxedInt32Policy<1>>)                        \
1268   _(MixPolicy<StringPolicy<0>, StringPolicy<1>>)                              \
1269   _(MixPolicy<BoxPolicy<0>, BoxPolicy<1>>)                                    \
1270   _(NoFloatPolicy<0>)                                                         \
1271   _(NoFloatPolicyAfter<0>)                                                    \
1272   _(NoFloatPolicyAfter<1>)                                                    \
1273   _(NoFloatPolicyAfter<2>)                                                    \
1274   _(ObjectPolicy<0>)                                                          \
1275   _(ObjectPolicy<1>)                                                          \
1276   _(ObjectPolicy<3>)                                                          \
1277   _(SimdPolicy<0>)                                                            \
1278   _(SimdSameAsReturnedTypePolicy<0>)                                          \
1279   _(SimdScalarPolicy<0>)                                                      \
1280   _(StringPolicy<0>)
1281 
1282 namespace js {
1283 namespace jit {
1284 
1285 // Define for all used TypePolicy specialization, the definition for
1286 // |TypePolicy::Data::thisTypePolicy|.  This function returns one constant
1287 // instance of the TypePolicy which is shared among all MIR Instructions of the
1288 // same type.
1289 //
1290 // This Macro use __VA_ARGS__ to account for commas of template parameters.
1291 #define DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_(...) \
1292   TypePolicy* __VA_ARGS__::Data::thisTypePolicy() {  \
1293     static __VA_ARGS__ singletonType;                \
1294     return &singletonType;                           \
1295   }
1296 
1297 TYPE_POLICY_LIST(DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
1298 TEMPLATE_TYPE_POLICY_LIST(template <> DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_)
1299 #undef DEFINE_TYPE_POLICY_SINGLETON_INSTANCES_
1300 
1301 }  // namespace jit
1302 }  // namespace js
1303 
1304 namespace {
1305 
1306 // For extra-good measure in case an unqualified use is ever introduced.  (The
1307 // main use in the macro below is explicitly qualified so as not to consult
1308 // this scope and find this function.)
1309 inline TypePolicy* thisTypePolicy() = delete;
1310 
thisTypeSpecialization()1311 static MIRType thisTypeSpecialization() {
1312   MOZ_CRASH("TypeSpecialization lacks definition of thisTypeSpecialization.");
1313 }
1314 
1315 }  // namespace
1316 
1317 // For each MIR Instruction, this macro define the |typePolicy| method which is
1318 // using the |thisTypePolicy| method.  The |thisTypePolicy| method is either a
1319 // member of the MIR Instruction, such as with MGetElementCache, a member
1320 // inherited from the TypePolicy::Data structure, or a member inherited from
1321 // NoTypePolicy if the MIR instruction has no type policy.
1322 #define DEFINE_MIR_TYPEPOLICY_MEMBERS_(op)                                     \
1323   TypePolicy* js::jit::M##op::typePolicy() { return M##op::thisTypePolicy(); } \
1324                                                                                \
1325   MIRType js::jit::M##op::typePolicySpecialization() {                         \
1326     return thisTypeSpecialization();                                           \
1327   }
1328 
1329 MIR_OPCODE_LIST(DEFINE_MIR_TYPEPOLICY_MEMBERS_)
1330 #undef DEFINE_MIR_TYPEPOLICY_MEMBERS_
1331