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