js/src/jit/MIR.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     7 #include "jit/MIR.h"
     9 #include "mozilla/FloatingPoint.h"
    11 #include <ctype.h>
    13 #include "jslibmath.h"
    14 #include "jsstr.h"
    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"
    22 #include "jsatominlines.h"
    23 #include "jsinferinlines.h"
    24 #include "jsobjinlines.h"
    26 using namespace js;
    27 using namespace js::jit;
    29 using mozilla::NumbersAreIdentical;
    30 using mozilla::IsFloat32Representable;
    31 using mozilla::Maybe;
    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 }
    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 }
    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 }
    65 static inline bool
    66 EqualValues(bool useGVN, MDefinition *left, MDefinition *right)
    67 {
    68     if (useGVN)
    69         return left->valueNumber() == right->valueNumber();
    71     return left == right;
    72 }
    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);
    80     if (!left->isConstant() || !right->isConstant())
    81         return nullptr;
    83     Value lhs = left->toConstant()->value();
    84     Value rhs = right->toConstant()->value();
    85     Value ret = UndefinedValue();
    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     }
   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());
   130     if (ins->type() != MIRTypeFromValue(ret)) {
   131         if (ptypeChange)
   132             *ptypeChange = true;
   133         return nullptr;
   134     }
   136     return MConstant::New(alloc, ret);
   137 }
   139 void
   140 MDefinition::printName(FILE *fp) const
   141 {
   142     PrintOpcodeName(fp, op());
   143     fprintf(fp, "%u", id());
   145     if (valueNumber() != 0)
   146         fprintf(fp, "-vn%u", valueNumber());
   147 }
   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 }
   160 bool
   161 MDefinition::congruentIfOperandsEqual(const MDefinition *ins) const
   162 {
   163     if (op() != ins->op())
   164         return false;
   166     if (type() != ins->type())
   167         return false;
   169     if (isEffectful() || ins->isEffectful())
   170         return false;
   172     if (numOperands() != ins->numOperands())
   173         return false;
   175     for (size_t i = 0, e = numOperands(); i < e; i++) {
   176         if (getOperand(i)->valueNumber() != ins->getOperand(i)->valueNumber())
   177             return false;
   178     }
   180     return true;
   181 }
   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 }
   190 void
   191 MDefinition::analyzeEdgeCasesForward()
   192 {
   193 }
   195 void
   196 MDefinition::analyzeEdgeCasesBackward()
   197 {
   198 }
   200 static bool
   201 MaybeEmulatesUndefined(MDefinition *op)
   202 {
   203     if (!op->mightBeType(MIRType_Object))
   204         return false;
   206     types::TemporaryTypeSet *types = op->resultTypeSet();
   207     if (!types)
   208         return true;
   210     return types->maybeEmulatesUndefined();
   211 }
   213 static bool
   214 MaybeCallable(MDefinition *op)
   215 {
   216     if (!op->mightBeType(MIRType_Object))
   217         return false;
   219     types::TemporaryTypeSet *types = op->resultTypeSet();
   220     if (!types)
   221         return true;
   223     return types->maybeCallable();
   224 }
   226 MTest *
   227 MTest::New(TempAllocator &alloc, MDefinition *ins, MBasicBlock *ifTrue, MBasicBlock *ifFalse)
   228 {
   229     return new(alloc) MTest(ins, ifTrue, ifFalse);
   230 }
   232 void
   233 MTest::infer()
   234 {
   235     JS_ASSERT(operandMightEmulateUndefined());
   237     if (!MaybeEmulatesUndefined(getOperand(0)))
   238         markOperandCantEmulateUndefined();
   239 }
   241 MDefinition *
   242 MTest::foldsTo(TempAllocator &alloc, bool useValueNumbers)
   243 {
   244     MDefinition *op = getOperand(0);
   246     if (op->isNot())
   247         return MTest::New(alloc, op->toNot()->operand(), ifFalse(), ifTrue());
   249     return this;
   250 }
   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     }
   262     if (!trueBranch && ins->isNot()) {
   263         *subject = ins->getOperand(0);
   264         *filtersUndefined = *filtersNull = true;
   265         return;
   266     }
   268     if (trueBranch) {
   269         *subject = ins;
   270         *filtersUndefined = *filtersNull = true;
   271         return;
   272     }
   274     *filtersUndefined = *filtersNull = false;
   275     *subject = nullptr;
   276 }
   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 }
   288 void
   289 MDefinition::dump(FILE *fp) const
   290 {
   291     printName(fp);
   292     fprintf(fp, " = ");
   293     printOpcode(fp);
   294     fprintf(fp, "\n");
   295 }
   297 void
   298 MDefinition::dump() const
   299 {
   300     dump(stderr);
   301 }
   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 }
   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 }
   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 }
   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;
   340         // We already have a definition use. So 1+
   341         if (hasOneDefUse)
   342             return false;
   344         // We saw one definition. Loop to test if there is another.
   345         hasOneDefUse = true;
   346     }
   348     return hasOneDefUse;
   349 }
   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     }
   359     return false;
   360 }
   362 MUseIterator
   363 MDefinition::removeUse(MUseIterator use)
   364 {
   365     return uses_.removeAt(use);
   366 }
   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();
   375     JS_ASSERT(use->index() < numOperands());
   376     JS_ASSERT(use->producer() == getOperand(index));
   377     JS_ASSERT(use->consumer() == this);
   379     if (prev == def)
   380         return use;
   382     MUseIterator result(prev->removeUse(use));
   383     setOperand(index, def);
   384     return result;
   385 }
   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();
   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);
   399     if (prev == def)
   400         return;
   402     prev->removeUse(use);
   403     setOperand(index, def);
   404 }
   406 void
   407 MNode::discardOperand(size_t index)
   408 {
   409     MUse *use = getUseFor(index);
   411     JS_ASSERT(use->index() == index);
   412     JS_ASSERT(use->producer() == getOperand(index));
   413     JS_ASSERT(use->consumer() == this);
   415     use->producer()->removeUse(use);
   417 #ifdef DEBUG
   418     // Causes any producer/consumer lookups to trip asserts.
   419     use->set(nullptr, nullptr, index);
   420 #endif
   421 }
   423 void
   424 MDefinition::replaceAllUsesWith(MDefinition *dom)
   425 {
   426     JS_ASSERT(dom != nullptr);
   427     if (dom == this)
   428         return;
   430     for (size_t i = 0, e = numOperands(); i < e; i++)
   431         getOperand(i)->setUseRemovedUnchecked();
   433     for (MUseIterator i(usesBegin()); i != usesEnd(); ) {
   434         JS_ASSERT(i->producer() == this);
   435         i = i->consumer()->replaceOperand(i, dom);
   436     }
   437 }
   439 bool
   440 MDefinition::emptyResultTypeSet() const
   441 {
   442     return resultTypeSet() && resultTypeSet()->empty();
   443 }
   445 MConstant *
   446 MConstant::New(TempAllocator &alloc, const Value &v, types::CompilerConstraintList *constraints)
   447 {
   448     return new(alloc) MConstant(v, constraints);
   449 }
   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 }
   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);
   470     return GetIonContext()->temp->lifoAlloc()->new_<types::TemporaryTypeSet>(types::Type::ObjectType(obj));
   471 }
   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     }
   483     setMovable();
   484 }
   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 }
   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 }
   568 bool
   569 MConstant::canProduceFloat32() const
   570 {
   571     if (!IsNumberType(type()))
   572         return false;
   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 }
   581 MCloneLiteral *
   582 MCloneLiteral::New(TempAllocator &alloc, MDefinition *obj)
   583 {
   584     return new(alloc) MCloneLiteral(obj);
   585 }
   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 }
   595 void
   596 MCompare::printOpcode(FILE *fp) const
   597 {
   598     MDefinition::printOpcode(fp);
   599     fprintf(fp, " %s", js_CodeName[jsop()]);
   600 }
   602 void
   603 MConstantElements::printOpcode(FILE *fp) const
   604 {
   605     PrintOpcodeName(fp, op());
   606     fprintf(fp, " %p", value());
   607 }
   609 void
   610 MLoadTypedArrayElement::printOpcode(FILE *fp) const
   611 {
   612     MDefinition::printOpcode(fp);
   613     fprintf(fp, " %s", ScalarTypeDescr::typeName(arrayType()));
   614 }
   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 }
   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 }
   659 void
   660 MMathFunction::printOpcode(FILE *fp) const
   661 {
   662     MDefinition::printOpcode(fp);
   663     fprintf(fp, " %s", FunctionName(function()));
   664 }
   666 MParameter *
   667 MParameter::New(TempAllocator &alloc, int32_t index, types::TemporaryTypeSet *types)
   668 {
   669     return new(alloc) MParameter(index, types);
   670 }
   672 void
   673 MParameter::printOpcode(FILE *fp) const
   674 {
   675     PrintOpcodeName(fp, op());
   676     fprintf(fp, " %d", index());
   677 }
   679 HashNumber
   680 MParameter::valueHash() const
   681 {
   682     return index_; // Why not?
   683 }
   685 bool
   686 MParameter::congruentTo(const MDefinition *ins) const
   687 {
   688     if (!ins->isParameter())
   689         return false;
   691     return ins->toParameter()->index() == index_;
   692 }
   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 }
   711 AliasSet
   712 MCallDOMNative::getAliasSet() const
   713 {
   714     const JSJitInfo *jitInfo = getJitInfo();
   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);
   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     }
   751     // We checked all the args, and they check out.  So we only
   752     // alias DOM mutations.
   753     return AliasSet::Load(AliasSet::DOMProperty);
   754 }
   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();
   764     JS_ASSERT_IF(jitInfo->isMovable,
   765                  jitInfo->aliasSet() != JSJitInfo::AliasEverything);
   767     if (jitInfo->isMovable && !isEffectful())
   768         setMovable();
   769 }
   771 bool
   772 MCallDOMNative::congruentTo(const MDefinition *ins) const
   773 {
   774     if (!isMovable())
   775         return false;
   777     if (!ins->isCall())
   778         return false;
   780     const MCall *call = ins->toCall();
   782     if (!call->isCallDOMNative())
   783         return false;
   785     if (getSingleTarget() != call->getSingleTarget())
   786         return false;
   788     if (isConstructing() != call->isConstructing())
   789         return false;
   791     if (numActualArgs() != call->numActualArgs())
   792         return false;
   794     if (needsArgCheck() != call->needsArgCheck())
   795         return false;
   797     if (!congruentIfOperandsEqual(call))
   798         return false;
   800     // The other call had better be movable at this point!
   801     JS_ASSERT(call->isMovable());
   803     return true;
   804 }
   806 const JSJitInfo *
   807 MCallDOMNative::getJitInfo() const
   808 {
   809     JS_ASSERT(getSingleTarget() && getSingleTarget()->isNative());
   811     const JSJitInfo *jitInfo = getSingleTarget()->jitInfo();
   812     JS_ASSERT(jitInfo);
   814     return jitInfo;
   815 }
   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 }
   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     }
   833     return this;
   834 }
   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     }
   846     if (type() == MIRType_Double)
   847         setResultType(MIRType_Float32);
   849     setPolicyType(MIRType_Float32);
   850 }
   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);
   859     if (!input()->canProduceFloat32()) {
   860         if (input()->type() == MIRType_Float32)
   861             ConvertDefinitionToDouble<0>(alloc, input(), this);
   862         return;
   863     }
   865     setPolicyType(MIRType_Float32);
   866 }
   868 MCompare *
   869 MCompare::New(TempAllocator &alloc, MDefinition *left, MDefinition *right, JSOp op)
   870 {
   871     return new(alloc) MCompare(left, right, op);
   872 }
   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 }
   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 }
   893 MGoto *
   894 MGoto::New(TempAllocator &alloc, MBasicBlock *target)
   895 {
   896     JS_ASSERT(target);
   897     return new(alloc) MGoto(target);
   898 }
   900 void
   901 MUnbox::printOpcode(FILE *fp) const
   902 {
   903     PrintOpcodeName(fp, op());
   904     fprintf(fp, " ");
   905     getOperand(0)->printName(fp);
   906     fprintf(fp, " ");
   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     }
   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 }
   925 void
   926 MTypeBarrier::printOpcode(FILE *fp) const
   927 {
   928     PrintOpcodeName(fp, op());
   929     fprintf(fp, " ");
   930     getOperand(0)->printName(fp);
   931 }
   933 void
   934 MPhi::removeOperand(size_t index)
   935 {
   936     MUse *use = getUseFor(index);
   938     JS_ASSERT(index < inputs_.length());
   939     JS_ASSERT(inputs_.length() > 1);
   941     JS_ASSERT(use->index() == index);
   942     JS_ASSERT(use->producer() == getOperand(index));
   943     JS_ASSERT(use->consumer() == this);
   945     // Remove use from producer's use chain.
   946     use->producer()->removeUse(use);
   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     }
   958     // truncate the inputs_ list:
   959     inputs_.shrinkBy(1);
   960 }
   962 MDefinition *
   963 MPhi::foldsTo(TempAllocator &alloc, bool useValueNumbers)
   964 {
   965     JS_ASSERT(!inputs_.empty());
   967     MDefinition *first = getOperand(0);
   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     }
   976     return first;
   977 }
   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;
   990     return congruentIfOperandsEqual(ins);
   991 }
   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);
  1006 static inline types::TemporaryTypeSet *
  1007 MakeMIRTypeSet(MIRType type)
  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);
  1016 bool
  1017 jit::MergeTypes(MIRType *ptype, types::TemporaryTypeSet **ptypeSet,
  1018                 MIRType newType, types::TemporaryTypeSet *newTypeSet)
  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;
  1031             *ptype = MIRType_Value;
  1032         } else if (*ptypeSet && (*ptypeSet)->empty()) {
  1033             *ptype = newType;
  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;
  1043         if (newTypeSet) {
  1044             if (!newTypeSet->isSubset(*ptypeSet))
  1045                 *ptypeSet = types::TypeSet::unionSets(*ptypeSet, newTypeSet, alloc);
  1046         } else {
  1047             *ptypeSet = nullptr;
  1050     return true;
  1053 bool
  1054 MPhi::specializeType()
  1056 #ifdef DEBUG
  1057     JS_ASSERT(!specialized_);
  1058     specialized_ = true;
  1059 #endif
  1061     JS_ASSERT(!inputs_.empty());
  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;
  1074     MIRType resultType = this->type();
  1075     types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
  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;
  1083     setResultType(resultType);
  1084     setResultTypeSet(resultTypeSet);
  1085     return true;
  1088 bool
  1089 MPhi::addBackedgeType(MIRType type, types::TemporaryTypeSet *typeSet)
  1091     JS_ASSERT(!specialized_);
  1093     if (hasBackedgeType_) {
  1094         MIRType resultType = this->type();
  1095         types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
  1097         if (!MergeTypes(&resultType, &resultTypeSet, type, typeSet))
  1098             return false;
  1100         setResultType(resultType);
  1101         setResultTypeSet(resultTypeSet);
  1102     } else {
  1103         setResultType(type);
  1104         setResultTypeSet(typeSet);
  1105         hasBackedgeType_ = true;
  1107     return true;
  1110 bool
  1111 MPhi::typeIncludes(MDefinition *def)
  1113     if (def->type() == MIRType_Int32 && this->type() == MIRType_Double)
  1114         return true;
  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();
  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());
  1130     return this->mightBeType(def->type());
  1133 void
  1134 MPhi::addInput(MDefinition *ins)
  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_);
  1140     uint32_t index = inputs_.length();
  1141     inputs_.append(MUse());
  1142     MPhi::setOperand(index, ins);
  1145 bool
  1146 MPhi::addInputSlow(MDefinition *ins, bool *ptypeChange)
  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);
  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);
  1165     // Insert the new input.
  1166     if (!inputs_.append(MUse()))
  1167         return false;
  1169     MPhi::setOperand(index, ins);
  1171     if (ptypeChange) {
  1172         MIRType resultType = this->type();
  1173         types::TemporaryTypeSet *resultTypeSet = this->resultTypeSet();
  1175         if (!MergeTypes(&resultType, &resultTypeSet, ins->type(), ins->resultTypeSet()))
  1176             return false;
  1178         if (resultType != this->type() || resultTypeSet != this->resultTypeSet()) {
  1179             *ptypeChange = true;
  1180             setResultType(resultType);
  1181             setResultTypeSet(resultTypeSet);
  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);
  1193     return true;
  1196 void
  1197 MCall::addArg(size_t argnum, MDefinition *arg)
  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);
  1204 void
  1205 MBitNot::infer()
  1207     if (getOperand(0)->mightBeType(MIRType_Object))
  1208         specialization_ = MIRType_None;
  1209     else
  1210         specialization_ = MIRType_Int32;
  1213 static inline bool
  1214 IsConstant(MDefinition *def, double v)
  1216     if (!def->isConstant())
  1217         return false;
  1219     return NumbersAreIdentical(def->toConstant()->value().toNumber(), v);
  1222 MDefinition *
  1223 MBinaryBitwiseInstruction::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  1225     if (specialization_ != MIRType_Int32)
  1226         return this;
  1228     if (MDefinition *folded = EvaluateConstantOperands(alloc, this))
  1229         return folded;
  1231     return this;
  1234 MDefinition *
  1235 MBinaryBitwiseInstruction::foldUnnecessaryBitop()
  1237     if (specialization_ != MIRType_Int32)
  1238         return this;
  1240     // Eliminate bitwise operations that are no-ops when used on integer
  1241     // inputs, such as (x | 0).
  1243     MDefinition *lhs = getOperand(0);
  1244     MDefinition *rhs = getOperand(1);
  1246     if (IsConstant(lhs, 0))
  1247         return foldIfZero(0);
  1249     if (IsConstant(rhs, 0))
  1250         return foldIfZero(1);
  1252     if (IsConstant(lhs, -1))
  1253         return foldIfNegOne(0);
  1255     if (IsConstant(rhs, -1))
  1256         return foldIfNegOne(1);
  1258     if (EqualValues(false, lhs, rhs))
  1259         return foldIfEqual();
  1261     return this;
  1264 void
  1265 MBinaryBitwiseInstruction::infer(BaselineInspector *, jsbytecode *)
  1267     if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object))
  1268         specialization_ = MIRType_None;
  1269     else
  1270         specializeAsInt32();
  1273 void
  1274 MBinaryBitwiseInstruction::specializeAsInt32()
  1276     specialization_ = MIRType_Int32;
  1277     JS_ASSERT(type() == MIRType_Int32);
  1279     if (isBitOr() || isBitAnd() || isBitXor())
  1280         setCommutative();
  1283 void
  1284 MShiftInstruction::infer(BaselineInspector *, jsbytecode *)
  1286     if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object))
  1287         specialization_ = MIRType_None;
  1288     else
  1289         specialization_ = MIRType_Int32;
  1292 void
  1293 MUrsh::infer(BaselineInspector *inspector, jsbytecode *pc)
  1295     if (getOperand(0)->mightBeType(MIRType_Object) || getOperand(1)->mightBeType(MIRType_Object)) {
  1296         specialization_ = MIRType_None;
  1297         setResultType(MIRType_Value);
  1298         return;
  1301     if (inspector->hasSeenDoubleResult(pc)) {
  1302         specialization_ = MIRType_Double;
  1303         setResultType(MIRType_Double);
  1304         return;
  1307     specialization_ = MIRType_Int32;
  1308     setResultType(MIRType_Int32);
  1311 static inline bool
  1312 NeedNegativeZeroCheck(MDefinition *def)
  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;
  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;
  1326             // x + y gives -0, when both x and y are -0
  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;
  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;
  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;
  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;
  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;
  1411     return false;
  1414 MDefinition *
  1415 MBinaryArithInstruction::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  1417     if (specialization_ == MIRType_None)
  1418         return this;
  1420     MDefinition *lhs = getOperand(0);
  1421     MDefinition *rhs = getOperand(1);
  1422     if (MDefinition *folded = EvaluateConstantOperands(alloc, this))
  1423         return folded;
  1425     // 0 + -0 = 0. So we can't remove addition
  1426     if (isAdd() && specialization_ != MIRType_Int32)
  1427         return this;
  1429     if (IsConstant(rhs, getIdentity()))
  1430         return lhs;
  1432     // subtraction isn't commutative. So we can't remove subtraction when lhs equals 0
  1433     if (isSub())
  1434         return this;
  1436     if (IsConstant(lhs, getIdentity()))
  1437         return rhs; // x op id => x
  1439     return this;
  1442 void
  1443 MBinaryArithInstruction::trySpecializeFloat32(TempAllocator &alloc)
  1445     MDefinition *left = lhs();
  1446     MDefinition *right = rhs();
  1448     if (!left->canProduceFloat32() || !right->canProduceFloat32()
  1449         || !CheckUsesAreFloat32Consumers(this))
  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;
  1458     specialization_ = MIRType_Float32;
  1459     setResultType(MIRType_Float32);
  1462 bool
  1463 MAbs::fallible() const
  1465     return !implicitTruncate_ && (!range() || !range()->hasInt32Bounds());
  1468 void
  1469 MAbs::trySpecializeFloat32(TempAllocator &alloc)
  1471     if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) {
  1472         if (input()->type() == MIRType_Float32)
  1473             ConvertDefinitionToDouble<0>(alloc, input(), this);
  1474         return;
  1477     setResultType(MIRType_Float32);
  1478     specialization_ = MIRType_Float32;
  1481 MDefinition *
  1482 MDiv::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  1484     if (specialization_ == MIRType_None)
  1485         return this;
  1487     if (MDefinition *folded = EvaluateConstantOperands(alloc, this))
  1488         return folded;
  1490     return this;
  1493 void
  1494 MDiv::analyzeEdgeCasesForward()
  1496     // This is only meaningful when doing integer division.
  1497     if (specialization_ != MIRType_Int32)
  1498         return;
  1500     // Try removing divide by zero check
  1501     if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(0))
  1502         canBeDivideByZero_ = false;
  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;
  1509     // If rhs is a constant int != -1, likewise.
  1510     if (rhs()->isConstant() && !rhs()->toConstant()->value().isInt32(-1))
  1511         canBeNegativeOverflow_ = false;
  1513     // If lhs is != 0, then negative zero check can be skipped.
  1514     if (lhs()->isConstant() && !lhs()->toConstant()->value().isInt32(0))
  1515         setCanBeNegativeZero(false);
  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);
  1525 void
  1526 MDiv::analyzeEdgeCasesBackward()
  1528     if (canBeNegativeZero() && !NeedNegativeZeroCheck(this))
  1529         setCanBeNegativeZero(false);
  1532 bool
  1533 MDiv::fallible() const
  1535     return !isTruncated();
  1538 bool
  1539 MMod::canBeDivideByZero() const
  1541     JS_ASSERT(specialization_ == MIRType_Int32);
  1542     return !rhs()->isConstant() || rhs()->toConstant()->value().toInt32() == 0;
  1545 bool
  1546 MMod::canBePowerOfTwoDivisor() const
  1548     JS_ASSERT(specialization_ == MIRType_Int32);
  1550     if (!rhs()->isConstant())
  1551         return true;
  1553     int32_t i = rhs()->toConstant()->value().toInt32();
  1554     if (i <= 0 || !IsPowerOfTwo(i))
  1555         return false;
  1557     return true;
  1560 MDefinition *
  1561 MMod::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  1563     if (specialization_ == MIRType_None)
  1564         return this;
  1566     if (MDefinition *folded = EvaluateConstantOperands(alloc, this))
  1567         return folded;
  1569     return this;
  1572 bool
  1573 MMod::fallible() const
  1575     return !isTruncated() &&
  1576            (isUnsigned() || canBeDivideByZero() || canBeNegativeDividend());
  1579 void
  1580 MMathFunction::trySpecializeFloat32(TempAllocator &alloc)
  1582     if (!input()->canProduceFloat32() || !CheckUsesAreFloat32Consumers(this)) {
  1583         if (input()->type() == MIRType_Float32)
  1584             ConvertDefinitionToDouble<0>(alloc, input(), this);
  1585         return;
  1588     setResultType(MIRType_Float32);
  1589     setPolicyType(MIRType_Float32);
  1592 bool
  1593 MAdd::fallible() const
  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;
  1604 bool
  1605 MSub::fallible() const
  1607     // see comment in MAdd::fallible()
  1608     if (isTruncated())
  1609         return false;
  1610     if (range() && range()->hasInt32Bounds())
  1611         return false;
  1612     return true;
  1615 MDefinition *
  1616 MMul::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  1618     MDefinition *out = MBinaryArithInstruction::foldsTo(alloc, useValueNumbers);
  1619     if (out != this)
  1620         return out;
  1622     if (specialization() != MIRType_Int32)
  1623         return this;
  1625     if (EqualValues(useValueNumbers, lhs(), rhs()))
  1626         setCanBeNegativeZero(false);
  1628     return this;
  1631 void
  1632 MMul::analyzeEdgeCasesForward()
  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;
  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);
  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);
  1654 void
  1655 MMul::analyzeEdgeCasesBackward()
  1657     if (canBeNegativeZero() && !NeedNegativeZeroCheck(this))
  1658         setCanBeNegativeZero(false);
  1661 bool
  1662 MMul::updateForReplacement(MDefinition *ins_)
  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;
  1673 bool
  1674 MMul::canOverflow() const
  1676     if (isTruncated())
  1677         return false;
  1678     return !range() || !range()->hasInt32Bounds();
  1681 bool
  1682 MUrsh::fallible() const
  1684     if (bailoutsDisabled())
  1685         return false;
  1686     return !range() || !range()->hasInt32Bounds();
  1689 static inline bool
  1690 KnownNonStringPrimitive(MDefinition *op)
  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);
  1699 void
  1700 MBinaryArithInstruction::infer(TempAllocator &alloc, BaselineInspector *inspector, jsbytecode *pc)
  1702     JS_ASSERT(this->type() == MIRType_Value);
  1704     specialization_ = MIRType_None;
  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;
  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);
  1717     // Retrieve type information of lhs and rhs.
  1718     MIRType lhs = getOperand(0)->type();
  1719     MIRType rhs = getOperand(1)->type();
  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);
  1732     // If the operation has ever overflowed, use a double specialization.
  1733     if (inspector->hasSeenDoubleResult(pc))
  1734         setResultType(MIRType_Double);
  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);
  1745     JS_ASSERT(lhs < MIRType_String || lhs == MIRType_Value);
  1746     JS_ASSERT(rhs < MIRType_String || rhs == MIRType_Value);
  1748     MIRType rval = this->type();
  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;
  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;
  1765     specialization_ = rval;
  1767     if (isAdd() || isMul())
  1768         setCommutative();
  1769     setResultType(rval);
  1772 void
  1773 MBinaryArithInstruction::inferFallback(BaselineInspector *inspector,
  1774                                        jsbytecode *pc)
  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;
  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;
  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);
  1805 static bool
  1806 SafelyCoercesToDouble(MDefinition *op)
  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);
  1813 static bool
  1814 ObjectOrSimplePrimitive(MDefinition *op)
  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);
  1825 static bool
  1826 CanDoValueBitwiseCmp(MDefinition *lhs, MDefinition *rhs, bool looseEq)
  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;
  1833     // Objects that emulate undefined are not supported.
  1834     if (MaybeEmulatesUndefined(lhs) || MaybeEmulatesUndefined(rhs))
  1835         return false;
  1837     // In the loose comparison more values could be the same,
  1838     // but value comparison reporting otherwise.
  1839     if (looseEq) {
  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)))
  1846             return false;
  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)))
  1854             return false;
  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))
  1864             return false;
  1868     return true;
  1871 MIRType
  1872 MCompare::inputType()
  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");
  1906 static inline bool
  1907 MustBeUInt32(MDefinition *def, MDefinition **pwrapped)
  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;
  1918     if (def->isConstant()) {
  1919         *pwrapped = def;
  1920         return def->toConstant()->value().isInt32()
  1921             && def->toConstant()->value().toInt32() >= 0;
  1924     return false;
  1927 bool
  1928 MBinaryInstruction::tryUseUnsignedOperands()
  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);
  1938         if (newrhs != getOperand(1)) {
  1939             getOperand(1)->setImplicitlyUsedUnchecked();
  1940             replaceOperand(1, newrhs);
  1942         return true;
  1944     return false;
  1947 void
  1948 MCompare::infer(BaselineInspector *inspector, jsbytecode *pc)
  1950     JS_ASSERT(operandMightEmulateUndefined());
  1952     if (!MaybeEmulatesUndefined(getOperand(0)) && !MaybeEmulatesUndefined(getOperand(1)))
  1953         markNoOperandEmulatesUndefined();
  1955     MIRType lhs = getOperand(0)->type();
  1956     MIRType rhs = getOperand(1)->type();
  1958     bool looseEq = jsop() == JSOP_EQ || jsop() == JSOP_NE;
  1959     bool strictEq = jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE;
  1960     bool relationalEq = !(looseEq || strictEq);
  1962     // Comparisons on unsigned integers may be treated as UInt32.
  1963     if (tryUseUnsignedOperands()) {
  1964         compareType_ = Compare_UInt32;
  1965         return;
  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))
  1972         compareType_ = Compare_Int32MaybeCoerceBoth;
  1973         return;
  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))
  1981         compareType_ = Compare_Int32MaybeCoerceBoth;
  1982         return;
  1985     // Numeric comparisons against a double coerce to double.
  1986     if (IsNumberType(lhs) && IsNumberType(rhs)) {
  1987         compareType_ = Compare_Double;
  1988         return;
  1991     // Any comparison is allowed except strict eq.
  1992     if (!strictEq && IsFloatingPointType(lhs) && SafelyCoercesToDouble(getOperand(1))) {
  1993         compareType_ = Compare_DoubleMaybeCoerceRHS;
  1994         return;
  1996     if (!strictEq && IsFloatingPointType(rhs) && SafelyCoercesToDouble(getOperand(0))) {
  1997         compareType_ = Compare_DoubleMaybeCoerceLHS;
  1998         return;
  2001     // Handle object comparison.
  2002     if (!relationalEq && lhs == MIRType_Object && rhs == MIRType_Object) {
  2003         compareType_ = Compare_Object;
  2004         return;
  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;
  2013     if (strictEq && lhs == MIRType_String) {
  2014         // Lowering expects the rhs to be definitly string.
  2015         compareType_ = Compare_StrictString;
  2016         swapOperands();
  2017         return;
  2020     if (strictEq && rhs == MIRType_String) {
  2021         compareType_ = Compare_StrictString;
  2022         return;
  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;
  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;
  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));
  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();
  2052         compareType_ = Compare_Boolean;
  2053         return;
  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;
  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.
  2068     if (!strictEq)
  2069         compareType_ = inspector->expectedCompareType(pc);
  2072 MBitNot *
  2073 MBitNot::New(TempAllocator &alloc, MDefinition *input)
  2075     return new(alloc) MBitNot(input);
  2078 MBitNot *
  2079 MBitNot::NewAsmJS(TempAllocator &alloc, MDefinition *input)
  2081     MBitNot *ins = new(alloc) MBitNot(input);
  2082     ins->specialization_ = MIRType_Int32;
  2083     JS_ASSERT(ins->type() == MIRType_Int32);
  2084     return ins;
  2087 MDefinition *
  2088 MBitNot::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  2090     if (specialization_ != MIRType_Int32)
  2091         return this;
  2093     MDefinition *input = getOperand(0);
  2095     if (input->isConstant()) {
  2096         js::Value v = Int32Value(~(input->toConstant()->value().toInt32()));
  2097         return MConstant::New(alloc, v);
  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
  2105     return this;
  2108 MDefinition *
  2109 MTypeOf::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  2111     // Note: we can't use input->type() here, type analysis has
  2112     // boxed the input.
  2113     JS_ASSERT(input()->type() == MIRType_Value);
  2115     JSType type;
  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;
  2141         // FALL THROUGH
  2142       default:
  2143         return this;
  2146     return MConstant::New(alloc, StringValue(TypeName(type, GetIonContext()->runtime->names())));
  2149 void
  2150 MTypeOf::infer()
  2152     JS_ASSERT(inputMaybeCallableOrEmulatesUndefined());
  2154     if (!MaybeEmulatesUndefined(input()) && !MaybeCallable(input()))
  2155         markInputNotCallableOrEmulatesUndefined();
  2158 MBitAnd *
  2159 MBitAnd::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2161     return new(alloc) MBitAnd(left, right);
  2164 MBitAnd *
  2165 MBitAnd::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2167     MBitAnd *ins = new(alloc) MBitAnd(left, right);
  2168     ins->specializeAsInt32();
  2169     return ins;
  2172 MBitOr *
  2173 MBitOr::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2175     return new(alloc) MBitOr(left, right);
  2178 MBitOr *
  2179 MBitOr::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2181     MBitOr *ins = new(alloc) MBitOr(left, right);
  2182     ins->specializeAsInt32();
  2183     return ins;
  2186 MBitXor *
  2187 MBitXor::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2189     return new(alloc) MBitXor(left, right);
  2192 MBitXor *
  2193 MBitXor::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2195     MBitXor *ins = new(alloc) MBitXor(left, right);
  2196     ins->specializeAsInt32();
  2197     return ins;
  2200 MLsh *
  2201 MLsh::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2203     return new(alloc) MLsh(left, right);
  2206 MLsh *
  2207 MLsh::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2209     MLsh *ins = new(alloc) MLsh(left, right);
  2210     ins->specializeAsInt32();
  2211     return ins;
  2214 MRsh *
  2215 MRsh::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2217     return new(alloc) MRsh(left, right);
  2220 MRsh *
  2221 MRsh::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2223     MRsh *ins = new(alloc) MRsh(left, right);
  2224     ins->specializeAsInt32();
  2225     return ins;
  2228 MUrsh *
  2229 MUrsh::New(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2231     return new(alloc) MUrsh(left, right);
  2234 MUrsh *
  2235 MUrsh::NewAsmJS(TempAllocator &alloc, MDefinition *left, MDefinition *right)
  2237     MUrsh *ins = new(alloc) MUrsh(left, right);
  2238     ins->specializeAsInt32();
  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;
  2247     return ins;
  2250 MResumePoint *
  2251 MResumePoint::New(TempAllocator &alloc, MBasicBlock *block, jsbytecode *pc, MResumePoint *parent,
  2252                   Mode mode)
  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;
  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)
  2270     block->addResumePoint(this);
  2273 void
  2274 MResumePoint::inherit(MBasicBlock *block)
  2276     for (size_t i = 0; i < stackDepth(); i++) {
  2277         MDefinition *def = block->getSlot(i);
  2278         setOperand(i, def);
  2282 MDefinition *
  2283 MToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  2285     MDefinition *input = getOperand(0);
  2286     if (input->type() == MIRType_Int32)
  2287         return input;
  2288     return this;
  2291 void
  2292 MToInt32::analyzeEdgeCasesBackward()
  2294     if (!NeedNegativeZeroCheck(this))
  2295         setCanBeNegativeZero(false);
  2298 MDefinition *
  2299 MTruncateToInt32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  2301     MDefinition *input = getOperand(0);
  2302     if (input->type() == MIRType_Int32)
  2303         return input;
  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));
  2311     return this;
  2314 MDefinition *
  2315 MToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  2317     MDefinition *in = input();
  2318     if (in->type() == MIRType_Double)
  2319         return in;
  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));
  2329     return this;
  2332 MDefinition *
  2333 MToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  2335     if (input()->type() == MIRType_Float32)
  2336         return input();
  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();
  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;
  2351     return this;
  2354 MDefinition *
  2355 MToString::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  2357     MDefinition *in = input();
  2358     if (in->type() == MIRType_String)
  2359         return in;
  2360     return this;
  2363 MDefinition *
  2364 MClampToUint8::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  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));
  2372         if (v.isInt32()) {
  2373             int32_t clamped = ClampIntForUint8Array(v.toInt32());
  2374             return MConstant::New(alloc, Int32Value(clamped));
  2377     return this;
  2380 bool
  2381 MCompare::tryFold(bool *result)
  2383     JSOp op = jsop();
  2385     if (compareType_ == Compare_Null || compareType_ == Compare_Undefined) {
  2386         JS_ASSERT(op == JSOP_EQ || op == JSOP_STRICTEQ ||
  2387                   op == JSOP_NE || op == JSOP_STRICTNE);
  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);
  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");
  2420     if (compareType_ == Compare_Boolean) {
  2421         JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
  2422         JS_ASSERT(rhs()->type() == MIRType_Boolean);
  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");
  2444     if (compareType_ == Compare_StrictString) {
  2445         JS_ASSERT(op == JSOP_STRICTEQ || op == JSOP_STRICTNE);
  2446         JS_ASSERT(rhs()->type() == MIRType_String);
  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");
  2468     return false;
  2471 bool
  2472 MCompare::evaluateConstantOperands(bool *result)
  2474     if (type() != MIRType_Boolean && type() != MIRType_Int32)
  2475         return false;
  2477     MDefinition *left = getOperand(0);
  2478     MDefinition *right = getOperand(1);
  2480     if (!left->isConstant() || !right->isConstant())
  2481         return false;
  2483     Value lhs = left->toConstant()->value();
  2484     Value rhs = right->toConstant()->value();
  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());
  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.");
  2517         return true;
  2520     if (compareType_ == Compare_UInt32) {
  2521         uint32_t lhsUint = uint32_t(lhs.toInt32());
  2522         uint32_t rhsUint = uint32_t(rhs.toInt32());
  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.");
  2549         return true;
  2552     if (!lhs.isNumber() || !rhs.isNumber())
  2553         return false;
  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;
  2578     return true;
  2581 MDefinition *
  2582 MCompare::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  2584     bool result;
  2586     if (tryFold(&result) || evaluateConstantOperands(&result)) {
  2587         if (type() == MIRType_Int32)
  2588             return MConstant::New(alloc, Int32Value(result));
  2590         JS_ASSERT(type() == MIRType_Boolean);
  2591         return MConstant::New(alloc, BooleanValue(result));
  2594     return this;
  2597 void
  2598 MCompare::trySpecializeFloat32(TempAllocator &alloc)
  2600     MDefinition *lhs = getOperand(0);
  2601     MDefinition *rhs = getOperand(1);
  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);
  2613 void
  2614 MCompare::filtersUndefinedOrNull(bool trueBranch, MDefinition **subject, bool *filtersUndefined,
  2615                                  bool *filtersNull)
  2617     *filtersNull = *filtersUndefined = false;
  2618     *subject = nullptr;
  2620     if (compareType() != Compare_Undefined && compareType() != Compare_Null)
  2621         return;
  2623     JS_ASSERT(jsop() == JSOP_STRICTNE || jsop() == JSOP_NE ||
  2624               jsop() == JSOP_STRICTEQ || jsop() == JSOP_EQ);
  2626     // JSOP_*NE only removes undefined/null from if/true branch
  2627     if (!trueBranch && (jsop() == JSOP_STRICTNE || jsop() == JSOP_NE))
  2628         return;
  2630     // JSOP_*EQ only removes undefined/null from else/false branch
  2631     if (trueBranch && (jsop() == JSOP_STRICTEQ || jsop() == JSOP_EQ))
  2632         return;
  2634     if (jsop() == JSOP_STRICTEQ || jsop() == JSOP_STRICTNE) {
  2635         *filtersUndefined = compareType() == Compare_Undefined;
  2636         *filtersNull = compareType() == Compare_Null;
  2637     } else {
  2638         *filtersUndefined = *filtersNull = true;
  2641     *subject = lhs();
  2644 void
  2645 MNot::infer()
  2647     JS_ASSERT(operandMightEmulateUndefined());
  2649     if (!MaybeEmulatesUndefined(getOperand(0)))
  2650         markOperandCantEmulateUndefined();
  2653 MDefinition *
  2654 MNot::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  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));
  2662         // ToBoolean can't cause side effects, so this is safe.
  2663         return MConstant::New(alloc, BooleanValue(!result));
  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));
  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));
  2674     return this;
  2677 void
  2678 MNot::trySpecializeFloat32(TempAllocator &alloc)
  2680     MDefinition *in = input();
  2681     if (!in->canProduceFloat32() && in->type() == MIRType_Float32)
  2682         ConvertDefinitionToDouble<0>(alloc, in, this);
  2685 void
  2686 MBeta::printOpcode(FILE *fp) const
  2688     MDefinition::printOpcode(fp);
  2690     Sprinter sp(GetIonContext()->cx);
  2691     sp.init();
  2692     comparison_->print(sp);
  2693     fprintf(fp, " %s", sp.string());
  2696 bool
  2697 MNewObject::shouldUseVM() const
  2699     return templateObject()->hasSingletonType() ||
  2700            templateObject()->hasDynamicSlots();
  2703 bool
  2704 MNewArray::shouldUseVM() const
  2706     JS_ASSERT(count() < JSObject::NELEMENTS_LIMIT);
  2708     size_t arraySlots =
  2709         gc::GetGCKindSlots(templateObject()->tenuredGetAllocKind()) - ObjectElements::VALUES_PER_HEADER;
  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;
  2716     return templateObject()->hasSingletonType() || allocating;
  2719 bool
  2720 MLoadFixedSlot::mightAlias(const MDefinition *store) const
  2722     if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot())
  2723         return false;
  2724     return true;
  2727 bool
  2728 MAsmJSLoadHeap::mightAlias(const MDefinition *def) const
  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();
  2739     return true;
  2742 bool
  2743 MAsmJSLoadHeap::congruentTo(const MDefinition *ins) const
  2745     if (!ins->isAsmJSLoadHeap())
  2746         return false;
  2747     const MAsmJSLoadHeap *load = ins->toAsmJSLoadHeap();
  2748     return load->viewType() == viewType() && congruentIfOperandsEqual(load);
  2751 bool
  2752 MAsmJSLoadGlobalVar::mightAlias(const MDefinition *def) const
  2754     if (def->isAsmJSStoreGlobalVar()) {
  2755         const MAsmJSStoreGlobalVar *store = def->toAsmJSStoreGlobalVar();
  2756         return store->globalDataOffset() == globalDataOffset_;
  2758     return true;
  2761 bool
  2762 MAsmJSLoadGlobalVar::congruentTo(const MDefinition *ins) const
  2764     if (ins->isAsmJSLoadGlobalVar()) {
  2765         const MAsmJSLoadGlobalVar *load = ins->toAsmJSLoadGlobalVar();
  2766         return globalDataOffset_ == load->globalDataOffset_;
  2768     return false;
  2771 bool
  2772 MLoadSlot::mightAlias(const MDefinition *store) const
  2774     if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot())
  2775         return false;
  2776     return true;
  2779 void
  2780 InlinePropertyTable::trimTo(ObjectVector &targets, BoolVector &choiceSet)
  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;
  2787         JSFunction *target = &targets[i]->as<JSFunction>();
  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++;
  2800 void
  2801 InlinePropertyTable::trimToTargets(ObjectVector &targets)
  2803     IonSpew(IonSpew_Inlining, "Got inlineable property cache with %d cases",
  2804             (int)numEntries());
  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;
  2815         if (!foundFunc)
  2816             entries_.erase(&(entries_[i]));
  2817         else
  2818             i++;
  2821     IonSpew(IonSpew_Inlining, "%d inlineable cases left after trimming to %d targets",
  2822             (int)numEntries(), (int)targets.length());
  2825 bool
  2826 InlinePropertyTable::hasFunction(JSFunction *func) const
  2828     for (size_t i = 0; i < numEntries(); i++) {
  2829         if (entries_[i]->func == func)
  2830             return true;
  2832     return false;
  2835 types::TemporaryTypeSet *
  2836 InlinePropertyTable::buildTypeSetForFunction(JSFunction *func) const
  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);
  2846     return types;
  2849 void *
  2850 MLoadTypedArrayElementStatic::base() const
  2852     return typedArray_->viewData();
  2855 size_t
  2856 MLoadTypedArrayElementStatic::length() const
  2858     return typedArray_->byteLength();
  2861 void *
  2862 MStoreTypedArrayElementStatic::base() const
  2864     return typedArray_->viewData();
  2867 bool
  2868 MGetElementCache::allowDoubleResult() const
  2870     if (!resultTypeSet())
  2871         return true;
  2873     return resultTypeSet()->hasType(types::Type::DoubleType());
  2876 size_t
  2877 MStoreTypedArrayElementStatic::length() const
  2879     return typedArray_->byteLength();
  2882 bool
  2883 MGetPropertyPolymorphic::mightAlias(const MDefinition *store) const
  2885     // Allow hoisting this instruction if the store does not write to a
  2886     // slot read by this instruction.
  2888     if (!store->isStoreFixedSlot() && !store->isStoreSlot())
  2889         return true;
  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;
  2909         return true;
  2912     return false;
  2915 void
  2916 MGetPropertyCache::setBlock(MBasicBlock *block)
  2918     MDefinition::setBlock(block);
  2919     // Track where we started.
  2920     if (!location_.pc) {
  2921         location_.pc = block->trackedPc();
  2922         location_.script = block->info().script();
  2926 bool
  2927 MGetPropertyCache::updateForReplacement(MDefinition *ins) {
  2928     MGetPropertyCache *other = ins->toGetPropertyCache();
  2929     location_.append(&other->location_);
  2930     return true;
  2933 MDefinition *
  2934 MAsmJSUnsignedToDouble::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  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())));
  2942     return this;
  2945 MDefinition *
  2946 MAsmJSUnsignedToFloat32::foldsTo(TempAllocator &alloc, bool useValueNumbers)
  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);
  2957     return this;
  2960 MAsmJSCall *
  2961 MAsmJSCall::New(TempAllocator &alloc, const CallSiteDesc &desc, Callee callee,
  2962                 const Args &args, MIRType resultType, size_t spIncrement)
  2964     MAsmJSCall *call = new(alloc) MAsmJSCall(desc, callee, spIncrement);
  2965     call->setResultType(resultType);
  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;
  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());
  2979     return call;
  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;
  2990     setResultType(MIRType_Float32);
  2991     setPolicyType(MIRType_Float32);
  2994 bool
  2995 jit::ElementAccessIsDenseNative(MDefinition *obj, MDefinition *id)
  2997     if (obj->mightBeType(MIRType_String))
  2998         return false;
  3000     if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
  3001         return false;
  3003     types::TemporaryTypeSet *types = obj->resultTypeSet();
  3004     if (!types)
  3005         return false;
  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);
  3012 bool
  3013 jit::ElementAccessIsTypedArray(MDefinition *obj, MDefinition *id,
  3014                                ScalarTypeDescr::Type *arrayType)
  3016     if (obj->mightBeType(MIRType_String))
  3017         return false;
  3019     if (id->type() != MIRType_Int32 && id->type() != MIRType_Double)
  3020         return false;
  3022     types::TemporaryTypeSet *types = obj->resultTypeSet();
  3023     if (!types)
  3024         return false;
  3026     *arrayType = (ScalarTypeDescr::Type) types->getTypedArrayType();
  3027     return *arrayType != ScalarTypeDescr::TYPE_MAX;
  3030 bool
  3031 jit::ElementAccessIsPacked(types::CompilerConstraintList *constraints, MDefinition *obj)
  3033     types::TemporaryTypeSet *types = obj->resultTypeSet();
  3034     return types && !types->hasObjectFlags(constraints, types::OBJECT_FLAG_NON_PACKED);
  3037 bool
  3038 jit::ElementAccessHasExtraIndexedProperty(types::CompilerConstraintList *constraints,
  3039                                           MDefinition *obj)
  3041     types::TemporaryTypeSet *types = obj->resultTypeSet();
  3043     if (!types || types->hasObjectFlags(constraints, types::OBJECT_FLAG_LENGTH_OVERFLOW))
  3044         return true;
  3046     return types::TypeCanHaveExtraIndexedProperties(constraints, types);
  3049 MIRType
  3050 jit::DenseNativeElementType(types::CompilerConstraintList *constraints, MDefinition *obj)
  3052     types::TemporaryTypeSet *types = obj->resultTypeSet();
  3053     MIRType elementType = MIRType_None;
  3054     unsigned count = types->getObjectCount();
  3056     for (unsigned i = 0; i < count; i++) {
  3057         types::TypeObjectKey *object = types->getObject(i);
  3058         if (!object)
  3059             continue;
  3061         if (object->unknownProperties())
  3062             return MIRType_None;
  3064         types::HeapTypeSetKey elementTypes = object->property(JSID_VOID);
  3066         MIRType type = elementTypes.knownMIRType(constraints);
  3067         if (type == MIRType_None)
  3068             return MIRType_None;
  3070         if (elementType == MIRType_None)
  3071             elementType = type;
  3072         else if (elementType != type)
  3073             return MIRType_None;
  3076     return elementType;
  3079 static bool
  3080 PropertyReadNeedsTypeBarrier(types::CompilerConstraintList *constraints,
  3081                              types::TypeObjectKey *object, PropertyName *name,
  3082                              types::TypeSet *observed)
  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())
  3095         return true;
  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;
  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()))
  3111             return true;
  3115     property.freeze(constraints);
  3116     return false;
  3119 bool
  3120 jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
  3121                                   types::CompilerConstraintList *constraints,
  3122                                   types::TypeObjectKey *object, PropertyName *name,
  3123                                   types::TemporaryTypeSet *observed, bool updateObserved)
  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;
  3136         while (obj) {
  3137             if (!obj->getClass()->isNative())
  3138                 break;
  3140             types::TypeObjectKey *typeObj = types::TypeObjectKey::get(obj);
  3141             if (propertycx)
  3142                 typeObj->ensureTrackedProperty(propertycx, NameToId(name));
  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;
  3158             if (!obj->hasTenuredProto())
  3159                 break;
  3160             obj = obj->getProto();
  3164     return PropertyReadNeedsTypeBarrier(constraints, object, name, observed);
  3167 bool
  3168 jit::PropertyReadNeedsTypeBarrier(JSContext *propertycx,
  3169                                   types::CompilerConstraintList *constraints,
  3170                                   MDefinition *obj, PropertyName *name,
  3171                                   types::TemporaryTypeSet *observed)
  3173     if (observed->unknown())
  3174         return false;
  3176     types::TypeSet *types = obj->resultTypeSet();
  3177     if (!types || types->unknownObject())
  3178         return true;
  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))
  3187                 return true;
  3192     return false;
  3195 bool
  3196 jit::PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *constraints,
  3197                                              MDefinition *obj, PropertyName *name,
  3198                                              types::TemporaryTypeSet *observed)
  3200     if (observed->unknown())
  3201         return false;
  3203     types::TypeSet *types = obj->resultTypeSet();
  3204     if (!types || types->unknownObject())
  3205         return true;
  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;
  3222     return false;
  3225 bool
  3226 jit::PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
  3227                               MDefinition *obj, PropertyName *name)
  3229     // Determine if reading a property from obj is likely to be idempotent.
  3231     types::TypeSet *types = obj->resultTypeSet();
  3232     if (!types || types->unknownObject())
  3233         return false;
  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;
  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;
  3248     return true;
  3251 void
  3252 jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
  3253                                types::TemporaryTypeSet *observed)
  3255     // Add objects to observed which *could* be observed by reading name from obj,
  3256     // to hopefully avoid unnecessary type barriers and code invalidations.
  3258     LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
  3260     types::TemporaryTypeSet *types = obj->resultTypeSet();
  3261     if (!types || types->unknownObject()) {
  3262         observed->addType(types::Type::AnyObjectType(), alloc);
  3263         return;
  3266     for (size_t i = 0; i < types->getObjectCount(); i++) {
  3267         types::TypeObjectKey *object = types->getObject(i);
  3268         if (!object)
  3269             continue;
  3271         if (object->unknownProperties()) {
  3272             observed->addType(types::Type::AnyObjectType(), alloc);
  3273             return;
  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;
  3282         if (types->unknownObject()) {
  3283             observed->addType(types::Type::AnyObjectType(), alloc);
  3284             return;
  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);
  3295 static bool
  3296 TryAddTypeBarrierForWrite(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  3297                           MBasicBlock *current, types::TemporaryTypeSet *objTypes,
  3298                           PropertyName *name, MDefinition **pvalue)
  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.
  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;
  3309     for (size_t i = 0; i < objTypes->getObjectCount(); i++) {
  3310         types::TypeObjectKey *object = objTypes->getObject(i);
  3311         if (!object)
  3312             continue;
  3314         if (object->unknownProperties())
  3315             return false;
  3317         jsid id = name ? NameToId(name) : JSID_VOID;
  3318         types::HeapTypeSetKey property = object->property(id);
  3319         if (!property.maybeTypes())
  3320             return false;
  3322         if (TypeSetIncludes(property.maybeTypes(), (*pvalue)->type(), (*pvalue)->resultTypeSet()))
  3323             return false;
  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);
  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()))
  3336                 return false;
  3341     JS_ASSERT(!aggregateProperty.empty());
  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;
  3357         MInstruction *ins = MUnbox::New(alloc, *pvalue, propertyType, MUnbox::Fallible);
  3358         current->add(ins);
  3359         *pvalue = ins;
  3360         return true;
  3362       default:;
  3365     if ((*pvalue)->type() != MIRType_Value)
  3366         return false;
  3368     types::TemporaryTypeSet *types = aggregateProperty.ref().maybeTypes()->clone(alloc.lifoAlloc());
  3369     if (!types)
  3370         return false;
  3372     MInstruction *ins = MMonitorTypes::New(alloc, *pvalue, types);
  3373     current->add(ins);
  3374     return true;
  3377 static MInstruction *
  3378 AddTypeGuard(TempAllocator &alloc, MBasicBlock *current, MDefinition *obj,
  3379              types::TypeObjectKey *type, bool bailOnEquality)
  3381     MInstruction *guard;
  3383     if (type->isTypeObject())
  3384         guard = MGuardObjectType::New(alloc, obj, type->asTypeObject(), bailOnEquality);
  3385     else
  3386         guard = MGuardObjectIdentity::New(alloc, obj, type->asSingleObject(), bailOnEquality);
  3388     current->add(guard);
  3390     // For now, never move type object guards.
  3391     guard->setNotMovable();
  3393     return guard;
  3396 bool
  3397 jit::PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstraintList *constraints,
  3398                                    MBasicBlock *current, MDefinition **pobj,
  3399                                    PropertyName *name, MDefinition **pvalue, bool canModify)
  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.
  3407     types::TemporaryTypeSet *types = (*pobj)->resultTypeSet();
  3408     if (!types || types->unknownObject())
  3409         return true;
  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.
  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;
  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;
  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;
  3441     if (success)
  3442         return false;
  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.
  3448     if (types->getObjectCount() <= 1)
  3449         return true;
  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;
  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;
  3464         if ((property.maybeTypes() && !property.maybeTypes()->empty()) || excluded)
  3465             return true;
  3466         excluded = object;
  3469     JS_ASSERT(excluded);
  3471     *pobj = AddTypeGuard(alloc, current, *pobj, excluded, /* bailOnEquality = */ true);
  3472     return false;

mercurial