js/src/jit/MIR.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:794429ec6faf
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/MIR.h"
8
9 #include "mozilla/FloatingPoint.h"
10
11 #include <ctype.h>
12
13 #include "jslibmath.h"
14 #include "jsstr.h"
15
16 #include "jit/BaselineInspector.h"
17 #include "jit/IonBuilder.h"
18 #include "jit/IonSpewer.h"
19 #include "jit/MIRGraph.h"
20 #include "jit/RangeAnalysis.h"
21
22 #include "jsatominlines.h"
23 #include "jsinferinlines.h"
24 #include "jsobjinlines.h"
25
26 using namespace js;
27 using namespace js::jit;
28
29 using mozilla::NumbersAreIdentical;
30 using mozilla::IsFloat32Representable;
31 using mozilla::Maybe;
32
33 template<size_t Op> static void
34 ConvertDefinitionToDouble(TempAllocator &alloc, MDefinition *def, MInstruction *consumer)
35 {
36 MInstruction *replace = MToDouble::New(alloc, def);
37 consumer->replaceOperand(Op, replace);
38 consumer->block()->insertBefore(consumer, replace);
39 }
40
41 static bool
42 CheckUsesAreFloat32Consumers(MInstruction *ins)
43 {
44 bool allConsumerUses = true;
45 for (MUseDefIterator use(ins); allConsumerUses && use; use++)
46 allConsumerUses &= use.def()->canConsumeFloat32(use.use());
47 return allConsumerUses;
48 }
49
50 void
51 MDefinition::PrintOpcodeName(FILE *fp, MDefinition::Opcode op)
52 {
53 static const char * const names[] =
54 {
55 #define NAME(x) #x,
56 MIR_OPCODE_LIST(NAME)
57 #undef NAME
58 };
59 const char *name = names[op];
60 size_t len = strlen(name);
61 for (size_t i = 0; i < len; i++)
62 fprintf(fp, "%c", tolower(name[i]));
63 }
64
65 static inline bool
66 EqualValues(bool useGVN, MDefinition *left, MDefinition *right)
67 {
68 if (useGVN)
69 return left->valueNumber() == right->valueNumber();
70
71 return left == right;
72 }
73
74 static MConstant *
75 EvaluateConstantOperands(TempAllocator &alloc, MBinaryInstruction *ins, bool *ptypeChange = nullptr)
76 {
77 MDefinition *left = ins->getOperand(0);
78 MDefinition *right = ins->getOperand(1);
79
80 if (!left->isConstant() || !right->isConstant())
81 return nullptr;
82
83 Value lhs = left->toConstant()->value();
84 Value rhs = right->toConstant()->value();
85 Value ret = UndefinedValue();
86
87 switch (ins->op()) {
88 case MDefinition::Op_BitAnd:
89 ret = Int32Value(lhs.toInt32() & rhs.toInt32());
90 break;
91 case MDefinition::Op_BitOr:
92 ret = Int32Value(lhs.toInt32() | rhs.toInt32());
93 break;
94 case MDefinition::Op_BitXor:
95 ret = Int32Value(lhs.toInt32() ^ rhs.toInt32());
96 break;
97 case MDefinition::Op_Lsh:
98 ret = Int32Value(uint32_t(lhs.toInt32()) << (rhs.toInt32() & 0x1F));
99 break;
100 case MDefinition::Op_Rsh:
101 ret = Int32Value(lhs.toInt32() >> (rhs.toInt32() & 0x1F));
102 break;
103 case MDefinition::Op_Ursh:
104 ret.setNumber(uint32_t(lhs.toInt32()) >> (rhs.toInt32() & 0x1F));
105 break;
106 case MDefinition::Op_Add:
107 ret.setNumber(lhs.toNumber() + rhs.toNumber());
108 break;
109 case MDefinition::Op_Sub:
110 ret.setNumber(lhs.toNumber() - rhs.toNumber());
111 break;
112 case MDefinition::Op_Mul:
113 ret.setNumber(lhs.toNumber() * rhs.toNumber());
114 break;
115 case MDefinition::Op_Div:
116 ret.setNumber(NumberDiv(lhs.toNumber(), rhs.toNumber()));
117 break;
118 case MDefinition::Op_Mod:
119 ret.setNumber(NumberMod(lhs.toNumber(), rhs.toNumber()));
120 break;
121 default:
122 MOZ_ASSUME_UNREACHABLE("NYI");
123 }
124
125 // setNumber eagerly transforms a number to int32.
126 // Transform back to double, if the output type is double.
127 if (ins->type() == MIRType_Double && ret.isInt32())
128 ret.setDouble(ret.toNumber());
129
130 if (ins->type() != MIRTypeFromValue(ret)) {
131 if (ptypeChange)
132 *ptypeChange = true;
133 return nullptr;
134 }
135
136 return MConstant::New(alloc, ret);
137 }
138
139 void
140 MDefinition::printName(FILE *fp) const
141 {
142 PrintOpcodeName(fp, op());
143 fprintf(fp, "%u", id());
144
145 if (valueNumber() != 0)
146 fprintf(fp, "-vn%u", valueNumber());
147 }
148
149 HashNumber
150 MDefinition::valueHash() const
151 {
152 HashNumber out = op();
153 for (size_t i = 0, e = numOperands(); i < e; i++) {
154 uint32_t valueNumber = getOperand(i)->valueNumber();
155 out = valueNumber + (out << 6) + (out << 16) - out;
156 }
157 return out;
158 }
159
160 bool
161 MDefinition::congruentIfOperandsEqual(const MDefinition *ins) const
162 {
163 if (op() != ins->op())
164 return false;
165
166 if (type() != ins->type())
167 return false;
168
169 if (isEffectful() || ins->isEffectful())
170 return false;
171
172 if (numOperands() != ins->numOperands())
173 return false;
174
175 for (size_t i = 0, e = numOperands(); i < e; i++) {
176 if (getOperand(i)->valueNumber() != ins->getOperand(i)->valueNumber())
177 return false;
178 }
179
180 return true;
181 }
182
183 MDefinition *
184 MDefinition::foldsTo(TempAllocator &alloc, bool useValueNumbers)
185 {
186 // In the default case, there are no constants to fold.
187 return this;
188 }
189
190 void
191 MDefinition::analyzeEdgeCasesForward()
192 {
193 }
194
195 void
196 MDefinition::analyzeEdgeCasesBackward()
197 {
198 }
199
200 static bool
201 MaybeEmulatesUndefined(MDefinition *op)
202 {
203 if (!op->mightBeType(MIRType_Object))
204 return false;
205
206 types::TemporaryTypeSet *types = op->resultTypeSet();
207 if (!types)
208 return true;
209
210 return types->maybeEmulatesUndefined();
211 }
212
213 static bool
214 MaybeCallable(MDefinition *op)
215 {
216 if (!op->mightBeType(MIRType_Object))
217 return false;
218
219 types::TemporaryTypeSet *types = op->resultTypeSet();
220 if (!types)
221 return true;
222
223 return types->maybeCallable();
224 }
225
226 MTest *
227 MTest::New(TempAllocator &alloc, MDefinition *ins, MBasicBlock *ifTrue, MBasicBlock *ifFalse)
228 {
229 return new(alloc) MTest(ins, ifTrue, ifFalse);
230 }
231
232 void
233 MTest::infer()
234 {
235 JS_ASSERT(operandMightEmulateUndefined());
236
237 if (!MaybeEmulatesUndefined(getOperand(0)))
238 markOperandCantEmulateUndefined();
239 }
240
241 MDefinition *
242 MTest::foldsTo(TempAllocator &alloc, bool useValueNumbers)
243 {
244 MDefinition *op = getOperand(0);
245
246 if (op->isNot())
247 return MTest::New(alloc, op->toNot()->operand(), ifFalse(), ifTrue());
248
249 return this;
250 }
251
252 void
253 MTest::filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
254 bool *filtersNull)
255 {
256 MDefinition *ins = getOperand(0);
257 if (ins->isCompare()) {
258 ins->toCompare()->filtersUndefinedOrNull(trueBranch, subject, filtersUndefined, filtersNull);
259 return;
260 }
261
262 if (!trueBranch && ins->isNot()) {
263 *subject = ins->getOperand(0);
264 *filtersUndefined = *filtersNull = true;
265 return;
266 }
267
268 if (trueBranch) {
269 *subject = ins;
270 *filtersUndefined = *filtersNull = true;
271 return;
272 }
273
274 *filtersUndefined = *filtersNull = false;
275 *subject = nullptr;
276 }
277
278 void
279 MDefinition::printOpcode(FILE *fp) const
280 {
281 PrintOpcodeName(fp, op());
282 for (size_t j = 0, e = numOperands(); j < e; j++) {
283 fprintf(fp, " ");
284 getOperand(j)->printName(fp);
285 }
286 }
287
288 void
289 MDefinition::dump(FILE *fp) const
290 {
291 printName(fp);
292 fprintf(fp, " = ");
293 printOpcode(fp);
294 fprintf(fp, "\n");
295 }
296
297 void
298 MDefinition::dump() const
299 {
300 dump(stderr);
301 }
302
303 size_t
304 MDefinition::useCount() const
305 {
306 size_t count = 0;
307 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++)
308 count++;
309 return count;
310 }
311
312 size_t
313 MDefinition::defUseCount() const
314 {
315 size_t count = 0;
316 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++)
317 if ((*i)->consumer()->isDefinition())
318 count++;
319 return count;
320 }
321
322 bool
323 MDefinition::hasOneUse() const
324 {
325 MUseIterator i(uses_.begin());
326 if (i == uses_.end())
327 return false;
328 i++;
329 return i == uses_.end();
330 }
331
332 bool
333 MDefinition::hasOneDefUse() const
334 {
335 bool hasOneDefUse = false;
336 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
337 if (!(*i)->consumer()->isDefinition())
338 continue;
339
340 // We already have a definition use. So 1+
341 if (hasOneDefUse)
342 return false;
343
344 // We saw one definition. Loop to test if there is another.
345 hasOneDefUse = true;
346 }
347
348 return hasOneDefUse;
349 }
350
351 bool
352 MDefinition::hasDefUses() const
353 {
354 for (MUseIterator i(uses_.begin()); i != uses_.end(); i++) {
355 if ((*i)->consumer()->isDefinition())
356 return true;
357 }
358
359 return false;
360 }
361
362 MUseIterator
363 MDefinition::removeUse(MUseIterator use)
364 {
365 return uses_.removeAt(use);
366 }
367
368 MUseIterator
369 MNode::replaceOperand(MUseIterator use, MDefinition *def)
370 {
371 JS_ASSERT(def != nullptr);
372 uint32_t index = use->index();
373 MDefinition *prev = use->producer();
374
375 JS_ASSERT(use->index() < numOperands());
376 JS_ASSERT(use->producer() == getOperand(index));
377 JS_ASSERT(use->consumer() == this);
378
379 if (prev == def)
380 return use;
381
382 MUseIterator result(prev->removeUse(use));
383 setOperand(index, def);
384 return result;
385 }
386
387 void
388 MNode::replaceOperand(size_t index, MDefinition *def)
389 {
390 JS_ASSERT(def != nullptr);
391 MUse *use = getUseFor(index);
392 MDefinition *prev = use->producer();
393
394 JS_ASSERT(use->index() == index);
395 JS_ASSERT(use->index() < numOperands());
396 JS_ASSERT(use->producer() == getOperand(index));
397 JS_ASSERT(use->consumer() == this);
398
399 if (prev == def)
400 return;
401
402 prev->removeUse(use);
403 setOperand(index, def);
404 }
405
406 void
407 MNode::discardOperand(size_t index)
408 {
409 MUse *use = getUseFor(index);
410
411 JS_ASSERT(use->index() == index);
412 JS_ASSERT(use->producer() == getOperand(index));
413 JS_ASSERT(use->consumer() == this);
414
415 use->producer()->removeUse(use);
416
417 #ifdef DEBUG
418 // Causes any producer/consumer lookups to trip asserts.
419 use->set(nullptr, nullptr, index);
420 #endif
421 }
422
423 void
424 MDefinition::replaceAllUsesWith(MDefinition *dom)
425 {
426 JS_ASSERT(dom != nullptr);
427 if (dom == this)
428 return;
429
430 for (size_t i = 0, e = numOperands(); i < e; i++)
431 getOperand(i)->setUseRemovedUnchecked();
432
433 for (MUseIterator i(usesBegin()); i != usesEnd(); ) {
434 JS_ASSERT(i->producer() == this);
435 i = i->consumer()->replaceOperand(i, dom);
436 }
437 }
438
439 bool
440 MDefinition::emptyResultTypeSet() const
441 {
442 return resultTypeSet() && resultTypeSet()->empty();
443 }
444
445 MConstant *
446 MConstant::New(TempAllocator &alloc, const Value &v, types::CompilerConstraintList *constraints)
447 {
448 return new(alloc) MConstant(v, constraints);
449 }
450
451 MConstant *
452 MConstant::NewAsmJS(TempAllocator &alloc, const Value &v, MIRType type)
453 {
454 MConstant *constant = new(alloc) MConstant(v, nullptr);
455 constant->setResultType(type);
456 return constant;
457 }
458
459 types::TemporaryTypeSet *
460 jit::MakeSingletonTypeSet(types::CompilerConstraintList *constraints, JSObject *obj)
461 {
462 // Invalidate when this object's TypeObject gets unknown properties. This
463 // happens for instance when we mutate an object's __proto__, in this case
464 // we want to invalidate and mark this TypeSet as containing AnyObject
465 // (because mutating __proto__ will change an object's TypeObject).
466 JS_ASSERT(constraints);
467 types::TypeObjectKey *objType = types::TypeObjectKey::get(obj);
468 objType->hasFlags(constraints, types::OBJECT_FLAG_UNKNOWN_PROPERTIES);
469
470 return GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(types::Type::ObjectType(obj));
471 }
472
473 MConstant::MConstant(const js::Value &vp, types::CompilerConstraintList *constraints)
474 : value_(vp)
475 {
476 setResultType(MIRTypeFromValue(vp));
477 if (vp.isObject()) {
478 // Create a singleton type set for the object. This isn't necessary for
479 // other types as the result type encodes all needed information.
480 setResultTypeSet(MakeSingletonTypeSet(constraints, &vp.toObject()));
481 }
482
483 setMovable();
484 }
485
486 HashNumber
487 MConstant::valueHash() const
488 {
489 // This disregards some state, since values are 64 bits. But for a hash,
490 // it's completely acceptable.
491 return (HashNumber)JSVAL_TO_IMPL(value_).asBits;
492 }
493 bool
494 MConstant::congruentTo(const MDefinition *ins) const
495 {
496 if (!ins->isConstant())
497 return false;
498 return ins->toConstant()->value() == value();
499 }
500
501 void
502 MConstant::printOpcode(FILE *fp) const
503 {
504 PrintOpcodeName(fp, op());
505 fprintf(fp, " ");
506 switch (type()) {
507 case MIRType_Undefined:
508 fprintf(fp, "undefined");
509 break;
510 case MIRType_Null:
511 fprintf(fp, "null");
512 break;
513 case MIRType_Boolean:
514 fprintf(fp, value().toBoolean() ? "true" : "false");
515 break;
516 case MIRType_Int32:
517 fprintf(fp, "0x%x", value().toInt32());
518 break;
519 case MIRType_Double:
520 fprintf(fp, "%f", value().toDouble());
521 break;
522 case MIRType_Float32:
523 {
524 float val = value().toDouble();
525 fprintf(fp, "%f", val);
526 break;
527 }
528 case MIRType_Object:
529 if (value().toObject().is<JSFunction>()) {
530 JSFunction *fun = &value().toObject().as<JSFunction>();
531 if (fun->displayAtom()) {
532 fputs("function ", fp);
533 FileEscapedString(fp, fun->displayAtom(), 0);
534 } else {
535 fputs("unnamed function", fp);
536 }
537 if (fun->hasScript()) {
538 JSScript *script = fun->nonLazyScript();
539 fprintf(fp, " (%s:%d)",
540 script->filename() ? script->filename() : "", (int) script->lineno());
541 }
542 fprintf(fp, " at %p", (void *) fun);
543 break;
544 }
545 fprintf(fp, "object %p (%s)", (void *)&value().toObject(),
546 value().toObject().getClass()->name);
547 break;
548 case MIRType_String:
549 fprintf(fp, "string %p", (void *)value().toString());
550 break;
551 case MIRType_MagicOptimizedArguments:
552 fprintf(fp, "magic lazyargs");
553 break;
554 case MIRType_MagicHole:
555 fprintf(fp, "magic hole");
556 break;
557 case MIRType_MagicIsConstructing:
558 fprintf(fp, "magic is-constructing");
559 break;
560 case MIRType_MagicOptimizedOut:
561 fprintf(fp, "magic optimized-out");
562 break;
563 default:
564 MOZ_ASSUME_UNREACHABLE("unexpected type");
565 }
566 }
567
568 bool
569 MConstant::canProduceFloat32() const
570 {
571 if (!IsNumberType(type()))
572 return false;
573
574 if (type() == MIRType_Int32)
575 return IsFloat32Representable(static_cast<double>(value_.toInt32()));
576 if (type() == MIRType_Double)
577 return IsFloat32Representable(value_.toDouble());
578 return true;
579 }
580
581 MCloneLiteral *
582 MCloneLiteral::New(TempAllocator &alloc, MDefinition *obj)
583 {
584 return new(alloc) MCloneLiteral(obj);
585 }
586
587 void
588 MControlInstruction::printOpcode(FILE *fp) const
589 {
590 MDefinition::printOpcode(fp);
591 for (size_t j = 0; j < numSuccessors(); j++)
592 fprintf(fp, " block%d", getSuccessor(j)->id());
593 }
594
595 void
596 MCompare::printOpcode(FILE *fp) const
597 {
598 MDefinition::printOpcode(fp);
599 fprintf(fp, " %s", js_CodeName[jsop()]);
600 }
601
602 void
603 MConstantElements::printOpcode(FILE *fp) const
604 {
605 PrintOpcodeName(fp, op());
606 fprintf(fp, " %p", value());
607 }
608
609 void
610 MLoadTypedArrayElement::printOpcode(FILE *fp) const
611 {
612 MDefinition::printOpcode(fp);
613 fprintf(fp, " %s", ScalarTypeDescr::typeName(arrayType()));
614 }
615
616 void
617 MAssertRange::printOpcode(FILE *fp) const
618 {
619 MDefinition::printOpcode(fp);
620 Sprinter sp(GetIonContext()->cx);
621 sp.init();
622 assertedRange()->print(sp);
623 fprintf(fp, " %s", sp.string());
624 }
625
626 const char *
627 MMathFunction::FunctionName(Function function)
628 {
629 switch (function) {
630 case Log: return "Log";
631 case Sin: return "Sin";
632 case Cos: return "Cos";
633 case Exp: return "Exp";
634 case Tan: return "Tan";
635 case ACos: return "ACos";
636 case ASin: return "ASin";
637 case ATan: return "ATan";
638 case Log10: return "Log10";
639 case Log2: return "Log2";
640 case Log1P: return "Log1P";
641 case ExpM1: return "ExpM1";
642 case CosH: return "CosH";
643 case SinH: return "SinH";
644 case TanH: return "TanH";
645 case ACosH: return "ACosH";
646 case ASinH: return "ASinH";
647 case ATanH: return "ATanH";
648 case Sign: return "Sign";
649 case Trunc: return "Trunc";
650 case Cbrt: return "Cbrt";
651 case Floor: return "Floor";
652 case Ceil: return "Ceil";
653 case Round: return "Round";
654 default:
655 MOZ_ASSUME_UNREACHABLE("Unknown math function");
656 }
657 }
658
659 void
660 MMathFunction::printOpcode(FILE *fp) const
661 {
662 MDefinition::printOpcode(fp);
663 fprintf(fp, " %s", FunctionName(function()));
664 }
665
666 MParameter *
667 MParameter::New(TempAllocator &alloc, int32_t index, types::TemporaryTypeSet *types)
668 {
669 return new(alloc) MParameter(index, types);
670 }
671
672 void
673 MParameter::printOpcode(FILE *fp) const
674 {
675 PrintOpcodeName(fp, op());
676 fprintf(fp, " %d", index());
677 }
678
679 HashNumber
680 MParameter::valueHash() const
681 {
682 return index_; // Why not?
683 }
684
685 bool
686 MParameter::congruentTo(const MDefinition *ins) const
687 {
688 if (!ins->isParameter())
689 return false;
690
691 return ins->toParameter()->index() == index_;
692 }
693
694 MCall *
695 MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc, size_t numActualArgs,
696 bool construct, bool isDOMCall)
697 {
698 JS_ASSERT(maxArgc >= numActualArgs);
699 MCall *ins;
700 if (isDOMCall) {
701 JS_ASSERT(!construct);
702 ins = new(alloc) MCallDOMNative(target, numActualArgs);
703 } else {
704 ins = new(alloc) MCall(target, numActualArgs, construct);
705 }
706 if (!ins->init(alloc, maxArgc + NumNonArgumentOperands))
707 return nullptr;
708 return ins;
709 }
710
711 AliasSet
712 MCallDOMNative::getAliasSet() const
713 {
714 const JSJitInfo *jitInfo = getJitInfo();
715
716 JS_ASSERT(jitInfo->aliasSet() != JSJitInfo::AliasNone);
717 // If we don't know anything about the types of our arguments, we have to
718 // assume that type-coercions can have side-effects, so we need to alias
719 // everything.
720 if (jitInfo->aliasSet() != JSJitInfo::AliasDOMSets || !jitInfo->isTypedMethodJitInfo())
721 return AliasSet::Store(AliasSet::Any);
722
723 uint32_t argIndex = 0;
724 const JSTypedMethodJitInfo *methodInfo =
725 reinterpret_cast<const JSTypedMethodJitInfo*>(jitInfo);
726 for (const JSJitInfo::ArgType *argType = methodInfo->argTypes;
727 *argType != JSJitInfo::ArgTypeListEnd;
728 ++argType, ++argIndex)
729 {
730 if (argIndex >= numActualArgs()) {
731 // Passing through undefined can't have side-effects
732 continue;
733 }
734 // getArg(0) is "this", so skip it
735 MDefinition *arg = getArg(argIndex+1);
736 MIRType actualType = arg->type();
737 // The only way to reliably avoid side-effects given the informtion we
738 // have here is if we're passing in a known primitive value to an
739 // argument that expects a primitive value. XXXbz maybe we need to
740 // communicate better information. For example, a sequence argument
741 // will sort of unavoidably have side effects, while a typed array
742 // argument won't have any, but both are claimed to be
743 // JSJitInfo::Object.
744 if ((actualType == MIRType_Value || actualType == MIRType_Object) ||
745 (*argType & JSJitInfo::Object))
746 {
747 return AliasSet::Store(AliasSet::Any);
748 }
749 }
750
751 // We checked all the args, and they check out. So we only
752 // alias DOM mutations.
753 return AliasSet::Load(AliasSet::DOMProperty);
754 }
755
756 void
757 MCallDOMNative::computeMovable()
758 {
759 // We are movable if the jitinfo says we can be and if we're also not
760 // effectful. The jitinfo can't check for the latter, since it depends on
761 // the types of our arguments.
762 const JSJitInfo *jitInfo = getJitInfo();
763
764 JS_ASSERT_IF(jitInfo->isMovable,
765 jitInfo->aliasSet() != JSJitInfo::AliasEverything);
766
767 if (jitInfo->isMovable && !isEffectful())
768 setMovable();
769 }
770
771 bool
772 MCallDOMNative::congruentTo(const MDefinition *ins) const
773 {
774 if (!isMovable())
775 return false;
776
777 if (!ins->isCall())
778 return false;
779
780 const MCall *call = ins->toCall();
781
782 if (!call->isCallDOMNative())
783 return false;
784
785 if (getSingleTarget() != call->getSingleTarget())
786 return false;
787
788 if (isConstructing() != call->isConstructing())
789 return false;
790
791 if (numActualArgs() != call->numActualArgs())
792 return false;
793
794 if (needsArgCheck() != call->needsArgCheck())
795 return false;
796
797 if (!congruentIfOperandsEqual(call))
798 return false;
799
800 // The other call had better be movable at this point!
801 JS_ASSERT(call->isMovable());
802
803 return true;
804 }
805
806 const JSJitInfo *
807 MCallDOMNative::getJitInfo() const
808 {
809 JS_ASSERT(getSingleTarget() && getSingleTarget()->isNative());
810
811 const JSJitInfo *jitInfo = getSingleTarget()->jitInfo();
812 JS_ASSERT(jitInfo);
813
814 return jitInfo;
815 }
816
817 MApplyArgs *
818 MApplyArgs::New(TempAllocator &alloc, JSFunction *target, MDefinition *fun, MDefinition *argc,
819 MDefinition *self)
820 {
821 return new(alloc) MApplyArgs(target, fun, argc, self);
822 }
823
824 MDefinition*
825 MStringLength::foldsTo(TempAllocator &alloc, bool useValueNumbers)
826 {
827 if ((type() == MIRType_Int32) && (string()->isConstant())) {
828 Value value = string()->toConstant()->value();
829 JSAtom *atom = &value.toString()->asAtom();
830 return MConstant::New(alloc, Int32Value(atom->length()));
831 }
832
833 return this;
834 }
835
836 void
837 MFloor::trySpecializeFloat32(TempAllocator &alloc)
838 {
839 // No need to look at the output, as it's an integer (see IonBuilder::inlineMathFloor)
840 if (!input()->canProduceFloat32()) {
841 if (input()->type() == MIRType_Float32)
842 ConvertDefinitionToDouble<0>(alloc, input(), this);
843 return;
844 }
845
846 if (type() == MIRType_Double)
847 setResultType(MIRType_Float32);
848
849 setPolicyType(MIRType_Float32);
850 }
851
852 void
853 MRound::trySpecializeFloat32(TempAllocator &alloc)
854 {
855 // No need to look at the output, as it's an integer (unique way to have
856 // this instruction in IonBuilder::inlineMathRound)
857 JS_ASSERT(type() == MIRType_Int32);
858
859 if (!input()->canProduceFloat32()) {
860 if (input()->type() == MIRType_Float32)
861 ConvertDefinitionToDouble<0>(alloc, input(), this);
862 return;
863 }
864
865 setPolicyType(MIRType_Float32);
866 }
867
868 MCompare *
869 MCompare::New(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op)
870 {
871 return new(alloc) MCompare(left, right, op);
872 }
873
874 MCompare *
875 MCompare::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op,
876 CompareType compareType)
877 {
878 JS_ASSERT(compareType == Compare_Int32 || compareType == Compare_UInt32 ||
879 compareType == Compare_Double || compareType == Compare_Float32);
880 MCompare *comp = new(alloc) MCompare(left, right, op);
881 comp->compareType_ = compareType;
882 comp->operandMightEmulateUndefined_ = false;
883 comp->setResultType(MIRType_Int32);
884 return comp;
885 }
886
887 MTableSwitch *
888 MTableSwitch::New(TempAllocator &alloc, MDefinition *ins, int32_t low, int32_t high)
889 {
890 return new(alloc) MTableSwitch(alloc, ins, low, high);
891 }
892
893 MGoto *
894 MGoto::New(TempAllocator &alloc, MBasicBlock *target)
895 {
896 JS_ASSERT(target);
897 return new(alloc) MGoto(target);
898 }
899
900 void
901 MUnbox::printOpcode(FILE *fp) const
902 {
903 PrintOpcodeName(fp, op());
904 fprintf(fp, " ");
905 getOperand(0)->printName(fp);
906 fprintf(fp, " ");
907
908 switch (type()) {
909 case MIRType_Int32: fprintf(fp, "to Int32"); break;
910 case MIRType_Double: fprintf(fp, "to Double"); break;
911 case MIRType_Boolean: fprintf(fp, "to Boolean"); break;
912 case MIRType_String: fprintf(fp, "to String"); break;
913 case MIRType_Object: fprintf(fp, "to Object"); break;
914 default: break;
915 }
916
917 switch (mode()) {
918 case Fallible: fprintf(fp, " (fallible)"); break;
919 case Infallible: fprintf(fp, " (infallible)"); break;
920 case TypeBarrier: fprintf(fp, " (typebarrier)"); break;
921 default: break;
922 }
923 }
924
925 void
926 MTypeBarrier::printOpcode(FILE *fp) const
927 {
928 PrintOpcodeName(fp, op());
929 fprintf(fp, " ");
930 getOperand(0)->printName(fp);
931 }
932
933 void
934 MPhi::removeOperand(size_t index)
935 {
936 MUse *use = getUseFor(index);
937
938 JS_ASSERT(index < inputs_.length());
939 JS_ASSERT(inputs_.length() > 1);
940
941 JS_ASSERT(use->index() == index);
942 JS_ASSERT(use->producer() == getOperand(index));
943 JS_ASSERT(use->consumer() == this);
944
945 // Remove use from producer's use chain.
946 use->producer()->removeUse(use);
947
948 // If we have phi(..., a, b, c, d, ..., z) and we plan
949 // on removing a, then first shift downward so that we have
950 // phi(..., b, c, d, ..., z, z):
951 size_t length = inputs_.length();
952 for (size_t i = index; i < length - 1; i++) {
953 MUse *next = MPhi::getUseFor(i + 1);
954 next->producer()->removeUse(next);
955 MPhi::setOperand(i, next->producer());
956 }
957
958 // truncate the inputs_ list:
959 inputs_.shrinkBy(1);
960 }
961
962 MDefinition *
963 MPhi::foldsTo(TempAllocator &alloc, bool useValueNumbers)
964 {
965 JS_ASSERT(!inputs_.empty());
966
967 MDefinition *first = getOperand(0);
968
969 for (size_t i = 1; i < inputs_.length(); i++) {
970 // Phis need dominator information to fold based on value numbers. For
971 // simplicity, we only compare SSA names right now (bug 714727).
972 if (!EqualValues(false, getOperand(i), first))
973 return this;
974 }
975
976 return first;
977 }
978
979 bool
980 MPhi::congruentTo(const MDefinition *ins) const
981 {
982 if (!ins->isPhi())
983 return false;
984 // Since we do not know which predecessor we are merging from, we must
985 // assume that phi instructions in different blocks are not equal.
986 // (Bug 674656)
987 if (ins->block()->id() != block()->id())
988 return false;
989
990 return congruentIfOperandsEqual(ins);
991 }
992
993 bool
994 MPhi::reserveLength(size_t length)
995 {
996 // Initializes a new MPhi to have an Operand vector of at least the given
997 // capacity. This permits use of addInput() instead of addInputSlow(), the
998 // latter of which may call realloc_().
999 JS_ASSERT(numOperands() == 0);
1000 #if DEBUG
1001 capacity_ = length;
1002 #endif
1003 return inputs_.reserve(length);
1004 }
1005
1006 static inline types::TemporaryTypeSet *
1007 MakeMIRTypeSet(MIRType type)
1008 {
1009 JS_ASSERT(type != MIRType_Value);
1010 types::Type ntype = type == MIRType_Object
1011 ? types::Type::AnyObjectType()
1012 : types::Type::PrimitiveType(ValueTypeFromMIRType(type));
1013 return GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(ntype);
1014 }
1015
1016 bool
1017 jit::MergeTypes(MIRType *ptype, types::TemporaryTypeSet **ptypeSet,
1018 MIRType newType, types::TemporaryTypeSet *newTypeSet)
1019 {
1020 if (newTypeSet && newTypeSet->empty())
1021 return true;
1022 if (newType != *ptype) {
1023 if (IsNumberType(newType) && IsNumberType(*ptype)) {
1024 *ptype = MIRType_Double;
1025 } else if (*ptype != MIRType_Value) {
1026 if (!*ptypeSet) {
1027 *ptypeSet = MakeMIRTypeSet(*ptype);
1028 if (!*ptypeSet)
1029 return false;
1030 }
1031 *ptype = MIRType_Value;
1032 } else if (*ptypeSet && (*ptypeSet)->empty()) {
1033 *ptype = newType;
1034 }
1035 }
1036 if (*ptypeSet) {
1037 LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
1038 if (!newTypeSet && newType != MIRType_Value) {
1039 newTypeSet = MakeMIRTypeSet(newType);
1040 if (!newTypeSet)
1041 return false;
1042 }
1043 if (newTypeSet) {
1044 if (!newTypeSet->isSubset(*ptypeSet))
1045 *ptypeSet = types::TypeSet::unionSets(*ptypeSet, newTypeSet, alloc);
1046 } else {
1047 *ptypeSet = nullptr;
1048 }
1049 }
1050 return true;
1051 }
1052
1053 bool
1054 MPhi::specializeType()
1055 {
1056 #ifdef DEBUG
1057 JS_ASSERT(!specialized_);
1058 specialized_ = true;
1059 #endif
1060
1061 JS_ASSERT(!inputs_.empty());
1062
1063 size_t start;
1064 if (hasBackedgeType_) {
1065 // The type of this phi has already been populated with potential types
1066 // that could come in via loop backedges.
1067 start = 0;
1068 } else {
1069 setResultType(getOperand(0)->type());
1070 setResultTypeSet(getOperand(0)->resultTypeSet());
1071 start = 1;
1072 }
1073
1074 MIRType resultType = this->type();
1075 types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
1076
1077 for (size_t i = start; i < inputs_.length(); i++) {
1078 MDefinition *def = getOperand(i);
1079 if (!MergeTypes(&resultType, &resultTypeSet, def->type(), def->resultTypeSet()))
1080 return false;
1081 }
1082
1083 setResultType(resultType);
1084 setResultTypeSet(resultTypeSet);
1085 return true;
1086 }
1087
1088 bool
1089 MPhi::addBackedgeType(MIRType type, types::TemporaryTypeSet *typeSet)
1090 {
1091 JS_ASSERT(!specialized_);
1092
1093 if (hasBackedgeType_) {
1094 MIRType resultType = this->type();
1095 types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
1096
1097 if (!MergeTypes(&resultType, &resultTypeSet, type, typeSet))
1098 return false;
1099
1100 setResultType(resultType);
1101 setResultTypeSet(resultTypeSet);
1102 } else {
1103 setResultType(type);
1104 setResultTypeSet(typeSet);
1105 hasBackedgeType_ = true;
1106 }
1107 return true;
1108 }
1109
1110 bool
1111 MPhi::typeIncludes(MDefinition *def)
1112 {
1113 if (def->type() == MIRType_Int32 && this->type() == MIRType_Double)
1114 return true;
1115
1116 if (types::TemporaryTypeSet *types = def->resultTypeSet()) {
1117 if (this->resultTypeSet())
1118 return types->isSubset(this->resultTypeSet());
1119 if (this->type() == MIRType_Value || types->empty())
1120 return true;
1121 return this->type() == types->getKnownMIRType();
1122 }
1123
1124 if (def->type() == MIRType_Value) {
1125 // This phi must be able to be any value.
1126 return this->type() == MIRType_Value
1127 && (!this->resultTypeSet() || this->resultTypeSet()->unknown());
1128 }
1129
1130 return this->mightBeType(def->type());
1131 }
1132
1133 void
1134 MPhi::addInput(MDefinition *ins)
1135 {
1136 // This can only been done if the length was reserved through reserveLength,
1137 // else the slower addInputSlow need to get called.
1138 JS_ASSERT(inputs_.length() < capacity_);
1139
1140 uint32_t index = inputs_.length();
1141 inputs_.append(MUse());
1142 MPhi::setOperand(index, ins);
1143 }
1144
1145 bool
1146 MPhi::addInputSlow(MDefinition *ins, bool *ptypeChange)
1147 {
1148 // The list of inputs to an MPhi is given as a vector of MUse nodes,
1149 // each of which is in the list of the producer MDefinition.
1150 // Because appending to a vector may reallocate the vector, it is possible
1151 // that this operation may cause the producers' linked lists to reference
1152 // invalid memory. Therefore, in the event of moving reallocation, each
1153 // MUse must be removed and reinserted from/into its producer's use chain.
1154 uint32_t index = inputs_.length();
1155 bool performingRealloc = !inputs_.canAppendWithoutRealloc(1);
1156
1157 // Remove all MUses from all use lists, in case realloc_() moves.
1158 if (performingRealloc) {
1159 for (uint32_t i = 0; i < index; i++) {
1160 MUse *use = &inputs_[i];
1161 use->producer()->removeUse(use);
1162 }
1163 }
1164
1165 // Insert the new input.
1166 if (!inputs_.append(MUse()))
1167 return false;
1168
1169 MPhi::setOperand(index, ins);
1170
1171 if (ptypeChange) {
1172 MIRType resultType = this->type();
1173 types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
1174
1175 if (!MergeTypes(&resultType, &resultTypeSet, ins->type(), ins->resultTypeSet()))
1176 return false;
1177
1178 if (resultType != this->type() || resultTypeSet != this->resultTypeSet()) {
1179 *ptypeChange = true;
1180 setResultType(resultType);
1181 setResultTypeSet(resultTypeSet);
1182 }
1183 }
1184
1185 // Add all previously-removed MUses back.
1186 if (performingRealloc) {
1187 for (uint32_t i = 0; i < index; i++) {
1188 MUse *use = &inputs_[i];
1189 use->producer()->addUse(use);
1190 }
1191 }
1192
1193 return true;
1194 }
1195
1196 void
1197 MCall::addArg(size_t argnum, MDefinition *arg)
1198 {
1199 // The operand vector is initialized in reverse order by the IonBuilder.
1200 // It cannot be checked for consistency until all arguments are added.
1201 setOperand(argnum + NumNonArgumentOperands, arg);
1202 }
1203
1204 void
1205 MBitNot::infer()
1206 {
1207 if (getOperand(0)->mightBeType(MIRType_Object))
1208 specialization_ = MIRType_None;
1209 else
1210 specialization_ = MIRType_Int32;
1211 }
1212
1213 static inline bool
1214 IsConstant(MDefinition *def, double v)
1215 {
1216 if (!def->isConstant())
1217 return false;
1218
1219 return NumbersAreIdentical(def->toConstant()->value().toNumber(), v);
1220 }
1221
1222 MDefinition *
1223 MBinaryBitwiseInstruction::foldsTo(TempAllocator &alloc, bool useValueNumbers)
1224 {
1225 if (specialization_ != MIRType_Int32)
1226 return this;
1227
1228 if (MDefinition *folded = EvaluateConstantOperands(alloc, this))
1229 return folded;
1230
1231 return this;
1232 }
1233
1234 MDefinition *
1235 MBinaryBitwiseInstruction::foldUnnecessaryBitop()
1236 {
1237 if (specialization_ != MIRType_Int32)
1238 return this;
1239
1240 // Eliminate bitwise operations that are no-ops when used on integer
1241 // inputs, such as (x | 0).
1242
1243 MDefinition *lhs = getOperand(0);
1244 MDefinition *rhs = getOperand(1);
1245
1246 if (IsConstant(lhs, 0))
1247 return foldIfZero(0);
1248
1249 if (IsConstant(rhs, 0))
1250 return foldIfZero(1);
1251
1252 if (IsConstant(lhs, -1))
1253 return foldIfNegOne(0);
1254
1255 if (IsConstant(rhs, -1))
1256 return foldIfNegOne(1);
1257
1258 if (EqualValues(false, lhs, rhs))
1259 return foldIfEqual();
1260
1261 return this;
1262 }
1263
1264 void
1265 MBinaryBitwiseInstruction::infer(BaselineInspector *, jsbytecode *)
1266 {
1267 if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object))
1268 specialization_ = MIRType_None;
1269 else
1270 specializeAsInt32();
1271 }
1272
1273 void
1274 MBinaryBitwiseInstruction::specializeAsInt32()
1275 {
1276 specialization_ = MIRType_Int32;
1277 JS_ASSERT(type() == MIRType_Int32);
1278
1279 if (isBitOr() || isBitAnd() || isBitXor())
1280 setCommutative();
1281 }
1282
1283 void
1284 MShiftInstruction::infer(BaselineInspector *, jsbytecode *)
1285 {
1286 if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object))
1287 specialization_ = MIRType_None;
1288 else
1289 specialization_ = MIRType_Int32;
1290 }
1291
1292 void
1293 MUrsh::infer(BaselineInspector *inspector, jsbytecode *pc)
1294 {
1295 if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object)) {
1296 specialization_ = MIRType_None;
1297 setResultType(MIRType_Value);
1298 return;
1299 }
1300
1301 if (inspector->hasSeenDoubleResult(pc)) {
1302 specialization_ = MIRType_Double;
1303 setResultType(MIRType_Double);
1304 return;
1305 }
1306
1307 specialization_ = MIRType_Int32;
1308 setResultType(MIRType_Int32);
1309 }
1310
1311 static inline bool
1312 NeedNegativeZeroCheck(MDefinition *def)
1313 {
1314 // Test if all uses have the same semantics for -0 and 0
1315 for (MUseIterator use = def->usesBegin(); use != def->usesEnd(); use++) {
1316 if (use->consumer()->isResumePoint())
1317 continue;
1318
1319 MDefinition *use_def = use->consumer()->toDefinition();
1320 switch (use_def->op()) {
1321 case MDefinition::Op_Add: {
1322 // If add is truncating -0 and 0 are observed as the same.
1323 if (use_def->toAdd()->isTruncated())
1324 break;
1325
1326 // x + y gives -0, when both x and y are -0
1327
1328 // Figure out the order in which the addition's operands will
1329 // execute. EdgeCaseAnalysis::analyzeLate has renumbered the MIR
1330 // definitions for us so that this just requires comparing ids.
1331 MDefinition *first = use_def->toAdd()->getOperand(0);
1332 MDefinition *second = use_def->toAdd()->getOperand(1);
1333 if (first->id() > second->id()) {
1334 MDefinition *temp = first;
1335 first = second;
1336 second = temp;
1337 }
1338
1339 if (def == first) {
1340 // Negative zero checks can be removed on the first executed
1341 // operand only if it is guaranteed the second executed operand
1342 // will produce a value other than -0. While the second is
1343 // typed as an int32, a bailout taken between execution of the
1344 // operands may change that type and cause a -0 to flow to the
1345 // second.
1346 //
1347 // There is no way to test whether there are any bailouts
1348 // between execution of the operands, so remove negative
1349 // zero checks from the first only if the second's type is
1350 // independent from type changes that may occur after bailing.
1351 switch (second->op()) {
1352 case MDefinition::Op_Constant:
1353 case MDefinition::Op_BitAnd:
1354 case MDefinition::Op_BitOr:
1355 case MDefinition::Op_BitXor:
1356 case MDefinition::Op_BitNot:
1357 case MDefinition::Op_Lsh:
1358 case MDefinition::Op_Rsh:
1359 break;
1360 default:
1361 return true;
1362 }
1363 }
1364
1365 // The negative zero check can always be removed on the second
1366 // executed operand; by the time this executes the first will have
1367 // been evaluated as int32 and the addition's result cannot be -0.
1368 break;
1369 }
1370 case MDefinition::Op_Sub:
1371 // If sub is truncating -0 and 0 are observed as the same
1372 if (use_def->toSub()->isTruncated())
1373 break;
1374 /* Fall through... */
1375 case MDefinition::Op_StoreElement:
1376 case MDefinition::Op_StoreElementHole:
1377 case MDefinition::Op_LoadElement:
1378 case MDefinition::Op_LoadElementHole:
1379 case MDefinition::Op_LoadTypedArrayElement:
1380 case MDefinition::Op_LoadTypedArrayElementHole:
1381 case MDefinition::Op_CharCodeAt:
1382 case MDefinition::Op_Mod:
1383 // Only allowed to remove check when definition is the second operand
1384 if (use_def->getOperand(0) == def)
1385 return true;
1386 for (size_t i = 2, e = use_def->numOperands(); i < e; i++) {
1387 if (use_def->getOperand(i) == def)
1388 return true;
1389 }
1390 break;
1391 case MDefinition::Op_BoundsCheck:
1392 // Only allowed to remove check when definition is the first operand
1393 if (use_def->toBoundsCheck()->getOperand(1) == def)
1394 return true;
1395 break;
1396 case MDefinition::Op_ToString:
1397 case MDefinition::Op_FromCharCode:
1398 case MDefinition::Op_TableSwitch:
1399 case MDefinition::Op_Compare:
1400 case MDefinition::Op_BitAnd:
1401 case MDefinition::Op_BitOr:
1402 case MDefinition::Op_BitXor:
1403 case MDefinition::Op_Abs:
1404 case MDefinition::Op_TruncateToInt32:
1405 // Always allowed to remove check. No matter which operand.
1406 break;
1407 default:
1408 return true;
1409 }
1410 }
1411 return false;
1412 }
1413
1414 MDefinition *
1415 MBinaryArithInstruction::foldsTo(TempAllocator &alloc, bool useValueNumbers)
1416 {
1417 if (specialization_ == MIRType_None)
1418 return this;
1419
1420 MDefinition *lhs = getOperand(0);
1421 MDefinition *rhs = getOperand(1);
1422 if (MDefinition *folded = EvaluateConstantOperands(alloc, this))
1423 return folded;
1424
1425 // 0 + -0 = 0. So we can't remove addition
1426 if (isAdd() && specialization_ != MIRType_Int32)
1427 return this;
1428
1429 if (IsConstant(rhs, getIdentity()))
1430 return lhs;
1431
1432 // subtraction isn't commutative. So we can't remove subtraction when lhs equals 0
1433 if (isSub())
1434 return this;
1435
1436 if (IsConstant(lhs, getIdentity()))
1437 return rhs; // x op id => x
1438
1439 return this;
1440 }
1441
1442 void
1443 MBinaryArithInstruction::trySpecializeFloat32(TempAllocator &alloc)
1444 {
1445 MDefinition *left = lhs();
1446 MDefinition *right = rhs();
1447
1448 if (!left->canProduceFloat32() || !right->canProduceFloat32()
1449 || !CheckUsesAreFloat32Consumers(this))
1450 {
1451 if (left->type() == MIRType_Float32)
1452 ConvertDefinitionToDouble<0>(alloc, left, this);
1453 if (right->type() == MIRType_Float32)
1454 ConvertDefinitionToDouble<1>(alloc, right, this);
1455 return;
1456 }
1457
1458 specialization_ = MIRType_Float32;
1459 setResultType(MIRType_Float32);
1460 }
1461
1462 bool
1463 MAbs::fallible() const
1464 {
1465 return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds());
1466 }
1467
1468 void
1469 MAbs::trySpecializeFloat32(TempAllocator &alloc)
1470 {
1471 if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) {
1472 if (input()->type() == MIRType_Float32)
1473 ConvertDefinitionToDouble<0>(alloc, input(), this);
1474 return;
1475 }
1476
1477 setResultType(MIRType_Float32);
1478 specialization_ = MIRType_Float32;
1479 }
1480
1481 MDefinition *
1482 MDiv::foldsTo(TempAllocator &alloc, bool useValueNumbers)
1483 {
1484 if (specialization_ == MIRType_None)
1485 return this;
1486
1487 if (MDefinition *folded = EvaluateConstantOperands(alloc, this))
1488 return folded;
1489
1490 return this;
1491 }
1492
1493 void
1494 MDiv::analyzeEdgeCasesForward()
1495 {
1496 // This is only meaningful when doing integer division.
1497 if (specialization_ != MIRType_Int32)
1498 return;
1499
1500 // Try removing divide by zero check
1501 if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0))
1502 canBeDivideByZero_ = false;
1503
1504 // If lhs is a constant int != INT32_MIN, then
1505 // negative overflow check can be skipped.
1506 if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(INT32_MIN))
1507 canBeNegativeOverflow_ = false;
1508
1509 // If rhs is a constant int != -1, likewise.
1510 if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(-1))
1511 canBeNegativeOverflow_ = false;
1512
1513 // If lhs is != 0, then negative zero check can be skipped.
1514 if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(0))
1515 setCanBeNegativeZero(false);
1516
1517 // If rhs is >= 0, likewise.
1518 if (rhs()->isConstant()) {
1519 const js::Value &val = rhs()->toConstant()->value();
1520 if (val.isInt32() && val.toInt32() >= 0)
1521 setCanBeNegativeZero(false);
1522 }
1523 }
1524
1525 void
1526 MDiv::analyzeEdgeCasesBackward()
1527 {
1528 if (canBeNegativeZero() && !NeedNegativeZeroCheck(this))
1529 setCanBeNegativeZero(false);
1530 }
1531
1532 bool
1533 MDiv::fallible() const
1534 {
1535 return !isTruncated();
1536 }
1537
1538 bool
1539 MMod::canBeDivideByZero() const
1540 {
1541 JS_ASSERT(specialization_ == MIRType_Int32);
1542 return !rhs()->isConstant() || rhs()->toConstant()->value().toInt32() == 0;
1543 }
1544
1545 bool
1546 MMod::canBePowerOfTwoDivisor() const
1547 {
1548 JS_ASSERT(specialization_ == MIRType_Int32);
1549
1550 if (!rhs()->isConstant())
1551 return true;
1552
1553 int32_t i = rhs()->toConstant()->value().toInt32();
1554 if (i <= 0 || !IsPowerOfTwo(i))
1555 return false;
1556
1557 return true;
1558 }
1559
1560 MDefinition *
1561 MMod::foldsTo(TempAllocator &alloc, bool useValueNumbers)
1562 {
1563 if (specialization_ == MIRType_None)
1564 return this;
1565
1566 if (MDefinition *folded = EvaluateConstantOperands(alloc, this))
1567 return folded;
1568
1569 return this;
1570 }
1571
1572 bool
1573 MMod::fallible() const
1574 {
1575 return !isTruncated() &&
1576 (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend());
1577 }
1578
1579 void
1580 MMathFunction::trySpecializeFloat32(TempAllocator &alloc)
1581 {
1582 if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) {
1583 if (input()->type() == MIRType_Float32)
1584 ConvertDefinitionToDouble<0>(alloc, input(), this);
1585 return;
1586 }
1587
1588 setResultType(MIRType_Float32);
1589 setPolicyType(MIRType_Float32);
1590 }
1591
1592 bool
1593 MAdd::fallible() const
1594 {
1595 // the add is fallible if range analysis does not say that it is finite, AND
1596 // either the truncation analysis shows that there are non-truncated uses.
1597 if (isTruncated())
1598 return false;
1599 if (range() && range()->hasInt32Bounds())
1600 return false;
1601 return true;
1602 }
1603
1604 bool
1605 MSub::fallible() const
1606 {
1607 // see comment in MAdd::fallible()
1608 if (isTruncated())
1609 return false;
1610 if (range() && range()->hasInt32Bounds())
1611 return false;
1612 return true;
1613 }
1614
1615 MDefinition *
1616 MMul::foldsTo(TempAllocator &alloc, bool useValueNumbers)
1617 {
1618 MDefinition *out = MBinaryArithInstruction::foldsTo(alloc, useValueNumbers);
1619 if (out != this)
1620 return out;
1621
1622 if (specialization() != MIRType_Int32)
1623 return this;
1624
1625 if (EqualValues(useValueNumbers, lhs(), rhs()))
1626 setCanBeNegativeZero(false);
1627
1628 return this;
1629 }
1630
1631 void
1632 MMul::analyzeEdgeCasesForward()
1633 {
1634 // Try to remove the check for negative zero
1635 // This only makes sense when using the integer multiplication
1636 if (specialization() != MIRType_Int32)
1637 return;
1638
1639 // If lhs is > 0, no need for negative zero check.
1640 if (lhs()->isConstant()) {
1641 const js::Value &val = lhs()->toConstant()->value();
1642 if (val.isInt32() && val.toInt32() > 0)
1643 setCanBeNegativeZero(false);
1644 }
1645
1646 // If rhs is > 0, likewise.
1647 if (rhs()->isConstant()) {
1648 const js::Value &val = rhs()->toConstant()->value();
1649 if (val.isInt32() && val.toInt32() > 0)
1650 setCanBeNegativeZero(false);
1651 }
1652 }
1653
1654 void
1655 MMul::analyzeEdgeCasesBackward()
1656 {
1657 if (canBeNegativeZero() && !NeedNegativeZeroCheck(this))
1658 setCanBeNegativeZero(false);
1659 }
1660
1661 bool
1662 MMul::updateForReplacement(MDefinition *ins_)
1663 {
1664 MMul *ins = ins_->toMul();
1665 bool negativeZero = canBeNegativeZero() || ins->canBeNegativeZero();
1666 setCanBeNegativeZero(negativeZero);
1667 // Remove the imul annotation when merging imul and normal multiplication.
1668 if (mode_ == Integer && ins->mode() != Integer)
1669 mode_ = Normal;
1670 return true;
1671 }
1672
1673 bool
1674 MMul::canOverflow() const
1675 {
1676 if (isTruncated())
1677 return false;
1678 return !range() || !range()->hasInt32Bounds();
1679 }
1680
1681 bool
1682 MUrsh::fallible() const
1683 {
1684 if (bailoutsDisabled())
1685 return false;
1686 return !range() || !range()->hasInt32Bounds();
1687 }
1688
1689 static inline bool
1690 KnownNonStringPrimitive(MDefinition *op)
1691 {
1692 return !op->mightBeType(MIRType_Object)
1693 && !op->mightBeType(MIRType_String)
1694 && !op->mightBeType(MIRType_MagicOptimizedArguments)
1695 && !op->mightBeType(MIRType_MagicHole)
1696 && !op->mightBeType(MIRType_MagicIsConstructing);
1697 }
1698
1699 void
1700 MBinaryArithInstruction::infer(TempAllocator &alloc, BaselineInspector *inspector, jsbytecode *pc)
1701 {
1702 JS_ASSERT(this->type() == MIRType_Value);
1703
1704 specialization_ = MIRType_None;
1705
1706 // Don't specialize if one operand could be an object. If we specialize
1707 // as int32 or double based on baseline feedback, we could DCE this
1708 // instruction and fail to invoke any valueOf methods.
1709 if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object))
1710 return;
1711
1712 // Anything complex - strings and objects - are not specialized
1713 // unless baseline type hints suggest it might be profitable
1714 if (!KnownNonStringPrimitive(getOperand(0)) || !KnownNonStringPrimitive(getOperand(1)))
1715 return inferFallback(inspector, pc);
1716
1717 // Retrieve type information of lhs and rhs.
1718 MIRType lhs = getOperand(0)->type();
1719 MIRType rhs = getOperand(1)->type();
1720
1721 // Guess a result type based on the inputs.
1722 // Don't specialize for neither-integer-nor-double results.
1723 if (lhs == MIRType_Int32 && rhs == MIRType_Int32)
1724 setResultType(MIRType_Int32);
1725 // Double operations are prioritary over float32 operations (i.e. if any operand needs
1726 // a double as an input, convert all operands to doubles)
1727 else if (IsFloatingPointType(lhs) || IsFloatingPointType(rhs))
1728 setResultType(MIRType_Double);
1729 else
1730 return inferFallback(inspector, pc);
1731
1732 // If the operation has ever overflowed, use a double specialization.
1733 if (inspector->hasSeenDoubleResult(pc))
1734 setResultType(MIRType_Double);
1735
1736 // If the operation will always overflow on its constant operands, use a
1737 // double specialization so that it can be constant folded later.
1738 if ((isMul() || isDiv()) && lhs == MIRType_Int32 && rhs == MIRType_Int32) {
1739 bool typeChange = false;
1740 EvaluateConstantOperands(alloc, this, &typeChange);
1741 if (typeChange)
1742 setResultType(MIRType_Double);
1743 }
1744
1745 JS_ASSERT(lhs < MIRType_String || lhs == MIRType_Value);
1746 JS_ASSERT(rhs < MIRType_String || rhs == MIRType_Value);
1747
1748 MIRType rval = this->type();
1749
1750 // Don't specialize values when result isn't double
1751 if (lhs == MIRType_Value || rhs == MIRType_Value) {
1752 if (!IsFloatingPointType(rval)) {
1753 specialization_ = MIRType_None;
1754 return;
1755 }
1756 }
1757
1758 // Don't specialize as int32 if one of the operands is undefined,
1759 // since ToNumber(undefined) is NaN.
1760 if (rval == MIRType_Int32 && (lhs == MIRType_Undefined || rhs == MIRType_Undefined)) {
1761 specialization_ = MIRType_None;
1762 return;
1763 }
1764
1765 specialization_ = rval;
1766
1767 if (isAdd() || isMul())
1768 setCommutative();
1769 setResultType(rval);
1770 }
1771
1772 void
1773 MBinaryArithInstruction::inferFallback(BaselineInspector *inspector,
1774 jsbytecode *pc)
1775 {
1776 // Try to specialize based on what baseline observed in practice.
1777 specialization_ = inspector->expectedBinaryArithSpecialization(pc);
1778 if (specialization_ != MIRType_None) {
1779 setResultType(specialization_);
1780 return;
1781 }
1782
1783 // In parallel execution, for now anyhow, we *only* support adding
1784 // and manipulating numbers (not strings or objects). So no
1785 // matter what we can specialize to double...if the result ought
1786 // to have been something else, we'll fail in the various type
1787 // guards that get inserted later.
1788 if (block()->info().executionMode() == ParallelExecution) {
1789 specialization_ = MIRType_Double;
1790 setResultType(MIRType_Double);
1791 return;
1792 }
1793
1794 // If we can't specialize because we have no type information at all for
1795 // the lhs or rhs, mark the binary instruction as having no possible types
1796 // either to avoid degrading subsequent analysis.
1797 if (getOperand(0)->emptyResultTypeSet() || getOperand(1)->emptyResultTypeSet()) {
1798 LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
1799 types::TemporaryTypeSet *types = alloc->new_<types::TemporaryTypeSet>();
1800 if (types)
1801 setResultTypeSet(types);
1802 }
1803 }
1804
1805 static bool
1806 SafelyCoercesToDouble(MDefinition *op)
1807 {
1808 // Strings are unhandled -- visitToDouble() doesn't support them yet.
1809 // Null is unhandled -- ToDouble(null) == 0, but (0 == null) is false.
1810 return KnownNonStringPrimitive(op) && !op->mightBeType(MIRType_Null);
1811 }
1812
1813 static bool
1814 ObjectOrSimplePrimitive(MDefinition *op)
1815 {
1816 // Return true if op is either undefined/null/boolean/int32 or an object.
1817 return !op->mightBeType(MIRType_String)
1818 && !op->mightBeType(MIRType_Double)
1819 && !op->mightBeType(MIRType_Float32)
1820 && !op->mightBeType(MIRType_MagicOptimizedArguments)
1821 && !op->mightBeType(MIRType_MagicHole)
1822 && !op->mightBeType(MIRType_MagicIsConstructing);
1823 }
1824
1825 static bool
1826 CanDoValueBitwiseCmp(MDefinition *lhs, MDefinition *rhs, bool looseEq)
1827 {
1828 // Only primitive (not double/string) or objects are supported.
1829 // I.e. Undefined/Null/Boolean/Int32 and Object
1830 if (!ObjectOrSimplePrimitive(lhs) || !ObjectOrSimplePrimitive(rhs))
1831 return false;
1832
1833 // Objects that emulate undefined are not supported.
1834 if (MaybeEmulatesUndefined(lhs) || MaybeEmulatesUndefined(rhs))
1835 return false;
1836
1837 // In the loose comparison more values could be the same,
1838 // but value comparison reporting otherwise.
1839 if (looseEq) {
1840
1841 // Undefined compared loosy to Null is not supported,
1842 // because tag is different, but value can be the same (undefined == null).
1843 if ((lhs->mightBeType(MIRType_Undefined) && rhs->mightBeType(MIRType_Null)) ||
1844 (lhs->mightBeType(MIRType_Null) && rhs->mightBeType(MIRType_Undefined)))
1845 {
1846 return false;
1847 }
1848
1849 // Int32 compared loosy to Boolean is not supported,
1850 // because tag is different, but value can be the same (1 == true).
1851 if ((lhs->mightBeType(MIRType_Int32) && rhs->mightBeType(MIRType_Boolean)) ||
1852 (lhs->mightBeType(MIRType_Boolean) && rhs->mightBeType(MIRType_Int32)))
1853 {
1854 return false;
1855 }
1856
1857 // For loosy comparison of an object with a Boolean/Number/String
1858 // the valueOf the object is taken. Therefore not supported.
1859 bool simpleLHS = lhs->mightBeType(MIRType_Boolean) || lhs->mightBeType(MIRType_Int32);
1860 bool simpleRHS = rhs->mightBeType(MIRType_Boolean) || rhs->mightBeType(MIRType_Int32);
1861 if ((lhs->mightBeType(MIRType_Object) && simpleRHS) ||
1862 (rhs->mightBeType(MIRType_Object) && simpleLHS))
1863 {
1864 return false;
1865 }
1866 }
1867
1868 return true;
1869 }
1870
1871 MIRType
1872 MCompare::inputType()
1873 {
1874 switch(compareType_) {
1875 case Compare_Undefined:
1876 return MIRType_Undefined;
1877 case Compare_Null:
1878 return MIRType_Null;
1879 case Compare_Boolean:
1880 return MIRType_Boolean;
1881 case Compare_UInt32:
1882 case Compare_Int32:
1883 case Compare_Int32MaybeCoerceBoth:
1884 case Compare_Int32MaybeCoerceLHS:
1885 case Compare_Int32MaybeCoerceRHS:
1886 return MIRType_Int32;
1887 case Compare_Double:
1888 case Compare_DoubleMaybeCoerceLHS:
1889 case Compare_DoubleMaybeCoerceRHS:
1890 return MIRType_Double;
1891 case Compare_Float32:
1892 return MIRType_Float32;
1893 case Compare_String:
1894 case Compare_StrictString:
1895 return MIRType_String;
1896 case Compare_Object:
1897 return MIRType_Object;
1898 case Compare_Unknown:
1899 case Compare_Value:
1900 return MIRType_Value;
1901 default:
1902 MOZ_ASSUME_UNREACHABLE("No known conversion");
1903 }
1904 }
1905
1906 static inline bool
1907 MustBeUInt32(MDefinition *def, MDefinition **pwrapped)
1908 {
1909 if (def->isUrsh()) {
1910 *pwrapped = def->toUrsh()->getOperand(0);
1911 MDefinition *rhs = def->toUrsh()->getOperand(1);
1912 return !def->toUrsh()->bailoutsDisabled()
1913 && rhs->isConstant()
1914 && rhs->toConstant()->value().isInt32()
1915 && rhs->toConstant()->value().toInt32() == 0;
1916 }
1917
1918 if (def->isConstant()) {
1919 *pwrapped = def;
1920 return def->toConstant()->value().isInt32()
1921 && def->toConstant()->value().toInt32() >= 0;
1922 }
1923
1924 return false;
1925 }
1926
1927 bool
1928 MBinaryInstruction::tryUseUnsignedOperands()
1929 {
1930 MDefinition *newlhs, *newrhs;
1931 if (MustBeUInt32(getOperand(0), &newlhs) && MustBeUInt32(getOperand(1), &newrhs)) {
1932 if (newlhs->type() != MIRType_Int32 || newrhs->type() != MIRType_Int32)
1933 return false;
1934 if (newlhs != getOperand(0)) {
1935 getOperand(0)->setImplicitlyUsedUnchecked();
1936 replaceOperand(0, newlhs);
1937 }
1938 if (newrhs != getOperand(1)) {
1939 getOperand(1)->setImplicitlyUsedUnchecked();
1940 replaceOperand(1, newrhs);
1941 }
1942 return true;
1943 }
1944 return false;
1945 }
1946
1947 void
1948 MCompare::infer(BaselineInspector *inspector, jsbytecode *pc)
1949 {
1950 JS_ASSERT(operandMightEmulateUndefined());
1951
1952 if (!MaybeEmulatesUndefined(getOperand(0)) && !MaybeEmulatesUndefined(getOperand(1)))
1953 markNoOperandEmulatesUndefined();
1954
1955 MIRType lhs = getOperand(0)->type();
1956 MIRType rhs = getOperand(1)->type();
1957
1958 bool looseEq = jsop() == JSOP_EQ || jsop() == JSOP_NE;
1959 bool strictEq = jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE;
1960 bool relationalEq = !(looseEq || strictEq);
1961
1962 // Comparisons on unsigned integers may be treated as UInt32.
1963 if (tryUseUnsignedOperands()) {
1964 compareType_ = Compare_UInt32;
1965 return;
1966 }
1967
1968 // Integer to integer or boolean to boolean comparisons may be treated as Int32.
1969 if ((lhs == MIRType_Int32 && rhs == MIRType_Int32) ||
1970 (lhs == MIRType_Boolean && rhs == MIRType_Boolean))
1971 {
1972 compareType_ = Compare_Int32MaybeCoerceBoth;
1973 return;
1974 }
1975
1976 // Loose/relational cross-integer/boolean comparisons may be treated as Int32.
1977 if (!strictEq &&
1978 (lhs == MIRType_Int32 || lhs == MIRType_Boolean) &&
1979 (rhs == MIRType_Int32 || rhs == MIRType_Boolean))
1980 {
1981 compareType_ = Compare_Int32MaybeCoerceBoth;
1982 return;
1983 }
1984
1985 // Numeric comparisons against a double coerce to double.
1986 if (IsNumberType(lhs) && IsNumberType(rhs)) {
1987 compareType_ = Compare_Double;
1988 return;
1989 }
1990
1991 // Any comparison is allowed except strict eq.
1992 if (!strictEq && IsFloatingPointType(lhs) && SafelyCoercesToDouble(getOperand(1))) {
1993 compareType_ = Compare_DoubleMaybeCoerceRHS;
1994 return;
1995 }
1996 if (!strictEq && IsFloatingPointType(rhs) && SafelyCoercesToDouble(getOperand(0))) {
1997 compareType_ = Compare_DoubleMaybeCoerceLHS;
1998 return;
1999 }
2000
2001 // Handle object comparison.
2002 if (!relationalEq && lhs == MIRType_Object && rhs == MIRType_Object) {
2003 compareType_ = Compare_Object;
2004 return;
2005 }
2006
2007 // Handle string comparisons. (Relational string compares are still unsupported).
2008 if (!relationalEq && lhs == MIRType_String && rhs == MIRType_String) {
2009 compareType_ = Compare_String;
2010 return;
2011 }
2012
2013 if (strictEq && lhs == MIRType_String) {
2014 // Lowering expects the rhs to be definitly string.
2015 compareType_ = Compare_StrictString;
2016 swapOperands();
2017 return;
2018 }
2019
2020 if (strictEq && rhs == MIRType_String) {
2021 compareType_ = Compare_StrictString;
2022 return;
2023 }
2024
2025 // Handle compare with lhs being Undefined or Null.
2026 if (!relationalEq && IsNullOrUndefined(lhs)) {
2027 // Lowering expects the rhs to be null/undefined, so we have to
2028 // swap the operands. This is necessary since we may not know which
2029 // operand was null/undefined during lowering (both operands may have
2030 // MIRType_Value).
2031 compareType_ = (lhs == MIRType_Null) ? Compare_Null : Compare_Undefined;
2032 swapOperands();
2033 return;
2034 }
2035
2036 // Handle compare with rhs being Undefined or Null.
2037 if (!relationalEq && IsNullOrUndefined(rhs)) {
2038 compareType_ = (rhs == MIRType_Null) ? Compare_Null : Compare_Undefined;
2039 return;
2040 }
2041
2042 // Handle strict comparison with lhs/rhs being typed Boolean.
2043 if (strictEq && (lhs == MIRType_Boolean || rhs == MIRType_Boolean)) {
2044 // bool/bool case got an int32 specialization earlier.
2045 JS_ASSERT(!(lhs == MIRType_Boolean && rhs == MIRType_Boolean));
2046
2047 // Ensure the boolean is on the right so that the type policy knows
2048 // which side to unbox.
2049 if (lhs == MIRType_Boolean)
2050 swapOperands();
2051
2052 compareType_ = Compare_Boolean;
2053 return;
2054 }
2055
2056 // Determine if we can do the compare based on a quick value check.
2057 if (!relationalEq && CanDoValueBitwiseCmp(getOperand(0), getOperand(1), looseEq)) {
2058 compareType_ = Compare_Value;
2059 return;
2060 }
2061
2062 // Type information is not good enough to pick out a particular type of
2063 // comparison we can do here. Try to specialize based on any baseline
2064 // caches that have been generated for the opcode. These will cause the
2065 // instruction's type policy to insert fallible unboxes to the appropriate
2066 // input types.
2067
2068 if (!strictEq)
2069 compareType_ = inspector->expectedCompareType(pc);
2070 }
2071
2072 MBitNot *
2073 MBitNot::New(TempAllocator &alloc, MDefinition *input)
2074 {
2075 return new(alloc) MBitNot(input);
2076 }
2077
2078 MBitNot *
2079 MBitNot::NewAsmJS(TempAllocator &alloc, MDefinition *input)
2080 {
2081 MBitNot *ins = new(alloc) MBitNot(input);
2082 ins->specialization_ = MIRType_Int32;
2083 JS_ASSERT(ins->type() == MIRType_Int32);
2084 return ins;
2085 }
2086
2087 MDefinition *
2088 MBitNot::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2089 {
2090 if (specialization_ != MIRType_Int32)
2091 return this;
2092
2093 MDefinition *input = getOperand(0);
2094
2095 if (input->isConstant()) {
2096 js::Value v = Int32Value(~(input->toConstant()->value().toInt32()));
2097 return MConstant::New(alloc, v);
2098 }
2099
2100 if (input->isBitNot() && input->toBitNot()->specialization_ == MIRType_Int32) {
2101 JS_ASSERT(input->toBitNot()->getOperand(0)->type() == MIRType_Int32);
2102 return input->toBitNot()->getOperand(0); // ~~x => x
2103 }
2104
2105 return this;
2106 }
2107
2108 MDefinition *
2109 MTypeOf::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2110 {
2111 // Note: we can't use input->type() here, type analysis has
2112 // boxed the input.
2113 JS_ASSERT(input()->type() == MIRType_Value);
2114
2115 JSType type;
2116
2117 switch (inputType()) {
2118 case MIRType_Double:
2119 case MIRType_Int32:
2120 type = JSTYPE_NUMBER;
2121 break;
2122 case MIRType_String:
2123 type = JSTYPE_STRING;
2124 break;
2125 case MIRType_Null:
2126 type = JSTYPE_OBJECT;
2127 break;
2128 case MIRType_Undefined:
2129 type = JSTYPE_VOID;
2130 break;
2131 case MIRType_Boolean:
2132 type = JSTYPE_BOOLEAN;
2133 break;
2134 case MIRType_Object:
2135 if (!inputMaybeCallableOrEmulatesUndefined()) {
2136 // Object is not callable and does not emulate undefined, so it's
2137 // safe to fold to "object".
2138 type = JSTYPE_OBJECT;
2139 break;
2140 }
2141 // FALL THROUGH
2142 default:
2143 return this;
2144 }
2145
2146 return MConstant::New(alloc, StringValue(TypeName(type, GetIonContext()->runtime->names())));
2147 }
2148
2149 void
2150 MTypeOf::infer()
2151 {
2152 JS_ASSERT(inputMaybeCallableOrEmulatesUndefined());
2153
2154 if (!MaybeEmulatesUndefined(input()) && !MaybeCallable(input()))
2155 markInputNotCallableOrEmulatesUndefined();
2156 }
2157
2158 MBitAnd *
2159 MBitAnd::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2160 {
2161 return new(alloc) MBitAnd(left, right);
2162 }
2163
2164 MBitAnd *
2165 MBitAnd::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2166 {
2167 MBitAnd *ins = new(alloc) MBitAnd(left, right);
2168 ins->specializeAsInt32();
2169 return ins;
2170 }
2171
2172 MBitOr *
2173 MBitOr::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2174 {
2175 return new(alloc) MBitOr(left, right);
2176 }
2177
2178 MBitOr *
2179 MBitOr::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2180 {
2181 MBitOr *ins = new(alloc) MBitOr(left, right);
2182 ins->specializeAsInt32();
2183 return ins;
2184 }
2185
2186 MBitXor *
2187 MBitXor::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2188 {
2189 return new(alloc) MBitXor(left, right);
2190 }
2191
2192 MBitXor *
2193 MBitXor::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2194 {
2195 MBitXor *ins = new(alloc) MBitXor(left, right);
2196 ins->specializeAsInt32();
2197 return ins;
2198 }
2199
2200 MLsh *
2201 MLsh::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2202 {
2203 return new(alloc) MLsh(left, right);
2204 }
2205
2206 MLsh *
2207 MLsh::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2208 {
2209 MLsh *ins = new(alloc) MLsh(left, right);
2210 ins->specializeAsInt32();
2211 return ins;
2212 }
2213
2214 MRsh *
2215 MRsh::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2216 {
2217 return new(alloc) MRsh(left, right);
2218 }
2219
2220 MRsh *
2221 MRsh::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2222 {
2223 MRsh *ins = new(alloc) MRsh(left, right);
2224 ins->specializeAsInt32();
2225 return ins;
2226 }
2227
2228 MUrsh *
2229 MUrsh::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2230 {
2231 return new(alloc) MUrsh(left, right);
2232 }
2233
2234 MUrsh *
2235 MUrsh::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
2236 {
2237 MUrsh *ins = new(alloc) MUrsh(left, right);
2238 ins->specializeAsInt32();
2239
2240 // Since Ion has no UInt32 type, we use Int32 and we have a special
2241 // exception to the type rules: we can return values in
2242 // (INT32_MIN,UINT32_MAX] and still claim that we have an Int32 type
2243 // without bailing out. This is necessary because Ion has no UInt32
2244 // type and we can't have bailouts in asm.js code.
2245 ins->bailoutsDisabled_ = true;
2246
2247 return ins;
2248 }
2249
2250 MResumePoint *
2251 MResumePoint::New(TempAllocator &alloc, MBasicBlock *block, jsbytecode *pc, MResumePoint *parent,
2252 Mode mode)
2253 {
2254 MResumePoint *resume = new(alloc) MResumePoint(block, pc, parent, mode);
2255 if (!resume->init(alloc))
2256 return nullptr;
2257 resume->inherit(block);
2258 return resume;
2259 }
2260
2261 MResumePoint::MResumePoint(MBasicBlock *block, jsbytecode *pc, MResumePoint *caller,
2262 Mode mode)
2263 : MNode(block),
2264 stackDepth_(block->stackDepth()),
2265 pc_(pc),
2266 caller_(caller),
2267 instruction_(nullptr),
2268 mode_(mode)
2269 {
2270 block->addResumePoint(this);
2271 }
2272
2273 void
2274 MResumePoint::inherit(MBasicBlock *block)
2275 {
2276 for (size_t i = 0; i < stackDepth(); i++) {
2277 MDefinition *def = block->getSlot(i);
2278 setOperand(i, def);
2279 }
2280 }
2281
2282 MDefinition *
2283 MToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2284 {
2285 MDefinition *input = getOperand(0);
2286 if (input->type() == MIRType_Int32)
2287 return input;
2288 return this;
2289 }
2290
2291 void
2292 MToInt32::analyzeEdgeCasesBackward()
2293 {
2294 if (!NeedNegativeZeroCheck(this))
2295 setCanBeNegativeZero(false);
2296 }
2297
2298 MDefinition *
2299 MTruncateToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2300 {
2301 MDefinition *input = getOperand(0);
2302 if (input->type() == MIRType_Int32)
2303 return input;
2304
2305 if (input->type() == MIRType_Double && input->isConstant()) {
2306 const Value &v = input->toConstant()->value();
2307 int32_t ret = ToInt32(v.toDouble());
2308 return MConstant::New(alloc, Int32Value(ret));
2309 }
2310
2311 return this;
2312 }
2313
2314 MDefinition *
2315 MToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2316 {
2317 MDefinition *in = input();
2318 if (in->type() == MIRType_Double)
2319 return in;
2320
2321 if (in->isConstant()) {
2322 const Value &v = in->toConstant()->value();
2323 if (v.isNumber()) {
2324 double out = v.toNumber();
2325 return MConstant::New(alloc, DoubleValue(out));
2326 }
2327 }
2328
2329 return this;
2330 }
2331
2332 MDefinition *
2333 MToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2334 {
2335 if (input()->type() == MIRType_Float32)
2336 return input();
2337
2338 // If x is a Float32, Float32(Double(x)) == x
2339 if (input()->isToDouble() && input()->toToDouble()->input()->type() == MIRType_Float32)
2340 return input()->toToDouble()->input();
2341
2342 if (input()->isConstant()) {
2343 const Value &v = input()->toConstant()->value();
2344 if (v.isNumber()) {
2345 float out = v.toNumber();
2346 MConstant *c = MConstant::New(alloc, DoubleValue(out));
2347 c->setResultType(MIRType_Float32);
2348 return c;
2349 }
2350 }
2351 return this;
2352 }
2353
2354 MDefinition *
2355 MToString::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2356 {
2357 MDefinition *in = input();
2358 if (in->type() == MIRType_String)
2359 return in;
2360 return this;
2361 }
2362
2363 MDefinition *
2364 MClampToUint8::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2365 {
2366 if (input()->isConstant()) {
2367 const Value &v = input()->toConstant()->value();
2368 if (v.isDouble()) {
2369 int32_t clamped = ClampDoubleToUint8(v.toDouble());
2370 return MConstant::New(alloc, Int32Value(clamped));
2371 }
2372 if (v.isInt32()) {
2373 int32_t clamped = ClampIntForUint8Array(v.toInt32());
2374 return MConstant::New(alloc, Int32Value(clamped));
2375 }
2376 }
2377 return this;
2378 }
2379
2380 bool
2381 MCompare::tryFold(bool *result)
2382 {
2383 JSOp op = jsop();
2384
2385 if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) {
2386 JS_ASSERT(op == JSOP_EQ || op == JSOP_STRICTEQ ||
2387 op == JSOP_NE || op == JSOP_STRICTNE);
2388
2389 // The LHS is the value we want to test against null or undefined.
2390 switch (lhs()->type()) {
2391 case MIRType_Value:
2392 return false;
2393 case MIRType_Undefined:
2394 case MIRType_Null:
2395 if (lhs()->type() == inputType()) {
2396 // Both sides have the same type, null or undefined.
2397 *result = (op == JSOP_EQ || op == JSOP_STRICTEQ);
2398 } else {
2399 // One side is null, the other side is undefined. The result is only
2400 // true for loose equality.
2401 *result = (op == JSOP_EQ || op == JSOP_STRICTNE);
2402 }
2403 return true;
2404 case MIRType_Object:
2405 if ((op == JSOP_EQ || op == JSOP_NE) && operandMightEmulateUndefined())
2406 return false;
2407 /* FALL THROUGH */
2408 case MIRType_Int32:
2409 case MIRType_Double:
2410 case MIRType_Float32:
2411 case MIRType_String:
2412 case MIRType_Boolean:
2413 *result = (op == JSOP_NE || op == JSOP_STRICTNE);
2414 return true;
2415 default:
2416 MOZ_ASSUME_UNREACHABLE("Unexpected type");
2417 }
2418 }
2419
2420 if (compareType_ == Compare_Boolean) {
2421 JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
2422 JS_ASSERT(rhs()->type() == MIRType_Boolean);
2423
2424 switch (lhs()->type()) {
2425 case MIRType_Value:
2426 return false;
2427 case MIRType_Int32:
2428 case MIRType_Double:
2429 case MIRType_Float32:
2430 case MIRType_String:
2431 case MIRType_Object:
2432 case MIRType_Null:
2433 case MIRType_Undefined:
2434 *result = (op == JSOP_STRICTNE);
2435 return true;
2436 case MIRType_Boolean:
2437 // Int32 specialization should handle this.
2438 MOZ_ASSUME_UNREACHABLE("Wrong specialization");
2439 default:
2440 MOZ_ASSUME_UNREACHABLE("Unexpected type");
2441 }
2442 }
2443
2444 if (compareType_ == Compare_StrictString) {
2445 JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
2446 JS_ASSERT(rhs()->type() == MIRType_String);
2447
2448 switch (lhs()->type()) {
2449 case MIRType_Value:
2450 return false;
2451 case MIRType_Boolean:
2452 case MIRType_Int32:
2453 case MIRType_Double:
2454 case MIRType_Float32:
2455 case MIRType_Object:
2456 case MIRType_Null:
2457 case MIRType_Undefined:
2458 *result = (op == JSOP_STRICTNE);
2459 return true;
2460 case MIRType_String:
2461 // Compare_String specialization should handle this.
2462 MOZ_ASSUME_UNREACHABLE("Wrong specialization");
2463 default:
2464 MOZ_ASSUME_UNREACHABLE("Unexpected type");
2465 }
2466 }
2467
2468 return false;
2469 }
2470
2471 bool
2472 MCompare::evaluateConstantOperands(bool *result)
2473 {
2474 if (type() != MIRType_Boolean && type() != MIRType_Int32)
2475 return false;
2476
2477 MDefinition *left = getOperand(0);
2478 MDefinition *right = getOperand(1);
2479
2480 if (!left->isConstant() || !right->isConstant())
2481 return false;
2482
2483 Value lhs = left->toConstant()->value();
2484 Value rhs = right->toConstant()->value();
2485
2486 // Fold away some String equality comparisons.
2487 if (lhs.isString() && rhs.isString()) {
2488 int32_t comp = 0; // Default to equal.
2489 if (left != right)
2490 comp = CompareAtoms(&lhs.toString()->asAtom(), &rhs.toString()->asAtom());
2491
2492 switch (jsop_) {
2493 case JSOP_LT:
2494 *result = (comp < 0);
2495 break;
2496 case JSOP_LE:
2497 *result = (comp <= 0);
2498 break;
2499 case JSOP_GT:
2500 *result = (comp > 0);
2501 break;
2502 case JSOP_GE:
2503 *result = (comp >= 0);
2504 break;
2505 case JSOP_STRICTEQ: // Fall through.
2506 case JSOP_EQ:
2507 *result = (comp == 0);
2508 break;
2509 case JSOP_STRICTNE: // Fall through.
2510 case JSOP_NE:
2511 *result = (comp != 0);
2512 break;
2513 default:
2514 MOZ_ASSUME_UNREACHABLE("Unexpected op.");
2515 }
2516
2517 return true;
2518 }
2519
2520 if (compareType_ == Compare_UInt32) {
2521 uint32_t lhsUint = uint32_t(lhs.toInt32());
2522 uint32_t rhsUint = uint32_t(rhs.toInt32());
2523
2524 switch (jsop_) {
2525 case JSOP_LT:
2526 *result = (lhsUint < rhsUint);
2527 break;
2528 case JSOP_LE:
2529 *result = (lhsUint <= rhsUint);
2530 break;
2531 case JSOP_GT:
2532 *result = (lhsUint > rhsUint);
2533 break;
2534 case JSOP_GE:
2535 *result = (lhsUint >= rhsUint);
2536 break;
2537 case JSOP_EQ:
2538 case JSOP_STRICTEQ:
2539 *result = (lhsUint == rhsUint);
2540 break;
2541 case JSOP_NE:
2542 case JSOP_STRICTNE:
2543 *result = (lhsUint != rhsUint);
2544 break;
2545 default:
2546 MOZ_ASSUME_UNREACHABLE("Unexpected op.");
2547 }
2548
2549 return true;
2550 }
2551
2552 if (!lhs.isNumber() || !rhs.isNumber())
2553 return false;
2554
2555 switch (jsop_) {
2556 case JSOP_LT:
2557 *result = (lhs.toNumber() < rhs.toNumber());
2558 break;
2559 case JSOP_LE:
2560 *result = (lhs.toNumber() <= rhs.toNumber());
2561 break;
2562 case JSOP_GT:
2563 *result = (lhs.toNumber() > rhs.toNumber());
2564 break;
2565 case JSOP_GE:
2566 *result = (lhs.toNumber() >= rhs.toNumber());
2567 break;
2568 case JSOP_EQ:
2569 *result = (lhs.toNumber() == rhs.toNumber());
2570 break;
2571 case JSOP_NE:
2572 *result = (lhs.toNumber() != rhs.toNumber());
2573 break;
2574 default:
2575 return false;
2576 }
2577
2578 return true;
2579 }
2580
2581 MDefinition *
2582 MCompare::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2583 {
2584 bool result;
2585
2586 if (tryFold(&result) || evaluateConstantOperands(&result)) {
2587 if (type() == MIRType_Int32)
2588 return MConstant::New(alloc, Int32Value(result));
2589
2590 JS_ASSERT(type() == MIRType_Boolean);
2591 return MConstant::New(alloc, BooleanValue(result));
2592 }
2593
2594 return this;
2595 }
2596
2597 void
2598 MCompare::trySpecializeFloat32(TempAllocator &alloc)
2599 {
2600 MDefinition *lhs = getOperand(0);
2601 MDefinition *rhs = getOperand(1);
2602
2603 if (lhs->canProduceFloat32() && rhs->canProduceFloat32() && compareType_ == Compare_Double) {
2604 compareType_ = Compare_Float32;
2605 } else {
2606 if (lhs->type() == MIRType_Float32)
2607 ConvertDefinitionToDouble<0>(alloc, lhs, this);
2608 if (rhs->type() == MIRType_Float32)
2609 ConvertDefinitionToDouble<1>(alloc, rhs, this);
2610 }
2611 }
2612
2613 void
2614 MCompare::filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
2615 bool *filtersNull)
2616 {
2617 *filtersNull = *filtersUndefined = false;
2618 *subject = nullptr;
2619
2620 if (compareType() != Compare_Undefined && compareType() != Compare_Null)
2621 return;
2622
2623 JS_ASSERT(jsop() == JSOP_STRICTNE || jsop() == JSOP_NE ||
2624 jsop() == JSOP_STRICTEQ || jsop() == JSOP_EQ);
2625
2626 // JSOP_*NE only removes undefined/null from if/true branch
2627 if (!trueBranch && (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE))
2628 return;
2629
2630 // JSOP_*EQ only removes undefined/null from else/false branch
2631 if (trueBranch && (jsop() == JSOP_STRICTEQ || jsop() == JSOP_EQ))
2632 return;
2633
2634 if (jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE) {
2635 *filtersUndefined = compareType() == Compare_Undefined;
2636 *filtersNull = compareType() == Compare_Null;
2637 } else {
2638 *filtersUndefined = *filtersNull = true;
2639 }
2640
2641 *subject = lhs();
2642 }
2643
2644 void
2645 MNot::infer()
2646 {
2647 JS_ASSERT(operandMightEmulateUndefined());
2648
2649 if (!MaybeEmulatesUndefined(getOperand(0)))
2650 markOperandCantEmulateUndefined();
2651 }
2652
2653 MDefinition *
2654 MNot::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2655 {
2656 // Fold if the input is constant
2657 if (operand()->isConstant()) {
2658 bool result = operand()->toConstant()->valueToBoolean();
2659 if (type() == MIRType_Int32)
2660 return MConstant::New(alloc, Int32Value(!result));
2661
2662 // ToBoolean can't cause side effects, so this is safe.
2663 return MConstant::New(alloc, BooleanValue(!result));
2664 }
2665
2666 // NOT of an undefined or null value is always true
2667 if (operand()->type() == MIRType_Undefined || operand()->type() == MIRType_Null)
2668 return MConstant::New(alloc, BooleanValue(true));
2669
2670 // NOT of an object that can't emulate undefined is always false.
2671 if (operand()->type() == MIRType_Object && !operandMightEmulateUndefined())
2672 return MConstant::New(alloc, BooleanValue(false));
2673
2674 return this;
2675 }
2676
2677 void
2678 MNot::trySpecializeFloat32(TempAllocator &alloc)
2679 {
2680 MDefinition *in = input();
2681 if (!in->canProduceFloat32() && in->type() == MIRType_Float32)
2682 ConvertDefinitionToDouble<0>(alloc, in, this);
2683 }
2684
2685 void
2686 MBeta::printOpcode(FILE *fp) const
2687 {
2688 MDefinition::printOpcode(fp);
2689
2690 Sprinter sp(GetIonContext()->cx);
2691 sp.init();
2692 comparison_->print(sp);
2693 fprintf(fp, " %s", sp.string());
2694 }
2695
2696 bool
2697 MNewObject::shouldUseVM() const
2698 {
2699 return templateObject()->hasSingletonType() ||
2700 templateObject()->hasDynamicSlots();
2701 }
2702
2703 bool
2704 MNewArray::shouldUseVM() const
2705 {
2706 JS_ASSERT(count() < JSObject::NELEMENTS_LIMIT);
2707
2708 size_t arraySlots =
2709 gc::GetGCKindSlots(templateObject()->tenuredGetAllocKind()) - ObjectElements::VALUES_PER_HEADER;
2710
2711 // Allocate space using the VMCall
2712 // when mir hints it needs to get allocated immediately,
2713 // but only when data doesn't fit the available array slots.
2714 bool allocating = isAllocating() && count() > arraySlots;
2715
2716 return templateObject()->hasSingletonType() || allocating;
2717 }
2718
2719 bool
2720 MLoadFixedSlot::mightAlias(const MDefinition *store) const
2721 {
2722 if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot())
2723 return false;
2724 return true;
2725 }
2726
2727 bool
2728 MAsmJSLoadHeap::mightAlias(const MDefinition *def) const
2729 {
2730 if (def->isAsmJSStoreHeap()) {
2731 const MAsmJSStoreHeap *store = def->toAsmJSStoreHeap();
2732 if (store->viewType() != viewType())
2733 return true;
2734 if (!ptr()->isConstant() || !store->ptr()->isConstant())
2735 return true;
2736 const MConstant *otherPtr = store->ptr()->toConstant();
2737 return ptr()->toConstant()->value() == otherPtr->value();
2738 }
2739 return true;
2740 }
2741
2742 bool
2743 MAsmJSLoadHeap::congruentTo(const MDefinition *ins) const
2744 {
2745 if (!ins->isAsmJSLoadHeap())
2746 return false;
2747 const MAsmJSLoadHeap *load = ins->toAsmJSLoadHeap();
2748 return load->viewType() == viewType() && congruentIfOperandsEqual(load);
2749 }
2750
2751 bool
2752 MAsmJSLoadGlobalVar::mightAlias(const MDefinition *def) const
2753 {
2754 if (def->isAsmJSStoreGlobalVar()) {
2755 const MAsmJSStoreGlobalVar *store = def->toAsmJSStoreGlobalVar();
2756 return store->globalDataOffset() == globalDataOffset_;
2757 }
2758 return true;
2759 }
2760
2761 bool
2762 MAsmJSLoadGlobalVar::congruentTo(const MDefinition *ins) const
2763 {
2764 if (ins->isAsmJSLoadGlobalVar()) {
2765 const MAsmJSLoadGlobalVar *load = ins->toAsmJSLoadGlobalVar();
2766 return globalDataOffset_ == load->globalDataOffset_;
2767 }
2768 return false;
2769 }
2770
2771 bool
2772 MLoadSlot::mightAlias(const MDefinition *store) const
2773 {
2774 if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot())
2775 return false;
2776 return true;
2777 }
2778
2779 void
2780 InlinePropertyTable::trimTo(ObjectVector &targets, BoolVector &choiceSet)
2781 {
2782 for (size_t i = 0; i < targets.length(); i++) {
2783 // If the target was inlined, don't erase the entry.
2784 if (choiceSet[i])
2785 continue;
2786
2787 JSFunction *target = &targets[i]->as<JSFunction>();
2788
2789 // Eliminate all entries containing the vetoed function from the map.
2790 size_t j = 0;
2791 while (j < numEntries()) {
2792 if (entries_[j]->func == target)
2793 entries_.erase(&entries_[j]);
2794 else
2795 j++;
2796 }
2797 }
2798 }
2799
2800 void
2801 InlinePropertyTable::trimToTargets(ObjectVector &targets)
2802 {
2803 IonSpew(IonSpew_Inlining, "Got inlineable property cache with %d cases",
2804 (int)numEntries());
2805
2806 size_t i = 0;
2807 while (i < numEntries()) {
2808 bool foundFunc = false;
2809 for (size_t j = 0; j < targets.length(); j++) {
2810 if (entries_[i]->func == targets[j]) {
2811 foundFunc = true;
2812 break;
2813 }
2814 }
2815 if (!foundFunc)
2816 entries_.erase(&(entries_[i]));
2817 else
2818 i++;
2819 }
2820
2821 IonSpew(IonSpew_Inlining, "%d inlineable cases left after trimming to %d targets",
2822 (int)numEntries(), (int)targets.length());
2823 }
2824
2825 bool
2826 InlinePropertyTable::hasFunction(JSFunction *func) const
2827 {
2828 for (size_t i = 0; i < numEntries(); i++) {
2829 if (entries_[i]->func == func)
2830 return true;
2831 }
2832 return false;
2833 }
2834
2835 types::TemporaryTypeSet *
2836 InlinePropertyTable::buildTypeSetForFunction(JSFunction *func) const
2837 {
2838 LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
2839 types::TemporaryTypeSet *types = alloc->new_<types::TemporaryTypeSet>();
2840 if (!types)
2841 return nullptr;
2842 for (size_t i = 0; i < numEntries(); i++) {
2843 if (entries_[i]->func == func)
2844 types->addType(types::Type::ObjectType(entries_[i]->typeObj), alloc);
2845 }
2846 return types;
2847 }
2848
2849 void *
2850 MLoadTypedArrayElementStatic::base() const
2851 {
2852 return typedArray_->viewData();
2853 }
2854
2855 size_t
2856 MLoadTypedArrayElementStatic::length() const
2857 {
2858 return typedArray_->byteLength();
2859 }
2860
2861 void *
2862 MStoreTypedArrayElementStatic::base() const
2863 {
2864 return typedArray_->viewData();
2865 }
2866
2867 bool
2868 MGetElementCache::allowDoubleResult() const
2869 {
2870 if (!resultTypeSet())
2871 return true;
2872
2873 return resultTypeSet()->hasType(types::Type::DoubleType());
2874 }
2875
2876 size_t
2877 MStoreTypedArrayElementStatic::length() const
2878 {
2879 return typedArray_->byteLength();
2880 }
2881
2882 bool
2883 MGetPropertyPolymorphic::mightAlias(const MDefinition *store) const
2884 {
2885 // Allow hoisting this instruction if the store does not write to a
2886 // slot read by this instruction.
2887
2888 if (!store->isStoreFixedSlot() && !store->isStoreSlot())
2889 return true;
2890
2891 for (size_t i = 0; i < numShapes(); i++) {
2892 const Shape *shape = this->shape(i);
2893 if (shape->slot() < shape->numFixedSlots()) {
2894 // Fixed slot.
2895 uint32_t slot = shape->slot();
2896 if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot)
2897 continue;
2898 if (store->isStoreSlot())
2899 continue;
2900 } else {
2901 // Dynamic slot.
2902 uint32_t slot = shape->slot() - shape->numFixedSlots();
2903 if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot)
2904 continue;
2905 if (store->isStoreFixedSlot())
2906 continue;
2907 }
2908
2909 return true;
2910 }
2911
2912 return false;
2913 }
2914
2915 void
2916 MGetPropertyCache::setBlock(MBasicBlock *block)
2917 {
2918 MDefinition::setBlock(block);
2919 // Track where we started.
2920 if (!location_.pc) {
2921 location_.pc = block->trackedPc();
2922 location_.script = block->info().script();
2923 }
2924 }
2925
2926 bool
2927 MGetPropertyCache::updateForReplacement(MDefinition *ins) {
2928 MGetPropertyCache *other = ins->toGetPropertyCache();
2929 location_.append(&other->location_);
2930 return true;
2931 }
2932
2933 MDefinition *
2934 MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2935 {
2936 if (input()->isConstant()) {
2937 const Value &v = input()->toConstant()->value();
2938 if (v.isInt32())
2939 return MConstant::New(alloc, DoubleValue(uint32_t(v.toInt32())));
2940 }
2941
2942 return this;
2943 }
2944
2945 MDefinition *
2946 MAsmJSUnsignedToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
2947 {
2948 if (input()->isConstant()) {
2949 const Value &v = input()->toConstant()->value();
2950 if (v.isInt32()) {
2951 double dval = double(uint32_t(v.toInt32()));
2952 if (IsFloat32Representable(dval))
2953 return MConstant::NewAsmJS(alloc, JS::Float32Value(float(dval)), MIRType_Float32);
2954 }
2955 }
2956
2957 return this;
2958 }
2959
2960 MAsmJSCall *
2961 MAsmJSCall::New(TempAllocator &alloc, const CallSiteDesc &desc, Callee callee,
2962 const Args &args, MIRType resultType, size_t spIncrement)
2963 {
2964 MAsmJSCall *call = new(alloc) MAsmJSCall(desc, callee, spIncrement);
2965 call->setResultType(resultType);
2966
2967 if (!call->argRegs_.init(alloc, args.length()))
2968 return nullptr;
2969 for (size_t i = 0; i < call->argRegs_.length(); i++)
2970 call->argRegs_[i] = args[i].reg;
2971
2972 if (!call->operands_.init(alloc, call->argRegs_.length() + (callee.which() == Callee::Dynamic ? 1 : 0)))
2973 return nullptr;
2974 for (size_t i = 0; i < call->argRegs_.length(); i++)
2975 call->setOperand(i, args[i].def);
2976 if (callee.which() == Callee::Dynamic)
2977 call->setOperand(call->argRegs_.length(), callee.dynamic());
2978
2979 return call;
2980 }
2981
2982 void
2983 MSqrt::trySpecializeFloat32(TempAllocator &alloc) {
2984 if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) {
2985 if (input()->type() == MIRType_Float32)
2986 ConvertDefinitionToDouble<0>(alloc, input(), this);
2987 return;
2988 }
2989
2990 setResultType(MIRType_Float32);
2991 setPolicyType(MIRType_Float32);
2992 }
2993
2994 bool
2995 jit::ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id)
2996 {
2997 if (obj->mightBeType(MIRType_String))
2998 return false;
2999
3000 if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
3001 return false;
3002
3003 types::TemporaryTypeSet *types = obj->resultTypeSet();
3004 if (!types)
3005 return false;
3006
3007 // Typed arrays are native classes but do not have dense elements.
3008 const Class *clasp = types->getKnownClass();
3009 return clasp && clasp->isNative() && !IsTypedArrayClass(clasp);
3010 }
3011
3012 bool
3013 jit::ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id,
3014 ScalarTypeDescr::Type *arrayType)
3015 {
3016 if (obj->mightBeType(MIRType_String))
3017 return false;
3018
3019 if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
3020 return false;
3021
3022 types::TemporaryTypeSet *types = obj->resultTypeSet();
3023 if (!types)
3024 return false;
3025
3026 *arrayType = (ScalarTypeDescr::Type) types->getTypedArrayType();
3027 return *arrayType != ScalarTypeDescr::TYPE_MAX;
3028 }
3029
3030 bool
3031 jit::ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefinition *obj)
3032 {
3033 types::TemporaryTypeSet *types = obj->resultTypeSet();
3034 return types && !types->hasObjectFlags(constraints, types::OBJECT_FLAG_NON_PACKED);
3035 }
3036
3037 bool
3038 jit::ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints,
3039 MDefinition *obj)
3040 {
3041 types::TemporaryTypeSet *types = obj->resultTypeSet();
3042
3043 if (!types || types->hasObjectFlags(constraints, types::OBJECT_FLAG_LENGTH_OVERFLOW))
3044 return true;
3045
3046 return types::TypeCanHaveExtraIndexedProperties(constraints, types);
3047 }
3048
3049 MIRType
3050 jit::DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj)
3051 {
3052 types::TemporaryTypeSet *types = obj->resultTypeSet();
3053 MIRType elementType = MIRType_None;
3054 unsigned count = types->getObjectCount();
3055
3056 for (unsigned i = 0; i < count; i++) {
3057 types::TypeObjectKey *object = types->getObject(i);
3058 if (!object)
3059 continue;
3060
3061 if (object->unknownProperties())
3062 return MIRType_None;
3063
3064 types::HeapTypeSetKey elementTypes = object->property(JSID_VOID);
3065
3066 MIRType type = elementTypes.knownMIRType(constraints);
3067 if (type == MIRType_None)
3068 return MIRType_None;
3069
3070 if (elementType == MIRType_None)
3071 elementType = type;
3072 else if (elementType != type)
3073 return MIRType_None;
3074 }
3075
3076 return elementType;
3077 }
3078
3079 static bool
3080 PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints,
3081 types::TypeObjectKey *object, PropertyName *name,
3082 types::TypeSet *observed)
3083 {
3084 // If the object being read from has types for the property which haven't
3085 // been observed at this access site, the read could produce a new type and
3086 // a barrier is needed. Note that this only covers reads from properties
3087 // which are accounted for by type information, i.e. native data properties
3088 // and elements.
3089 //
3090 // We also need a barrier if the object is a proxy, because then all bets
3091 // are off, just as if it has unknown properties.
3092 if (object->unknownProperties() || observed->empty() ||
3093 object->clasp()->isProxy())
3094 {
3095 return true;
3096 }
3097
3098 jsid id = name ? NameToId(name) : JSID_VOID;
3099 types::HeapTypeSetKey property = object->property(id);
3100 if (property.maybeTypes() && !TypeSetIncludes(observed, MIRType_Value, property.maybeTypes()))
3101 return true;
3102
3103 // Type information for global objects is not required to reflect the
3104 // initial 'undefined' value for properties, in particular global
3105 // variables declared with 'var'. Until the property is assigned a value
3106 // other than undefined, a barrier is required.
3107 if (JSObject *obj = object->singleton()) {
3108 if (name && types::CanHaveEmptyPropertyTypesForOwnProperty(obj) &&
3109 (!property.maybeTypes() || property.maybeTypes()->empty()))
3110 {
3111 return true;
3112 }
3113 }
3114
3115 property.freeze(constraints);
3116 return false;
3117 }
3118
3119 bool
3120 jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
3121 types::CompilerConstraintList *constraints,
3122 types::TypeObjectKey *object, PropertyName *name,
3123 types::TemporaryTypeSet *observed, bool updateObserved)
3124 {
3125 // If this access has never executed, try to add types to the observed set
3126 // according to any property which exists on the object or its prototype.
3127 if (updateObserved && observed->empty() && name) {
3128 JSObject *obj;
3129 if (object->singleton())
3130 obj = object->singleton();
3131 else if (object->hasTenuredProto())
3132 obj = object->proto().toObjectOrNull();
3133 else
3134 obj = nullptr;
3135
3136 while (obj) {
3137 if (!obj->getClass()->isNative())
3138 break;
3139
3140 types::TypeObjectKey *typeObj = types::TypeObjectKey::get(obj);
3141 if (propertycx)
3142 typeObj->ensureTrackedProperty(propertycx, NameToId(name));
3143
3144 if (!typeObj->unknownProperties()) {
3145 types::HeapTypeSetKey property = typeObj->property(NameToId(name));
3146 if (property.maybeTypes()) {
3147 types::TypeSet::TypeList types;
3148 if (!property.maybeTypes()->enumerateTypes(&types))
3149 break;
3150 if (types.length()) {
3151 // Note: the return value here is ignored.
3152 observed->addType(types[0], GetIonContext()->temp->lifoAlloc());
3153 break;
3154 }
3155 }
3156 }
3157
3158 if (!obj->hasTenuredProto())
3159 break;
3160 obj = obj->getProto();
3161 }
3162 }
3163
3164 return PropertyReadNeedsTypeBarrier(constraints, object, name, observed);
3165 }
3166
3167 bool
3168 jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
3169 types::CompilerConstraintList *constraints,
3170 MDefinition *obj, PropertyName *name,
3171 types::TemporaryTypeSet *observed)
3172 {
3173 if (observed->unknown())
3174 return false;
3175
3176 types::TypeSet *types = obj->resultTypeSet();
3177 if (!types || types->unknownObject())
3178 return true;
3179
3180 bool updateObserved = types->getObjectCount() == 1;
3181 for (size_t i = 0; i < types->getObjectCount(); i++) {
3182 types::TypeObjectKey *object = types->getObject(i);
3183 if (object) {
3184 if (PropertyReadNeedsTypeBarrier(propertycx, constraints, object, name,
3185 observed, updateObserved))
3186 {
3187 return true;
3188 }
3189 }
3190 }
3191
3192 return false;
3193 }
3194
3195 bool
3196 jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints,
3197 MDefinition *obj, PropertyName *name,
3198 types::TemporaryTypeSet *observed)
3199 {
3200 if (observed->unknown())
3201 return false;
3202
3203 types::TypeSet *types = obj->resultTypeSet();
3204 if (!types || types->unknownObject())
3205 return true;
3206
3207 for (size_t i = 0; i < types->getObjectCount(); i++) {
3208 types::TypeObjectKey *object = types->getObject(i);
3209 if (!object)
3210 continue;
3211 while (true) {
3212 if (!object->hasTenuredProto())
3213 return true;
3214 if (!object->proto().isObject())
3215 break;
3216 object = types::TypeObjectKey::get(object->proto().toObject());
3217 if (PropertyReadNeedsTypeBarrier(constraints, object, name, observed))
3218 return true;
3219 }
3220 }
3221
3222 return false;
3223 }
3224
3225 bool
3226 jit::PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
3227 MDefinition *obj, PropertyName *name)
3228 {
3229 // Determine if reading a property from obj is likely to be idempotent.
3230
3231 types::TypeSet *types = obj->resultTypeSet();
3232 if (!types || types->unknownObject())
3233 return false;
3234
3235 for (size_t i = 0; i < types->getObjectCount(); i++) {
3236 types::TypeObjectKey *object = types->getObject(i);
3237 if (object) {
3238 if (object->unknownProperties())
3239 return false;
3240
3241 // Check if the property has been reconfigured or is a getter.
3242 types::HeapTypeSetKey property = object->property(NameToId(name));
3243 if (property.nonData(constraints))
3244 return false;
3245 }
3246 }
3247
3248 return true;
3249 }
3250
3251 void
3252 jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
3253 types::TemporaryTypeSet *observed)
3254 {
3255 // Add objects to observed which *could* be observed by reading name from obj,
3256 // to hopefully avoid unnecessary type barriers and code invalidations.
3257
3258 LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
3259
3260 types::TemporaryTypeSet *types = obj->resultTypeSet();
3261 if (!types || types->unknownObject()) {
3262 observed->addType(types::Type::AnyObjectType(), alloc);
3263 return;
3264 }
3265
3266 for (size_t i = 0; i < types->getObjectCount(); i++) {
3267 types::TypeObjectKey *object = types->getObject(i);
3268 if (!object)
3269 continue;
3270
3271 if (object->unknownProperties()) {
3272 observed->addType(types::Type::AnyObjectType(), alloc);
3273 return;
3274 }
3275
3276 jsid id = name ? NameToId(name) : JSID_VOID;
3277 types::HeapTypeSetKey property = object->property(id);
3278 types::HeapTypeSet *types = property.maybeTypes();
3279 if (!types)
3280 continue;
3281
3282 if (types->unknownObject()) {
3283 observed->addType(types::Type::AnyObjectType(), alloc);
3284 return;
3285 }
3286
3287 for (size_t i = 0; i < types->getObjectCount(); i++) {
3288 types::TypeObjectKey *object = types->getObject(i);
3289 if (object)
3290 observed->addType(types::Type::ObjectType(object), alloc);
3291 }
3292 }
3293 }
3294
3295 static bool
3296 TryAddTypeBarrierForWrite(TempAllocator &alloc, types::CompilerConstraintList *constraints,
3297 MBasicBlock *current, types::TemporaryTypeSet *objTypes,
3298 PropertyName *name, MDefinition **pvalue)
3299 {
3300 // Return whether pvalue was modified to include a type barrier ensuring
3301 // that writing the value to objTypes/id will not require changing type
3302 // information.
3303
3304 // All objects in the set must have the same types for name. Otherwise, we
3305 // could bail out without subsequently triggering a type change that
3306 // invalidates the compiled code.
3307 Maybe<types::HeapTypeSetKey> aggregateProperty;
3308
3309 for (size_t i = 0; i < objTypes->getObjectCount(); i++) {
3310 types::TypeObjectKey *object = objTypes->getObject(i);
3311 if (!object)
3312 continue;
3313
3314 if (object->unknownProperties())
3315 return false;
3316
3317 jsid id = name ? NameToId(name) : JSID_VOID;
3318 types::HeapTypeSetKey property = object->property(id);
3319 if (!property.maybeTypes())
3320 return false;
3321
3322 if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet()))
3323 return false;
3324
3325 // This freeze is not required for correctness, but ensures that we
3326 // will recompile if the property types change and the barrier can
3327 // potentially be removed.
3328 property.freeze(constraints);
3329
3330 if (aggregateProperty.empty()) {
3331 aggregateProperty.construct(property);
3332 } else {
3333 if (!aggregateProperty.ref().maybeTypes()->isSubset(property.maybeTypes()) ||
3334 !property.maybeTypes()->isSubset(aggregateProperty.ref().maybeTypes()))
3335 {
3336 return false;
3337 }
3338 }
3339 }
3340
3341 JS_ASSERT(!aggregateProperty.empty());
3342
3343 MIRType propertyType = aggregateProperty.ref().knownMIRType(constraints);
3344 switch (propertyType) {
3345 case MIRType_Boolean:
3346 case MIRType_Int32:
3347 case MIRType_Double:
3348 case MIRType_String: {
3349 // The property is a particular primitive type, guard by unboxing the
3350 // value before the write.
3351 if (!(*pvalue)->mightBeType(propertyType)) {
3352 // The value's type does not match the property type. Just do a VM
3353 // call as it will always trigger invalidation of the compiled code.
3354 JS_ASSERT_IF((*pvalue)->type() != MIRType_Value, (*pvalue)->type() != propertyType);
3355 return false;
3356 }
3357 MInstruction *ins = MUnbox::New(alloc, *pvalue, propertyType, MUnbox::Fallible);
3358 current->add(ins);
3359 *pvalue = ins;
3360 return true;
3361 }
3362 default:;
3363 }
3364
3365 if ((*pvalue)->type() != MIRType_Value)
3366 return false;
3367
3368 types::TemporaryTypeSet *types = aggregateProperty.ref().maybeTypes()->clone(alloc.lifoAlloc());
3369 if (!types)
3370 return false;
3371
3372 MInstruction *ins = MMonitorTypes::New(alloc, *pvalue, types);
3373 current->add(ins);
3374 return true;
3375 }
3376
3377 static MInstruction *
3378 AddTypeGuard(TempAllocator &alloc, MBasicBlock *current, MDefinition *obj,
3379 types::TypeObjectKey *type, bool bailOnEquality)
3380 {
3381 MInstruction *guard;
3382
3383 if (type->isTypeObject())
3384 guard = MGuardObjectType::New(alloc, obj, type->asTypeObject(), bailOnEquality);
3385 else
3386 guard = MGuardObjectIdentity::New(alloc, obj, type->asSingleObject(), bailOnEquality);
3387
3388 current->add(guard);
3389
3390 // For now, never move type object guards.
3391 guard->setNotMovable();
3392
3393 return guard;
3394 }
3395
3396 bool
3397 jit::PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstraintList *constraints,
3398 MBasicBlock *current, MDefinition **pobj,
3399 PropertyName *name, MDefinition **pvalue, bool canModify)
3400 {
3401 // If any value being written is not reflected in the type information for
3402 // objects which obj could represent, a type barrier is needed when writing
3403 // the value. As for propertyReadNeedsTypeBarrier, this only applies for
3404 // properties that are accounted for by type information, i.e. normal data
3405 // properties and elements.
3406
3407 types::TemporaryTypeSet *types = (*pobj)->resultTypeSet();
3408 if (!types || types->unknownObject())
3409 return true;
3410
3411 // If all of the objects being written to have property types which already
3412 // reflect the value, no barrier at all is needed. Additionally, if all
3413 // objects being written to have the same types for the property, and those
3414 // types do *not* reflect the value, add a type barrier for the value.
3415
3416 bool success = true;
3417 for (size_t i = 0; i < types->getObjectCount(); i++) {
3418 types::TypeObjectKey *object = types->getObject(i);
3419 if (!object || object->unknownProperties())
3420 continue;
3421
3422 // TI doesn't track TypedArray objects and should never insert a type
3423 // barrier for them.
3424 if (!name && IsTypedArrayClass(object->clasp()))
3425 continue;
3426
3427 jsid id = name ? NameToId(name) : JSID_VOID;
3428 types::HeapTypeSetKey property = object->property(id);
3429 if (!TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet())) {
3430 // Either pobj or pvalue needs to be modified to filter out the
3431 // types which the value could have but are not in the property,
3432 // or a VM call is required. A VM call is always required if pobj
3433 // and pvalue cannot be modified.
3434 if (!canModify)
3435 return true;
3436 success = TryAddTypeBarrierForWrite(alloc, constraints, current, types, name, pvalue);
3437 break;
3438 }
3439 }
3440
3441 if (success)
3442 return false;
3443
3444 // If all of the objects except one have property types which reflect the
3445 // value, and the remaining object has no types at all for the property,
3446 // add a guard that the object does not have that remaining object's type.
3447
3448 if (types->getObjectCount() <= 1)
3449 return true;
3450
3451 types::TypeObjectKey *excluded = nullptr;
3452 for (size_t i = 0; i < types->getObjectCount(); i++) {
3453 types::TypeObjectKey *object = types->getObject(i);
3454 if (!object || object->unknownProperties())
3455 continue;
3456 if (!name && IsTypedArrayClass(object->clasp()))
3457 continue;
3458
3459 jsid id = name ? NameToId(name) : JSID_VOID;
3460 types::HeapTypeSetKey property = object->property(id);
3461 if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet()))
3462 continue;
3463
3464 if ((property.maybeTypes() && !property.maybeTypes()->empty()) || excluded)
3465 return true;
3466 excluded = object;
3467 }
3468
3469 JS_ASSERT(excluded);
3470
3471 *pobj = AddTypeGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true);
3472 return false;
3473 }

mercurial