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 +}