js/src/jit/TypePolicy.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:9d4dc610b527
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 using namespace js;
14 using namespace js::jit;
15
16 using JS::DoubleNaNValue;
17
18 static void
19 EnsureOperandNotFloat32(TempAllocator &alloc, MInstruction *def, unsigned op)
20 {
21 MDefinition *in = def->getOperand(op);
22 if (in->type() == MIRType_Float32) {
23 MToDouble *replace = MToDouble::New(alloc, in);
24 def->block()->insertBefore(def, replace);
25 def->replaceOperand(op, replace);
26 }
27 }
28
29 MDefinition *
30 BoxInputsPolicy::boxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
31 {
32 if (operand->isUnbox())
33 return operand->toUnbox()->input();
34 return alwaysBoxAt(alloc, at, operand);
35 }
36
37 MDefinition *
38 BoxInputsPolicy::alwaysBoxAt(TempAllocator &alloc, MInstruction *at, MDefinition *operand)
39 {
40 MDefinition *boxedOperand = operand;
41 // Replace Float32 by double
42 if (operand->type() == MIRType_Float32) {
43 MInstruction *replace = MToDouble::New(alloc, operand);
44 at->block()->insertBefore(at, replace);
45 boxedOperand = replace;
46 }
47 MBox *box = MBox::New(alloc, boxedOperand);
48 at->block()->insertBefore(at, box);
49 return box;
50 }
51
52 bool
53 BoxInputsPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
54 {
55 for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
56 MDefinition *in = ins->getOperand(i);
57 if (in->type() == MIRType_Value)
58 continue;
59 ins->replaceOperand(i, boxAt(alloc, ins, in));
60 }
61 return true;
62 }
63
64 bool
65 ArithPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
66 {
67 if (specialization_ == MIRType_None)
68 return BoxInputsPolicy::adjustInputs(alloc, ins);
69
70 JS_ASSERT(ins->type() == MIRType_Double || ins->type() == MIRType_Int32 || ins->type() == MIRType_Float32);
71
72 for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
73 MDefinition *in = ins->getOperand(i);
74 if (in->type() == ins->type())
75 continue;
76
77 MInstruction *replace;
78
79 // If the input is a string or an object, the conversion is not
80 // possible, at least, we can't specialize. So box the input.
81 if (in->type() == MIRType_Object || in->type() == MIRType_String ||
82 (in->type() == MIRType_Undefined && specialization_ == MIRType_Int32))
83 {
84 in = boxAt(alloc, ins, in);
85 }
86
87 if (ins->type() == MIRType_Double)
88 replace = MToDouble::New(alloc, in);
89 else if (ins->type() == MIRType_Float32)
90 replace = MToFloat32::New(alloc, in);
91 else
92 replace = MToInt32::New(alloc, in);
93
94 ins->block()->insertBefore(ins, replace);
95 ins->replaceOperand(i, replace);
96 }
97
98 return true;
99 }
100
101 bool
102 ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
103 {
104 JS_ASSERT(def->isCompare());
105 MCompare *compare = def->toCompare();
106
107 // Convert Float32 operands to doubles
108 for (size_t i = 0; i < 2; i++) {
109 MDefinition *in = def->getOperand(i);
110 if (in->type() == MIRType_Float32) {
111 MInstruction *replace = MToDouble::New(alloc, in);
112 def->block()->insertBefore(def, replace);
113 def->replaceOperand(i, replace);
114 }
115 }
116
117 // Box inputs to get value
118 if (compare->compareType() == MCompare::Compare_Unknown ||
119 compare->compareType() == MCompare::Compare_Value)
120 {
121 return BoxInputsPolicy::adjustInputs(alloc, def);
122 }
123
124 // Compare_Boolean specialization is done for "Anything === Bool"
125 // If the LHS is boolean, we set the specialization to Compare_Int32.
126 // This matches other comparisons of the form bool === bool and
127 // generated code of Compare_Int32 is more efficient.
128 if (compare->compareType() == MCompare::Compare_Boolean &&
129 def->getOperand(0)->type() == MIRType_Boolean)
130 {
131 compare->setCompareType(MCompare::Compare_Int32MaybeCoerceBoth);
132 }
133
134 // Compare_Boolean specialization is done for "Anything === Bool"
135 // As of previous line Anything can't be Boolean
136 if (compare->compareType() == MCompare::Compare_Boolean) {
137 // Unbox rhs that is definitely Boolean
138 MDefinition *rhs = def->getOperand(1);
139 if (rhs->type() != MIRType_Boolean) {
140 if (rhs->type() != MIRType_Value)
141 rhs = boxAt(alloc, def, rhs);
142 MInstruction *unbox = MUnbox::New(alloc, rhs, MIRType_Boolean, MUnbox::Infallible);
143 def->block()->insertBefore(def, unbox);
144 def->replaceOperand(1, unbox);
145 }
146
147 JS_ASSERT(def->getOperand(0)->type() != MIRType_Boolean);
148 JS_ASSERT(def->getOperand(1)->type() == MIRType_Boolean);
149 return true;
150 }
151
152 // Compare_StrictString specialization is done for "Anything === String"
153 // If the LHS is string, we set the specialization to Compare_String.
154 if (compare->compareType() == MCompare::Compare_StrictString &&
155 def->getOperand(0)->type() == MIRType_String)
156 {
157 compare->setCompareType(MCompare::Compare_String);
158 }
159
160 // Compare_StrictString specialization is done for "Anything === String"
161 // As of previous line Anything can't be String
162 if (compare->compareType() == MCompare::Compare_StrictString) {
163 // Unbox rhs that is definitely String
164 MDefinition *rhs = def->getOperand(1);
165 if (rhs->type() != MIRType_String) {
166 if (rhs->type() != MIRType_Value)
167 rhs = boxAt(alloc, def, rhs);
168 MInstruction *unbox = MUnbox::New(alloc, rhs, MIRType_String, MUnbox::Infallible);
169 def->block()->insertBefore(def, unbox);
170 def->replaceOperand(1, unbox);
171 }
172
173 JS_ASSERT(def->getOperand(0)->type() != MIRType_String);
174 JS_ASSERT(def->getOperand(1)->type() == MIRType_String);
175 return true;
176 }
177
178 if (compare->compareType() == MCompare::Compare_Undefined ||
179 compare->compareType() == MCompare::Compare_Null)
180 {
181 // Nothing to do for undefined and null, lowering handles all types.
182 return true;
183 }
184
185 // Convert all inputs to the right input type
186 MIRType type = compare->inputType();
187 JS_ASSERT(type == MIRType_Int32 || type == MIRType_Double ||
188 type == MIRType_Object || type == MIRType_String || type == MIRType_Float32);
189 for (size_t i = 0; i < 2; i++) {
190 MDefinition *in = def->getOperand(i);
191 if (in->type() == type)
192 continue;
193
194 MInstruction *replace;
195
196 // See BinaryArithPolicy::adjustInputs for an explanation of the following
197 if (in->type() == MIRType_Object || in->type() == MIRType_String ||
198 in->type() == MIRType_Undefined)
199 {
200 in = boxAt(alloc, def, in);
201 }
202
203 switch (type) {
204 case MIRType_Double: {
205 MToDouble::ConversionKind convert = MToDouble::NumbersOnly;
206 if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0)
207 convert = MToDouble::NonNullNonStringPrimitives;
208 else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1)
209 convert = MToDouble::NonNullNonStringPrimitives;
210 if (in->type() == MIRType_Null ||
211 (in->type() == MIRType_Boolean && convert == MToDouble::NumbersOnly))
212 {
213 in = boxAt(alloc, def, in);
214 }
215 replace = MToDouble::New(alloc, in, convert);
216 break;
217 }
218 case MIRType_Float32: {
219 MToFloat32::ConversionKind convert = MToFloat32::NumbersOnly;
220 if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceLHS && i == 0)
221 convert = MToFloat32::NonNullNonStringPrimitives;
222 else if (compare->compareType() == MCompare::Compare_DoubleMaybeCoerceRHS && i == 1)
223 convert = MToFloat32::NonNullNonStringPrimitives;
224 if (in->type() == MIRType_Null ||
225 (in->type() == MIRType_Boolean && convert == MToFloat32::NumbersOnly))
226 {
227 in = boxAt(alloc, def, in);
228 }
229 replace = MToFloat32::New(alloc, in, convert);
230 break;
231 }
232 case MIRType_Int32: {
233 MacroAssembler::IntConversionInputKind convert = MacroAssembler::IntConversion_NumbersOnly;
234 if (compare->compareType() == MCompare::Compare_Int32MaybeCoerceBoth ||
235 (compare->compareType() == MCompare::Compare_Int32MaybeCoerceLHS && i == 0) ||
236 (compare->compareType() == MCompare::Compare_Int32MaybeCoerceRHS && i == 1))
237 {
238 convert = MacroAssembler::IntConversion_NumbersOrBoolsOnly;
239 }
240 if (convert == MacroAssembler::IntConversion_NumbersOnly) {
241 if (in->type() != MIRType_Int32 && in->type() != MIRType_Value)
242 in = boxAt(alloc, def, in);
243 } else {
244 MOZ_ASSERT(convert == MacroAssembler::IntConversion_NumbersOrBoolsOnly);
245 if (in->type() != MIRType_Int32 &&
246 in->type() != MIRType_Boolean &&
247 in->type() != MIRType_Value)
248 {
249 in = boxAt(alloc, def, in);
250 }
251 }
252 replace = MToInt32::New(alloc, in, convert);
253 break;
254 }
255 case MIRType_Object:
256 replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Infallible);
257 break;
258 case MIRType_String:
259 replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Infallible);
260 break;
261 default:
262 MOZ_ASSUME_UNREACHABLE("Unknown compare specialization");
263 }
264
265 def->block()->insertBefore(def, replace);
266 def->replaceOperand(i, replace);
267 }
268
269 return true;
270 }
271
272 bool
273 TypeBarrierPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
274 {
275 MTypeBarrier *ins = def->toTypeBarrier();
276 MIRType inputType = ins->getOperand(0)->type();
277 MIRType outputType = ins->type();
278
279 // Input and output type are already in accordance.
280 if (inputType == outputType)
281 return true;
282
283 // Output is a value, currently box the input.
284 if (outputType == MIRType_Value) {
285 // XXX: Possible optimization: decrease resultTypeSet to only include
286 // the inputType. This will remove the need for boxing.
287 JS_ASSERT(inputType != MIRType_Value);
288 ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
289 return true;
290 }
291
292 // Input is a value. Unbox the input to the requested type.
293 if (inputType == MIRType_Value) {
294 JS_ASSERT(outputType != MIRType_Value);
295
296 // We can't unbox a value to null/undefined/lazyargs. So keep output
297 // also a value.
298 if (IsNullOrUndefined(outputType) || outputType == MIRType_MagicOptimizedArguments) {
299 JS_ASSERT(ins->defUseCount() == 0);
300 ins->setResultType(MIRType_Value);
301 return true;
302 }
303
304 MUnbox *unbox = MUnbox::New(alloc, ins->getOperand(0), outputType, MUnbox::TypeBarrier);
305 ins->block()->insertBefore(ins, unbox);
306 ins->replaceOperand(0, unbox);
307 return true;
308 }
309
310 // In the remaining cases we will alway bail. OutputType doesn't matter.
311 // Take inputType so we can use redefine during lowering.
312 JS_ASSERT(ins->alwaysBails());
313 ins->setResultType(inputType);
314
315 return true;
316 }
317
318 bool
319 TestPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
320 {
321 MDefinition *op = ins->getOperand(0);
322 switch (op->type()) {
323 case MIRType_Value:
324 case MIRType_Null:
325 case MIRType_Undefined:
326 case MIRType_Boolean:
327 case MIRType_Int32:
328 case MIRType_Double:
329 case MIRType_Float32:
330 case MIRType_Object:
331 break;
332
333 case MIRType_String:
334 {
335 MStringLength *length = MStringLength::New(alloc, op);
336 ins->block()->insertBefore(ins, length);
337 ins->replaceOperand(0, length);
338 break;
339 }
340
341 default:
342 ins->replaceOperand(0, boxAt(alloc, ins, op));
343 break;
344 }
345 return true;
346 }
347
348 bool
349 BitwisePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
350 {
351 if (specialization_ == MIRType_None)
352 return BoxInputsPolicy::adjustInputs(alloc, ins);
353
354 JS_ASSERT(ins->type() == specialization_);
355 JS_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Double);
356
357 // This policy works for both unary and binary bitwise operations.
358 for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
359 MDefinition *in = ins->getOperand(i);
360 if (in->type() == MIRType_Int32)
361 continue;
362
363 // See BinaryArithPolicy::adjustInputs for an explanation of the following
364 if (in->type() == MIRType_Object || in->type() == MIRType_String)
365 in = boxAt(alloc, ins, in);
366
367 MInstruction *replace = MTruncateToInt32::New(alloc, in);
368 ins->block()->insertBefore(ins, replace);
369 ins->replaceOperand(i, replace);
370 }
371
372 return true;
373 }
374
375 bool
376 PowPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
377 {
378 JS_ASSERT(specialization_ == MIRType_Int32 || specialization_ == MIRType_Double);
379
380 // Input must be a double.
381 if (!DoublePolicy<0>::staticAdjustInputs(alloc, ins))
382 return false;
383
384 // Power may be an int32 or a double. Integers receive a faster path.
385 if (specialization_ == MIRType_Double)
386 return DoublePolicy<1>::staticAdjustInputs(alloc, ins);
387 return IntPolicy<1>::staticAdjustInputs(alloc, ins);
388 }
389
390 template <unsigned Op>
391 bool
392 StringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
393 {
394 MDefinition *in = ins->getOperand(Op);
395 if (in->type() == MIRType_String)
396 return true;
397
398 if (in->type() != MIRType_Value)
399 in = boxAt(alloc, ins, in);
400
401 MUnbox *replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible);
402 ins->block()->insertBefore(ins, replace);
403 ins->replaceOperand(Op, replace);
404 return true;
405 }
406
407 template bool StringPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
408 template bool StringPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
409 template bool StringPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
410
411 template <unsigned Op>
412 bool
413 ConvertToStringPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
414 {
415 MDefinition *in = ins->getOperand(Op);
416 if (in->type() == MIRType_String)
417 return true;
418
419 MInstruction *replace;
420 if (in->mightBeType(MIRType_Object)) {
421 if (in->type() != MIRType_Value)
422 in = boxAt(alloc, ins, in);
423
424 replace = MUnbox::New(alloc, in, MIRType_String, MUnbox::Fallible);
425 } else {
426 // TODO remove these two lines once 966957 has landed
427 EnsureOperandNotFloat32(alloc, ins, Op);
428 in = ins->getOperand(Op);
429 replace = MToString::New(alloc, in);
430 }
431
432 ins->block()->insertBefore(ins, replace);
433 ins->replaceOperand(Op, replace);
434 return true;
435 }
436
437 template bool ConvertToStringPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
438 template bool ConvertToStringPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
439
440 template <unsigned Op>
441 bool
442 IntPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
443 {
444 MDefinition *in = def->getOperand(Op);
445 if (in->type() == MIRType_Int32)
446 return true;
447
448 if (in->type() != MIRType_Value)
449 in = boxAt(alloc, def, in);
450
451 MUnbox *replace = MUnbox::New(alloc, in, MIRType_Int32, MUnbox::Fallible);
452 def->block()->insertBefore(def, replace);
453 def->replaceOperand(Op, replace);
454 return true;
455 }
456
457 template bool IntPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
458 template bool IntPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
459 template bool IntPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
460
461 template <unsigned Op>
462 bool
463 ConvertToInt32Policy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
464 {
465 MDefinition *in = def->getOperand(Op);
466 if (in->type() == MIRType_Int32)
467 return true;
468
469 MToInt32 *replace = MToInt32::New(alloc, in);
470 def->block()->insertBefore(def, replace);
471 def->replaceOperand(Op, replace);
472 return true;
473 }
474
475 template bool ConvertToInt32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
476
477 template <unsigned Op>
478 bool
479 DoublePolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
480 {
481 MDefinition *in = def->getOperand(Op);
482 if (in->type() == MIRType_Double)
483 return true;
484
485 // Force a bailout. Objects may be effectful; strings are currently unhandled.
486 if (in->type() == MIRType_Object || in->type() == MIRType_String) {
487 MBox *box = MBox::New(alloc, in);
488 def->block()->insertBefore(def, box);
489
490 MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible);
491 def->block()->insertBefore(def, unbox);
492 def->replaceOperand(Op, unbox);
493 return true;
494 }
495
496 MToDouble *replace = MToDouble::New(alloc, in);
497 def->block()->insertBefore(def, replace);
498 def->replaceOperand(Op, replace);
499 return true;
500 }
501
502 template bool DoublePolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
503 template bool DoublePolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
504
505 template <unsigned Op>
506 bool
507 Float32Policy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
508 {
509 MDefinition *in = def->getOperand(Op);
510 if (in->type() == MIRType_Float32)
511 return true;
512
513 // Force a bailout. Objects may be effectful; strings are currently unhandled.
514 if (in->type() == MIRType_Object || in->type() == MIRType_String) {
515 MToDouble *toDouble = MToDouble::New(alloc, in);
516 def->block()->insertBefore(def, toDouble);
517
518 MBox *box = MBox::New(alloc, toDouble);
519 def->block()->insertBefore(def, box);
520
521 MUnbox *unbox = MUnbox::New(alloc, box, MIRType_Double, MUnbox::Fallible);
522 def->block()->insertBefore(def, unbox);
523
524 MToFloat32 *toFloat32 = MToFloat32::New(alloc, unbox);
525 def->block()->insertBefore(def, toFloat32);
526
527 def->replaceOperand(Op, unbox);
528
529 return true;
530 }
531
532 MToFloat32 *replace = MToFloat32::New(alloc, in);
533 def->block()->insertBefore(def, replace);
534 def->replaceOperand(Op, replace);
535 return true;
536 }
537
538 template bool Float32Policy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
539 template bool Float32Policy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
540 template bool Float32Policy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
541
542 template <unsigned Op>
543 bool
544 NoFloatPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def)
545 {
546 EnsureOperandNotFloat32(alloc, def, Op);
547 return true;
548 }
549
550 template bool NoFloatPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
551 template bool NoFloatPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
552 template bool NoFloatPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
553 template bool NoFloatPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *def);
554
555 template <unsigned Op>
556 bool
557 BoxPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
558 {
559 MDefinition *in = ins->getOperand(Op);
560 if (in->type() == MIRType_Value)
561 return true;
562
563 ins->replaceOperand(Op, boxAt(alloc, ins, in));
564 return true;
565 }
566
567 template bool BoxPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
568 template bool BoxPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
569 template bool BoxPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
570
571 template <unsigned Op, MIRType Type>
572 bool
573 BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
574 {
575 MDefinition *in = ins->getOperand(Op);
576 if (in->type() == Type)
577 return true;
578 return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
579 }
580
581 template bool BoxExceptPolicy<0, MIRType_String>::staticAdjustInputs(TempAllocator &alloc,
582 MInstruction *ins);
583 template bool BoxExceptPolicy<1, MIRType_String>::staticAdjustInputs(TempAllocator &alloc,
584 MInstruction *ins);
585 template bool BoxExceptPolicy<2, MIRType_String>::staticAdjustInputs(TempAllocator &alloc,
586 MInstruction *ins);
587
588 bool
589 ToDoublePolicy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
590 {
591 MDefinition *in = ins->getOperand(0);
592 if (in->type() != MIRType_Object && in->type() != MIRType_String)
593 return true;
594
595 in = boxAt(alloc, ins, in);
596 ins->replaceOperand(0, in);
597 return true;
598 }
599
600 bool
601 ToInt32Policy::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
602 {
603 JS_ASSERT(ins->isToInt32());
604
605 MDefinition *in = ins->getOperand(0);
606 switch (in->type()) {
607 case MIRType_Object:
608 case MIRType_String:
609 case MIRType_Undefined:
610 // Objects might be effectful. Undefined coerces to NaN, not int32.
611 in = boxAt(alloc, ins, in);
612 ins->replaceOperand(0, in);
613 break;
614 default:
615 break;
616 }
617
618 return true;
619 }
620
621 template <unsigned Op>
622 bool
623 ObjectPolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
624 {
625 MDefinition *in = ins->getOperand(Op);
626 if (in->type() == MIRType_Object || in->type() == MIRType_Slots ||
627 in->type() == MIRType_Elements)
628 {
629 return true;
630 }
631
632 if (in->type() != MIRType_Value)
633 in = boxAt(alloc, ins, in);
634
635 MUnbox *replace = MUnbox::New(alloc, in, MIRType_Object, MUnbox::Fallible);
636 ins->block()->insertBefore(ins, replace);
637 ins->replaceOperand(Op, replace);
638 return true;
639 }
640
641 template bool ObjectPolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
642 template bool ObjectPolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
643 template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
644 template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
645
646 bool
647 CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
648 {
649 MCall *call = ins->toCall();
650
651 MDefinition *func = call->getFunction();
652 if (func->type() != MIRType_Object) {
653 // If the function is impossible to call,
654 // bail out by causing a subsequent unbox to fail.
655 if (func->type() != MIRType_Value)
656 func = boxAt(alloc, call, func);
657
658 MInstruction *unbox = MUnbox::New(alloc, func, MIRType_Object, MUnbox::Fallible);
659 call->block()->insertBefore(call, unbox);
660 call->replaceFunction(unbox);
661 }
662
663 for (uint32_t i = 0; i < call->numStackArgs(); i++)
664 EnsureOperandNotFloat32(alloc, call, MCall::IndexOfStackArg(i));
665
666 return true;
667 }
668
669 bool
670 CallSetElementPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
671 {
672 // The first operand should be an object.
673 SingleObjectPolicy::adjustInputs(alloc, ins);
674
675 // Box the index and value operands.
676 for (size_t i = 1, e = ins->numOperands(); i < e; i++) {
677 MDefinition *in = ins->getOperand(i);
678 if (in->type() == MIRType_Value)
679 continue;
680 ins->replaceOperand(i, boxAt(alloc, ins, in));
681 }
682 return true;
683 }
684
685 bool
686 InstanceOfPolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
687 {
688 // Box first operand if it isn't object
689 if (def->getOperand(0)->type() != MIRType_Object)
690 BoxPolicy<0>::staticAdjustInputs(alloc, def);
691
692 return true;
693 }
694
695 bool
696 StoreTypedArrayPolicy::adjustValueInput(TempAllocator &alloc, MInstruction *ins, int arrayType,
697 MDefinition *value, int valueOperand)
698 {
699 MDefinition *curValue = value;
700 // First, ensure the value is int32, boolean, double or Value.
701 // The conversion is based on TypedArrayObjectTemplate::setElementTail.
702 switch (value->type()) {
703 case MIRType_Int32:
704 case MIRType_Double:
705 case MIRType_Float32:
706 case MIRType_Boolean:
707 case MIRType_Value:
708 break;
709 case MIRType_Null:
710 value->setImplicitlyUsedUnchecked();
711 value = MConstant::New(alloc, Int32Value(0));
712 ins->block()->insertBefore(ins, value->toInstruction());
713 break;
714 case MIRType_Undefined:
715 value->setImplicitlyUsedUnchecked();
716 value = MConstant::New(alloc, DoubleNaNValue());
717 ins->block()->insertBefore(ins, value->toInstruction());
718 break;
719 case MIRType_Object:
720 case MIRType_String:
721 value = boxAt(alloc, ins, value);
722 break;
723 default:
724 MOZ_ASSUME_UNREACHABLE("Unexpected type");
725 }
726
727 if (value != curValue) {
728 ins->replaceOperand(valueOperand, value);
729 curValue = value;
730 }
731
732 JS_ASSERT(value->type() == MIRType_Int32 ||
733 value->type() == MIRType_Boolean ||
734 value->type() == MIRType_Double ||
735 value->type() == MIRType_Float32 ||
736 value->type() == MIRType_Value);
737
738 switch (arrayType) {
739 case ScalarTypeDescr::TYPE_INT8:
740 case ScalarTypeDescr::TYPE_UINT8:
741 case ScalarTypeDescr::TYPE_INT16:
742 case ScalarTypeDescr::TYPE_UINT16:
743 case ScalarTypeDescr::TYPE_INT32:
744 case ScalarTypeDescr::TYPE_UINT32:
745 if (value->type() != MIRType_Int32) {
746 value = MTruncateToInt32::New(alloc, value);
747 ins->block()->insertBefore(ins, value->toInstruction());
748 }
749 break;
750 case ScalarTypeDescr::TYPE_UINT8_CLAMPED:
751 // IonBuilder should have inserted ClampToUint8.
752 JS_ASSERT(value->type() == MIRType_Int32);
753 break;
754 case ScalarTypeDescr::TYPE_FLOAT32:
755 if (LIRGenerator::allowFloat32Optimizations()) {
756 if (value->type() != MIRType_Float32) {
757 value = MToFloat32::New(alloc, value);
758 ins->block()->insertBefore(ins, value->toInstruction());
759 }
760 break;
761 }
762 // Fallthrough: if the LIRGenerator cannot directly store Float32, it will expect the
763 // stored value to be a double.
764 case ScalarTypeDescr::TYPE_FLOAT64:
765 if (value->type() != MIRType_Double) {
766 value = MToDouble::New(alloc, value);
767 ins->block()->insertBefore(ins, value->toInstruction());
768 }
769 break;
770 default:
771 MOZ_ASSUME_UNREACHABLE("Invalid array type");
772 }
773
774 if (value != curValue) {
775 ins->replaceOperand(valueOperand, value);
776 curValue = value;
777 }
778 return true;
779 }
780
781 bool
782 StoreTypedArrayPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
783 {
784 MStoreTypedArrayElement *store = ins->toStoreTypedArrayElement();
785 JS_ASSERT(store->elements()->type() == MIRType_Elements);
786 JS_ASSERT(store->index()->type() == MIRType_Int32);
787
788 return adjustValueInput(alloc, ins, store->arrayType(), store->value(), 2);
789 }
790
791 bool
792 StoreTypedArrayHolePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
793 {
794 MStoreTypedArrayElementHole *store = ins->toStoreTypedArrayElementHole();
795 JS_ASSERT(store->elements()->type() == MIRType_Elements);
796 JS_ASSERT(store->index()->type() == MIRType_Int32);
797 JS_ASSERT(store->length()->type() == MIRType_Int32);
798
799 return adjustValueInput(alloc, ins, store->arrayType(), store->value(), 3);
800 }
801
802 bool
803 StoreTypedArrayElementStaticPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
804 {
805 MStoreTypedArrayElementStatic *store = ins->toStoreTypedArrayElementStatic();
806
807 return ConvertToInt32Policy<0>::staticAdjustInputs(alloc, ins) &&
808 adjustValueInput(alloc, ins, store->viewType(), store->value(), 1);
809 }
810
811 bool
812 ClampPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
813 {
814 MDefinition *in = ins->toClampToUint8()->input();
815
816 switch (in->type()) {
817 case MIRType_Int32:
818 case MIRType_Double:
819 case MIRType_Value:
820 break;
821 default:
822 ins->replaceOperand(0, boxAt(alloc, ins, in));
823 break;
824 }
825
826 return true;
827 }
828
829 bool
830 FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
831 {
832 MOZ_ASSERT(ins->numOperands() == 1);
833
834 // Do nothing if already same type.
835 if (ins->type() == ins->getOperand(0)->type())
836 return true;
837
838 // Box input if ouput type is MIRType_Value
839 if (ins->type() == MIRType_Value) {
840 ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
841 return true;
842 }
843
844 // For simplicity just mark output type as MIRType_Value if input type
845 // is MIRType_Value. It should be possible to unbox, but we need to
846 // add extra code for Undefined/Null.
847 if (ins->getOperand(0)->type() == MIRType_Value) {
848 ins->setResultType(MIRType_Value);
849 return true;
850 }
851
852 // In all other cases we will definitely bail, since types don't
853 // correspond. Just box and mark output as MIRType_Value.
854 ins->replaceOperand(0, boxAt(alloc, ins, ins->getOperand(0)));
855 ins->setResultType(MIRType_Value);
856
857 return true;
858 }

mercurial