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