js/src/jit/Lowering.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/Lowering.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3763 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jit/Lowering.h"
    1.11 +
    1.12 +#include "mozilla/DebugOnly.h"
    1.13 +
    1.14 +#include "jsanalyze.h"
    1.15 +
    1.16 +#include "jit/IonSpewer.h"
    1.17 +#include "jit/LIR.h"
    1.18 +#include "jit/MIR.h"
    1.19 +#include "jit/MIRGraph.h"
    1.20 +
    1.21 +#include "jsinferinlines.h"
    1.22 +#include "jsobjinlines.h"
    1.23 +#include "jsopcodeinlines.h"
    1.24 +
    1.25 +#include "jit/shared/Lowering-shared-inl.h"
    1.26 +
    1.27 +using namespace js;
    1.28 +using namespace jit;
    1.29 +
    1.30 +using mozilla::DebugOnly;
    1.31 +using JS::GenericNaN;
    1.32 +
    1.33 +bool
    1.34 +LIRGenerator::visitCloneLiteral(MCloneLiteral *ins)
    1.35 +{
    1.36 +    JS_ASSERT(ins->type() == MIRType_Object);
    1.37 +    JS_ASSERT(ins->input()->type() == MIRType_Object);
    1.38 +
    1.39 +    LCloneLiteral *lir = new(alloc()) LCloneLiteral(useRegisterAtStart(ins->input()));
    1.40 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
    1.41 +}
    1.42 +
    1.43 +bool
    1.44 +LIRGenerator::visitParameter(MParameter *param)
    1.45 +{
    1.46 +    ptrdiff_t offset;
    1.47 +    if (param->index() == MParameter::THIS_SLOT)
    1.48 +        offset = THIS_FRAME_ARGSLOT;
    1.49 +    else
    1.50 +        offset = 1 + param->index();
    1.51 +
    1.52 +    LParameter *ins = new(alloc()) LParameter;
    1.53 +    if (!defineBox(ins, param, LDefinition::PRESET))
    1.54 +        return false;
    1.55 +
    1.56 +    offset *= sizeof(Value);
    1.57 +#if defined(JS_NUNBOX32)
    1.58 +# if defined(IS_BIG_ENDIAN)
    1.59 +    ins->getDef(0)->setOutput(LArgument(offset));
    1.60 +    ins->getDef(1)->setOutput(LArgument(offset + 4));
    1.61 +# else
    1.62 +    ins->getDef(0)->setOutput(LArgument(offset + 4));
    1.63 +    ins->getDef(1)->setOutput(LArgument(offset));
    1.64 +# endif
    1.65 +#elif defined(JS_PUNBOX64)
    1.66 +    ins->getDef(0)->setOutput(LArgument(offset));
    1.67 +#endif
    1.68 +
    1.69 +    return true;
    1.70 +}
    1.71 +
    1.72 +bool
    1.73 +LIRGenerator::visitCallee(MCallee *ins)
    1.74 +{
    1.75 +    return define(new(alloc()) LCallee(), ins);
    1.76 +}
    1.77 +
    1.78 +bool
    1.79 +LIRGenerator::visitGoto(MGoto *ins)
    1.80 +{
    1.81 +    return add(new(alloc()) LGoto(ins->target()));
    1.82 +}
    1.83 +
    1.84 +bool
    1.85 +LIRGenerator::visitTableSwitch(MTableSwitch *tableswitch)
    1.86 +{
    1.87 +    MDefinition *opd = tableswitch->getOperand(0);
    1.88 +
    1.89 +    // There should be at least 1 successor. The default case!
    1.90 +    JS_ASSERT(tableswitch->numSuccessors() > 0);
    1.91 +
    1.92 +    // If there are no cases, the default case is always taken.
    1.93 +    if (tableswitch->numSuccessors() == 1)
    1.94 +        return add(new(alloc()) LGoto(tableswitch->getDefault()));
    1.95 +
    1.96 +    // If we don't know the type.
    1.97 +    if (opd->type() == MIRType_Value) {
    1.98 +        LTableSwitchV *lir = newLTableSwitchV(tableswitch);
    1.99 +        if (!useBox(lir, LTableSwitchV::InputValue, opd))
   1.100 +            return false;
   1.101 +        return add(lir);
   1.102 +    }
   1.103 +
   1.104 +    // Case indices are numeric, so other types will always go to the default case.
   1.105 +    if (opd->type() != MIRType_Int32 && opd->type() != MIRType_Double)
   1.106 +        return add(new(alloc()) LGoto(tableswitch->getDefault()));
   1.107 +
   1.108 +    // Return an LTableSwitch, capable of handling either an integer or
   1.109 +    // floating-point index.
   1.110 +    LAllocation index;
   1.111 +    LDefinition tempInt;
   1.112 +    if (opd->type() == MIRType_Int32) {
   1.113 +        index = useRegisterAtStart(opd);
   1.114 +        tempInt = tempCopy(opd, 0);
   1.115 +    } else {
   1.116 +        index = useRegister(opd);
   1.117 +        tempInt = temp(LDefinition::GENERAL);
   1.118 +    }
   1.119 +    return add(newLTableSwitch(index, tempInt, tableswitch));
   1.120 +}
   1.121 +
   1.122 +bool
   1.123 +LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed *ins)
   1.124 +{
   1.125 +    LCheckOverRecursed *lir = new(alloc()) LCheckOverRecursed();
   1.126 +
   1.127 +    if (!add(lir, ins))
   1.128 +        return false;
   1.129 +    if (!assignSafepoint(lir, ins))
   1.130 +        return false;
   1.131 +
   1.132 +    return true;
   1.133 +}
   1.134 +
   1.135 +bool
   1.136 +LIRGenerator::visitCheckOverRecursedPar(MCheckOverRecursedPar *ins)
   1.137 +{
   1.138 +    LCheckOverRecursedPar *lir =
   1.139 +        new(alloc()) LCheckOverRecursedPar(useRegister(ins->forkJoinContext()), temp());
   1.140 +    if (!add(lir, ins))
   1.141 +        return false;
   1.142 +    if (!assignSafepoint(lir, ins))
   1.143 +        return false;
   1.144 +    return true;
   1.145 +}
   1.146 +
   1.147 +bool
   1.148 +LIRGenerator::visitDefVar(MDefVar *ins)
   1.149 +{
   1.150 +    LDefVar *lir = new(alloc()) LDefVar(useRegisterAtStart(ins->scopeChain()));
   1.151 +    if (!add(lir, ins))
   1.152 +        return false;
   1.153 +    if (!assignSafepoint(lir, ins))
   1.154 +        return false;
   1.155 +
   1.156 +    return true;
   1.157 +}
   1.158 +
   1.159 +bool
   1.160 +LIRGenerator::visitDefFun(MDefFun *ins)
   1.161 +{
   1.162 +    LDefFun *lir = new(alloc()) LDefFun(useRegisterAtStart(ins->scopeChain()));
   1.163 +    return add(lir, ins) && assignSafepoint(lir, ins);
   1.164 +}
   1.165 +
   1.166 +bool
   1.167 +LIRGenerator::visitNewSlots(MNewSlots *ins)
   1.168 +{
   1.169 +    // No safepoint needed, since we don't pass a cx.
   1.170 +    LNewSlots *lir = new(alloc()) LNewSlots(tempFixed(CallTempReg0), tempFixed(CallTempReg1),
   1.171 +                                            tempFixed(CallTempReg2));
   1.172 +    if (!assignSnapshot(lir))
   1.173 +        return false;
   1.174 +    return defineReturn(lir, ins);
   1.175 +}
   1.176 +
   1.177 +bool
   1.178 +LIRGenerator::visitNewArray(MNewArray *ins)
   1.179 +{
   1.180 +    LNewArray *lir = new(alloc()) LNewArray(temp());
   1.181 +    return define(lir, ins) && assignSafepoint(lir, ins);
   1.182 +}
   1.183 +
   1.184 +bool
   1.185 +LIRGenerator::visitNewObject(MNewObject *ins)
   1.186 +{
   1.187 +    LNewObject *lir = new(alloc()) LNewObject(temp());
   1.188 +    return define(lir, ins) && assignSafepoint(lir, ins);
   1.189 +}
   1.190 +
   1.191 +bool
   1.192 +LIRGenerator::visitNewDeclEnvObject(MNewDeclEnvObject *ins)
   1.193 +{
   1.194 +    LNewDeclEnvObject *lir = new(alloc()) LNewDeclEnvObject(temp());
   1.195 +    return define(lir, ins) && assignSafepoint(lir, ins);
   1.196 +}
   1.197 +
   1.198 +bool
   1.199 +LIRGenerator::visitNewCallObject(MNewCallObject *ins)
   1.200 +{
   1.201 +    LAllocation slots;
   1.202 +    if (ins->slots()->type() == MIRType_Slots)
   1.203 +        slots = useRegister(ins->slots());
   1.204 +    else
   1.205 +        slots = LConstantIndex::Bogus();
   1.206 +
   1.207 +    LInstruction *lir;
   1.208 +    if (ins->templateObject()->hasSingletonType()) {
   1.209 +        LNewSingletonCallObject *singletonLir = new(alloc()) LNewSingletonCallObject(slots);
   1.210 +        if (!define(singletonLir, ins))
   1.211 +            return false;
   1.212 +        lir = singletonLir;
   1.213 +    } else {
   1.214 +        LNewCallObject *normalLir = new(alloc()) LNewCallObject(slots, temp());
   1.215 +        if (!define(normalLir, ins))
   1.216 +            return false;
   1.217 +        lir = normalLir;
   1.218 +    }
   1.219 +
   1.220 +    if (!assignSafepoint(lir, ins))
   1.221 +        return false;
   1.222 +
   1.223 +    return true;
   1.224 +}
   1.225 +
   1.226 +bool
   1.227 +LIRGenerator::visitNewRunOnceCallObject(MNewRunOnceCallObject *ins)
   1.228 +{
   1.229 +    LAllocation slots;
   1.230 +    if (ins->slots()->type() == MIRType_Slots)
   1.231 +        slots = useRegister(ins->slots());
   1.232 +    else
   1.233 +        slots = LConstantIndex::Bogus();
   1.234 +
   1.235 +    LNewSingletonCallObject *lir = new(alloc()) LNewSingletonCallObject(slots);
   1.236 +    if (!define(lir, ins))
   1.237 +        return false;
   1.238 +
   1.239 +    if (!assignSafepoint(lir, ins))
   1.240 +        return false;
   1.241 +
   1.242 +    return true;
   1.243 +}
   1.244 +
   1.245 +bool
   1.246 +LIRGenerator::visitNewDerivedTypedObject(MNewDerivedTypedObject *ins)
   1.247 +{
   1.248 +    LNewDerivedTypedObject *lir =
   1.249 +        new(alloc()) LNewDerivedTypedObject(useRegisterAtStart(ins->type()),
   1.250 +                                            useRegisterAtStart(ins->owner()),
   1.251 +                                            useRegisterAtStart(ins->offset()));
   1.252 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
   1.253 +}
   1.254 +
   1.255 +bool
   1.256 +LIRGenerator::visitNewCallObjectPar(MNewCallObjectPar *ins)
   1.257 +{
   1.258 +    const LAllocation &parThreadContext = useRegister(ins->forkJoinContext());
   1.259 +    const LDefinition &temp1 = temp();
   1.260 +    const LDefinition &temp2 = temp();
   1.261 +
   1.262 +    LNewCallObjectPar *lir;
   1.263 +    if (ins->slots()->type() == MIRType_Slots) {
   1.264 +        const LAllocation &slots = useRegister(ins->slots());
   1.265 +        lir = LNewCallObjectPar::NewWithSlots(alloc(), parThreadContext, slots, temp1, temp2);
   1.266 +    } else {
   1.267 +        lir = LNewCallObjectPar::NewSansSlots(alloc(), parThreadContext, temp1, temp2);
   1.268 +    }
   1.269 +
   1.270 +    return define(lir, ins);
   1.271 +}
   1.272 +
   1.273 +bool
   1.274 +LIRGenerator::visitNewStringObject(MNewStringObject *ins)
   1.275 +{
   1.276 +    JS_ASSERT(ins->input()->type() == MIRType_String);
   1.277 +
   1.278 +    LNewStringObject *lir = new(alloc()) LNewStringObject(useRegister(ins->input()), temp());
   1.279 +    return define(lir, ins) && assignSafepoint(lir, ins);
   1.280 +}
   1.281 +
   1.282 +bool
   1.283 +LIRGenerator::visitAbortPar(MAbortPar *ins)
   1.284 +{
   1.285 +    LAbortPar *lir = new(alloc()) LAbortPar();
   1.286 +    return add(lir, ins);
   1.287 +}
   1.288 +
   1.289 +bool
   1.290 +LIRGenerator::visitInitElem(MInitElem *ins)
   1.291 +{
   1.292 +    LInitElem *lir = new(alloc()) LInitElem(useRegisterAtStart(ins->getObject()));
   1.293 +    if (!useBoxAtStart(lir, LInitElem::IdIndex, ins->getId()))
   1.294 +        return false;
   1.295 +    if (!useBoxAtStart(lir, LInitElem::ValueIndex, ins->getValue()))
   1.296 +        return false;
   1.297 +
   1.298 +    return add(lir, ins) && assignSafepoint(lir, ins);
   1.299 +}
   1.300 +
   1.301 +bool
   1.302 +LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter *ins)
   1.303 +{
   1.304 +    LInitElemGetterSetter *lir =
   1.305 +        new(alloc()) LInitElemGetterSetter(useRegisterAtStart(ins->object()),
   1.306 +                                           useRegisterAtStart(ins->value()));
   1.307 +    if (!useBoxAtStart(lir, LInitElemGetterSetter::IdIndex, ins->idValue()))
   1.308 +        return false;
   1.309 +
   1.310 +    return add(lir, ins) && assignSafepoint(lir, ins);
   1.311 +}
   1.312 +
   1.313 +bool
   1.314 +LIRGenerator::visitMutateProto(MMutateProto *ins)
   1.315 +{
   1.316 +    LMutateProto *lir = new(alloc()) LMutateProto(useRegisterAtStart(ins->getObject()));
   1.317 +    if (!useBoxAtStart(lir, LMutateProto::ValueIndex, ins->getValue()))
   1.318 +        return false;
   1.319 +
   1.320 +    return add(lir, ins) && assignSafepoint(lir, ins);
   1.321 +}
   1.322 +
   1.323 +bool
   1.324 +LIRGenerator::visitInitProp(MInitProp *ins)
   1.325 +{
   1.326 +    LInitProp *lir = new(alloc()) LInitProp(useRegisterAtStart(ins->getObject()));
   1.327 +    if (!useBoxAtStart(lir, LInitProp::ValueIndex, ins->getValue()))
   1.328 +        return false;
   1.329 +
   1.330 +    return add(lir, ins) && assignSafepoint(lir, ins);
   1.331 +}
   1.332 +
   1.333 +bool
   1.334 +LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter *ins)
   1.335 +{
   1.336 +    LInitPropGetterSetter *lir =
   1.337 +        new(alloc()) LInitPropGetterSetter(useRegisterAtStart(ins->object()),
   1.338 +                                           useRegisterAtStart(ins->value()));
   1.339 +    return add(lir, ins) && assignSafepoint(lir, ins);
   1.340 +}
   1.341 +
   1.342 +bool
   1.343 +LIRGenerator::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins)
   1.344 +{
   1.345 +    LCreateThisWithTemplate *lir = new(alloc()) LCreateThisWithTemplate(temp());
   1.346 +    return define(lir, ins) && assignSafepoint(lir, ins);
   1.347 +}
   1.348 +
   1.349 +bool
   1.350 +LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto *ins)
   1.351 +{
   1.352 +    LCreateThisWithProto *lir =
   1.353 +        new(alloc()) LCreateThisWithProto(useRegisterOrConstantAtStart(ins->getCallee()),
   1.354 +                                          useRegisterOrConstantAtStart(ins->getPrototype()));
   1.355 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
   1.356 +}
   1.357 +
   1.358 +bool
   1.359 +LIRGenerator::visitCreateThis(MCreateThis *ins)
   1.360 +{
   1.361 +    LCreateThis *lir = new(alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->getCallee()));
   1.362 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
   1.363 +}
   1.364 +
   1.365 +bool
   1.366 +LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject *ins)
   1.367 +{
   1.368 +    // LAllocation callObj = useRegisterAtStart(ins->getCallObject());
   1.369 +    LAllocation callObj = useFixed(ins->getCallObject(), CallTempReg0);
   1.370 +    LCreateArgumentsObject *lir = new(alloc()) LCreateArgumentsObject(callObj, tempFixed(CallTempReg1));
   1.371 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
   1.372 +}
   1.373 +
   1.374 +bool
   1.375 +LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg *ins)
   1.376 +{
   1.377 +    LAllocation argsObj = useRegister(ins->getArgsObject());
   1.378 +    LGetArgumentsObjectArg *lir = new(alloc()) LGetArgumentsObjectArg(argsObj, temp());
   1.379 +    return defineBox(lir, ins);
   1.380 +}
   1.381 +
   1.382 +bool
   1.383 +LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg *ins)
   1.384 +{
   1.385 +    LAllocation argsObj = useRegister(ins->getArgsObject());
   1.386 +    LSetArgumentsObjectArg *lir = new(alloc()) LSetArgumentsObjectArg(argsObj, temp());
   1.387 +    if (!useBox(lir, LSetArgumentsObjectArg::ValueIndex, ins->getValue()))
   1.388 +        return false;
   1.389 +
   1.390 +    return add(lir, ins);
   1.391 +}
   1.392 +
   1.393 +bool
   1.394 +LIRGenerator::visitReturnFromCtor(MReturnFromCtor *ins)
   1.395 +{
   1.396 +    LReturnFromCtor *lir = new(alloc()) LReturnFromCtor(useRegister(ins->getObject()));
   1.397 +    if (!useBox(lir, LReturnFromCtor::ValueIndex, ins->getValue()))
   1.398 +        return false;
   1.399 +
   1.400 +    return define(lir, ins);
   1.401 +}
   1.402 +
   1.403 +bool
   1.404 +LIRGenerator::visitComputeThis(MComputeThis *ins)
   1.405 +{
   1.406 +    JS_ASSERT(ins->type() == MIRType_Object);
   1.407 +    JS_ASSERT(ins->input()->type() == MIRType_Value);
   1.408 +
   1.409 +    LComputeThis *lir = new(alloc()) LComputeThis();
   1.410 +
   1.411 +    // Don't use useBoxAtStart because ComputeThis has a safepoint and needs to
   1.412 +    // have its inputs in different registers than its return value so that
   1.413 +    // they aren't clobbered.
   1.414 +    if (!useBox(lir, LComputeThis::ValueIndex, ins->input()))
   1.415 +        return false;
   1.416 +
   1.417 +    return define(lir, ins) && assignSafepoint(lir, ins);
   1.418 +}
   1.419 +
   1.420 +bool
   1.421 +LIRGenerator::visitLoadArrowThis(MLoadArrowThis *ins)
   1.422 +{
   1.423 +    JS_ASSERT(ins->type() == MIRType_Value);
   1.424 +    JS_ASSERT(ins->callee()->type() == MIRType_Object);
   1.425 +
   1.426 +    LLoadArrowThis *lir = new(alloc()) LLoadArrowThis(useRegister(ins->callee()));
   1.427 +    return defineBox(lir, ins);
   1.428 +}
   1.429 +
   1.430 +bool
   1.431 +LIRGenerator::lowerCallArguments(MCall *call)
   1.432 +{
   1.433 +    uint32_t argc = call->numStackArgs();
   1.434 +    if (argc > maxargslots_)
   1.435 +        maxargslots_ = argc;
   1.436 +
   1.437 +    for (size_t i = 0; i < argc; i++) {
   1.438 +        MDefinition *arg = call->getArg(i);
   1.439 +        uint32_t argslot = argc - i;
   1.440 +
   1.441 +        // Values take a slow path.
   1.442 +        if (arg->type() == MIRType_Value) {
   1.443 +            LStackArgV *stack = new(alloc()) LStackArgV(argslot);
   1.444 +            if (!useBox(stack, 0, arg) || !add(stack))
   1.445 +                return false;
   1.446 +        } else {
   1.447 +            // Known types can move constant types and/or payloads.
   1.448 +            LStackArgT *stack = new(alloc()) LStackArgT(argslot, arg->type(), useRegisterOrConstant(arg));
   1.449 +            if (!add(stack))
   1.450 +                return false;
   1.451 +        }
   1.452 +    }
   1.453 +
   1.454 +    return true;
   1.455 +}
   1.456 +
   1.457 +bool
   1.458 +LIRGenerator::visitCall(MCall *call)
   1.459 +{
   1.460 +    JS_ASSERT(CallTempReg0 != CallTempReg1);
   1.461 +    JS_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
   1.462 +    JS_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
   1.463 +    JS_ASSERT(call->getFunction()->type() == MIRType_Object);
   1.464 +
   1.465 +    if (!lowerCallArguments(call))
   1.466 +        return false;
   1.467 +
   1.468 +    // Height of the current argument vector.
   1.469 +    JSFunction *target = call->getSingleTarget();
   1.470 +
   1.471 +    // Call DOM functions.
   1.472 +    if (call->isCallDOMNative()) {
   1.473 +        JS_ASSERT(target && target->isNative());
   1.474 +        Register cxReg, objReg, privReg, argsReg;
   1.475 +        GetTempRegForIntArg(0, 0, &cxReg);
   1.476 +        GetTempRegForIntArg(1, 0, &objReg);
   1.477 +        GetTempRegForIntArg(2, 0, &privReg);
   1.478 +        mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &argsReg);
   1.479 +        MOZ_ASSERT(ok, "How can we not have four temp registers?");
   1.480 +        LCallDOMNative *lir = new(alloc()) LCallDOMNative(tempFixed(cxReg), tempFixed(objReg),
   1.481 +                                                          tempFixed(privReg), tempFixed(argsReg));
   1.482 +        return defineReturn(lir, call) && assignSafepoint(lir, call);
   1.483 +    }
   1.484 +
   1.485 +    // Call known functions.
   1.486 +    if (target) {
   1.487 +        if (target->isNative()) {
   1.488 +            Register cxReg, numReg, vpReg, tmpReg;
   1.489 +            GetTempRegForIntArg(0, 0, &cxReg);
   1.490 +            GetTempRegForIntArg(1, 0, &numReg);
   1.491 +            GetTempRegForIntArg(2, 0, &vpReg);
   1.492 +
   1.493 +            // Even though this is just a temp reg, use the same API to avoid
   1.494 +            // register collisions.
   1.495 +            mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
   1.496 +            MOZ_ASSERT(ok, "How can we not have four temp registers?");
   1.497 +
   1.498 +            LCallNative *lir = new(alloc()) LCallNative(tempFixed(cxReg), tempFixed(numReg),
   1.499 +                                                        tempFixed(vpReg), tempFixed(tmpReg));
   1.500 +            return defineReturn(lir, call) && assignSafepoint(lir, call);
   1.501 +        }
   1.502 +
   1.503 +        LCallKnown *lir = new(alloc()) LCallKnown(useFixed(call->getFunction(), CallTempReg0),
   1.504 +                                                  tempFixed(CallTempReg2));
   1.505 +        return defineReturn(lir, call) && assignSafepoint(lir, call);
   1.506 +    }
   1.507 +
   1.508 +    // Call anything, using the most generic code.
   1.509 +    LCallGeneric *lir = new(alloc()) LCallGeneric(useFixed(call->getFunction(), CallTempReg0),
   1.510 +                                                  tempFixed(ArgumentsRectifierReg),
   1.511 +                                                  tempFixed(CallTempReg2));
   1.512 +    return defineReturn(lir, call) && assignSafepoint(lir, call);
   1.513 +}
   1.514 +
   1.515 +bool
   1.516 +LIRGenerator::visitApplyArgs(MApplyArgs *apply)
   1.517 +{
   1.518 +    JS_ASSERT(apply->getFunction()->type() == MIRType_Object);
   1.519 +
   1.520 +    // Assert if we cannot build a rectifier frame.
   1.521 +    JS_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
   1.522 +    JS_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
   1.523 +
   1.524 +    // Assert if the return value is already erased.
   1.525 +    JS_ASSERT(CallTempReg2 != JSReturnReg_Type);
   1.526 +    JS_ASSERT(CallTempReg2 != JSReturnReg_Data);
   1.527 +
   1.528 +    LApplyArgsGeneric *lir = new(alloc()) LApplyArgsGeneric(
   1.529 +        useFixed(apply->getFunction(), CallTempReg3),
   1.530 +        useFixed(apply->getArgc(), CallTempReg0),
   1.531 +        tempFixed(CallTempReg1),  // object register
   1.532 +        tempFixed(CallTempReg2)); // copy register
   1.533 +
   1.534 +    MDefinition *self = apply->getThis();
   1.535 +    if (!useBoxFixed(lir, LApplyArgsGeneric::ThisIndex, self, CallTempReg4, CallTempReg5))
   1.536 +        return false;
   1.537 +
   1.538 +    // Bailout is only needed in the case of possible non-JSFunction callee.
   1.539 +    if (!apply->getSingleTarget() && !assignSnapshot(lir))
   1.540 +        return false;
   1.541 +
   1.542 +    if (!defineReturn(lir, apply))
   1.543 +        return false;
   1.544 +    if (!assignSafepoint(lir, apply))
   1.545 +        return false;
   1.546 +    return true;
   1.547 +}
   1.548 +
   1.549 +bool
   1.550 +LIRGenerator::visitBail(MBail *bail)
   1.551 +{
   1.552 +    LBail *lir = new(alloc()) LBail();
   1.553 +    return assignSnapshot(lir) && add(lir, bail);
   1.554 +}
   1.555 +
   1.556 +bool
   1.557 +LIRGenerator::visitAssertFloat32(MAssertFloat32 *assertion)
   1.558 +{
   1.559 +    MIRType type = assertion->input()->type();
   1.560 +    DebugOnly<bool> checkIsFloat32 = assertion->mustBeFloat32();
   1.561 +
   1.562 +    if (!allowFloat32Optimizations())
   1.563 +        return true;
   1.564 +
   1.565 +    if (type != MIRType_Value && !js_JitOptions.eagerCompilation) {
   1.566 +        JS_ASSERT_IF(checkIsFloat32, type == MIRType_Float32);
   1.567 +        JS_ASSERT_IF(!checkIsFloat32, type != MIRType_Float32);
   1.568 +    }
   1.569 +    return true;
   1.570 +}
   1.571 +
   1.572 +bool
   1.573 +LIRGenerator::visitArraySplice(MArraySplice *ins)
   1.574 +{
   1.575 +    LArraySplice *lir = new(alloc()) LArraySplice(useRegisterAtStart(ins->object()),
   1.576 +                                                  useRegisterAtStart(ins->start()),
   1.577 +                                                  useRegisterAtStart(ins->deleteCount()));
   1.578 +    return add(lir, ins) && assignSafepoint(lir, ins);
   1.579 +}
   1.580 +
   1.581 +bool
   1.582 +LIRGenerator::visitGetDynamicName(MGetDynamicName *ins)
   1.583 +{
   1.584 +    MDefinition *scopeChain = ins->getScopeChain();
   1.585 +    JS_ASSERT(scopeChain->type() == MIRType_Object);
   1.586 +
   1.587 +    MDefinition *name = ins->getName();
   1.588 +    JS_ASSERT(name->type() == MIRType_String);
   1.589 +
   1.590 +    LGetDynamicName *lir = new(alloc()) LGetDynamicName(useFixed(scopeChain, CallTempReg0),
   1.591 +                                                        useFixed(name, CallTempReg1),
   1.592 +                                                        tempFixed(CallTempReg2),
   1.593 +                                                        tempFixed(CallTempReg3),
   1.594 +                                                        tempFixed(CallTempReg4));
   1.595 +
   1.596 +    return assignSnapshot(lir) && defineReturn(lir, ins);
   1.597 +}
   1.598 +
   1.599 +bool
   1.600 +LIRGenerator::visitFilterArgumentsOrEval(MFilterArgumentsOrEval *ins)
   1.601 +{
   1.602 +    MDefinition *string = ins->getString();
   1.603 +    MOZ_ASSERT(string->type() == MIRType_String || string->type() == MIRType_Value);
   1.604 +
   1.605 +    LInstruction *lir;
   1.606 +    if (string->type() == MIRType_String) {
   1.607 +        lir = new(alloc()) LFilterArgumentsOrEvalS(useFixed(string, CallTempReg0),
   1.608 +                                                   tempFixed(CallTempReg1),
   1.609 +                                                   tempFixed(CallTempReg2));
   1.610 +    } else {
   1.611 +        lir = new(alloc()) LFilterArgumentsOrEvalV(tempFixed(CallTempReg0),
   1.612 +                                                   tempFixed(CallTempReg1),
   1.613 +                                                   tempFixed(CallTempReg2));
   1.614 +        if (!useBoxFixed(lir, LFilterArgumentsOrEvalV::Input, string,
   1.615 +                         CallTempReg3, CallTempReg4))
   1.616 +        {
   1.617 +            return false;
   1.618 +        }
   1.619 +    }
   1.620 +
   1.621 +    return assignSnapshot(lir) && add(lir, ins) && assignSafepoint(lir, ins);
   1.622 +}
   1.623 +
   1.624 +bool
   1.625 +LIRGenerator::visitCallDirectEval(MCallDirectEval *ins)
   1.626 +{
   1.627 +    MDefinition *scopeChain = ins->getScopeChain();
   1.628 +    JS_ASSERT(scopeChain->type() == MIRType_Object);
   1.629 +
   1.630 +    MDefinition *string = ins->getString();
   1.631 +    JS_ASSERT(string->type() == MIRType_String || string->type() == MIRType_Value);
   1.632 +
   1.633 +    MDefinition *thisValue = ins->getThisValue();
   1.634 +
   1.635 +
   1.636 +    LInstruction *lir;
   1.637 +    if (string->type() == MIRType_String) {
   1.638 +        lir = new(alloc()) LCallDirectEvalS(useRegisterAtStart(scopeChain),
   1.639 +                                            useRegisterAtStart(string));
   1.640 +    } else {
   1.641 +        lir = new(alloc()) LCallDirectEvalV(useRegisterAtStart(scopeChain));
   1.642 +        if (!useBoxAtStart(lir, LCallDirectEvalV::Argument, string))
   1.643 +            return false;
   1.644 +    }
   1.645 +
   1.646 +    if (string->type() == MIRType_String) {
   1.647 +        if (!useBoxAtStart(lir, LCallDirectEvalS::ThisValue, thisValue))
   1.648 +            return false;
   1.649 +    } else {
   1.650 +        if (!useBoxAtStart(lir, LCallDirectEvalV::ThisValue, thisValue))
   1.651 +            return false;
   1.652 +    }
   1.653 +
   1.654 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
   1.655 +}
   1.656 +
   1.657 +static JSOp
   1.658 +ReorderComparison(JSOp op, MDefinition **lhsp, MDefinition **rhsp)
   1.659 +{
   1.660 +    MDefinition *lhs = *lhsp;
   1.661 +    MDefinition *rhs = *rhsp;
   1.662 +
   1.663 +    if (lhs->isConstant()) {
   1.664 +        *rhsp = lhs;
   1.665 +        *lhsp = rhs;
   1.666 +        return ReverseCompareOp(op);
   1.667 +    }
   1.668 +    return op;
   1.669 +}
   1.670 +
   1.671 +static void
   1.672 +ReorderCommutative(MDefinition **lhsp, MDefinition **rhsp)
   1.673 +{
   1.674 +    MDefinition *lhs = *lhsp;
   1.675 +    MDefinition *rhs = *rhsp;
   1.676 +
   1.677 +    // Ensure that if there is a constant, then it is in rhs.
   1.678 +    // In addition, since clobbering binary operations clobber the left
   1.679 +    // operand, prefer a non-constant lhs operand with no further uses.
   1.680 +
   1.681 +    if (rhs->isConstant())
   1.682 +        return;
   1.683 +
   1.684 +    // lhs and rhs are used by the commutative operator. If they have any
   1.685 +    // *other* uses besides, try to reorder to avoid clobbering them. To
   1.686 +    // be fully precise, we should check whether this is the *last* use,
   1.687 +    // but checking hasOneDefUse() is a decent approximation which doesn't
   1.688 +    // require any extra analysis.
   1.689 +    JS_ASSERT(lhs->defUseCount() > 0);
   1.690 +    JS_ASSERT(rhs->defUseCount() > 0);
   1.691 +    if (lhs->isConstant() || (rhs->hasOneDefUse() && !lhs->hasOneDefUse())) {
   1.692 +        *rhsp = lhs;
   1.693 +        *lhsp = rhs;
   1.694 +    }
   1.695 +}
   1.696 +
   1.697 +bool
   1.698 +LIRGenerator::visitTest(MTest *test)
   1.699 +{
   1.700 +    MDefinition *opd = test->getOperand(0);
   1.701 +    MBasicBlock *ifTrue = test->ifTrue();
   1.702 +    MBasicBlock *ifFalse = test->ifFalse();
   1.703 +
   1.704 +    // String is converted to length of string in the type analysis phase (see
   1.705 +    // TestPolicy).
   1.706 +    JS_ASSERT(opd->type() != MIRType_String);
   1.707 +
   1.708 +    if (opd->type() == MIRType_Value) {
   1.709 +        LDefinition temp0, temp1;
   1.710 +        if (test->operandMightEmulateUndefined()) {
   1.711 +            temp0 = temp();
   1.712 +            temp1 = temp();
   1.713 +        } else {
   1.714 +            temp0 = LDefinition::BogusTemp();
   1.715 +            temp1 = LDefinition::BogusTemp();
   1.716 +        }
   1.717 +        LTestVAndBranch *lir = new(alloc()) LTestVAndBranch(ifTrue, ifFalse, tempDouble(), temp0, temp1);
   1.718 +        if (!useBox(lir, LTestVAndBranch::Input, opd))
   1.719 +            return false;
   1.720 +        return add(lir, test);
   1.721 +    }
   1.722 +
   1.723 +    if (opd->type() == MIRType_Object) {
   1.724 +        // If the object might emulate undefined, we have to test for that.
   1.725 +        if (test->operandMightEmulateUndefined())
   1.726 +            return add(new(alloc()) LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp()), test);
   1.727 +
   1.728 +        // Otherwise we know it's truthy.
   1.729 +        return add(new(alloc()) LGoto(ifTrue));
   1.730 +    }
   1.731 +
   1.732 +    // These must be explicitly sniffed out since they are constants and have
   1.733 +    // no payload.
   1.734 +    if (opd->type() == MIRType_Undefined || opd->type() == MIRType_Null)
   1.735 +        return add(new(alloc()) LGoto(ifFalse));
   1.736 +
   1.737 +    // Constant Double operand.
   1.738 +    if (opd->type() == MIRType_Double && opd->isConstant()) {
   1.739 +        bool result = opd->toConstant()->valueToBoolean();
   1.740 +        return add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
   1.741 +    }
   1.742 +
   1.743 +    // Constant Float32 operand.
   1.744 +    if (opd->type() == MIRType_Float32 && opd->isConstant()) {
   1.745 +        bool result = opd->toConstant()->valueToBoolean();
   1.746 +        return add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
   1.747 +    }
   1.748 +
   1.749 +    // Constant Int32 operand.
   1.750 +    if (opd->type() == MIRType_Int32 && opd->isConstant()) {
   1.751 +        int32_t num = opd->toConstant()->value().toInt32();
   1.752 +        return add(new(alloc()) LGoto(num ? ifTrue : ifFalse));
   1.753 +    }
   1.754 +
   1.755 +    // Constant Boolean operand.
   1.756 +    if (opd->type() == MIRType_Boolean && opd->isConstant()) {
   1.757 +        bool result = opd->toConstant()->value().toBoolean();
   1.758 +        return add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
   1.759 +    }
   1.760 +
   1.761 +    // Check if the operand for this test is a compare operation. If it is, we want
   1.762 +    // to emit an LCompare*AndBranch rather than an LTest*AndBranch, to fuse the
   1.763 +    // compare and jump instructions.
   1.764 +    if (opd->isCompare() && opd->isEmittedAtUses()) {
   1.765 +        MCompare *comp = opd->toCompare();
   1.766 +        MDefinition *left = comp->lhs();
   1.767 +        MDefinition *right = comp->rhs();
   1.768 +
   1.769 +        // Try to fold the comparison so that we don't have to handle all cases.
   1.770 +        bool result;
   1.771 +        if (comp->tryFold(&result))
   1.772 +            return add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
   1.773 +
   1.774 +        // Emit LCompare*AndBranch.
   1.775 +
   1.776 +        // Compare and branch null/undefined.
   1.777 +        // The second operand has known null/undefined type,
   1.778 +        // so just test the first operand.
   1.779 +        if (comp->compareType() == MCompare::Compare_Null ||
   1.780 +            comp->compareType() == MCompare::Compare_Undefined)
   1.781 +        {
   1.782 +            if (left->type() == MIRType_Object) {
   1.783 +                MOZ_ASSERT(comp->operandMightEmulateUndefined(),
   1.784 +                           "MCompare::tryFold should handle the never-emulates-undefined case");
   1.785 +
   1.786 +                LEmulatesUndefinedAndBranch *lir =
   1.787 +                    new(alloc()) LEmulatesUndefinedAndBranch(comp, useRegister(left),
   1.788 +                                                             ifTrue, ifFalse, temp());
   1.789 +                return add(lir, test);
   1.790 +            }
   1.791 +
   1.792 +            LDefinition tmp, tmpToUnbox;
   1.793 +            if (comp->operandMightEmulateUndefined()) {
   1.794 +                tmp = temp();
   1.795 +                tmpToUnbox = tempToUnbox();
   1.796 +            } else {
   1.797 +                tmp = LDefinition::BogusTemp();
   1.798 +                tmpToUnbox = LDefinition::BogusTemp();
   1.799 +            }
   1.800 +
   1.801 +            LIsNullOrLikeUndefinedAndBranch *lir =
   1.802 +                new(alloc()) LIsNullOrLikeUndefinedAndBranch(comp, ifTrue, ifFalse,
   1.803 +                                                             tmp, tmpToUnbox);
   1.804 +            if (!useBox(lir, LIsNullOrLikeUndefinedAndBranch::Value, left))
   1.805 +                return false;
   1.806 +            return add(lir, test);
   1.807 +        }
   1.808 +
   1.809 +        // Compare and branch booleans.
   1.810 +        if (comp->compareType() == MCompare::Compare_Boolean) {
   1.811 +            JS_ASSERT(left->type() == MIRType_Value);
   1.812 +            JS_ASSERT(right->type() == MIRType_Boolean);
   1.813 +
   1.814 +            LAllocation rhs = useRegisterOrConstant(right);
   1.815 +            LCompareBAndBranch *lir = new(alloc()) LCompareBAndBranch(comp, rhs, ifTrue, ifFalse);
   1.816 +            if (!useBox(lir, LCompareBAndBranch::Lhs, left))
   1.817 +                return false;
   1.818 +            return add(lir, test);
   1.819 +        }
   1.820 +
   1.821 +        // Compare and branch Int32 or Object pointers.
   1.822 +        if (comp->isInt32Comparison() ||
   1.823 +            comp->compareType() == MCompare::Compare_UInt32 ||
   1.824 +            comp->compareType() == MCompare::Compare_Object)
   1.825 +        {
   1.826 +            JSOp op = ReorderComparison(comp->jsop(), &left, &right);
   1.827 +            LAllocation lhs = useRegister(left);
   1.828 +            LAllocation rhs;
   1.829 +            if (comp->isInt32Comparison() || comp->compareType() == MCompare::Compare_UInt32)
   1.830 +                rhs = useAnyOrConstant(right);
   1.831 +            else
   1.832 +                rhs = useRegister(right);
   1.833 +            LCompareAndBranch *lir = new(alloc()) LCompareAndBranch(comp, op, lhs, rhs,
   1.834 +                                                                    ifTrue, ifFalse);
   1.835 +            return add(lir, test);
   1.836 +        }
   1.837 +
   1.838 +        // Compare and branch doubles.
   1.839 +        if (comp->isDoubleComparison()) {
   1.840 +            LAllocation lhs = useRegister(left);
   1.841 +            LAllocation rhs = useRegister(right);
   1.842 +            LCompareDAndBranch *lir = new(alloc()) LCompareDAndBranch(comp, lhs, rhs,
   1.843 +                                                                      ifTrue, ifFalse);
   1.844 +            return add(lir, test);
   1.845 +        }
   1.846 +
   1.847 +        // Compare and branch floats.
   1.848 +        if (comp->isFloat32Comparison()) {
   1.849 +            LAllocation lhs = useRegister(left);
   1.850 +            LAllocation rhs = useRegister(right);
   1.851 +            LCompareFAndBranch *lir = new(alloc()) LCompareFAndBranch(comp, lhs, rhs,
   1.852 +                                                                      ifTrue, ifFalse);
   1.853 +            return add(lir, test);
   1.854 +        }
   1.855 +
   1.856 +        // Compare values.
   1.857 +        if (comp->compareType() == MCompare::Compare_Value) {
   1.858 +            LCompareVAndBranch *lir = new(alloc()) LCompareVAndBranch(comp, ifTrue, ifFalse);
   1.859 +            if (!useBoxAtStart(lir, LCompareVAndBranch::LhsInput, left))
   1.860 +                return false;
   1.861 +            if (!useBoxAtStart(lir, LCompareVAndBranch::RhsInput, right))
   1.862 +                return false;
   1.863 +            return add(lir, test);
   1.864 +        }
   1.865 +    }
   1.866 +
   1.867 +    // Check if the operand for this test is a bitand operation. If it is, we want
   1.868 +    // to emit an LBitAndAndBranch rather than an LTest*AndBranch.
   1.869 +    if (opd->isBitAnd() && opd->isEmittedAtUses()) {
   1.870 +        MDefinition *lhs = opd->getOperand(0);
   1.871 +        MDefinition *rhs = opd->getOperand(1);
   1.872 +        if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
   1.873 +            ReorderCommutative(&lhs, &rhs);
   1.874 +            return lowerForBitAndAndBranch(new(alloc()) LBitAndAndBranch(ifTrue, ifFalse), test, lhs, rhs);
   1.875 +        }
   1.876 +    }
   1.877 +
   1.878 +    if (opd->type() == MIRType_Double)
   1.879 +        return add(new(alloc()) LTestDAndBranch(useRegister(opd), ifTrue, ifFalse));
   1.880 +
   1.881 +    if (opd->type() == MIRType_Float32)
   1.882 +        return add(new(alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse));
   1.883 +
   1.884 +    JS_ASSERT(opd->type() == MIRType_Int32 || opd->type() == MIRType_Boolean);
   1.885 +    return add(new(alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse));
   1.886 +}
   1.887 +
   1.888 +bool
   1.889 +LIRGenerator::visitFunctionDispatch(MFunctionDispatch *ins)
   1.890 +{
   1.891 +    LFunctionDispatch *lir = new(alloc()) LFunctionDispatch(useRegister(ins->input()));
   1.892 +    return add(lir, ins);
   1.893 +}
   1.894 +
   1.895 +bool
   1.896 +LIRGenerator::visitTypeObjectDispatch(MTypeObjectDispatch *ins)
   1.897 +{
   1.898 +    LTypeObjectDispatch *lir = new(alloc()) LTypeObjectDispatch(useRegister(ins->input()), temp());
   1.899 +    return add(lir, ins);
   1.900 +}
   1.901 +
   1.902 +static inline bool
   1.903 +CanEmitCompareAtUses(MInstruction *ins)
   1.904 +{
   1.905 +    if (!ins->canEmitAtUses())
   1.906 +        return false;
   1.907 +
   1.908 +    bool foundTest = false;
   1.909 +    for (MUseIterator iter(ins->usesBegin()); iter != ins->usesEnd(); iter++) {
   1.910 +        MNode *node = iter->consumer();
   1.911 +        if (!node->isDefinition())
   1.912 +            return false;
   1.913 +        if (!node->toDefinition()->isTest())
   1.914 +            return false;
   1.915 +        if (foundTest)
   1.916 +            return false;
   1.917 +        foundTest = true;
   1.918 +    }
   1.919 +    return true;
   1.920 +}
   1.921 +
   1.922 +bool
   1.923 +LIRGenerator::visitCompare(MCompare *comp)
   1.924 +{
   1.925 +    MDefinition *left = comp->lhs();
   1.926 +    MDefinition *right = comp->rhs();
   1.927 +
   1.928 +    // Try to fold the comparison so that we don't have to handle all cases.
   1.929 +    bool result;
   1.930 +    if (comp->tryFold(&result))
   1.931 +        return define(new(alloc()) LInteger(result), comp);
   1.932 +
   1.933 +    // Move below the emitAtUses call if we ever implement
   1.934 +    // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't
   1.935 +    // make sense and avoids confusion.
   1.936 +    if (comp->compareType() == MCompare::Compare_String) {
   1.937 +        LCompareS *lir = new(alloc()) LCompareS(useRegister(left), useRegister(right), temp());
   1.938 +        if (!define(lir, comp))
   1.939 +            return false;
   1.940 +        return assignSafepoint(lir, comp);
   1.941 +    }
   1.942 +
   1.943 +    // Strict compare between value and string
   1.944 +    if (comp->compareType() == MCompare::Compare_StrictString) {
   1.945 +        JS_ASSERT(left->type() == MIRType_Value);
   1.946 +        JS_ASSERT(right->type() == MIRType_String);
   1.947 +
   1.948 +        LCompareStrictS *lir = new(alloc()) LCompareStrictS(useRegister(right), temp(), tempToUnbox());
   1.949 +        if (!useBox(lir, LCompareStrictS::Lhs, left))
   1.950 +            return false;
   1.951 +        if (!define(lir, comp))
   1.952 +            return false;
   1.953 +        return assignSafepoint(lir, comp);
   1.954 +    }
   1.955 +
   1.956 +    // Unknown/unspecialized compare use a VM call.
   1.957 +    if (comp->compareType() == MCompare::Compare_Unknown) {
   1.958 +        LCompareVM *lir = new(alloc()) LCompareVM();
   1.959 +        if (!useBoxAtStart(lir, LCompareVM::LhsInput, left))
   1.960 +            return false;
   1.961 +        if (!useBoxAtStart(lir, LCompareVM::RhsInput, right))
   1.962 +            return false;
   1.963 +        return defineReturn(lir, comp) && assignSafepoint(lir, comp);
   1.964 +    }
   1.965 +
   1.966 +    // Sniff out if the output of this compare is used only for a branching.
   1.967 +    // If it is, then we will emit an LCompare*AndBranch instruction in place
   1.968 +    // of this compare and any test that uses this compare. Thus, we can
   1.969 +    // ignore this Compare.
   1.970 +    if (CanEmitCompareAtUses(comp))
   1.971 +        return emitAtUses(comp);
   1.972 +
   1.973 +    // Compare Null and Undefined.
   1.974 +    if (comp->compareType() == MCompare::Compare_Null ||
   1.975 +        comp->compareType() == MCompare::Compare_Undefined)
   1.976 +    {
   1.977 +        if (left->type() == MIRType_Object) {
   1.978 +            MOZ_ASSERT(comp->operandMightEmulateUndefined(),
   1.979 +                       "MCompare::tryFold should have folded this away");
   1.980 +
   1.981 +            return define(new(alloc()) LEmulatesUndefined(useRegister(left)), comp);
   1.982 +        }
   1.983 +
   1.984 +        LDefinition tmp, tmpToUnbox;
   1.985 +        if (comp->operandMightEmulateUndefined()) {
   1.986 +            tmp = temp();
   1.987 +            tmpToUnbox = tempToUnbox();
   1.988 +        } else {
   1.989 +            tmp = LDefinition::BogusTemp();
   1.990 +            tmpToUnbox = LDefinition::BogusTemp();
   1.991 +        }
   1.992 +
   1.993 +        LIsNullOrLikeUndefined *lir = new(alloc()) LIsNullOrLikeUndefined(tmp, tmpToUnbox);
   1.994 +        if (!useBox(lir, LIsNullOrLikeUndefined::Value, left))
   1.995 +            return false;
   1.996 +        return define(lir, comp);
   1.997 +    }
   1.998 +
   1.999 +    // Compare booleans.
  1.1000 +    if (comp->compareType() == MCompare::Compare_Boolean) {
  1.1001 +        JS_ASSERT(left->type() == MIRType_Value);
  1.1002 +        JS_ASSERT(right->type() == MIRType_Boolean);
  1.1003 +
  1.1004 +        LCompareB *lir = new(alloc()) LCompareB(useRegisterOrConstant(right));
  1.1005 +        if (!useBox(lir, LCompareB::Lhs, left))
  1.1006 +            return false;
  1.1007 +        return define(lir, comp);
  1.1008 +    }
  1.1009 +
  1.1010 +    // Compare Int32 or Object pointers.
  1.1011 +    if (comp->isInt32Comparison() ||
  1.1012 +        comp->compareType() == MCompare::Compare_UInt32 ||
  1.1013 +        comp->compareType() == MCompare::Compare_Object)
  1.1014 +    {
  1.1015 +        JSOp op = ReorderComparison(comp->jsop(), &left, &right);
  1.1016 +        LAllocation lhs = useRegister(left);
  1.1017 +        LAllocation rhs;
  1.1018 +        if (comp->isInt32Comparison() ||
  1.1019 +            comp->compareType() == MCompare::Compare_UInt32)
  1.1020 +        {
  1.1021 +            rhs = useAnyOrConstant(right);
  1.1022 +        } else {
  1.1023 +            rhs = useRegister(right);
  1.1024 +        }
  1.1025 +        return define(new(alloc()) LCompare(op, lhs, rhs), comp);
  1.1026 +    }
  1.1027 +
  1.1028 +    // Compare doubles.
  1.1029 +    if (comp->isDoubleComparison())
  1.1030 +        return define(new(alloc()) LCompareD(useRegister(left), useRegister(right)), comp);
  1.1031 +
  1.1032 +    // Compare float32.
  1.1033 +    if (comp->isFloat32Comparison())
  1.1034 +        return define(new(alloc()) LCompareF(useRegister(left), useRegister(right)), comp);
  1.1035 +
  1.1036 +    // Compare values.
  1.1037 +    if (comp->compareType() == MCompare::Compare_Value) {
  1.1038 +        LCompareV *lir = new(alloc()) LCompareV();
  1.1039 +        if (!useBoxAtStart(lir, LCompareV::LhsInput, left))
  1.1040 +            return false;
  1.1041 +        if (!useBoxAtStart(lir, LCompareV::RhsInput, right))
  1.1042 +            return false;
  1.1043 +        return define(lir, comp);
  1.1044 +    }
  1.1045 +
  1.1046 +    MOZ_ASSUME_UNREACHABLE("Unrecognized compare type.");
  1.1047 +}
  1.1048 +
  1.1049 +bool
  1.1050 +LIRGenerator::lowerBitOp(JSOp op, MInstruction *ins)
  1.1051 +{
  1.1052 +    MDefinition *lhs = ins->getOperand(0);
  1.1053 +    MDefinition *rhs = ins->getOperand(1);
  1.1054 +
  1.1055 +    if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
  1.1056 +        ReorderCommutative(&lhs, &rhs);
  1.1057 +        return lowerForALU(new(alloc()) LBitOpI(op), ins, lhs, rhs);
  1.1058 +    }
  1.1059 +
  1.1060 +    LBitOpV *lir = new(alloc()) LBitOpV(op);
  1.1061 +    if (!useBoxAtStart(lir, LBitOpV::LhsInput, lhs))
  1.1062 +        return false;
  1.1063 +    if (!useBoxAtStart(lir, LBitOpV::RhsInput, rhs))
  1.1064 +        return false;
  1.1065 +
  1.1066 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.1067 +}
  1.1068 +
  1.1069 +bool
  1.1070 +LIRGenerator::visitTypeOf(MTypeOf *ins)
  1.1071 +{
  1.1072 +    MDefinition *opd = ins->input();
  1.1073 +    JS_ASSERT(opd->type() == MIRType_Value);
  1.1074 +
  1.1075 +    LTypeOfV *lir = new(alloc()) LTypeOfV(tempToUnbox());
  1.1076 +    if (!useBox(lir, LTypeOfV::Input, opd))
  1.1077 +        return false;
  1.1078 +    return define(lir, ins);
  1.1079 +}
  1.1080 +
  1.1081 +bool
  1.1082 +LIRGenerator::visitToId(MToId *ins)
  1.1083 +{
  1.1084 +    LToIdV *lir = new(alloc()) LToIdV(tempDouble());
  1.1085 +    if (!useBox(lir, LToIdV::Object, ins->lhs()))
  1.1086 +        return false;
  1.1087 +    if (!useBox(lir, LToIdV::Index, ins->rhs()))
  1.1088 +        return false;
  1.1089 +    return defineBox(lir, ins) && assignSafepoint(lir, ins);
  1.1090 +}
  1.1091 +
  1.1092 +bool
  1.1093 +LIRGenerator::visitBitNot(MBitNot *ins)
  1.1094 +{
  1.1095 +    MDefinition *input = ins->getOperand(0);
  1.1096 +
  1.1097 +    if (input->type() == MIRType_Int32)
  1.1098 +        return lowerForALU(new(alloc()) LBitNotI(), ins, input);
  1.1099 +
  1.1100 +    LBitNotV *lir = new(alloc()) LBitNotV;
  1.1101 +    if (!useBoxAtStart(lir, LBitNotV::Input, input))
  1.1102 +        return false;
  1.1103 +    if (!defineReturn(lir, ins))
  1.1104 +        return false;
  1.1105 +    return assignSafepoint(lir, ins);
  1.1106 +}
  1.1107 +
  1.1108 +static bool
  1.1109 +CanEmitBitAndAtUses(MInstruction *ins)
  1.1110 +{
  1.1111 +    if (!ins->canEmitAtUses())
  1.1112 +        return false;
  1.1113 +
  1.1114 +    if (ins->getOperand(0)->type() != MIRType_Int32 || ins->getOperand(1)->type() != MIRType_Int32)
  1.1115 +        return false;
  1.1116 +
  1.1117 +    MUseIterator iter(ins->usesBegin());
  1.1118 +    if (iter == ins->usesEnd())
  1.1119 +        return false;
  1.1120 +
  1.1121 +    MNode *node = iter->consumer();
  1.1122 +    if (!node->isDefinition())
  1.1123 +        return false;
  1.1124 +
  1.1125 +    if (!node->toDefinition()->isTest())
  1.1126 +        return false;
  1.1127 +
  1.1128 +    iter++;
  1.1129 +    return iter == ins->usesEnd();
  1.1130 +}
  1.1131 +
  1.1132 +bool
  1.1133 +LIRGenerator::visitBitAnd(MBitAnd *ins)
  1.1134 +{
  1.1135 +    // Sniff out if the output of this bitand is used only for a branching.
  1.1136 +    // If it is, then we will emit an LBitAndAndBranch instruction in place
  1.1137 +    // of this bitand and any test that uses this bitand. Thus, we can
  1.1138 +    // ignore this BitAnd.
  1.1139 +    if (CanEmitBitAndAtUses(ins))
  1.1140 +        return emitAtUses(ins);
  1.1141 +
  1.1142 +    return lowerBitOp(JSOP_BITAND, ins);
  1.1143 +}
  1.1144 +
  1.1145 +bool
  1.1146 +LIRGenerator::visitBitOr(MBitOr *ins)
  1.1147 +{
  1.1148 +    return lowerBitOp(JSOP_BITOR, ins);
  1.1149 +}
  1.1150 +
  1.1151 +bool
  1.1152 +LIRGenerator::visitBitXor(MBitXor *ins)
  1.1153 +{
  1.1154 +    return lowerBitOp(JSOP_BITXOR, ins);
  1.1155 +}
  1.1156 +
  1.1157 +bool
  1.1158 +LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction *ins)
  1.1159 +{
  1.1160 +    MDefinition *lhs = ins->getOperand(0);
  1.1161 +    MDefinition *rhs = ins->getOperand(1);
  1.1162 +
  1.1163 +    if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
  1.1164 +        if (ins->type() == MIRType_Double) {
  1.1165 +            JS_ASSERT(op == JSOP_URSH);
  1.1166 +            return lowerUrshD(ins->toUrsh());
  1.1167 +        }
  1.1168 +
  1.1169 +        LShiftI *lir = new(alloc()) LShiftI(op);
  1.1170 +        if (op == JSOP_URSH) {
  1.1171 +            if (ins->toUrsh()->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
  1.1172 +                return false;
  1.1173 +        }
  1.1174 +        return lowerForShift(lir, ins, lhs, rhs);
  1.1175 +    }
  1.1176 +
  1.1177 +    JS_ASSERT(ins->specialization() == MIRType_None);
  1.1178 +
  1.1179 +    if (op == JSOP_URSH) {
  1.1180 +        // Result is either int32 or double so we have to use BinaryV.
  1.1181 +        return lowerBinaryV(JSOP_URSH, ins);
  1.1182 +    }
  1.1183 +
  1.1184 +    LBitOpV *lir = new(alloc()) LBitOpV(op);
  1.1185 +    if (!useBoxAtStart(lir, LBitOpV::LhsInput, lhs))
  1.1186 +        return false;
  1.1187 +    if (!useBoxAtStart(lir, LBitOpV::RhsInput, rhs))
  1.1188 +        return false;
  1.1189 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.1190 +}
  1.1191 +
  1.1192 +bool
  1.1193 +LIRGenerator::visitLsh(MLsh *ins)
  1.1194 +{
  1.1195 +    return lowerShiftOp(JSOP_LSH, ins);
  1.1196 +}
  1.1197 +
  1.1198 +bool
  1.1199 +LIRGenerator::visitRsh(MRsh *ins)
  1.1200 +{
  1.1201 +    return lowerShiftOp(JSOP_RSH, ins);
  1.1202 +}
  1.1203 +
  1.1204 +bool
  1.1205 +LIRGenerator::visitUrsh(MUrsh *ins)
  1.1206 +{
  1.1207 +    return lowerShiftOp(JSOP_URSH, ins);
  1.1208 +}
  1.1209 +
  1.1210 +bool
  1.1211 +LIRGenerator::visitFloor(MFloor *ins)
  1.1212 +{
  1.1213 +    MIRType type = ins->num()->type();
  1.1214 +    JS_ASSERT(IsFloatingPointType(type));
  1.1215 +
  1.1216 +    if (type == MIRType_Double) {
  1.1217 +        LFloor *lir = new(alloc()) LFloor(useRegister(ins->num()));
  1.1218 +        if (!assignSnapshot(lir))
  1.1219 +            return false;
  1.1220 +        return define(lir, ins);
  1.1221 +    }
  1.1222 +
  1.1223 +    LFloorF *lir = new(alloc()) LFloorF(useRegister(ins->num()));
  1.1224 +    if (!assignSnapshot(lir))
  1.1225 +        return false;
  1.1226 +    return define(lir, ins);
  1.1227 +}
  1.1228 +
  1.1229 +bool
  1.1230 +LIRGenerator::visitRound(MRound *ins)
  1.1231 +{
  1.1232 +    MIRType type = ins->num()->type();
  1.1233 +    JS_ASSERT(IsFloatingPointType(type));
  1.1234 +
  1.1235 +    if (type == MIRType_Double) {
  1.1236 +        LRound *lir = new (alloc()) LRound(useRegister(ins->num()), tempDouble());
  1.1237 +        if (!assignSnapshot(lir))
  1.1238 +            return false;
  1.1239 +        return define(lir, ins);
  1.1240 +    }
  1.1241 +
  1.1242 +    LRoundF *lir = new (alloc()) LRoundF(useRegister(ins->num()), tempDouble());
  1.1243 +    if (!assignSnapshot(lir))
  1.1244 +        return false;
  1.1245 +    return define(lir, ins);
  1.1246 +}
  1.1247 +
  1.1248 +bool
  1.1249 +LIRGenerator::visitMinMax(MMinMax *ins)
  1.1250 +{
  1.1251 +    MDefinition *first = ins->getOperand(0);
  1.1252 +    MDefinition *second = ins->getOperand(1);
  1.1253 +
  1.1254 +    ReorderCommutative(&first, &second);
  1.1255 +
  1.1256 +    if (ins->specialization() == MIRType_Int32) {
  1.1257 +        LMinMaxI *lir = new(alloc()) LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
  1.1258 +        return defineReuseInput(lir, ins, 0);
  1.1259 +    }
  1.1260 +
  1.1261 +    LMinMaxD *lir = new(alloc()) LMinMaxD(useRegisterAtStart(first), useRegister(second));
  1.1262 +    return defineReuseInput(lir, ins, 0);
  1.1263 +}
  1.1264 +
  1.1265 +bool
  1.1266 +LIRGenerator::visitAbs(MAbs *ins)
  1.1267 +{
  1.1268 +    MDefinition *num = ins->num();
  1.1269 +    JS_ASSERT(IsNumberType(num->type()));
  1.1270 +
  1.1271 +    if (num->type() == MIRType_Int32) {
  1.1272 +        LAbsI *lir = new(alloc()) LAbsI(useRegisterAtStart(num));
  1.1273 +        // needed to handle abs(INT32_MIN)
  1.1274 +        if (ins->fallible() && !assignSnapshot(lir))
  1.1275 +            return false;
  1.1276 +        return defineReuseInput(lir, ins, 0);
  1.1277 +    }
  1.1278 +    if (num->type() == MIRType_Float32) {
  1.1279 +        LAbsF *lir = new(alloc()) LAbsF(useRegisterAtStart(num));
  1.1280 +        return defineReuseInput(lir, ins, 0);
  1.1281 +    }
  1.1282 +
  1.1283 +    LAbsD *lir = new(alloc()) LAbsD(useRegisterAtStart(num));
  1.1284 +    return defineReuseInput(lir, ins, 0);
  1.1285 +}
  1.1286 +
  1.1287 +bool
  1.1288 +LIRGenerator::visitSqrt(MSqrt *ins)
  1.1289 +{
  1.1290 +    MDefinition *num = ins->num();
  1.1291 +    JS_ASSERT(IsFloatingPointType(num->type()));
  1.1292 +    if (num->type() == MIRType_Double) {
  1.1293 +        LSqrtD *lir = new(alloc()) LSqrtD(useRegisterAtStart(num));
  1.1294 +        return define(lir, ins);
  1.1295 +    }
  1.1296 +
  1.1297 +    LSqrtF *lir = new(alloc()) LSqrtF(useRegisterAtStart(num));
  1.1298 +    return define(lir, ins);
  1.1299 +}
  1.1300 +
  1.1301 +bool
  1.1302 +LIRGenerator::visitAtan2(MAtan2 *ins)
  1.1303 +{
  1.1304 +    MDefinition *y = ins->y();
  1.1305 +    JS_ASSERT(y->type() == MIRType_Double);
  1.1306 +
  1.1307 +    MDefinition *x = ins->x();
  1.1308 +    JS_ASSERT(x->type() == MIRType_Double);
  1.1309 +
  1.1310 +    LAtan2D *lir = new(alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x), tempFixed(CallTempReg0));
  1.1311 +    return defineReturn(lir, ins);
  1.1312 +}
  1.1313 +
  1.1314 +bool
  1.1315 +LIRGenerator::visitHypot(MHypot *ins)
  1.1316 +{
  1.1317 +    MDefinition *x = ins->x();
  1.1318 +    JS_ASSERT(x->type() == MIRType_Double);
  1.1319 +
  1.1320 +    MDefinition *y = ins->y();
  1.1321 +    JS_ASSERT(y->type() == MIRType_Double);
  1.1322 +
  1.1323 +    LHypot *lir = new(alloc()) LHypot(useRegisterAtStart(x), useRegisterAtStart(y), tempFixed(CallTempReg0));
  1.1324 +    return defineReturn(lir, ins);
  1.1325 +}
  1.1326 +
  1.1327 +bool
  1.1328 +LIRGenerator::visitPow(MPow *ins)
  1.1329 +{
  1.1330 +    MDefinition *input = ins->input();
  1.1331 +    JS_ASSERT(input->type() == MIRType_Double);
  1.1332 +
  1.1333 +    MDefinition *power = ins->power();
  1.1334 +    JS_ASSERT(power->type() == MIRType_Int32 || power->type() == MIRType_Double);
  1.1335 +
  1.1336 +    if (power->type() == MIRType_Int32) {
  1.1337 +        // Note: useRegisterAtStart here is safe, the temp is a GP register so
  1.1338 +        // it will never get the same register.
  1.1339 +        LPowI *lir = new(alloc()) LPowI(useRegisterAtStart(input), useFixed(power, CallTempReg1),
  1.1340 +                                        tempFixed(CallTempReg0));
  1.1341 +        return defineReturn(lir, ins);
  1.1342 +    }
  1.1343 +
  1.1344 +    LPowD *lir = new(alloc()) LPowD(useRegisterAtStart(input), useRegisterAtStart(power),
  1.1345 +                                    tempFixed(CallTempReg0));
  1.1346 +    return defineReturn(lir, ins);
  1.1347 +}
  1.1348 +
  1.1349 +bool
  1.1350 +LIRGenerator::visitRandom(MRandom *ins)
  1.1351 +{
  1.1352 +    LRandom *lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
  1.1353 +    return defineReturn(lir, ins);
  1.1354 +}
  1.1355 +
  1.1356 +bool
  1.1357 +LIRGenerator::visitMathFunction(MMathFunction *ins)
  1.1358 +{
  1.1359 +    JS_ASSERT(IsFloatingPointType(ins->type()));
  1.1360 +    JS_ASSERT_IF(ins->type() == MIRType_Double, ins->input()->type() == MIRType_Double);
  1.1361 +    JS_ASSERT_IF(ins->type() == MIRType_Float32, ins->input()->type() == MIRType_Float32);
  1.1362 +
  1.1363 +    if (ins->type() == MIRType_Double) {
  1.1364 +        // Note: useRegisterAtStart is safe here, the temp is not a FP register.
  1.1365 +        LMathFunctionD *lir = new(alloc()) LMathFunctionD(useRegisterAtStart(ins->input()),
  1.1366 +                                                          tempFixed(CallTempReg0));
  1.1367 +        return defineReturn(lir, ins);
  1.1368 +    }
  1.1369 +
  1.1370 +    LMathFunctionF *lir = new(alloc()) LMathFunctionF(useRegisterAtStart(ins->input()),
  1.1371 +                                                      tempFixed(CallTempReg0));
  1.1372 +    return defineReturn(lir, ins);
  1.1373 +}
  1.1374 +
  1.1375 +// Try to mark an add or sub instruction as able to recover its input when
  1.1376 +// bailing out.
  1.1377 +template <typename S, typename T>
  1.1378 +static void
  1.1379 +MaybeSetRecoversInput(S *mir, T *lir)
  1.1380 +{
  1.1381 +    JS_ASSERT(lir->mirRaw() == mir);
  1.1382 +    if (!mir->fallible())
  1.1383 +        return;
  1.1384 +
  1.1385 +    if (lir->output()->policy() != LDefinition::MUST_REUSE_INPUT)
  1.1386 +        return;
  1.1387 +
  1.1388 +    // The original operands to an add or sub can't be recovered if they both
  1.1389 +    // use the same register.
  1.1390 +    if (lir->lhs()->isUse() && lir->rhs()->isUse() &&
  1.1391 +        lir->lhs()->toUse()->virtualRegister() == lir->rhs()->toUse()->virtualRegister())
  1.1392 +    {
  1.1393 +        return;
  1.1394 +    }
  1.1395 +
  1.1396 +    // Add instructions that are on two different values can recover
  1.1397 +    // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy
  1.1398 +    // of that input does not need to be kept alive in the snapshot
  1.1399 +    // for the instruction.
  1.1400 +
  1.1401 +    lir->setRecoversInput();
  1.1402 +
  1.1403 +    const LUse *input = lir->getOperand(lir->output()->getReusedInput())->toUse();
  1.1404 +    lir->snapshot()->rewriteRecoveredInput(*input);
  1.1405 +}
  1.1406 +
  1.1407 +bool
  1.1408 +LIRGenerator::visitAdd(MAdd *ins)
  1.1409 +{
  1.1410 +    MDefinition *lhs = ins->getOperand(0);
  1.1411 +    MDefinition *rhs = ins->getOperand(1);
  1.1412 +
  1.1413 +    JS_ASSERT(lhs->type() == rhs->type());
  1.1414 +
  1.1415 +    if (ins->specialization() == MIRType_Int32) {
  1.1416 +        JS_ASSERT(lhs->type() == MIRType_Int32);
  1.1417 +        ReorderCommutative(&lhs, &rhs);
  1.1418 +        LAddI *lir = new(alloc()) LAddI;
  1.1419 +
  1.1420 +        if (ins->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
  1.1421 +            return false;
  1.1422 +
  1.1423 +        if (!lowerForALU(lir, ins, lhs, rhs))
  1.1424 +            return false;
  1.1425 +
  1.1426 +        MaybeSetRecoversInput(ins, lir);
  1.1427 +        return true;
  1.1428 +    }
  1.1429 +
  1.1430 +    if (ins->specialization() == MIRType_Double) {
  1.1431 +        JS_ASSERT(lhs->type() == MIRType_Double);
  1.1432 +        ReorderCommutative(&lhs, &rhs);
  1.1433 +        return lowerForFPU(new(alloc()) LMathD(JSOP_ADD), ins, lhs, rhs);
  1.1434 +    }
  1.1435 +
  1.1436 +    if (ins->specialization() == MIRType_Float32) {
  1.1437 +        JS_ASSERT(lhs->type() == MIRType_Float32);
  1.1438 +        ReorderCommutative(&lhs, &rhs);
  1.1439 +        return lowerForFPU(new(alloc()) LMathF(JSOP_ADD), ins, lhs, rhs);
  1.1440 +    }
  1.1441 +
  1.1442 +    return lowerBinaryV(JSOP_ADD, ins);
  1.1443 +}
  1.1444 +
  1.1445 +bool
  1.1446 +LIRGenerator::visitSub(MSub *ins)
  1.1447 +{
  1.1448 +    MDefinition *lhs = ins->lhs();
  1.1449 +    MDefinition *rhs = ins->rhs();
  1.1450 +
  1.1451 +    JS_ASSERT(lhs->type() == rhs->type());
  1.1452 +
  1.1453 +    if (ins->specialization() == MIRType_Int32) {
  1.1454 +        JS_ASSERT(lhs->type() == MIRType_Int32);
  1.1455 +
  1.1456 +        LSubI *lir = new(alloc()) LSubI;
  1.1457 +        if (ins->fallible() && !assignSnapshot(lir))
  1.1458 +            return false;
  1.1459 +
  1.1460 +        if (!lowerForALU(lir, ins, lhs, rhs))
  1.1461 +            return false;
  1.1462 +
  1.1463 +        MaybeSetRecoversInput(ins, lir);
  1.1464 +        return true;
  1.1465 +    }
  1.1466 +    if (ins->specialization() == MIRType_Double) {
  1.1467 +        JS_ASSERT(lhs->type() == MIRType_Double);
  1.1468 +        return lowerForFPU(new(alloc()) LMathD(JSOP_SUB), ins, lhs, rhs);
  1.1469 +    }
  1.1470 +    if (ins->specialization() == MIRType_Float32) {
  1.1471 +        JS_ASSERT(lhs->type() == MIRType_Float32);
  1.1472 +        return lowerForFPU(new(alloc()) LMathF(JSOP_SUB), ins, lhs, rhs);
  1.1473 +    }
  1.1474 +
  1.1475 +    return lowerBinaryV(JSOP_SUB, ins);
  1.1476 +}
  1.1477 +
  1.1478 +bool
  1.1479 +LIRGenerator::visitMul(MMul *ins)
  1.1480 +{
  1.1481 +    MDefinition *lhs = ins->lhs();
  1.1482 +    MDefinition *rhs = ins->rhs();
  1.1483 +    JS_ASSERT(lhs->type() == rhs->type());
  1.1484 +
  1.1485 +    if (ins->specialization() == MIRType_Int32) {
  1.1486 +        JS_ASSERT(lhs->type() == MIRType_Int32);
  1.1487 +        ReorderCommutative(&lhs, &rhs);
  1.1488 +
  1.1489 +        // If our RHS is a constant -1 and we don't have to worry about
  1.1490 +        // overflow, we can optimize to an LNegI.
  1.1491 +        if (!ins->fallible() && rhs->isConstant() && rhs->toConstant()->value() == Int32Value(-1))
  1.1492 +            return defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(lhs)), ins, 0);
  1.1493 +
  1.1494 +        return lowerMulI(ins, lhs, rhs);
  1.1495 +    }
  1.1496 +    if (ins->specialization() == MIRType_Double) {
  1.1497 +        JS_ASSERT(lhs->type() == MIRType_Double);
  1.1498 +        ReorderCommutative(&lhs, &rhs);
  1.1499 +
  1.1500 +        // If our RHS is a constant -1.0, we can optimize to an LNegD.
  1.1501 +        if (rhs->isConstant() && rhs->toConstant()->value() == DoubleValue(-1.0))
  1.1502 +            return defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0);
  1.1503 +
  1.1504 +        return lowerForFPU(new(alloc()) LMathD(JSOP_MUL), ins, lhs, rhs);
  1.1505 +    }
  1.1506 +    if (ins->specialization() == MIRType_Float32) {
  1.1507 +        JS_ASSERT(lhs->type() == MIRType_Float32);
  1.1508 +        ReorderCommutative(&lhs, &rhs);
  1.1509 +
  1.1510 +        // We apply the same optimizations as for doubles
  1.1511 +        if (rhs->isConstant() && rhs->toConstant()->value() == Float32Value(-1.0f))
  1.1512 +            return defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0);
  1.1513 +
  1.1514 +        return lowerForFPU(new(alloc()) LMathF(JSOP_MUL), ins, lhs, rhs);
  1.1515 +    }
  1.1516 +
  1.1517 +    return lowerBinaryV(JSOP_MUL, ins);
  1.1518 +}
  1.1519 +
  1.1520 +bool
  1.1521 +LIRGenerator::visitDiv(MDiv *ins)
  1.1522 +{
  1.1523 +    MDefinition *lhs = ins->lhs();
  1.1524 +    MDefinition *rhs = ins->rhs();
  1.1525 +    JS_ASSERT(lhs->type() == rhs->type());
  1.1526 +
  1.1527 +    if (ins->specialization() == MIRType_Int32) {
  1.1528 +        JS_ASSERT(lhs->type() == MIRType_Int32);
  1.1529 +        return lowerDivI(ins);
  1.1530 +    }
  1.1531 +    if (ins->specialization() == MIRType_Double) {
  1.1532 +        JS_ASSERT(lhs->type() == MIRType_Double);
  1.1533 +        return lowerForFPU(new(alloc()) LMathD(JSOP_DIV), ins, lhs, rhs);
  1.1534 +    }
  1.1535 +    if (ins->specialization() == MIRType_Float32) {
  1.1536 +        JS_ASSERT(lhs->type() == MIRType_Float32);
  1.1537 +        return lowerForFPU(new(alloc()) LMathF(JSOP_DIV), ins, lhs, rhs);
  1.1538 +    }
  1.1539 +
  1.1540 +    return lowerBinaryV(JSOP_DIV, ins);
  1.1541 +}
  1.1542 +
  1.1543 +bool
  1.1544 +LIRGenerator::visitMod(MMod *ins)
  1.1545 +{
  1.1546 +    JS_ASSERT(ins->lhs()->type() == ins->rhs()->type());
  1.1547 +
  1.1548 +    if (ins->specialization() == MIRType_Int32) {
  1.1549 +        JS_ASSERT(ins->type() == MIRType_Int32);
  1.1550 +        JS_ASSERT(ins->lhs()->type() == MIRType_Int32);
  1.1551 +        return lowerModI(ins);
  1.1552 +    }
  1.1553 +
  1.1554 +    if (ins->specialization() == MIRType_Double) {
  1.1555 +        JS_ASSERT(ins->type() == MIRType_Double);
  1.1556 +        JS_ASSERT(ins->lhs()->type() == MIRType_Double);
  1.1557 +        JS_ASSERT(ins->rhs()->type() == MIRType_Double);
  1.1558 +
  1.1559 +        // Note: useRegisterAtStart is safe here, the temp is not a FP register.
  1.1560 +        LModD *lir = new(alloc()) LModD(useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()),
  1.1561 +                                        tempFixed(CallTempReg0));
  1.1562 +        return defineReturn(lir, ins);
  1.1563 +    }
  1.1564 +
  1.1565 +    return lowerBinaryV(JSOP_MOD, ins);
  1.1566 +}
  1.1567 +
  1.1568 +bool
  1.1569 +LIRGenerator::lowerBinaryV(JSOp op, MBinaryInstruction *ins)
  1.1570 +{
  1.1571 +    MDefinition *lhs = ins->getOperand(0);
  1.1572 +    MDefinition *rhs = ins->getOperand(1);
  1.1573 +
  1.1574 +    JS_ASSERT(lhs->type() == MIRType_Value);
  1.1575 +    JS_ASSERT(rhs->type() == MIRType_Value);
  1.1576 +
  1.1577 +    LBinaryV *lir = new(alloc()) LBinaryV(op);
  1.1578 +    if (!useBoxAtStart(lir, LBinaryV::LhsInput, lhs))
  1.1579 +        return false;
  1.1580 +    if (!useBoxAtStart(lir, LBinaryV::RhsInput, rhs))
  1.1581 +        return false;
  1.1582 +    if (!defineReturn(lir, ins))
  1.1583 +        return false;
  1.1584 +    return assignSafepoint(lir, ins);
  1.1585 +}
  1.1586 +
  1.1587 +bool
  1.1588 +LIRGenerator::visitConcat(MConcat *ins)
  1.1589 +{
  1.1590 +    MDefinition *lhs = ins->getOperand(0);
  1.1591 +    MDefinition *rhs = ins->getOperand(1);
  1.1592 +
  1.1593 +    JS_ASSERT(lhs->type() == MIRType_String);
  1.1594 +    JS_ASSERT(rhs->type() == MIRType_String);
  1.1595 +    JS_ASSERT(ins->type() == MIRType_String);
  1.1596 +
  1.1597 +    LConcat *lir = new(alloc()) LConcat(useFixedAtStart(lhs, CallTempReg0),
  1.1598 +                                        useFixedAtStart(rhs, CallTempReg1),
  1.1599 +                                        tempFixed(CallTempReg0),
  1.1600 +                                        tempFixed(CallTempReg1),
  1.1601 +                                        tempFixed(CallTempReg2),
  1.1602 +                                        tempFixed(CallTempReg3),
  1.1603 +                                        tempFixed(CallTempReg4));
  1.1604 +    if (!defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5))))
  1.1605 +        return false;
  1.1606 +    return assignSafepoint(lir, ins);
  1.1607 +}
  1.1608 +
  1.1609 +bool
  1.1610 +LIRGenerator::visitConcatPar(MConcatPar *ins)
  1.1611 +{
  1.1612 +    MDefinition *cx = ins->forkJoinContext();
  1.1613 +    MDefinition *lhs = ins->lhs();
  1.1614 +    MDefinition *rhs = ins->rhs();
  1.1615 +
  1.1616 +    JS_ASSERT(lhs->type() == MIRType_String);
  1.1617 +    JS_ASSERT(rhs->type() == MIRType_String);
  1.1618 +    JS_ASSERT(ins->type() == MIRType_String);
  1.1619 +
  1.1620 +    LConcatPar *lir = new(alloc()) LConcatPar(useFixed(cx, CallTempReg4),
  1.1621 +                                              useFixedAtStart(lhs, CallTempReg0),
  1.1622 +                                              useFixedAtStart(rhs, CallTempReg1),
  1.1623 +                                              tempFixed(CallTempReg0),
  1.1624 +                                              tempFixed(CallTempReg1),
  1.1625 +                                              tempFixed(CallTempReg2),
  1.1626 +                                              tempFixed(CallTempReg3));
  1.1627 +    if (!defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5))))
  1.1628 +        return false;
  1.1629 +    return assignSafepoint(lir, ins);
  1.1630 +}
  1.1631 +
  1.1632 +bool
  1.1633 +LIRGenerator::visitCharCodeAt(MCharCodeAt *ins)
  1.1634 +{
  1.1635 +    MDefinition *str = ins->getOperand(0);
  1.1636 +    MDefinition *idx = ins->getOperand(1);
  1.1637 +
  1.1638 +    JS_ASSERT(str->type() == MIRType_String);
  1.1639 +    JS_ASSERT(idx->type() == MIRType_Int32);
  1.1640 +
  1.1641 +    LCharCodeAt *lir = new(alloc()) LCharCodeAt(useRegister(str), useRegister(idx));
  1.1642 +    if (!define(lir, ins))
  1.1643 +        return false;
  1.1644 +    return assignSafepoint(lir, ins);
  1.1645 +}
  1.1646 +
  1.1647 +bool
  1.1648 +LIRGenerator::visitFromCharCode(MFromCharCode *ins)
  1.1649 +{
  1.1650 +    MDefinition *code = ins->getOperand(0);
  1.1651 +
  1.1652 +    JS_ASSERT(code->type() == MIRType_Int32);
  1.1653 +
  1.1654 +    LFromCharCode *lir = new(alloc()) LFromCharCode(useRegister(code));
  1.1655 +    if (!define(lir, ins))
  1.1656 +        return false;
  1.1657 +    return assignSafepoint(lir, ins);
  1.1658 +}
  1.1659 +
  1.1660 +bool
  1.1661 +LIRGenerator::visitStart(MStart *start)
  1.1662 +{
  1.1663 +    // Create a snapshot that captures the initial state of the function.
  1.1664 +    LStart *lir = new(alloc()) LStart;
  1.1665 +    if (!assignSnapshot(lir))
  1.1666 +        return false;
  1.1667 +
  1.1668 +    if (start->startType() == MStart::StartType_Default)
  1.1669 +        lirGraph_.setEntrySnapshot(lir->snapshot());
  1.1670 +    return add(lir);
  1.1671 +}
  1.1672 +
  1.1673 +bool
  1.1674 +LIRGenerator::visitNop(MNop *nop)
  1.1675 +{
  1.1676 +    return true;
  1.1677 +}
  1.1678 +
  1.1679 +bool
  1.1680 +LIRGenerator::visitOsrEntry(MOsrEntry *entry)
  1.1681 +{
  1.1682 +    LOsrEntry *lir = new(alloc()) LOsrEntry;
  1.1683 +    return defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg)));
  1.1684 +}
  1.1685 +
  1.1686 +bool
  1.1687 +LIRGenerator::visitOsrValue(MOsrValue *value)
  1.1688 +{
  1.1689 +    LOsrValue *lir = new(alloc()) LOsrValue(useRegister(value->entry()));
  1.1690 +    return defineBox(lir, value);
  1.1691 +}
  1.1692 +
  1.1693 +bool
  1.1694 +LIRGenerator::visitOsrReturnValue(MOsrReturnValue *value)
  1.1695 +{
  1.1696 +    LOsrReturnValue *lir = new(alloc()) LOsrReturnValue(useRegister(value->entry()));
  1.1697 +    return defineBox(lir, value);
  1.1698 +}
  1.1699 +
  1.1700 +bool
  1.1701 +LIRGenerator::visitOsrScopeChain(MOsrScopeChain *object)
  1.1702 +{
  1.1703 +    LOsrScopeChain *lir = new(alloc()) LOsrScopeChain(useRegister(object->entry()));
  1.1704 +    return define(lir, object);
  1.1705 +}
  1.1706 +
  1.1707 +bool
  1.1708 +LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject *object)
  1.1709 +{
  1.1710 +    LOsrArgumentsObject *lir = new(alloc()) LOsrArgumentsObject(useRegister(object->entry()));
  1.1711 +    return define(lir, object);
  1.1712 +}
  1.1713 +
  1.1714 +bool
  1.1715 +LIRGenerator::visitToDouble(MToDouble *convert)
  1.1716 +{
  1.1717 +    MDefinition *opd = convert->input();
  1.1718 +    mozilla::DebugOnly<MToDouble::ConversionKind> conversion = convert->conversion();
  1.1719 +
  1.1720 +    switch (opd->type()) {
  1.1721 +      case MIRType_Value:
  1.1722 +      {
  1.1723 +        LValueToDouble *lir = new(alloc()) LValueToDouble();
  1.1724 +        if (!useBox(lir, LValueToDouble::Input, opd))
  1.1725 +            return false;
  1.1726 +        return assignSnapshot(lir) && define(lir, convert);
  1.1727 +      }
  1.1728 +
  1.1729 +      case MIRType_Null:
  1.1730 +        JS_ASSERT(conversion != MToDouble::NumbersOnly && conversion != MToDouble::NonNullNonStringPrimitives);
  1.1731 +        return lowerConstantDouble(0, convert);
  1.1732 +
  1.1733 +      case MIRType_Undefined:
  1.1734 +        JS_ASSERT(conversion != MToDouble::NumbersOnly);
  1.1735 +        return lowerConstantDouble(GenericNaN(), convert);
  1.1736 +
  1.1737 +      case MIRType_Boolean:
  1.1738 +        JS_ASSERT(conversion != MToDouble::NumbersOnly);
  1.1739 +        /* FALLTHROUGH */
  1.1740 +
  1.1741 +      case MIRType_Int32:
  1.1742 +      {
  1.1743 +        LInt32ToDouble *lir = new(alloc()) LInt32ToDouble(useRegister(opd));
  1.1744 +        return define(lir, convert);
  1.1745 +      }
  1.1746 +
  1.1747 +      case MIRType_Float32:
  1.1748 +      {
  1.1749 +        LFloat32ToDouble *lir = new(alloc()) LFloat32ToDouble(useRegisterAtStart(opd));
  1.1750 +        return define(lir, convert);
  1.1751 +      }
  1.1752 +
  1.1753 +      case MIRType_Double:
  1.1754 +        return redefine(convert, opd);
  1.1755 +
  1.1756 +      default:
  1.1757 +        // Objects might be effectful.
  1.1758 +        // Strings are complicated - we don't handle them yet.
  1.1759 +        MOZ_ASSUME_UNREACHABLE("unexpected type");
  1.1760 +    }
  1.1761 +}
  1.1762 +
  1.1763 +bool
  1.1764 +LIRGenerator::visitToFloat32(MToFloat32 *convert)
  1.1765 +{
  1.1766 +    MDefinition *opd = convert->input();
  1.1767 +    mozilla::DebugOnly<MToFloat32::ConversionKind> conversion = convert->conversion();
  1.1768 +
  1.1769 +    switch (opd->type()) {
  1.1770 +      case MIRType_Value:
  1.1771 +      {
  1.1772 +        LValueToFloat32 *lir = new(alloc()) LValueToFloat32();
  1.1773 +        if (!useBox(lir, LValueToFloat32::Input, opd))
  1.1774 +            return false;
  1.1775 +        return assignSnapshot(lir) && define(lir, convert);
  1.1776 +      }
  1.1777 +
  1.1778 +      case MIRType_Null:
  1.1779 +        JS_ASSERT(conversion != MToFloat32::NonStringPrimitives);
  1.1780 +        return lowerConstantFloat32(0, convert);
  1.1781 +
  1.1782 +      case MIRType_Undefined:
  1.1783 +        JS_ASSERT(conversion != MToFloat32::NumbersOnly);
  1.1784 +        return lowerConstantFloat32(GenericNaN(), convert);
  1.1785 +
  1.1786 +      case MIRType_Boolean:
  1.1787 +        JS_ASSERT(conversion != MToFloat32::NumbersOnly);
  1.1788 +        /* FALLTHROUGH */
  1.1789 +
  1.1790 +      case MIRType_Int32:
  1.1791 +      {
  1.1792 +        LInt32ToFloat32 *lir = new(alloc()) LInt32ToFloat32(useRegister(opd));
  1.1793 +        return define(lir, convert);
  1.1794 +      }
  1.1795 +
  1.1796 +      case MIRType_Double:
  1.1797 +      {
  1.1798 +        LDoubleToFloat32 *lir = new(alloc()) LDoubleToFloat32(useRegister(opd));
  1.1799 +        return define(lir, convert);
  1.1800 +      }
  1.1801 +
  1.1802 +      case MIRType_Float32:
  1.1803 +        return redefine(convert, opd);
  1.1804 +
  1.1805 +      default:
  1.1806 +        // Objects might be effectful.
  1.1807 +        // Strings are complicated - we don't handle them yet.
  1.1808 +        MOZ_ASSUME_UNREACHABLE("unexpected type");
  1.1809 +        return false;
  1.1810 +    }
  1.1811 +}
  1.1812 +
  1.1813 +bool
  1.1814 +LIRGenerator::visitToInt32(MToInt32 *convert)
  1.1815 +{
  1.1816 +    MDefinition *opd = convert->input();
  1.1817 +
  1.1818 +    switch (opd->type()) {
  1.1819 +      case MIRType_Value:
  1.1820 +      {
  1.1821 +        LValueToInt32 *lir = new(alloc()) LValueToInt32(tempDouble(), temp(), LValueToInt32::NORMAL);
  1.1822 +        if (!useBox(lir, LValueToInt32::Input, opd))
  1.1823 +            return false;
  1.1824 +        return assignSnapshot(lir) && define(lir, convert) && assignSafepoint(lir, convert);
  1.1825 +      }
  1.1826 +
  1.1827 +      case MIRType_Null:
  1.1828 +        return define(new(alloc()) LInteger(0), convert);
  1.1829 +
  1.1830 +      case MIRType_Int32:
  1.1831 +      case MIRType_Boolean:
  1.1832 +        return redefine(convert, opd);
  1.1833 +
  1.1834 +      case MIRType_Float32:
  1.1835 +      {
  1.1836 +        LFloat32ToInt32 *lir = new(alloc()) LFloat32ToInt32(useRegister(opd));
  1.1837 +        return assignSnapshot(lir) && define(lir, convert);
  1.1838 +      }
  1.1839 +
  1.1840 +      case MIRType_Double:
  1.1841 +      {
  1.1842 +        LDoubleToInt32 *lir = new(alloc()) LDoubleToInt32(useRegister(opd));
  1.1843 +        return assignSnapshot(lir) && define(lir, convert);
  1.1844 +      }
  1.1845 +
  1.1846 +      case MIRType_String:
  1.1847 +      case MIRType_Object:
  1.1848 +      case MIRType_Undefined:
  1.1849 +        // Objects might be effectful. Undefined coerces to NaN, not int32.
  1.1850 +        MOZ_ASSUME_UNREACHABLE("ToInt32 invalid input type");
  1.1851 +        return false;
  1.1852 +
  1.1853 +      default:
  1.1854 +        MOZ_ASSUME_UNREACHABLE("unexpected type");
  1.1855 +    }
  1.1856 +}
  1.1857 +
  1.1858 +bool
  1.1859 +LIRGenerator::visitTruncateToInt32(MTruncateToInt32 *truncate)
  1.1860 +{
  1.1861 +    MDefinition *opd = truncate->input();
  1.1862 +
  1.1863 +    switch (opd->type()) {
  1.1864 +      case MIRType_Value:
  1.1865 +      {
  1.1866 +        LValueToInt32 *lir = new(alloc()) LValueToInt32(tempDouble(), temp(), LValueToInt32::TRUNCATE);
  1.1867 +        if (!useBox(lir, LValueToInt32::Input, opd))
  1.1868 +            return false;
  1.1869 +        return assignSnapshot(lir) && define(lir, truncate) && assignSafepoint(lir, truncate);
  1.1870 +      }
  1.1871 +
  1.1872 +      case MIRType_Null:
  1.1873 +      case MIRType_Undefined:
  1.1874 +        return define(new(alloc()) LInteger(0), truncate);
  1.1875 +
  1.1876 +      case MIRType_Int32:
  1.1877 +      case MIRType_Boolean:
  1.1878 +        return redefine(truncate, opd);
  1.1879 +
  1.1880 +      case MIRType_Double:
  1.1881 +        return lowerTruncateDToInt32(truncate);
  1.1882 +
  1.1883 +      case MIRType_Float32:
  1.1884 +        return lowerTruncateFToInt32(truncate);
  1.1885 +
  1.1886 +      default:
  1.1887 +        // Objects might be effectful.
  1.1888 +        // Strings are complicated - we don't handle them yet.
  1.1889 +        MOZ_ASSUME_UNREACHABLE("unexpected type");
  1.1890 +    }
  1.1891 +}
  1.1892 +
  1.1893 +bool
  1.1894 +LIRGenerator::visitToString(MToString *ins)
  1.1895 +{
  1.1896 +    MDefinition *opd = ins->input();
  1.1897 +
  1.1898 +    switch (opd->type()) {
  1.1899 +      case MIRType_Null: {
  1.1900 +        const JSAtomState &names = GetIonContext()->runtime->names();
  1.1901 +        LPointer *lir = new(alloc()) LPointer(names.null);
  1.1902 +        return define(lir, ins);
  1.1903 +      }
  1.1904 +
  1.1905 +      case MIRType_Undefined: {
  1.1906 +        const JSAtomState &names = GetIonContext()->runtime->names();
  1.1907 +        LPointer *lir = new(alloc()) LPointer(names.undefined);
  1.1908 +        return define(lir, ins);
  1.1909 +      }
  1.1910 +
  1.1911 +      case MIRType_Boolean: {
  1.1912 +        LBooleanToString *lir = new(alloc()) LBooleanToString(useRegister(opd));
  1.1913 +        return define(lir, ins);
  1.1914 +      }
  1.1915 +
  1.1916 +      case MIRType_Double: {
  1.1917 +        LDoubleToString *lir = new(alloc()) LDoubleToString(useRegister(opd), temp());
  1.1918 +
  1.1919 +        if (!define(lir, ins))
  1.1920 +            return false;
  1.1921 +        return assignSafepoint(lir, ins);
  1.1922 +      }
  1.1923 +
  1.1924 +      case MIRType_Int32: {
  1.1925 +        LIntToString *lir = new(alloc()) LIntToString(useRegister(opd));
  1.1926 +
  1.1927 +        if (!define(lir, ins))
  1.1928 +            return false;
  1.1929 +        return assignSafepoint(lir, ins);
  1.1930 +      }
  1.1931 +
  1.1932 +      case MIRType_Value: {
  1.1933 +        JS_ASSERT(!opd->mightBeType(MIRType_Object));
  1.1934 +        LPrimitiveToString *lir = new(alloc()) LPrimitiveToString(tempToUnbox());
  1.1935 +        if (!useBox(lir, LPrimitiveToString::Input, opd))
  1.1936 +            return false;
  1.1937 +        if (!define(lir, ins))
  1.1938 +            return false;
  1.1939 +        return assignSafepoint(lir, ins);
  1.1940 +      }
  1.1941 +
  1.1942 +      default:
  1.1943 +        // Objects might be effectful. (see ToPrimitive)
  1.1944 +        MOZ_ASSUME_UNREACHABLE("unexpected type");
  1.1945 +    }
  1.1946 +}
  1.1947 +
  1.1948 +static bool
  1.1949 +MustCloneRegExpForCall(MCall *call, uint32_t useIndex)
  1.1950 +{
  1.1951 +    // We have a regex literal flowing into a call. Return |false| iff
  1.1952 +    // this is a native call that does not let the regex escape.
  1.1953 +
  1.1954 +    JSFunction *target = call->getSingleTarget();
  1.1955 +    if (!target || !target->isNative())
  1.1956 +        return true;
  1.1957 +
  1.1958 +    if (useIndex == MCall::IndexOfThis() &&
  1.1959 +        (target->native() == regexp_exec || target->native() == regexp_test))
  1.1960 +    {
  1.1961 +        return false;
  1.1962 +    }
  1.1963 +
  1.1964 +    if (useIndex == MCall::IndexOfArgument(0) &&
  1.1965 +        (target->native() == str_split ||
  1.1966 +         target->native() == str_replace ||
  1.1967 +         target->native() == str_match ||
  1.1968 +         target->native() == str_search))
  1.1969 +    {
  1.1970 +        return false;
  1.1971 +    }
  1.1972 +
  1.1973 +    return true;
  1.1974 +}
  1.1975 +
  1.1976 +
  1.1977 +static bool
  1.1978 +MustCloneRegExp(MRegExp *regexp)
  1.1979 +{
  1.1980 +    if (regexp->mustClone())
  1.1981 +        return true;
  1.1982 +
  1.1983 +    // If this regex literal only flows into known natives that don't let
  1.1984 +    // it escape, we don't have to clone it.
  1.1985 +
  1.1986 +    for (MUseIterator iter(regexp->usesBegin()); iter != regexp->usesEnd(); iter++) {
  1.1987 +        MNode *node = iter->consumer();
  1.1988 +        if (!node->isDefinition())
  1.1989 +            return true;
  1.1990 +
  1.1991 +        MDefinition *def = node->toDefinition();
  1.1992 +        if (def->isRegExpTest() && iter->index() == 1) {
  1.1993 +            // Optimized RegExp.prototype.test.
  1.1994 +            JS_ASSERT(def->toRegExpTest()->regexp() == regexp);
  1.1995 +            continue;
  1.1996 +        }
  1.1997 +
  1.1998 +        if (def->isCall() && !MustCloneRegExpForCall(def->toCall(), iter->index()))
  1.1999 +            continue;
  1.2000 +
  1.2001 +        return true;
  1.2002 +    }
  1.2003 +    return false;
  1.2004 +}
  1.2005 +
  1.2006 +bool
  1.2007 +LIRGenerator::visitRegExp(MRegExp *ins)
  1.2008 +{
  1.2009 +    if (!MustCloneRegExp(ins)) {
  1.2010 +        RegExpObject *source = ins->source();
  1.2011 +        return define(new(alloc()) LPointer(source), ins);
  1.2012 +    }
  1.2013 +
  1.2014 +    LRegExp *lir = new(alloc()) LRegExp();
  1.2015 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.2016 +}
  1.2017 +
  1.2018 +bool
  1.2019 +LIRGenerator::visitRegExpExec(MRegExpExec *ins)
  1.2020 +{
  1.2021 +    JS_ASSERT(ins->regexp()->type() == MIRType_Object);
  1.2022 +    JS_ASSERT(ins->string()->type() == MIRType_String);
  1.2023 +
  1.2024 +    LRegExpExec *lir = new(alloc()) LRegExpExec(useRegisterAtStart(ins->regexp()),
  1.2025 +                                                useRegisterAtStart(ins->string()));
  1.2026 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.2027 +}
  1.2028 +
  1.2029 +bool
  1.2030 +LIRGenerator::visitRegExpTest(MRegExpTest *ins)
  1.2031 +{
  1.2032 +    JS_ASSERT(ins->regexp()->type() == MIRType_Object);
  1.2033 +    JS_ASSERT(ins->string()->type() == MIRType_String);
  1.2034 +
  1.2035 +    LRegExpTest *lir = new(alloc()) LRegExpTest(useRegisterAtStart(ins->regexp()),
  1.2036 +                                                useRegisterAtStart(ins->string()));
  1.2037 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.2038 +}
  1.2039 +
  1.2040 +bool
  1.2041 +LIRGenerator::visitRegExpReplace(MRegExpReplace *ins)
  1.2042 +{
  1.2043 +    JS_ASSERT(ins->pattern()->type() == MIRType_Object);
  1.2044 +    JS_ASSERT(ins->string()->type() == MIRType_String);
  1.2045 +    JS_ASSERT(ins->replacement()->type() == MIRType_String);
  1.2046 +
  1.2047 +    LRegExpReplace *lir = new(alloc()) LRegExpReplace(useRegisterOrConstantAtStart(ins->string()),
  1.2048 +                                                      useRegisterAtStart(ins->pattern()),
  1.2049 +                                                      useRegisterOrConstantAtStart(ins->replacement()));
  1.2050 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.2051 +}
  1.2052 +
  1.2053 +bool
  1.2054 +LIRGenerator::visitStringReplace(MStringReplace *ins)
  1.2055 +{
  1.2056 +    JS_ASSERT(ins->pattern()->type() == MIRType_String);
  1.2057 +    JS_ASSERT(ins->string()->type() == MIRType_String);
  1.2058 +    JS_ASSERT(ins->replacement()->type() == MIRType_String);
  1.2059 +
  1.2060 +    LStringReplace *lir = new(alloc()) LStringReplace(useRegisterOrConstantAtStart(ins->string()),
  1.2061 +                                                      useRegisterAtStart(ins->pattern()),
  1.2062 +                                                      useRegisterOrConstantAtStart(ins->replacement()));
  1.2063 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.2064 +}
  1.2065 +
  1.2066 +bool
  1.2067 +LIRGenerator::visitLambda(MLambda *ins)
  1.2068 +{
  1.2069 +    if (ins->info().singletonType || ins->info().useNewTypeForClone) {
  1.2070 +        // If the function has a singleton type, this instruction will only be
  1.2071 +        // executed once so we don't bother inlining it.
  1.2072 +        //
  1.2073 +        // If UseNewTypeForClone is true, we will assign a singleton type to
  1.2074 +        // the clone and we have to clone the script, we can't do that inline.
  1.2075 +        LLambdaForSingleton *lir = new(alloc()) LLambdaForSingleton(useRegisterAtStart(ins->scopeChain()));
  1.2076 +        return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.2077 +    }
  1.2078 +
  1.2079 +    LLambda *lir = new(alloc()) LLambda(useRegister(ins->scopeChain()), temp());
  1.2080 +    return define(lir, ins) && assignSafepoint(lir, ins);
  1.2081 +}
  1.2082 +
  1.2083 +bool
  1.2084 +LIRGenerator::visitLambdaArrow(MLambdaArrow *ins)
  1.2085 +{
  1.2086 +    MOZ_ASSERT(ins->scopeChain()->type() == MIRType_Object);
  1.2087 +    MOZ_ASSERT(ins->thisDef()->type() == MIRType_Value);
  1.2088 +
  1.2089 +    LLambdaArrow *lir = new(alloc()) LLambdaArrow(useRegister(ins->scopeChain()), temp());
  1.2090 +    if (!useBox(lir, LLambdaArrow::ThisValue, ins->thisDef()))
  1.2091 +        return false;
  1.2092 +    return define(lir, ins) && assignSafepoint(lir, ins);
  1.2093 +}
  1.2094 +
  1.2095 +bool
  1.2096 +LIRGenerator::visitLambdaPar(MLambdaPar *ins)
  1.2097 +{
  1.2098 +    JS_ASSERT(!ins->info().singletonType);
  1.2099 +    JS_ASSERT(!ins->info().useNewTypeForClone);
  1.2100 +    LLambdaPar *lir = new(alloc()) LLambdaPar(useRegister(ins->forkJoinContext()),
  1.2101 +                                              useRegister(ins->scopeChain()),
  1.2102 +                                              temp(), temp());
  1.2103 +    return define(lir, ins);
  1.2104 +}
  1.2105 +
  1.2106 +bool
  1.2107 +LIRGenerator::visitImplicitThis(MImplicitThis *ins)
  1.2108 +{
  1.2109 +    JS_ASSERT(ins->callee()->type() == MIRType_Object);
  1.2110 +
  1.2111 +    LImplicitThis *lir = new(alloc()) LImplicitThis(useRegister(ins->callee()));
  1.2112 +    return assignSnapshot(lir) && defineBox(lir, ins);
  1.2113 +}
  1.2114 +
  1.2115 +bool
  1.2116 +LIRGenerator::visitSlots(MSlots *ins)
  1.2117 +{
  1.2118 +    return define(new(alloc()) LSlots(useRegisterAtStart(ins->object())), ins);
  1.2119 +}
  1.2120 +
  1.2121 +bool
  1.2122 +LIRGenerator::visitElements(MElements *ins)
  1.2123 +{
  1.2124 +    return define(new(alloc()) LElements(useRegisterAtStart(ins->object())), ins);
  1.2125 +}
  1.2126 +
  1.2127 +bool
  1.2128 +LIRGenerator::visitConstantElements(MConstantElements *ins)
  1.2129 +{
  1.2130 +    return define(new(alloc()) LPointer(ins->value(), LPointer::NON_GC_THING), ins);
  1.2131 +}
  1.2132 +
  1.2133 +bool
  1.2134 +LIRGenerator::visitConvertElementsToDoubles(MConvertElementsToDoubles *ins)
  1.2135 +{
  1.2136 +    LInstruction *check = new(alloc()) LConvertElementsToDoubles(useRegister(ins->elements()));
  1.2137 +    return add(check, ins) && assignSafepoint(check, ins);
  1.2138 +}
  1.2139 +
  1.2140 +bool
  1.2141 +LIRGenerator::visitMaybeToDoubleElement(MMaybeToDoubleElement *ins)
  1.2142 +{
  1.2143 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2144 +    JS_ASSERT(ins->value()->type() == MIRType_Int32);
  1.2145 +
  1.2146 +    LMaybeToDoubleElement *lir = new(alloc()) LMaybeToDoubleElement(useRegisterAtStart(ins->elements()),
  1.2147 +                                                                    useRegisterAtStart(ins->value()),
  1.2148 +                                                                    tempDouble());
  1.2149 +    return defineBox(lir, ins);
  1.2150 +}
  1.2151 +
  1.2152 +bool
  1.2153 +LIRGenerator::visitLoadSlot(MLoadSlot *ins)
  1.2154 +{
  1.2155 +    switch (ins->type()) {
  1.2156 +      case MIRType_Value:
  1.2157 +        return defineBox(new(alloc()) LLoadSlotV(useRegister(ins->slots())), ins);
  1.2158 +
  1.2159 +      case MIRType_Undefined:
  1.2160 +      case MIRType_Null:
  1.2161 +        MOZ_ASSUME_UNREACHABLE("typed load must have a payload");
  1.2162 +
  1.2163 +      default:
  1.2164 +        return define(new(alloc()) LLoadSlotT(useRegister(ins->slots())), ins);
  1.2165 +    }
  1.2166 +}
  1.2167 +
  1.2168 +bool
  1.2169 +LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment *ins)
  1.2170 +{
  1.2171 +    return define(new(alloc()) LFunctionEnvironment(useRegisterAtStart(ins->function())), ins);
  1.2172 +}
  1.2173 +
  1.2174 +bool
  1.2175 +LIRGenerator::visitForkJoinContext(MForkJoinContext *ins)
  1.2176 +{
  1.2177 +    LForkJoinContext *lir = new(alloc()) LForkJoinContext(tempFixed(CallTempReg0));
  1.2178 +    return defineReturn(lir, ins);
  1.2179 +}
  1.2180 +
  1.2181 +bool
  1.2182 +LIRGenerator::visitGuardThreadExclusive(MGuardThreadExclusive *ins)
  1.2183 +{
  1.2184 +    // FIXME (Bug 956281) -- For now, we always generate the most
  1.2185 +    // general form of write guard check. we could employ TI feedback
  1.2186 +    // to optimize this if we know that the object being tested is a
  1.2187 +    // typed object or know that it is definitely NOT a typed object.
  1.2188 +    LGuardThreadExclusive *lir =
  1.2189 +        new(alloc()) LGuardThreadExclusive(useFixed(ins->forkJoinContext(), CallTempReg0),
  1.2190 +                                           useFixed(ins->object(), CallTempReg1),
  1.2191 +                                           tempFixed(CallTempReg2));
  1.2192 +    lir->setMir(ins);
  1.2193 +    return add(lir, ins);
  1.2194 +}
  1.2195 +
  1.2196 +bool
  1.2197 +LIRGenerator::visitInterruptCheck(MInterruptCheck *ins)
  1.2198 +{
  1.2199 +    // Implicit interrupt checks require asm.js signal handlers to be
  1.2200 +    // installed. ARM does not yet use implicit interrupt checks, see
  1.2201 +    // bug 864220.
  1.2202 +#ifndef JS_CODEGEN_ARM
  1.2203 +    if (GetIonContext()->runtime->signalHandlersInstalled()) {
  1.2204 +        LInterruptCheckImplicit *lir = new(alloc()) LInterruptCheckImplicit();
  1.2205 +        return add(lir, ins) && assignSafepoint(lir, ins);
  1.2206 +    }
  1.2207 +#endif
  1.2208 +
  1.2209 +    LInterruptCheck *lir = new(alloc()) LInterruptCheck();
  1.2210 +    return add(lir, ins) && assignSafepoint(lir, ins);
  1.2211 +}
  1.2212 +
  1.2213 +bool
  1.2214 +LIRGenerator::visitInterruptCheckPar(MInterruptCheckPar *ins)
  1.2215 +{
  1.2216 +    LInterruptCheckPar *lir =
  1.2217 +        new(alloc()) LInterruptCheckPar(useRegister(ins->forkJoinContext()), temp());
  1.2218 +    if (!add(lir, ins))
  1.2219 +        return false;
  1.2220 +    if (!assignSafepoint(lir, ins))
  1.2221 +        return false;
  1.2222 +    return true;
  1.2223 +}
  1.2224 +
  1.2225 +bool
  1.2226 +LIRGenerator::visitNewPar(MNewPar *ins)
  1.2227 +{
  1.2228 +    LNewPar *lir = new(alloc()) LNewPar(useRegister(ins->forkJoinContext()), temp(), temp());
  1.2229 +    return define(lir, ins);
  1.2230 +}
  1.2231 +
  1.2232 +bool
  1.2233 +LIRGenerator::visitNewDenseArrayPar(MNewDenseArrayPar *ins)
  1.2234 +{
  1.2235 +    LNewDenseArrayPar *lir =
  1.2236 +        new(alloc()) LNewDenseArrayPar(useFixed(ins->forkJoinContext(), CallTempReg0),
  1.2237 +                                       useFixed(ins->length(), CallTempReg1),
  1.2238 +                                       tempFixed(CallTempReg2),
  1.2239 +                                       tempFixed(CallTempReg3),
  1.2240 +                                       tempFixed(CallTempReg4));
  1.2241 +    return defineReturn(lir, ins);
  1.2242 +}
  1.2243 +
  1.2244 +bool
  1.2245 +LIRGenerator::visitStoreSlot(MStoreSlot *ins)
  1.2246 +{
  1.2247 +    LInstruction *lir;
  1.2248 +
  1.2249 +    switch (ins->value()->type()) {
  1.2250 +      case MIRType_Value:
  1.2251 +        lir = new(alloc()) LStoreSlotV(useRegister(ins->slots()));
  1.2252 +        if (!useBox(lir, LStoreSlotV::Value, ins->value()))
  1.2253 +            return false;
  1.2254 +        return add(lir, ins);
  1.2255 +
  1.2256 +      case MIRType_Double:
  1.2257 +        return add(new(alloc()) LStoreSlotT(useRegister(ins->slots()), useRegister(ins->value())), ins);
  1.2258 +
  1.2259 +      case MIRType_Float32:
  1.2260 +        MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be stored in a slot.");
  1.2261 +
  1.2262 +      default:
  1.2263 +        return add(new(alloc()) LStoreSlotT(useRegister(ins->slots()), useRegisterOrConstant(ins->value())),
  1.2264 +                   ins);
  1.2265 +    }
  1.2266 +
  1.2267 +    return true;
  1.2268 +}
  1.2269 +
  1.2270 +bool
  1.2271 +LIRGenerator::visitFilterTypeSet(MFilterTypeSet *ins)
  1.2272 +{
  1.2273 +    return redefine(ins, ins->input());
  1.2274 +}
  1.2275 +
  1.2276 +bool
  1.2277 +LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
  1.2278 +{
  1.2279 +    // Requesting a non-GC pointer is safe here since we never re-enter C++
  1.2280 +    // from inside a type barrier test.
  1.2281 +
  1.2282 +    const types::TemporaryTypeSet *types = ins->resultTypeSet();
  1.2283 +    bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
  1.2284 +
  1.2285 +    MIRType inputType = ins->getOperand(0)->type();
  1.2286 +    DebugOnly<MIRType> outputType = ins->type();
  1.2287 +
  1.2288 +    JS_ASSERT(inputType == outputType);
  1.2289 +
  1.2290 +    // Handle typebarrier that will always bail.
  1.2291 +    // (Emit LBail for visibility).
  1.2292 +    if (ins->alwaysBails()) {
  1.2293 +        LBail *bail = new(alloc()) LBail();
  1.2294 +        if (!assignSnapshot(bail))
  1.2295 +            return false;
  1.2296 +        return redefine(ins, ins->input()) && add(bail, ins);
  1.2297 +    }
  1.2298 +
  1.2299 +    // Handle typebarrier with Value as input.
  1.2300 +    if (inputType == MIRType_Value) {
  1.2301 +        LDefinition tmp = needTemp ? temp() : tempToUnbox();
  1.2302 +        LTypeBarrierV *barrier = new(alloc()) LTypeBarrierV(tmp);
  1.2303 +        if (!useBox(barrier, LTypeBarrierV::Input, ins->input()))
  1.2304 +            return false;
  1.2305 +        if (!assignSnapshot(barrier))
  1.2306 +            return false;
  1.2307 +        return redefine(ins, ins->input()) && add(barrier, ins);
  1.2308 +    }
  1.2309 +
  1.2310 +    // Handle typebarrier with specific TypeObject/SingleObjects.
  1.2311 +    if (inputType == MIRType_Object && !types->hasType(types::Type::AnyObjectType()))
  1.2312 +    {
  1.2313 +        LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp();
  1.2314 +        LTypeBarrierO *barrier = new(alloc()) LTypeBarrierO(useRegister(ins->getOperand(0)), tmp);
  1.2315 +        if (!assignSnapshot(barrier))
  1.2316 +            return false;
  1.2317 +        return redefine(ins, ins->getOperand(0)) && add(barrier, ins);
  1.2318 +    }
  1.2319 +
  1.2320 +    // Handle remaining cases: No-op, unbox did everything.
  1.2321 +    return redefine(ins, ins->getOperand(0));
  1.2322 +}
  1.2323 +
  1.2324 +bool
  1.2325 +LIRGenerator::visitMonitorTypes(MMonitorTypes *ins)
  1.2326 +{
  1.2327 +    // Requesting a non-GC pointer is safe here since we never re-enter C++
  1.2328 +    // from inside a type check.
  1.2329 +
  1.2330 +    const types::TemporaryTypeSet *types = ins->typeSet();
  1.2331 +    bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
  1.2332 +    LDefinition tmp = needTemp ? temp() : tempToUnbox();
  1.2333 +
  1.2334 +    LMonitorTypes *lir = new(alloc()) LMonitorTypes(tmp);
  1.2335 +    if (!useBox(lir, LMonitorTypes::Input, ins->input()))
  1.2336 +        return false;
  1.2337 +    return assignSnapshot(lir, Bailout_Normal) && add(lir, ins);
  1.2338 +}
  1.2339 +
  1.2340 +bool
  1.2341 +LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier *ins)
  1.2342 +{
  1.2343 +#ifdef JSGC_GENERATIONAL
  1.2344 +    switch (ins->value()->type()) {
  1.2345 +      case MIRType_Object: {
  1.2346 +        LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
  1.2347 +        LPostWriteBarrierO *lir =
  1.2348 +            new(alloc()) LPostWriteBarrierO(useRegisterOrConstant(ins->object()),
  1.2349 +                                            useRegister(ins->value()), tmp);
  1.2350 +        return add(lir, ins) && assignSafepoint(lir, ins);
  1.2351 +      }
  1.2352 +      case MIRType_Value: {
  1.2353 +        LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
  1.2354 +        LPostWriteBarrierV *lir =
  1.2355 +            new(alloc()) LPostWriteBarrierV(useRegisterOrConstant(ins->object()), tmp);
  1.2356 +        if (!useBox(lir, LPostWriteBarrierV::Input, ins->value()))
  1.2357 +            return false;
  1.2358 +        return add(lir, ins) && assignSafepoint(lir, ins);
  1.2359 +      }
  1.2360 +      default:
  1.2361 +        // Currently, only objects can be in the nursery. Other instruction
  1.2362 +        // types cannot hold nursery pointers.
  1.2363 +        return true;
  1.2364 +    }
  1.2365 +#endif // JSGC_GENERATIONAL
  1.2366 +    return true;
  1.2367 +}
  1.2368 +
  1.2369 +bool
  1.2370 +LIRGenerator::visitArrayLength(MArrayLength *ins)
  1.2371 +{
  1.2372 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2373 +    return define(new(alloc()) LArrayLength(useRegisterAtStart(ins->elements())), ins);
  1.2374 +}
  1.2375 +
  1.2376 +bool
  1.2377 +LIRGenerator::visitSetArrayLength(MSetArrayLength *ins)
  1.2378 +{
  1.2379 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2380 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2381 +
  1.2382 +    JS_ASSERT(ins->index()->isConstant());
  1.2383 +    return add(new(alloc()) LSetArrayLength(useRegister(ins->elements()),
  1.2384 +                                            useRegisterOrConstant(ins->index())), ins);
  1.2385 +}
  1.2386 +
  1.2387 +bool
  1.2388 +LIRGenerator::visitTypedArrayLength(MTypedArrayLength *ins)
  1.2389 +{
  1.2390 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.2391 +    return define(new(alloc()) LTypedArrayLength(useRegisterAtStart(ins->object())), ins);
  1.2392 +}
  1.2393 +
  1.2394 +bool
  1.2395 +LIRGenerator::visitTypedArrayElements(MTypedArrayElements *ins)
  1.2396 +{
  1.2397 +    JS_ASSERT(ins->type() == MIRType_Elements);
  1.2398 +    return define(new(alloc()) LTypedArrayElements(useRegisterAtStart(ins->object())), ins);
  1.2399 +}
  1.2400 +
  1.2401 +bool
  1.2402 +LIRGenerator::visitTypedObjectElements(MTypedObjectElements *ins)
  1.2403 +{
  1.2404 +    JS_ASSERT(ins->type() == MIRType_Elements);
  1.2405 +    return define(new(alloc()) LTypedObjectElements(useRegisterAtStart(ins->object())), ins);
  1.2406 +}
  1.2407 +
  1.2408 +bool
  1.2409 +LIRGenerator::visitSetTypedObjectOffset(MSetTypedObjectOffset *ins)
  1.2410 +{
  1.2411 +    return add(new(alloc()) LSetTypedObjectOffset(
  1.2412 +                   useRegister(ins->object()),
  1.2413 +                   useRegister(ins->offset()),
  1.2414 +                   temp()),
  1.2415 +               ins);
  1.2416 +}
  1.2417 +
  1.2418 +bool
  1.2419 +LIRGenerator::visitInitializedLength(MInitializedLength *ins)
  1.2420 +{
  1.2421 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2422 +    return define(new(alloc()) LInitializedLength(useRegisterAtStart(ins->elements())), ins);
  1.2423 +}
  1.2424 +
  1.2425 +bool
  1.2426 +LIRGenerator::visitSetInitializedLength(MSetInitializedLength *ins)
  1.2427 +{
  1.2428 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2429 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2430 +
  1.2431 +    JS_ASSERT(ins->index()->isConstant());
  1.2432 +    return add(new(alloc()) LSetInitializedLength(useRegister(ins->elements()),
  1.2433 +                                                  useRegisterOrConstant(ins->index())), ins);
  1.2434 +}
  1.2435 +
  1.2436 +bool
  1.2437 +LIRGenerator::visitNot(MNot *ins)
  1.2438 +{
  1.2439 +    MDefinition *op = ins->operand();
  1.2440 +
  1.2441 +    // String is converted to length of string in the type analysis phase (see
  1.2442 +    // TestPolicy).
  1.2443 +    JS_ASSERT(op->type() != MIRType_String);
  1.2444 +
  1.2445 +    // - boolean: x xor 1
  1.2446 +    // - int32: LCompare(x, 0)
  1.2447 +    // - double: LCompare(x, 0)
  1.2448 +    // - null or undefined: true
  1.2449 +    // - object: false if it never emulates undefined, else LNotO(x)
  1.2450 +    switch (op->type()) {
  1.2451 +      case MIRType_Boolean: {
  1.2452 +        MConstant *cons = MConstant::New(alloc(), Int32Value(1));
  1.2453 +        ins->block()->insertBefore(ins, cons);
  1.2454 +        return lowerForALU(new(alloc()) LBitOpI(JSOP_BITXOR), ins, op, cons);
  1.2455 +      }
  1.2456 +      case MIRType_Int32: {
  1.2457 +        return define(new(alloc()) LNotI(useRegisterAtStart(op)), ins);
  1.2458 +      }
  1.2459 +      case MIRType_Double:
  1.2460 +        return define(new(alloc()) LNotD(useRegister(op)), ins);
  1.2461 +      case MIRType_Float32:
  1.2462 +        return define(new(alloc()) LNotF(useRegister(op)), ins);
  1.2463 +      case MIRType_Undefined:
  1.2464 +      case MIRType_Null:
  1.2465 +        return define(new(alloc()) LInteger(1), ins);
  1.2466 +      case MIRType_Object: {
  1.2467 +        // Objects that don't emulate undefined can be constant-folded.
  1.2468 +        if (!ins->operandMightEmulateUndefined())
  1.2469 +            return define(new(alloc()) LInteger(0), ins);
  1.2470 +        // All others require further work.
  1.2471 +        return define(new(alloc()) LNotO(useRegister(op)), ins);
  1.2472 +      }
  1.2473 +      case MIRType_Value: {
  1.2474 +        LDefinition temp0, temp1;
  1.2475 +        if (ins->operandMightEmulateUndefined()) {
  1.2476 +            temp0 = temp();
  1.2477 +            temp1 = temp();
  1.2478 +        } else {
  1.2479 +            temp0 = LDefinition::BogusTemp();
  1.2480 +            temp1 = LDefinition::BogusTemp();
  1.2481 +        }
  1.2482 +
  1.2483 +        LNotV *lir = new(alloc()) LNotV(tempDouble(), temp0, temp1);
  1.2484 +        if (!useBox(lir, LNotV::Input, op))
  1.2485 +            return false;
  1.2486 +        return define(lir, ins);
  1.2487 +      }
  1.2488 +
  1.2489 +      default:
  1.2490 +        MOZ_ASSUME_UNREACHABLE("Unexpected MIRType.");
  1.2491 +    }
  1.2492 +}
  1.2493 +
  1.2494 +bool
  1.2495 +LIRGenerator::visitNeuterCheck(MNeuterCheck *ins)
  1.2496 +{
  1.2497 +    LNeuterCheck *chk = new(alloc()) LNeuterCheck(useRegister(ins->object()),
  1.2498 +                                                  temp());
  1.2499 +    if (!assignSnapshot(chk, Bailout_BoundsCheck))
  1.2500 +        return false;
  1.2501 +    return redefine(ins, ins->input()) && add(chk, ins);
  1.2502 +}
  1.2503 +
  1.2504 +bool
  1.2505 +LIRGenerator::visitBoundsCheck(MBoundsCheck *ins)
  1.2506 +{
  1.2507 +    LInstruction *check;
  1.2508 +    if (ins->minimum() || ins->maximum()) {
  1.2509 +        check = new(alloc()) LBoundsCheckRange(useRegisterOrConstant(ins->index()),
  1.2510 +                                               useAny(ins->length()),
  1.2511 +                                               temp());
  1.2512 +    } else {
  1.2513 +        check = new(alloc()) LBoundsCheck(useRegisterOrConstant(ins->index()),
  1.2514 +                                          useAnyOrConstant(ins->length()));
  1.2515 +    }
  1.2516 +    return assignSnapshot(check, Bailout_BoundsCheck) && add(check, ins);
  1.2517 +}
  1.2518 +
  1.2519 +bool
  1.2520 +LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower *ins)
  1.2521 +{
  1.2522 +    if (!ins->fallible())
  1.2523 +        return true;
  1.2524 +
  1.2525 +    LInstruction *check = new(alloc()) LBoundsCheckLower(useRegister(ins->index()));
  1.2526 +    return assignSnapshot(check, Bailout_BoundsCheck) && add(check, ins);
  1.2527 +}
  1.2528 +
  1.2529 +bool
  1.2530 +LIRGenerator::visitInArray(MInArray *ins)
  1.2531 +{
  1.2532 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2533 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2534 +    JS_ASSERT(ins->initLength()->type() == MIRType_Int32);
  1.2535 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.2536 +    JS_ASSERT(ins->type() == MIRType_Boolean);
  1.2537 +
  1.2538 +    LAllocation object;
  1.2539 +    if (ins->needsNegativeIntCheck())
  1.2540 +        object = useRegister(ins->object());
  1.2541 +    else
  1.2542 +        object = LConstantIndex::Bogus();
  1.2543 +
  1.2544 +    LInArray *lir = new(alloc()) LInArray(useRegister(ins->elements()),
  1.2545 +                                          useRegisterOrConstant(ins->index()),
  1.2546 +                                          useRegister(ins->initLength()),
  1.2547 +                                          object);
  1.2548 +    return define(lir, ins) && assignSafepoint(lir, ins);
  1.2549 +}
  1.2550 +
  1.2551 +bool
  1.2552 +LIRGenerator::visitLoadElement(MLoadElement *ins)
  1.2553 +{
  1.2554 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2555 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2556 +
  1.2557 +    switch (ins->type()) {
  1.2558 +      case MIRType_Value:
  1.2559 +      {
  1.2560 +        LLoadElementV *lir = new(alloc()) LLoadElementV(useRegister(ins->elements()),
  1.2561 +                                               useRegisterOrConstant(ins->index()));
  1.2562 +        if (ins->fallible() && !assignSnapshot(lir))
  1.2563 +            return false;
  1.2564 +        return defineBox(lir, ins);
  1.2565 +      }
  1.2566 +      case MIRType_Undefined:
  1.2567 +      case MIRType_Null:
  1.2568 +        MOZ_ASSUME_UNREACHABLE("typed load must have a payload");
  1.2569 +
  1.2570 +      default:
  1.2571 +      {
  1.2572 +        LLoadElementT *lir = new(alloc()) LLoadElementT(useRegister(ins->elements()),
  1.2573 +                                               useRegisterOrConstant(ins->index()));
  1.2574 +        if (ins->fallible() && !assignSnapshot(lir))
  1.2575 +            return false;
  1.2576 +        return define(lir, ins);
  1.2577 +      }
  1.2578 +    }
  1.2579 +}
  1.2580 +
  1.2581 +bool
  1.2582 +LIRGenerator::visitLoadElementHole(MLoadElementHole *ins)
  1.2583 +{
  1.2584 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2585 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2586 +    JS_ASSERT(ins->initLength()->type() == MIRType_Int32);
  1.2587 +    JS_ASSERT(ins->type() == MIRType_Value);
  1.2588 +
  1.2589 +    LLoadElementHole *lir = new(alloc()) LLoadElementHole(useRegister(ins->elements()),
  1.2590 +                                                          useRegisterOrConstant(ins->index()),
  1.2591 +                                                          useRegister(ins->initLength()));
  1.2592 +    if (ins->needsNegativeIntCheck() && !assignSnapshot(lir))
  1.2593 +        return false;
  1.2594 +    return defineBox(lir, ins);
  1.2595 +}
  1.2596 +
  1.2597 +bool
  1.2598 +LIRGenerator::visitStoreElement(MStoreElement *ins)
  1.2599 +{
  1.2600 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2601 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2602 +
  1.2603 +    const LUse elements = useRegister(ins->elements());
  1.2604 +    const LAllocation index = useRegisterOrConstant(ins->index());
  1.2605 +
  1.2606 +    switch (ins->value()->type()) {
  1.2607 +      case MIRType_Value:
  1.2608 +      {
  1.2609 +        LInstruction *lir = new(alloc()) LStoreElementV(elements, index);
  1.2610 +        if (ins->fallible() && !assignSnapshot(lir))
  1.2611 +            return false;
  1.2612 +        if (!useBox(lir, LStoreElementV::Value, ins->value()))
  1.2613 +            return false;
  1.2614 +        return add(lir, ins);
  1.2615 +      }
  1.2616 +
  1.2617 +      default:
  1.2618 +      {
  1.2619 +        const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
  1.2620 +        LInstruction *lir = new(alloc()) LStoreElementT(elements, index, value);
  1.2621 +        if (ins->fallible() && !assignSnapshot(lir))
  1.2622 +            return false;
  1.2623 +        return add(lir, ins);
  1.2624 +      }
  1.2625 +    }
  1.2626 +}
  1.2627 +
  1.2628 +bool
  1.2629 +LIRGenerator::visitStoreElementHole(MStoreElementHole *ins)
  1.2630 +{
  1.2631 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2632 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2633 +
  1.2634 +    const LUse object = useRegister(ins->object());
  1.2635 +    const LUse elements = useRegister(ins->elements());
  1.2636 +    const LAllocation index = useRegisterOrConstant(ins->index());
  1.2637 +
  1.2638 +    LInstruction *lir;
  1.2639 +    switch (ins->value()->type()) {
  1.2640 +      case MIRType_Value:
  1.2641 +        lir = new(alloc()) LStoreElementHoleV(object, elements, index);
  1.2642 +        if (!useBox(lir, LStoreElementHoleV::Value, ins->value()))
  1.2643 +            return false;
  1.2644 +        break;
  1.2645 +
  1.2646 +      default:
  1.2647 +      {
  1.2648 +        const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
  1.2649 +        lir = new(alloc()) LStoreElementHoleT(object, elements, index, value);
  1.2650 +        break;
  1.2651 +      }
  1.2652 +    }
  1.2653 +
  1.2654 +    return add(lir, ins) && assignSafepoint(lir, ins);
  1.2655 +}
  1.2656 +
  1.2657 +bool
  1.2658 +LIRGenerator::visitEffectiveAddress(MEffectiveAddress *ins)
  1.2659 +{
  1.2660 +    return define(new(alloc()) LEffectiveAddress(useRegister(ins->base()), useRegister(ins->index())), ins);
  1.2661 +}
  1.2662 +
  1.2663 +bool
  1.2664 +LIRGenerator::visitArrayPopShift(MArrayPopShift *ins)
  1.2665 +{
  1.2666 +    LUse object = useRegister(ins->object());
  1.2667 +
  1.2668 +    switch (ins->type()) {
  1.2669 +      case MIRType_Value:
  1.2670 +      {
  1.2671 +        LArrayPopShiftV *lir = new(alloc()) LArrayPopShiftV(object, temp(), temp());
  1.2672 +        return defineBox(lir, ins) && assignSafepoint(lir, ins);
  1.2673 +      }
  1.2674 +      case MIRType_Undefined:
  1.2675 +      case MIRType_Null:
  1.2676 +        MOZ_ASSUME_UNREACHABLE("typed load must have a payload");
  1.2677 +
  1.2678 +      default:
  1.2679 +      {
  1.2680 +        LArrayPopShiftT *lir = new(alloc()) LArrayPopShiftT(object, temp(), temp());
  1.2681 +        return define(lir, ins) && assignSafepoint(lir, ins);
  1.2682 +      }
  1.2683 +    }
  1.2684 +}
  1.2685 +
  1.2686 +bool
  1.2687 +LIRGenerator::visitArrayPush(MArrayPush *ins)
  1.2688 +{
  1.2689 +    JS_ASSERT(ins->type() == MIRType_Int32);
  1.2690 +
  1.2691 +    LUse object = useRegister(ins->object());
  1.2692 +
  1.2693 +    switch (ins->value()->type()) {
  1.2694 +      case MIRType_Value:
  1.2695 +      {
  1.2696 +        LArrayPushV *lir = new(alloc()) LArrayPushV(object, temp());
  1.2697 +        if (!useBox(lir, LArrayPushV::Value, ins->value()))
  1.2698 +            return false;
  1.2699 +        return define(lir, ins) && assignSafepoint(lir, ins);
  1.2700 +      }
  1.2701 +
  1.2702 +      default:
  1.2703 +      {
  1.2704 +        const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
  1.2705 +        LArrayPushT *lir = new(alloc()) LArrayPushT(object, value, temp());
  1.2706 +        return define(lir, ins) && assignSafepoint(lir, ins);
  1.2707 +      }
  1.2708 +    }
  1.2709 +}
  1.2710 +
  1.2711 +bool
  1.2712 +LIRGenerator::visitArrayConcat(MArrayConcat *ins)
  1.2713 +{
  1.2714 +    JS_ASSERT(ins->type() == MIRType_Object);
  1.2715 +    JS_ASSERT(ins->lhs()->type() == MIRType_Object);
  1.2716 +    JS_ASSERT(ins->rhs()->type() == MIRType_Object);
  1.2717 +
  1.2718 +    LArrayConcat *lir = new(alloc()) LArrayConcat(useFixed(ins->lhs(), CallTempReg1),
  1.2719 +                                                  useFixed(ins->rhs(), CallTempReg2),
  1.2720 +                                                  tempFixed(CallTempReg3),
  1.2721 +                                                  tempFixed(CallTempReg4));
  1.2722 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.2723 +}
  1.2724 +
  1.2725 +bool
  1.2726 +LIRGenerator::visitStringSplit(MStringSplit *ins)
  1.2727 +{
  1.2728 +    JS_ASSERT(ins->type() == MIRType_Object);
  1.2729 +    JS_ASSERT(ins->string()->type() == MIRType_String);
  1.2730 +    JS_ASSERT(ins->separator()->type() == MIRType_String);
  1.2731 +
  1.2732 +    LStringSplit *lir = new(alloc()) LStringSplit(useRegisterAtStart(ins->string()),
  1.2733 +                                                  useRegisterAtStart(ins->separator()));
  1.2734 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.2735 +}
  1.2736 +
  1.2737 +bool
  1.2738 +LIRGenerator::visitLoadTypedArrayElement(MLoadTypedArrayElement *ins)
  1.2739 +{
  1.2740 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2741 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2742 +
  1.2743 +    const LUse elements = useRegister(ins->elements());
  1.2744 +    const LAllocation index = useRegisterOrConstant(ins->index());
  1.2745 +
  1.2746 +    JS_ASSERT(IsNumberType(ins->type()));
  1.2747 +
  1.2748 +    // We need a temp register for Uint32Array with known double result.
  1.2749 +    LDefinition tempDef = LDefinition::BogusTemp();
  1.2750 +    if (ins->arrayType() == ScalarTypeDescr::TYPE_UINT32 && IsFloatingPointType(ins->type()))
  1.2751 +        tempDef = temp();
  1.2752 +
  1.2753 +    LLoadTypedArrayElement *lir = new(alloc()) LLoadTypedArrayElement(elements, index, tempDef);
  1.2754 +    if (ins->fallible() && !assignSnapshot(lir))
  1.2755 +        return false;
  1.2756 +    return define(lir, ins);
  1.2757 +}
  1.2758 +
  1.2759 +bool
  1.2760 +LIRGenerator::visitClampToUint8(MClampToUint8 *ins)
  1.2761 +{
  1.2762 +    MDefinition *in = ins->input();
  1.2763 +
  1.2764 +    switch (in->type()) {
  1.2765 +      case MIRType_Boolean:
  1.2766 +        return redefine(ins, in);
  1.2767 +
  1.2768 +      case MIRType_Int32:
  1.2769 +        return defineReuseInput(new(alloc()) LClampIToUint8(useRegisterAtStart(in)), ins, 0);
  1.2770 +
  1.2771 +      case MIRType_Double:
  1.2772 +        return define(new(alloc()) LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)), ins);
  1.2773 +
  1.2774 +      case MIRType_Value:
  1.2775 +      {
  1.2776 +        LClampVToUint8 *lir = new(alloc()) LClampVToUint8(tempDouble());
  1.2777 +        if (!useBox(lir, LClampVToUint8::Input, in))
  1.2778 +            return false;
  1.2779 +        return assignSnapshot(lir) && define(lir, ins) && assignSafepoint(lir, ins);
  1.2780 +      }
  1.2781 +
  1.2782 +      default:
  1.2783 +        MOZ_ASSUME_UNREACHABLE("unexpected type");
  1.2784 +    }
  1.2785 +}
  1.2786 +
  1.2787 +bool
  1.2788 +LIRGenerator::visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole *ins)
  1.2789 +{
  1.2790 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.2791 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2792 +
  1.2793 +    JS_ASSERT(ins->type() == MIRType_Value);
  1.2794 +
  1.2795 +    const LUse object = useRegister(ins->object());
  1.2796 +    const LAllocation index = useRegisterOrConstant(ins->index());
  1.2797 +
  1.2798 +    LLoadTypedArrayElementHole *lir = new(alloc()) LLoadTypedArrayElementHole(object, index);
  1.2799 +    if (ins->fallible() && !assignSnapshot(lir))
  1.2800 +        return false;
  1.2801 +    return defineBox(lir, ins) && assignSafepoint(lir, ins);
  1.2802 +}
  1.2803 +
  1.2804 +bool
  1.2805 +LIRGenerator::visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic *ins)
  1.2806 +{
  1.2807 +    LLoadTypedArrayElementStatic *lir =
  1.2808 +        new(alloc()) LLoadTypedArrayElementStatic(useRegisterAtStart(ins->ptr()));
  1.2809 +
  1.2810 +    if (ins->fallible() && !assignSnapshot(lir))
  1.2811 +        return false;
  1.2812 +    return define(lir, ins);
  1.2813 +}
  1.2814 +
  1.2815 +bool
  1.2816 +LIRGenerator::visitStoreTypedArrayElement(MStoreTypedArrayElement *ins)
  1.2817 +{
  1.2818 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2819 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2820 +
  1.2821 +    if (ins->isFloatArray()) {
  1.2822 +        DebugOnly<bool> optimizeFloat32 = allowFloat32Optimizations();
  1.2823 +        JS_ASSERT_IF(optimizeFloat32 && ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT32,
  1.2824 +                     ins->value()->type() == MIRType_Float32);
  1.2825 +        JS_ASSERT_IF(!optimizeFloat32 || ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT64,
  1.2826 +                     ins->value()->type() == MIRType_Double);
  1.2827 +    } else {
  1.2828 +        JS_ASSERT(ins->value()->type() == MIRType_Int32);
  1.2829 +    }
  1.2830 +
  1.2831 +    LUse elements = useRegister(ins->elements());
  1.2832 +    LAllocation index = useRegisterOrConstant(ins->index());
  1.2833 +    LAllocation value;
  1.2834 +
  1.2835 +    // For byte arrays, the value has to be in a byte register on x86.
  1.2836 +    if (ins->isByteArray())
  1.2837 +        value = useByteOpRegisterOrNonDoubleConstant(ins->value());
  1.2838 +    else
  1.2839 +        value = useRegisterOrNonDoubleConstant(ins->value());
  1.2840 +    return add(new(alloc()) LStoreTypedArrayElement(elements, index, value), ins);
  1.2841 +}
  1.2842 +
  1.2843 +bool
  1.2844 +LIRGenerator::visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole *ins)
  1.2845 +{
  1.2846 +    JS_ASSERT(ins->elements()->type() == MIRType_Elements);
  1.2847 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.2848 +    JS_ASSERT(ins->length()->type() == MIRType_Int32);
  1.2849 +
  1.2850 +    if (ins->isFloatArray()) {
  1.2851 +        DebugOnly<bool> optimizeFloat32 = allowFloat32Optimizations();
  1.2852 +        JS_ASSERT_IF(optimizeFloat32 && ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT32,
  1.2853 +                     ins->value()->type() == MIRType_Float32);
  1.2854 +        JS_ASSERT_IF(!optimizeFloat32 || ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT64,
  1.2855 +                     ins->value()->type() == MIRType_Double);
  1.2856 +    } else {
  1.2857 +        JS_ASSERT(ins->value()->type() == MIRType_Int32);
  1.2858 +    }
  1.2859 +
  1.2860 +    LUse elements = useRegister(ins->elements());
  1.2861 +    LAllocation length = useAnyOrConstant(ins->length());
  1.2862 +    LAllocation index = useRegisterOrConstant(ins->index());
  1.2863 +    LAllocation value;
  1.2864 +
  1.2865 +    // For byte arrays, the value has to be in a byte register on x86.
  1.2866 +    if (ins->isByteArray())
  1.2867 +        value = useByteOpRegisterOrNonDoubleConstant(ins->value());
  1.2868 +    else
  1.2869 +        value = useRegisterOrNonDoubleConstant(ins->value());
  1.2870 +    return add(new(alloc()) LStoreTypedArrayElementHole(elements, length, index, value), ins);
  1.2871 +}
  1.2872 +
  1.2873 +bool
  1.2874 +LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot *ins)
  1.2875 +{
  1.2876 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.2877 +
  1.2878 +    if (ins->type() == MIRType_Value) {
  1.2879 +        LLoadFixedSlotV *lir = new(alloc()) LLoadFixedSlotV(useRegister(ins->object()));
  1.2880 +        return defineBox(lir, ins);
  1.2881 +    }
  1.2882 +
  1.2883 +    LLoadFixedSlotT *lir = new(alloc()) LLoadFixedSlotT(useRegister(ins->object()));
  1.2884 +    return define(lir, ins);
  1.2885 +}
  1.2886 +
  1.2887 +bool
  1.2888 +LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot *ins)
  1.2889 +{
  1.2890 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.2891 +
  1.2892 +    if (ins->value()->type() == MIRType_Value) {
  1.2893 +        LStoreFixedSlotV *lir = new(alloc()) LStoreFixedSlotV(useRegister(ins->object()));
  1.2894 +
  1.2895 +        if (!useBox(lir, LStoreFixedSlotV::Value, ins->value()))
  1.2896 +            return false;
  1.2897 +        return add(lir, ins);
  1.2898 +    }
  1.2899 +
  1.2900 +    LStoreFixedSlotT *lir = new(alloc()) LStoreFixedSlotT(useRegister(ins->object()),
  1.2901 +                                                          useRegisterOrConstant(ins->value()));
  1.2902 +    return add(lir, ins);
  1.2903 +}
  1.2904 +
  1.2905 +bool
  1.2906 +LIRGenerator::visitGetNameCache(MGetNameCache *ins)
  1.2907 +{
  1.2908 +    JS_ASSERT(ins->scopeObj()->type() == MIRType_Object);
  1.2909 +
  1.2910 +    LGetNameCache *lir = new(alloc()) LGetNameCache(useRegister(ins->scopeObj()));
  1.2911 +    if (!defineBox(lir, ins))
  1.2912 +        return false;
  1.2913 +    return assignSafepoint(lir, ins);
  1.2914 +}
  1.2915 +
  1.2916 +bool
  1.2917 +LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue *ins)
  1.2918 +{
  1.2919 +    LCallGetIntrinsicValue *lir = new(alloc()) LCallGetIntrinsicValue();
  1.2920 +    if (!defineReturn(lir, ins))
  1.2921 +        return false;
  1.2922 +    return assignSafepoint(lir, ins);
  1.2923 +}
  1.2924 +
  1.2925 +bool
  1.2926 +LIRGenerator::visitCallsiteCloneCache(MCallsiteCloneCache *ins)
  1.2927 +{
  1.2928 +    JS_ASSERT(ins->callee()->type() == MIRType_Object);
  1.2929 +
  1.2930 +    LCallsiteCloneCache *lir = new(alloc()) LCallsiteCloneCache(useRegister(ins->callee()));
  1.2931 +    if (!define(lir, ins))
  1.2932 +        return false;
  1.2933 +    return assignSafepoint(lir, ins);
  1.2934 +}
  1.2935 +
  1.2936 +bool
  1.2937 +LIRGenerator::visitGetPropertyCache(MGetPropertyCache *ins)
  1.2938 +{
  1.2939 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.2940 +    if (ins->type() == MIRType_Value) {
  1.2941 +        LGetPropertyCacheV *lir = new(alloc()) LGetPropertyCacheV(useRegister(ins->object()));
  1.2942 +        if (!defineBox(lir, ins))
  1.2943 +            return false;
  1.2944 +        return assignSafepoint(lir, ins);
  1.2945 +    }
  1.2946 +
  1.2947 +    LGetPropertyCacheT *lir = new(alloc()) LGetPropertyCacheT(useRegister(ins->object()),
  1.2948 +                                                              tempForDispatchCache(ins->type()));
  1.2949 +    if (!define(lir, ins))
  1.2950 +        return false;
  1.2951 +    return assignSafepoint(lir, ins);
  1.2952 +}
  1.2953 +
  1.2954 +bool
  1.2955 +LIRGenerator::visitGetPropertyPolymorphic(MGetPropertyPolymorphic *ins)
  1.2956 +{
  1.2957 +    JS_ASSERT(ins->obj()->type() == MIRType_Object);
  1.2958 +
  1.2959 +    if (ins->type() == MIRType_Value) {
  1.2960 +        LGetPropertyPolymorphicV *lir = new(alloc()) LGetPropertyPolymorphicV(useRegister(ins->obj()));
  1.2961 +        return assignSnapshot(lir, Bailout_ShapeGuard) && defineBox(lir, ins);
  1.2962 +    }
  1.2963 +
  1.2964 +    LDefinition maybeTemp = (ins->type() == MIRType_Double) ? temp() : LDefinition::BogusTemp();
  1.2965 +    LGetPropertyPolymorphicT *lir = new(alloc()) LGetPropertyPolymorphicT(useRegister(ins->obj()), maybeTemp);
  1.2966 +    return assignSnapshot(lir, Bailout_ShapeGuard) && define(lir, ins);
  1.2967 +}
  1.2968 +
  1.2969 +bool
  1.2970 +LIRGenerator::visitSetPropertyPolymorphic(MSetPropertyPolymorphic *ins)
  1.2971 +{
  1.2972 +    JS_ASSERT(ins->obj()->type() == MIRType_Object);
  1.2973 +
  1.2974 +    if (ins->value()->type() == MIRType_Value) {
  1.2975 +        LSetPropertyPolymorphicV *lir = new(alloc()) LSetPropertyPolymorphicV(useRegister(ins->obj()), temp());
  1.2976 +        if (!useBox(lir, LSetPropertyPolymorphicV::Value, ins->value()))
  1.2977 +            return false;
  1.2978 +        return assignSnapshot(lir, Bailout_ShapeGuard) && add(lir, ins);
  1.2979 +    }
  1.2980 +
  1.2981 +    LAllocation value = useRegisterOrConstant(ins->value());
  1.2982 +    LSetPropertyPolymorphicT *lir =
  1.2983 +        new(alloc()) LSetPropertyPolymorphicT(useRegister(ins->obj()), value, ins->value()->type(), temp());
  1.2984 +    return assignSnapshot(lir, Bailout_ShapeGuard) && add(lir, ins);
  1.2985 +}
  1.2986 +
  1.2987 +bool
  1.2988 +LIRGenerator::visitGetElementCache(MGetElementCache *ins)
  1.2989 +{
  1.2990 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.2991 +
  1.2992 +    if (ins->type() == MIRType_Value) {
  1.2993 +        JS_ASSERT(ins->index()->type() == MIRType_Value);
  1.2994 +        LGetElementCacheV *lir = new(alloc()) LGetElementCacheV(useRegister(ins->object()));
  1.2995 +        if (!useBox(lir, LGetElementCacheV::Index, ins->index()))
  1.2996 +            return false;
  1.2997 +        return defineBox(lir, ins) && assignSafepoint(lir, ins);
  1.2998 +    }
  1.2999 +
  1.3000 +    JS_ASSERT(ins->index()->type() == MIRType_Int32);
  1.3001 +    LGetElementCacheT *lir = new(alloc()) LGetElementCacheT(useRegister(ins->object()),
  1.3002 +                                                            useRegister(ins->index()),
  1.3003 +                                                            tempForDispatchCache(ins->type()));
  1.3004 +    return define(lir, ins) && assignSafepoint(lir, ins);
  1.3005 +}
  1.3006 +
  1.3007 +bool
  1.3008 +LIRGenerator::visitBindNameCache(MBindNameCache *ins)
  1.3009 +{
  1.3010 +    JS_ASSERT(ins->scopeChain()->type() == MIRType_Object);
  1.3011 +    JS_ASSERT(ins->type() == MIRType_Object);
  1.3012 +
  1.3013 +    LBindNameCache *lir = new(alloc()) LBindNameCache(useRegister(ins->scopeChain()));
  1.3014 +    return define(lir, ins) && assignSafepoint(lir, ins);
  1.3015 +}
  1.3016 +
  1.3017 +bool
  1.3018 +LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity *ins)
  1.3019 +{
  1.3020 +    LGuardObjectIdentity *guard = new(alloc()) LGuardObjectIdentity(useRegister(ins->obj()));
  1.3021 +    return assignSnapshot(guard) && add(guard, ins) && redefine(ins, ins->obj());
  1.3022 +}
  1.3023 +
  1.3024 +bool
  1.3025 +LIRGenerator::visitGuardClass(MGuardClass *ins)
  1.3026 +{
  1.3027 +    LDefinition t = temp();
  1.3028 +    LGuardClass *guard = new(alloc()) LGuardClass(useRegister(ins->obj()), t);
  1.3029 +    return assignSnapshot(guard) && add(guard, ins);
  1.3030 +}
  1.3031 +
  1.3032 +bool
  1.3033 +LIRGenerator::visitGuardObject(MGuardObject *ins)
  1.3034 +{
  1.3035 +    // The type policy does all the work, so at this point the input
  1.3036 +    // is guaranteed to be an object.
  1.3037 +    JS_ASSERT(ins->input()->type() == MIRType_Object);
  1.3038 +    return redefine(ins, ins->input());
  1.3039 +}
  1.3040 +
  1.3041 +bool
  1.3042 +LIRGenerator::visitGuardString(MGuardString *ins)
  1.3043 +{
  1.3044 +    // The type policy does all the work, so at this point the input
  1.3045 +    // is guaranteed to be a string.
  1.3046 +    JS_ASSERT(ins->input()->type() == MIRType_String);
  1.3047 +    return redefine(ins, ins->input());
  1.3048 +}
  1.3049 +
  1.3050 +bool
  1.3051 +LIRGenerator::visitAssertRange(MAssertRange *ins)
  1.3052 +{
  1.3053 +    MDefinition *input = ins->input();
  1.3054 +    LInstruction *lir = nullptr;
  1.3055 +
  1.3056 +    switch (input->type()) {
  1.3057 +      case MIRType_Boolean:
  1.3058 +      case MIRType_Int32:
  1.3059 +        lir = new(alloc()) LAssertRangeI(useRegisterAtStart(input));
  1.3060 +        break;
  1.3061 +
  1.3062 +      case MIRType_Double:
  1.3063 +        lir = new(alloc()) LAssertRangeD(useRegister(input), tempDouble());
  1.3064 +        break;
  1.3065 +
  1.3066 +      case MIRType_Float32:
  1.3067 +        lir = new(alloc()) LAssertRangeF(useRegister(input), tempFloat32());
  1.3068 +        break;
  1.3069 +
  1.3070 +      case MIRType_Value:
  1.3071 +        lir = new(alloc()) LAssertRangeV(tempToUnbox(), tempDouble(), tempDouble());
  1.3072 +        if (!useBox(lir, LAssertRangeV::Input, input))
  1.3073 +            return false;
  1.3074 +        break;
  1.3075 +
  1.3076 +      default:
  1.3077 +        MOZ_ASSUME_UNREACHABLE("Unexpected Range for MIRType");
  1.3078 +        break;
  1.3079 +    }
  1.3080 +
  1.3081 +    lir->setMir(ins);
  1.3082 +    return add(lir);
  1.3083 +}
  1.3084 +
  1.3085 +bool
  1.3086 +LIRGenerator::visitCallGetProperty(MCallGetProperty *ins)
  1.3087 +{
  1.3088 +    LCallGetProperty *lir = new(alloc()) LCallGetProperty();
  1.3089 +    if (!useBoxAtStart(lir, LCallGetProperty::Value, ins->value()))
  1.3090 +        return false;
  1.3091 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.3092 +}
  1.3093 +
  1.3094 +bool
  1.3095 +LIRGenerator::visitCallGetElement(MCallGetElement *ins)
  1.3096 +{
  1.3097 +    JS_ASSERT(ins->lhs()->type() == MIRType_Value);
  1.3098 +    JS_ASSERT(ins->rhs()->type() == MIRType_Value);
  1.3099 +
  1.3100 +    LCallGetElement *lir = new(alloc()) LCallGetElement();
  1.3101 +    if (!useBoxAtStart(lir, LCallGetElement::LhsInput, ins->lhs()))
  1.3102 +        return false;
  1.3103 +    if (!useBoxAtStart(lir, LCallGetElement::RhsInput, ins->rhs()))
  1.3104 +        return false;
  1.3105 +    if (!defineReturn(lir, ins))
  1.3106 +        return false;
  1.3107 +    return assignSafepoint(lir, ins);
  1.3108 +}
  1.3109 +
  1.3110 +bool
  1.3111 +LIRGenerator::visitCallSetProperty(MCallSetProperty *ins)
  1.3112 +{
  1.3113 +    LInstruction *lir = new(alloc()) LCallSetProperty(useRegisterAtStart(ins->object()));
  1.3114 +    if (!useBoxAtStart(lir, LCallSetProperty::Value, ins->value()))
  1.3115 +        return false;
  1.3116 +    if (!add(lir, ins))
  1.3117 +        return false;
  1.3118 +    return assignSafepoint(lir, ins);
  1.3119 +}
  1.3120 +
  1.3121 +bool
  1.3122 +LIRGenerator::visitDeleteProperty(MDeleteProperty *ins)
  1.3123 +{
  1.3124 +    LCallDeleteProperty *lir = new(alloc()) LCallDeleteProperty();
  1.3125 +    if(!useBoxAtStart(lir, LCallDeleteProperty::Value, ins->value()))
  1.3126 +        return false;
  1.3127 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.3128 +}
  1.3129 +
  1.3130 +bool
  1.3131 +LIRGenerator::visitDeleteElement(MDeleteElement *ins)
  1.3132 +{
  1.3133 +    LCallDeleteElement *lir = new(alloc()) LCallDeleteElement();
  1.3134 +    if(!useBoxAtStart(lir, LCallDeleteElement::Value, ins->value()))
  1.3135 +        return false;
  1.3136 +    if(!useBoxAtStart(lir, LCallDeleteElement::Index, ins->index()))
  1.3137 +        return false;
  1.3138 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.3139 +}
  1.3140 +
  1.3141 +bool
  1.3142 +LIRGenerator::visitSetPropertyCache(MSetPropertyCache *ins)
  1.3143 +{
  1.3144 +    LUse obj = useRegisterAtStart(ins->object());
  1.3145 +    LDefinition slots = tempCopy(ins->object(), 0);
  1.3146 +    LDefinition dispatchTemp = tempForDispatchCache();
  1.3147 +
  1.3148 +    LInstruction *lir;
  1.3149 +    if (ins->value()->type() == MIRType_Value) {
  1.3150 +        lir = new(alloc()) LSetPropertyCacheV(obj, slots, dispatchTemp);
  1.3151 +        if (!useBox(lir, LSetPropertyCacheV::Value, ins->value()))
  1.3152 +            return false;
  1.3153 +    } else {
  1.3154 +        LAllocation value = useRegisterOrConstant(ins->value());
  1.3155 +        lir = new(alloc()) LSetPropertyCacheT(obj, slots, value, dispatchTemp, ins->value()->type());
  1.3156 +    }
  1.3157 +
  1.3158 +    if (!add(lir, ins))
  1.3159 +        return false;
  1.3160 +
  1.3161 +    return assignSafepoint(lir, ins);
  1.3162 +}
  1.3163 +
  1.3164 +bool
  1.3165 +LIRGenerator::visitSetElementCache(MSetElementCache *ins)
  1.3166 +{
  1.3167 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.3168 +    JS_ASSERT(ins->index()->type() == MIRType_Value);
  1.3169 +
  1.3170 +    // Due to lack of registers on x86, we reuse the object register as a
  1.3171 +    // temporary. This register may be used in a 1-byte store, which on x86
  1.3172 +    // again has constraints; thus the use of |useByteOpRegister| over
  1.3173 +    // |useRegister| below.
  1.3174 +    LInstruction *lir;
  1.3175 +    if (ins->value()->type() == MIRType_Value) {
  1.3176 +        lir = new(alloc()) LSetElementCacheV(useByteOpRegister(ins->object()), tempToUnbox(),
  1.3177 +                                             temp(), tempDouble());
  1.3178 +
  1.3179 +        if (!useBox(lir, LSetElementCacheV::Index, ins->index()))
  1.3180 +            return false;
  1.3181 +        if (!useBox(lir, LSetElementCacheV::Value, ins->value()))
  1.3182 +            return false;
  1.3183 +    } else {
  1.3184 +        lir = new(alloc()) LSetElementCacheT(useByteOpRegister(ins->object()),
  1.3185 +                                             useRegisterOrConstant(ins->value()),
  1.3186 +                                             tempToUnbox(), temp(), tempDouble());
  1.3187 +
  1.3188 +        if (!useBox(lir, LSetElementCacheT::Index, ins->index()))
  1.3189 +            return false;
  1.3190 +    }
  1.3191 +
  1.3192 +    return add(lir, ins) && assignSafepoint(lir, ins);
  1.3193 +}
  1.3194 +
  1.3195 +bool
  1.3196 +LIRGenerator::visitCallSetElement(MCallSetElement *ins)
  1.3197 +{
  1.3198 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.3199 +    JS_ASSERT(ins->index()->type() == MIRType_Value);
  1.3200 +    JS_ASSERT(ins->value()->type() == MIRType_Value);
  1.3201 +
  1.3202 +    LCallSetElement *lir = new(alloc()) LCallSetElement();
  1.3203 +    lir->setOperand(0, useRegisterAtStart(ins->object()));
  1.3204 +    if (!useBoxAtStart(lir, LCallSetElement::Index, ins->index()))
  1.3205 +        return false;
  1.3206 +    if (!useBoxAtStart(lir, LCallSetElement::Value, ins->value()))
  1.3207 +        return false;
  1.3208 +    return add(lir, ins) && assignSafepoint(lir, ins);
  1.3209 +}
  1.3210 +
  1.3211 +bool
  1.3212 +LIRGenerator::visitCallInitElementArray(MCallInitElementArray *ins)
  1.3213 +{
  1.3214 +    LCallInitElementArray *lir = new(alloc()) LCallInitElementArray();
  1.3215 +    lir->setOperand(0, useRegisterAtStart(ins->object()));
  1.3216 +    if (!useBoxAtStart(lir, LCallInitElementArray::Value, ins->value()))
  1.3217 +        return false;
  1.3218 +    return add(lir, ins) && assignSafepoint(lir, ins);
  1.3219 +}
  1.3220 +
  1.3221 +bool
  1.3222 +LIRGenerator::visitIteratorStart(MIteratorStart *ins)
  1.3223 +{
  1.3224 +    // Call a stub if this is not a simple for-in loop.
  1.3225 +    if (ins->flags() != JSITER_ENUMERATE) {
  1.3226 +        LCallIteratorStart *lir = new(alloc()) LCallIteratorStart(useRegisterAtStart(ins->object()));
  1.3227 +        return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.3228 +    }
  1.3229 +
  1.3230 +    LIteratorStart *lir = new(alloc()) LIteratorStart(useRegister(ins->object()), temp(), temp(), temp());
  1.3231 +    return define(lir, ins) && assignSafepoint(lir, ins);
  1.3232 +}
  1.3233 +
  1.3234 +bool
  1.3235 +LIRGenerator::visitIteratorNext(MIteratorNext *ins)
  1.3236 +{
  1.3237 +    LIteratorNext *lir = new(alloc()) LIteratorNext(useRegister(ins->iterator()), temp());
  1.3238 +    return defineBox(lir, ins) && assignSafepoint(lir, ins);
  1.3239 +}
  1.3240 +
  1.3241 +bool
  1.3242 +LIRGenerator::visitIteratorMore(MIteratorMore *ins)
  1.3243 +{
  1.3244 +    LIteratorMore *lir = new(alloc()) LIteratorMore(useRegister(ins->iterator()), temp());
  1.3245 +    return define(lir, ins) && assignSafepoint(lir, ins);
  1.3246 +}
  1.3247 +
  1.3248 +bool
  1.3249 +LIRGenerator::visitIteratorEnd(MIteratorEnd *ins)
  1.3250 +{
  1.3251 +    LIteratorEnd *lir = new(alloc()) LIteratorEnd(useRegister(ins->iterator()), temp(), temp(), temp());
  1.3252 +    return add(lir, ins) && assignSafepoint(lir, ins);
  1.3253 +}
  1.3254 +
  1.3255 +bool
  1.3256 +LIRGenerator::visitStringLength(MStringLength *ins)
  1.3257 +{
  1.3258 +    JS_ASSERT(ins->string()->type() == MIRType_String);
  1.3259 +    return define(new(alloc()) LStringLength(useRegisterAtStart(ins->string())), ins);
  1.3260 +}
  1.3261 +
  1.3262 +bool
  1.3263 +LIRGenerator::visitArgumentsLength(MArgumentsLength *ins)
  1.3264 +{
  1.3265 +    return define(new(alloc()) LArgumentsLength(), ins);
  1.3266 +}
  1.3267 +
  1.3268 +bool
  1.3269 +LIRGenerator::visitGetFrameArgument(MGetFrameArgument *ins)
  1.3270 +{
  1.3271 +    LGetFrameArgument *lir = new(alloc()) LGetFrameArgument(useRegisterOrConstant(ins->index()));
  1.3272 +    return defineBox(lir, ins);
  1.3273 +}
  1.3274 +
  1.3275 +bool
  1.3276 +LIRGenerator::visitSetFrameArgument(MSetFrameArgument *ins)
  1.3277 +{
  1.3278 +    MDefinition *input = ins->input();
  1.3279 +
  1.3280 +    if (input->type() == MIRType_Value) {
  1.3281 +        LSetFrameArgumentV *lir = new(alloc()) LSetFrameArgumentV();
  1.3282 +        if (!useBox(lir, LSetFrameArgumentV::Input, input))
  1.3283 +            return false;
  1.3284 +        return add(lir, ins);
  1.3285 +    }
  1.3286 +
  1.3287 +    if (input->type() == MIRType_Undefined || input->type() == MIRType_Null) {
  1.3288 +        Value val = input->type() == MIRType_Undefined ? UndefinedValue() : NullValue();
  1.3289 +        LSetFrameArgumentC *lir = new(alloc()) LSetFrameArgumentC(val);
  1.3290 +        return add(lir, ins);
  1.3291 +    }
  1.3292 +
  1.3293 +    LSetFrameArgumentT *lir = new(alloc()) LSetFrameArgumentT(useRegister(input));
  1.3294 +    return add(lir, ins);
  1.3295 +}
  1.3296 +
  1.3297 +bool
  1.3298 +LIRGenerator::visitRunOncePrologue(MRunOncePrologue *ins)
  1.3299 +{
  1.3300 +    LRunOncePrologue *lir = new(alloc()) LRunOncePrologue;
  1.3301 +    return add(lir, ins) && assignSafepoint(lir, ins);
  1.3302 +}
  1.3303 +
  1.3304 +bool
  1.3305 +LIRGenerator::visitRest(MRest *ins)
  1.3306 +{
  1.3307 +    JS_ASSERT(ins->numActuals()->type() == MIRType_Int32);
  1.3308 +
  1.3309 +    LRest *lir = new(alloc()) LRest(useFixed(ins->numActuals(), CallTempReg0),
  1.3310 +                                    tempFixed(CallTempReg1),
  1.3311 +                                    tempFixed(CallTempReg2),
  1.3312 +                                    tempFixed(CallTempReg3));
  1.3313 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.3314 +}
  1.3315 +
  1.3316 +bool
  1.3317 +LIRGenerator::visitRestPar(MRestPar *ins)
  1.3318 +{
  1.3319 +    JS_ASSERT(ins->numActuals()->type() == MIRType_Int32);
  1.3320 +
  1.3321 +    LRestPar *lir = new(alloc()) LRestPar(useFixed(ins->forkJoinContext(), CallTempReg0),
  1.3322 +                                          useFixed(ins->numActuals(), CallTempReg1),
  1.3323 +                                          tempFixed(CallTempReg2),
  1.3324 +                                          tempFixed(CallTempReg3),
  1.3325 +                                          tempFixed(CallTempReg4));
  1.3326 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.3327 +}
  1.3328 +
  1.3329 +bool
  1.3330 +LIRGenerator::visitThrow(MThrow *ins)
  1.3331 +{
  1.3332 +    MDefinition *value = ins->getOperand(0);
  1.3333 +    JS_ASSERT(value->type() == MIRType_Value);
  1.3334 +
  1.3335 +    LThrow *lir = new(alloc()) LThrow;
  1.3336 +    if (!useBoxAtStart(lir, LThrow::Value, value))
  1.3337 +        return false;
  1.3338 +    return add(lir, ins) && assignSafepoint(lir, ins);
  1.3339 +}
  1.3340 +
  1.3341 +bool
  1.3342 +LIRGenerator::visitIn(MIn *ins)
  1.3343 +{
  1.3344 +    MDefinition *lhs = ins->lhs();
  1.3345 +    MDefinition *rhs = ins->rhs();
  1.3346 +
  1.3347 +    JS_ASSERT(lhs->type() == MIRType_Value);
  1.3348 +    JS_ASSERT(rhs->type() == MIRType_Object);
  1.3349 +
  1.3350 +    LIn *lir = new(alloc()) LIn(useRegisterAtStart(rhs));
  1.3351 +    if (!useBoxAtStart(lir, LIn::LHS, lhs))
  1.3352 +        return false;
  1.3353 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.3354 +}
  1.3355 +
  1.3356 +bool
  1.3357 +LIRGenerator::visitInstanceOf(MInstanceOf *ins)
  1.3358 +{
  1.3359 +    MDefinition *lhs = ins->getOperand(0);
  1.3360 +
  1.3361 +    JS_ASSERT(lhs->type() == MIRType_Value || lhs->type() == MIRType_Object);
  1.3362 +
  1.3363 +    if (lhs->type() == MIRType_Object) {
  1.3364 +        LInstanceOfO *lir = new(alloc()) LInstanceOfO(useRegister(lhs));
  1.3365 +        return define(lir, ins) && assignSafepoint(lir, ins);
  1.3366 +    }
  1.3367 +
  1.3368 +    LInstanceOfV *lir = new(alloc()) LInstanceOfV();
  1.3369 +    return useBox(lir, LInstanceOfV::LHS, lhs) && define(lir, ins) && assignSafepoint(lir, ins);
  1.3370 +}
  1.3371 +
  1.3372 +bool
  1.3373 +LIRGenerator::visitCallInstanceOf(MCallInstanceOf *ins)
  1.3374 +{
  1.3375 +    MDefinition *lhs = ins->lhs();
  1.3376 +    MDefinition *rhs = ins->rhs();
  1.3377 +
  1.3378 +    JS_ASSERT(lhs->type() == MIRType_Value);
  1.3379 +    JS_ASSERT(rhs->type() == MIRType_Object);
  1.3380 +
  1.3381 +    LCallInstanceOf *lir = new(alloc()) LCallInstanceOf(useRegisterAtStart(rhs));
  1.3382 +    if (!useBoxAtStart(lir, LCallInstanceOf::LHS, lhs))
  1.3383 +        return false;
  1.3384 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.3385 +}
  1.3386 +
  1.3387 +bool
  1.3388 +LIRGenerator::visitProfilerStackOp(MProfilerStackOp *ins)
  1.3389 +{
  1.3390 +    LProfilerStackOp *lir = new(alloc()) LProfilerStackOp(temp());
  1.3391 +    if (!add(lir, ins))
  1.3392 +        return false;
  1.3393 +    // If slow assertions are enabled, then this node will result in a callVM
  1.3394 +    // out to a C++ function for the assertions, so we will need a safepoint.
  1.3395 +    return !gen->options.spsSlowAssertionsEnabled() || assignSafepoint(lir, ins);
  1.3396 +}
  1.3397 +
  1.3398 +bool
  1.3399 +LIRGenerator::visitIsCallable(MIsCallable *ins)
  1.3400 +{
  1.3401 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.3402 +    JS_ASSERT(ins->type() == MIRType_Boolean);
  1.3403 +    return define(new(alloc()) LIsCallable(useRegister(ins->object())), ins);
  1.3404 +}
  1.3405 +
  1.3406 +bool
  1.3407 +LIRGenerator::visitHaveSameClass(MHaveSameClass *ins)
  1.3408 +{
  1.3409 +    MDefinition *lhs = ins->lhs();
  1.3410 +    MDefinition *rhs = ins->rhs();
  1.3411 +
  1.3412 +    JS_ASSERT(lhs->type() == MIRType_Object);
  1.3413 +    JS_ASSERT(rhs->type() == MIRType_Object);
  1.3414 +
  1.3415 +    return define(new(alloc()) LHaveSameClass(useRegister(lhs), useRegister(rhs), temp()), ins);
  1.3416 +}
  1.3417 +
  1.3418 +bool
  1.3419 +LIRGenerator::visitHasClass(MHasClass *ins)
  1.3420 +{
  1.3421 +    JS_ASSERT(ins->object()->type() == MIRType_Object);
  1.3422 +    JS_ASSERT(ins->type() == MIRType_Boolean);
  1.3423 +    return define(new(alloc()) LHasClass(useRegister(ins->object())), ins);
  1.3424 +}
  1.3425 +
  1.3426 +bool
  1.3427 +LIRGenerator::visitAsmJSLoadGlobalVar(MAsmJSLoadGlobalVar *ins)
  1.3428 +{
  1.3429 +    return define(new(alloc()) LAsmJSLoadGlobalVar, ins);
  1.3430 +}
  1.3431 +
  1.3432 +bool
  1.3433 +LIRGenerator::visitAsmJSStoreGlobalVar(MAsmJSStoreGlobalVar *ins)
  1.3434 +{
  1.3435 +    return add(new(alloc()) LAsmJSStoreGlobalVar(useRegisterAtStart(ins->value())), ins);
  1.3436 +}
  1.3437 +
  1.3438 +bool
  1.3439 +LIRGenerator::visitAsmJSLoadFFIFunc(MAsmJSLoadFFIFunc *ins)
  1.3440 +{
  1.3441 +    return define(new(alloc()) LAsmJSLoadFFIFunc, ins);
  1.3442 +}
  1.3443 +
  1.3444 +bool
  1.3445 +LIRGenerator::visitAsmJSParameter(MAsmJSParameter *ins)
  1.3446 +{
  1.3447 +    ABIArg abi = ins->abi();
  1.3448 +    if (abi.argInRegister())
  1.3449 +        return defineFixed(new(alloc()) LAsmJSParameter, ins, LAllocation(abi.reg()));
  1.3450 +
  1.3451 +    JS_ASSERT(IsNumberType(ins->type()));
  1.3452 +    return defineFixed(new(alloc()) LAsmJSParameter, ins, LArgument(abi.offsetFromArgBase()));
  1.3453 +}
  1.3454 +
  1.3455 +bool
  1.3456 +LIRGenerator::visitAsmJSReturn(MAsmJSReturn *ins)
  1.3457 +{
  1.3458 +    MDefinition *rval = ins->getOperand(0);
  1.3459 +    LAsmJSReturn *lir = new(alloc()) LAsmJSReturn;
  1.3460 +    if (IsFloatingPointType(rval->type()))
  1.3461 +        lir->setOperand(0, useFixed(rval, ReturnFloatReg));
  1.3462 +    else if (rval->type() == MIRType_Int32)
  1.3463 +        lir->setOperand(0, useFixed(rval, ReturnReg));
  1.3464 +    else
  1.3465 +        MOZ_ASSUME_UNREACHABLE("Unexpected asm.js return type");
  1.3466 +    return add(lir);
  1.3467 +}
  1.3468 +
  1.3469 +bool
  1.3470 +LIRGenerator::visitAsmJSVoidReturn(MAsmJSVoidReturn *ins)
  1.3471 +{
  1.3472 +    return add(new(alloc()) LAsmJSVoidReturn);
  1.3473 +}
  1.3474 +
  1.3475 +bool
  1.3476 +LIRGenerator::visitAsmJSPassStackArg(MAsmJSPassStackArg *ins)
  1.3477 +{
  1.3478 +    if (IsFloatingPointType(ins->arg()->type())) {
  1.3479 +        JS_ASSERT(!ins->arg()->isEmittedAtUses());
  1.3480 +        return add(new(alloc()) LAsmJSPassStackArg(useRegisterAtStart(ins->arg())), ins);
  1.3481 +    }
  1.3482 +
  1.3483 +    return add(new(alloc()) LAsmJSPassStackArg(useRegisterOrConstantAtStart(ins->arg())), ins);
  1.3484 +}
  1.3485 +
  1.3486 +bool
  1.3487 +LIRGenerator::visitAsmJSCall(MAsmJSCall *ins)
  1.3488 +{
  1.3489 +    gen->setPerformsAsmJSCall();
  1.3490 +
  1.3491 +    LAllocation *args = gen->allocate<LAllocation>(ins->numOperands());
  1.3492 +    if (!args)
  1.3493 +        return false;
  1.3494 +
  1.3495 +    for (unsigned i = 0; i < ins->numArgs(); i++)
  1.3496 +        args[i] = useFixed(ins->getOperand(i), ins->registerForArg(i));
  1.3497 +
  1.3498 +    if (ins->callee().which() == MAsmJSCall::Callee::Dynamic)
  1.3499 +        args[ins->dynamicCalleeOperandIndex()] = useFixed(ins->callee().dynamic(), CallTempReg0);
  1.3500 +
  1.3501 +    LInstruction *lir = new(alloc()) LAsmJSCall(args, ins->numOperands());
  1.3502 +    if (ins->type() == MIRType_None) {
  1.3503 +        return add(lir, ins);
  1.3504 +    }
  1.3505 +    return defineReturn(lir, ins);
  1.3506 +}
  1.3507 +
  1.3508 +bool
  1.3509 +LIRGenerator::visitSetDOMProperty(MSetDOMProperty *ins)
  1.3510 +{
  1.3511 +    MDefinition *val = ins->value();
  1.3512 +
  1.3513 +    Register cxReg, objReg, privReg, valueReg;
  1.3514 +    GetTempRegForIntArg(0, 0, &cxReg);
  1.3515 +    GetTempRegForIntArg(1, 0, &objReg);
  1.3516 +    GetTempRegForIntArg(2, 0, &privReg);
  1.3517 +    GetTempRegForIntArg(3, 0, &valueReg);
  1.3518 +    LSetDOMProperty *lir = new(alloc()) LSetDOMProperty(tempFixed(cxReg),
  1.3519 +                                                        useFixed(ins->object(), objReg),
  1.3520 +                                                        tempFixed(privReg),
  1.3521 +                                                        tempFixed(valueReg));
  1.3522 +
  1.3523 +    // Keep using GetTempRegForIntArg, since we want to make sure we
  1.3524 +    // don't clobber registers we're already using.
  1.3525 +    Register tempReg1, tempReg2;
  1.3526 +    GetTempRegForIntArg(4, 0, &tempReg1);
  1.3527 +    mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2);
  1.3528 +    MOZ_ASSERT(ok, "How can we not have six temp registers?");
  1.3529 +    if (!useBoxFixed(lir, LSetDOMProperty::Value, val, tempReg1, tempReg2))
  1.3530 +        return false;
  1.3531 +
  1.3532 +    return add(lir, ins) && assignSafepoint(lir, ins);
  1.3533 +}
  1.3534 +
  1.3535 +bool
  1.3536 +LIRGenerator::visitGetDOMProperty(MGetDOMProperty *ins)
  1.3537 +{
  1.3538 +    Register cxReg, objReg, privReg, valueReg;
  1.3539 +    GetTempRegForIntArg(0, 0, &cxReg);
  1.3540 +    GetTempRegForIntArg(1, 0, &objReg);
  1.3541 +    GetTempRegForIntArg(2, 0, &privReg);
  1.3542 +    mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg);
  1.3543 +    MOZ_ASSERT(ok, "How can we not have four temp registers?");
  1.3544 +    LGetDOMProperty *lir = new(alloc()) LGetDOMProperty(tempFixed(cxReg),
  1.3545 +                                                        useFixed(ins->object(), objReg),
  1.3546 +                                                        tempFixed(privReg),
  1.3547 +                                                        tempFixed(valueReg));
  1.3548 +
  1.3549 +    return defineReturn(lir, ins) && assignSafepoint(lir, ins);
  1.3550 +}
  1.3551 +
  1.3552 +bool
  1.3553 +LIRGenerator::visitGetDOMMember(MGetDOMMember *ins)
  1.3554 +{
  1.3555 +    MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
  1.3556 +    // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
  1.3557 +    // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
  1.3558 +    // value can in fact change as a result of DOM setters and method calls.
  1.3559 +    MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
  1.3560 +               "Member gets had better not alias the world");
  1.3561 +    LGetDOMMember *lir =
  1.3562 +        new(alloc()) LGetDOMMember(useRegister(ins->object()));
  1.3563 +    return defineBox(lir, ins);
  1.3564 +}
  1.3565 +
  1.3566 +bool
  1.3567 +LIRGenerator::visitRecompileCheck(MRecompileCheck *ins)
  1.3568 +{
  1.3569 +    LRecompileCheck *lir = new(alloc()) LRecompileCheck(temp());
  1.3570 +    if (!add(lir, ins))
  1.3571 +        return false;
  1.3572 +    return assignSafepoint(lir, ins);
  1.3573 +}
  1.3574 +
  1.3575 +static void
  1.3576 +SpewResumePoint(MBasicBlock *block, MInstruction *ins, MResumePoint *resumePoint)
  1.3577 +{
  1.3578 +    fprintf(IonSpewFile, "Current resume point %p details:\n", (void *)resumePoint);
  1.3579 +    fprintf(IonSpewFile, "    frame count: %u\n", resumePoint->frameCount());
  1.3580 +
  1.3581 +    if (ins) {
  1.3582 +        fprintf(IonSpewFile, "    taken after: ");
  1.3583 +        ins->printName(IonSpewFile);
  1.3584 +    } else {
  1.3585 +        fprintf(IonSpewFile, "    taken at block %d entry", block->id());
  1.3586 +    }
  1.3587 +    fprintf(IonSpewFile, "\n");
  1.3588 +
  1.3589 +    fprintf(IonSpewFile, "    pc: %p (script: %p, offset: %d)\n",
  1.3590 +            (void *)resumePoint->pc(),
  1.3591 +            (void *)resumePoint->block()->info().script(),
  1.3592 +            int(resumePoint->block()->info().script()->pcToOffset(resumePoint->pc())));
  1.3593 +
  1.3594 +    for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) {
  1.3595 +        MDefinition *in = resumePoint->getOperand(i);
  1.3596 +        fprintf(IonSpewFile, "    slot%u: ", (unsigned)i);
  1.3597 +        in->printName(IonSpewFile);
  1.3598 +        fprintf(IonSpewFile, "\n");
  1.3599 +    }
  1.3600 +}
  1.3601 +
  1.3602 +bool
  1.3603 +LIRGenerator::visitInstruction(MInstruction *ins)
  1.3604 +{
  1.3605 +    if (!gen->ensureBallast())
  1.3606 +        return false;
  1.3607 +    if (!ins->accept(this))
  1.3608 +        return false;
  1.3609 +
  1.3610 +    if (ins->possiblyCalls())
  1.3611 +        gen->setPerformsCall();
  1.3612 +
  1.3613 +    if (ins->resumePoint())
  1.3614 +        updateResumeState(ins);
  1.3615 +
  1.3616 +    if (gen->errored())
  1.3617 +        return false;
  1.3618 +#ifdef DEBUG
  1.3619 +    ins->setInWorklistUnchecked();
  1.3620 +#endif
  1.3621 +
  1.3622 +    // If no safepoint was created, there's no need for an OSI point.
  1.3623 +    if (LOsiPoint *osiPoint = popOsiPoint()) {
  1.3624 +        if (!add(osiPoint))
  1.3625 +            return false;
  1.3626 +    }
  1.3627 +
  1.3628 +    return true;
  1.3629 +}
  1.3630 +
  1.3631 +bool
  1.3632 +LIRGenerator::definePhis()
  1.3633 +{
  1.3634 +    size_t lirIndex = 0;
  1.3635 +    MBasicBlock *block = current->mir();
  1.3636 +    for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
  1.3637 +        if (phi->type() == MIRType_Value) {
  1.3638 +            if (!defineUntypedPhi(*phi, lirIndex))
  1.3639 +                return false;
  1.3640 +            lirIndex += BOX_PIECES;
  1.3641 +        } else {
  1.3642 +            if (!defineTypedPhi(*phi, lirIndex))
  1.3643 +                return false;
  1.3644 +            lirIndex += 1;
  1.3645 +        }
  1.3646 +    }
  1.3647 +    return true;
  1.3648 +}
  1.3649 +
  1.3650 +void
  1.3651 +LIRGenerator::updateResumeState(MInstruction *ins)
  1.3652 +{
  1.3653 +    lastResumePoint_ = ins->resumePoint();
  1.3654 +    if (IonSpewEnabled(IonSpew_Snapshots) && lastResumePoint_)
  1.3655 +        SpewResumePoint(nullptr, ins, lastResumePoint_);
  1.3656 +}
  1.3657 +
  1.3658 +void
  1.3659 +LIRGenerator::updateResumeState(MBasicBlock *block)
  1.3660 +{
  1.3661 +    lastResumePoint_ = block->entryResumePoint();
  1.3662 +    if (IonSpewEnabled(IonSpew_Snapshots) && lastResumePoint_)
  1.3663 +        SpewResumePoint(block, nullptr, lastResumePoint_);
  1.3664 +}
  1.3665 +
  1.3666 +bool
  1.3667 +LIRGenerator::visitBlock(MBasicBlock *block)
  1.3668 +{
  1.3669 +    current = block->lir();
  1.3670 +    updateResumeState(block);
  1.3671 +
  1.3672 +    if (!definePhis())
  1.3673 +        return false;
  1.3674 +
  1.3675 +    if (gen->optimizationInfo().registerAllocator() == RegisterAllocator_LSRA) {
  1.3676 +        if (!add(new(alloc()) LLabel()))
  1.3677 +            return false;
  1.3678 +    }
  1.3679 +
  1.3680 +    for (MInstructionIterator iter = block->begin(); *iter != block->lastIns(); iter++) {
  1.3681 +        if (!visitInstruction(*iter))
  1.3682 +            return false;
  1.3683 +    }
  1.3684 +
  1.3685 +    if (block->successorWithPhis()) {
  1.3686 +        // If we have a successor with phis, lower the phi input now that we
  1.3687 +        // are approaching the join point.
  1.3688 +        MBasicBlock *successor = block->successorWithPhis();
  1.3689 +        uint32_t position = block->positionInPhiSuccessor();
  1.3690 +        size_t lirIndex = 0;
  1.3691 +        for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd(); phi++) {
  1.3692 +            MDefinition *opd = phi->getOperand(position);
  1.3693 +            if (!ensureDefined(opd))
  1.3694 +                return false;
  1.3695 +
  1.3696 +            JS_ASSERT(opd->type() == phi->type());
  1.3697 +
  1.3698 +            if (phi->type() == MIRType_Value) {
  1.3699 +                lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex);
  1.3700 +                lirIndex += BOX_PIECES;
  1.3701 +            } else {
  1.3702 +                lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex);
  1.3703 +                lirIndex += 1;
  1.3704 +            }
  1.3705 +        }
  1.3706 +    }
  1.3707 +
  1.3708 +    // Now emit the last instruction, which is some form of branch.
  1.3709 +    if (!visitInstruction(block->lastIns()))
  1.3710 +        return false;
  1.3711 +
  1.3712 +    return true;
  1.3713 +}
  1.3714 +
  1.3715 +bool
  1.3716 +LIRGenerator::precreatePhi(LBlock *block, MPhi *phi)
  1.3717 +{
  1.3718 +    LPhi *lir = LPhi::New(gen, phi);
  1.3719 +    if (!lir)
  1.3720 +        return false;
  1.3721 +    if (!block->addPhi(lir))
  1.3722 +        return false;
  1.3723 +    return true;
  1.3724 +}
  1.3725 +
  1.3726 +bool
  1.3727 +LIRGenerator::generate()
  1.3728 +{
  1.3729 +    // Create all blocks and prep all phis beforehand.
  1.3730 +    for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
  1.3731 +        if (gen->shouldCancel("Lowering (preparation loop)"))
  1.3732 +            return false;
  1.3733 +
  1.3734 +        current = LBlock::New(alloc(), *block);
  1.3735 +        if (!current)
  1.3736 +            return false;
  1.3737 +        if (!lirGraph_.addBlock(current))
  1.3738 +            return false;
  1.3739 +        block->assignLir(current);
  1.3740 +
  1.3741 +        // For each MIR phi, add LIR phis as appropriate. We'll fill in their
  1.3742 +        // operands on each incoming edge, and set their definitions at the
  1.3743 +        // start of their defining block.
  1.3744 +        for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
  1.3745 +            int numPhis = (phi->type() == MIRType_Value) ? BOX_PIECES : 1;
  1.3746 +            for (int i = 0; i < numPhis; i++) {
  1.3747 +                if (!precreatePhi(block->lir(), *phi))
  1.3748 +                    return false;
  1.3749 +            }
  1.3750 +        }
  1.3751 +    }
  1.3752 +
  1.3753 +    for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
  1.3754 +        if (gen->shouldCancel("Lowering (main loop)"))
  1.3755 +            return false;
  1.3756 +
  1.3757 +        if (!visitBlock(*block))
  1.3758 +            return false;
  1.3759 +    }
  1.3760 +
  1.3761 +    if (graph.osrBlock())
  1.3762 +        lirGraph_.setOsrBlock(graph.osrBlock()->lir());
  1.3763 +
  1.3764 +    lirGraph_.setArgumentSlotCount(maxargslots_);
  1.3765 +    return true;
  1.3766 +}

mercurial