js/src/jit/Lowering.cpp

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

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

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

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "jit/Lowering.h"
michael@0 8
michael@0 9 #include "mozilla/DebugOnly.h"
michael@0 10
michael@0 11 #include "jsanalyze.h"
michael@0 12
michael@0 13 #include "jit/IonSpewer.h"
michael@0 14 #include "jit/LIR.h"
michael@0 15 #include "jit/MIR.h"
michael@0 16 #include "jit/MIRGraph.h"
michael@0 17
michael@0 18 #include "jsinferinlines.h"
michael@0 19 #include "jsobjinlines.h"
michael@0 20 #include "jsopcodeinlines.h"
michael@0 21
michael@0 22 #include "jit/shared/Lowering-shared-inl.h"
michael@0 23
michael@0 24 using namespace js;
michael@0 25 using namespace jit;
michael@0 26
michael@0 27 using mozilla::DebugOnly;
michael@0 28 using JS::GenericNaN;
michael@0 29
michael@0 30 bool
michael@0 31 LIRGenerator::visitCloneLiteral(MCloneLiteral *ins)
michael@0 32 {
michael@0 33 JS_ASSERT(ins->type() == MIRType_Object);
michael@0 34 JS_ASSERT(ins->input()->type() == MIRType_Object);
michael@0 35
michael@0 36 LCloneLiteral *lir = new(alloc()) LCloneLiteral(useRegisterAtStart(ins->input()));
michael@0 37 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 38 }
michael@0 39
michael@0 40 bool
michael@0 41 LIRGenerator::visitParameter(MParameter *param)
michael@0 42 {
michael@0 43 ptrdiff_t offset;
michael@0 44 if (param->index() == MParameter::THIS_SLOT)
michael@0 45 offset = THIS_FRAME_ARGSLOT;
michael@0 46 else
michael@0 47 offset = 1 + param->index();
michael@0 48
michael@0 49 LParameter *ins = new(alloc()) LParameter;
michael@0 50 if (!defineBox(ins, param, LDefinition::PRESET))
michael@0 51 return false;
michael@0 52
michael@0 53 offset *= sizeof(Value);
michael@0 54 #if defined(JS_NUNBOX32)
michael@0 55 # if defined(IS_BIG_ENDIAN)
michael@0 56 ins->getDef(0)->setOutput(LArgument(offset));
michael@0 57 ins->getDef(1)->setOutput(LArgument(offset + 4));
michael@0 58 # else
michael@0 59 ins->getDef(0)->setOutput(LArgument(offset + 4));
michael@0 60 ins->getDef(1)->setOutput(LArgument(offset));
michael@0 61 # endif
michael@0 62 #elif defined(JS_PUNBOX64)
michael@0 63 ins->getDef(0)->setOutput(LArgument(offset));
michael@0 64 #endif
michael@0 65
michael@0 66 return true;
michael@0 67 }
michael@0 68
michael@0 69 bool
michael@0 70 LIRGenerator::visitCallee(MCallee *ins)
michael@0 71 {
michael@0 72 return define(new(alloc()) LCallee(), ins);
michael@0 73 }
michael@0 74
michael@0 75 bool
michael@0 76 LIRGenerator::visitGoto(MGoto *ins)
michael@0 77 {
michael@0 78 return add(new(alloc()) LGoto(ins->target()));
michael@0 79 }
michael@0 80
michael@0 81 bool
michael@0 82 LIRGenerator::visitTableSwitch(MTableSwitch *tableswitch)
michael@0 83 {
michael@0 84 MDefinition *opd = tableswitch->getOperand(0);
michael@0 85
michael@0 86 // There should be at least 1 successor. The default case!
michael@0 87 JS_ASSERT(tableswitch->numSuccessors() > 0);
michael@0 88
michael@0 89 // If there are no cases, the default case is always taken.
michael@0 90 if (tableswitch->numSuccessors() == 1)
michael@0 91 return add(new(alloc()) LGoto(tableswitch->getDefault()));
michael@0 92
michael@0 93 // If we don't know the type.
michael@0 94 if (opd->type() == MIRType_Value) {
michael@0 95 LTableSwitchV *lir = newLTableSwitchV(tableswitch);
michael@0 96 if (!useBox(lir, LTableSwitchV::InputValue, opd))
michael@0 97 return false;
michael@0 98 return add(lir);
michael@0 99 }
michael@0 100
michael@0 101 // Case indices are numeric, so other types will always go to the default case.
michael@0 102 if (opd->type() != MIRType_Int32 && opd->type() != MIRType_Double)
michael@0 103 return add(new(alloc()) LGoto(tableswitch->getDefault()));
michael@0 104
michael@0 105 // Return an LTableSwitch, capable of handling either an integer or
michael@0 106 // floating-point index.
michael@0 107 LAllocation index;
michael@0 108 LDefinition tempInt;
michael@0 109 if (opd->type() == MIRType_Int32) {
michael@0 110 index = useRegisterAtStart(opd);
michael@0 111 tempInt = tempCopy(opd, 0);
michael@0 112 } else {
michael@0 113 index = useRegister(opd);
michael@0 114 tempInt = temp(LDefinition::GENERAL);
michael@0 115 }
michael@0 116 return add(newLTableSwitch(index, tempInt, tableswitch));
michael@0 117 }
michael@0 118
michael@0 119 bool
michael@0 120 LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed *ins)
michael@0 121 {
michael@0 122 LCheckOverRecursed *lir = new(alloc()) LCheckOverRecursed();
michael@0 123
michael@0 124 if (!add(lir, ins))
michael@0 125 return false;
michael@0 126 if (!assignSafepoint(lir, ins))
michael@0 127 return false;
michael@0 128
michael@0 129 return true;
michael@0 130 }
michael@0 131
michael@0 132 bool
michael@0 133 LIRGenerator::visitCheckOverRecursedPar(MCheckOverRecursedPar *ins)
michael@0 134 {
michael@0 135 LCheckOverRecursedPar *lir =
michael@0 136 new(alloc()) LCheckOverRecursedPar(useRegister(ins->forkJoinContext()), temp());
michael@0 137 if (!add(lir, ins))
michael@0 138 return false;
michael@0 139 if (!assignSafepoint(lir, ins))
michael@0 140 return false;
michael@0 141 return true;
michael@0 142 }
michael@0 143
michael@0 144 bool
michael@0 145 LIRGenerator::visitDefVar(MDefVar *ins)
michael@0 146 {
michael@0 147 LDefVar *lir = new(alloc()) LDefVar(useRegisterAtStart(ins->scopeChain()));
michael@0 148 if (!add(lir, ins))
michael@0 149 return false;
michael@0 150 if (!assignSafepoint(lir, ins))
michael@0 151 return false;
michael@0 152
michael@0 153 return true;
michael@0 154 }
michael@0 155
michael@0 156 bool
michael@0 157 LIRGenerator::visitDefFun(MDefFun *ins)
michael@0 158 {
michael@0 159 LDefFun *lir = new(alloc()) LDefFun(useRegisterAtStart(ins->scopeChain()));
michael@0 160 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 161 }
michael@0 162
michael@0 163 bool
michael@0 164 LIRGenerator::visitNewSlots(MNewSlots *ins)
michael@0 165 {
michael@0 166 // No safepoint needed, since we don't pass a cx.
michael@0 167 LNewSlots *lir = new(alloc()) LNewSlots(tempFixed(CallTempReg0), tempFixed(CallTempReg1),
michael@0 168 tempFixed(CallTempReg2));
michael@0 169 if (!assignSnapshot(lir))
michael@0 170 return false;
michael@0 171 return defineReturn(lir, ins);
michael@0 172 }
michael@0 173
michael@0 174 bool
michael@0 175 LIRGenerator::visitNewArray(MNewArray *ins)
michael@0 176 {
michael@0 177 LNewArray *lir = new(alloc()) LNewArray(temp());
michael@0 178 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 179 }
michael@0 180
michael@0 181 bool
michael@0 182 LIRGenerator::visitNewObject(MNewObject *ins)
michael@0 183 {
michael@0 184 LNewObject *lir = new(alloc()) LNewObject(temp());
michael@0 185 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 186 }
michael@0 187
michael@0 188 bool
michael@0 189 LIRGenerator::visitNewDeclEnvObject(MNewDeclEnvObject *ins)
michael@0 190 {
michael@0 191 LNewDeclEnvObject *lir = new(alloc()) LNewDeclEnvObject(temp());
michael@0 192 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 193 }
michael@0 194
michael@0 195 bool
michael@0 196 LIRGenerator::visitNewCallObject(MNewCallObject *ins)
michael@0 197 {
michael@0 198 LAllocation slots;
michael@0 199 if (ins->slots()->type() == MIRType_Slots)
michael@0 200 slots = useRegister(ins->slots());
michael@0 201 else
michael@0 202 slots = LConstantIndex::Bogus();
michael@0 203
michael@0 204 LInstruction *lir;
michael@0 205 if (ins->templateObject()->hasSingletonType()) {
michael@0 206 LNewSingletonCallObject *singletonLir = new(alloc()) LNewSingletonCallObject(slots);
michael@0 207 if (!define(singletonLir, ins))
michael@0 208 return false;
michael@0 209 lir = singletonLir;
michael@0 210 } else {
michael@0 211 LNewCallObject *normalLir = new(alloc()) LNewCallObject(slots, temp());
michael@0 212 if (!define(normalLir, ins))
michael@0 213 return false;
michael@0 214 lir = normalLir;
michael@0 215 }
michael@0 216
michael@0 217 if (!assignSafepoint(lir, ins))
michael@0 218 return false;
michael@0 219
michael@0 220 return true;
michael@0 221 }
michael@0 222
michael@0 223 bool
michael@0 224 LIRGenerator::visitNewRunOnceCallObject(MNewRunOnceCallObject *ins)
michael@0 225 {
michael@0 226 LAllocation slots;
michael@0 227 if (ins->slots()->type() == MIRType_Slots)
michael@0 228 slots = useRegister(ins->slots());
michael@0 229 else
michael@0 230 slots = LConstantIndex::Bogus();
michael@0 231
michael@0 232 LNewSingletonCallObject *lir = new(alloc()) LNewSingletonCallObject(slots);
michael@0 233 if (!define(lir, ins))
michael@0 234 return false;
michael@0 235
michael@0 236 if (!assignSafepoint(lir, ins))
michael@0 237 return false;
michael@0 238
michael@0 239 return true;
michael@0 240 }
michael@0 241
michael@0 242 bool
michael@0 243 LIRGenerator::visitNewDerivedTypedObject(MNewDerivedTypedObject *ins)
michael@0 244 {
michael@0 245 LNewDerivedTypedObject *lir =
michael@0 246 new(alloc()) LNewDerivedTypedObject(useRegisterAtStart(ins->type()),
michael@0 247 useRegisterAtStart(ins->owner()),
michael@0 248 useRegisterAtStart(ins->offset()));
michael@0 249 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 250 }
michael@0 251
michael@0 252 bool
michael@0 253 LIRGenerator::visitNewCallObjectPar(MNewCallObjectPar *ins)
michael@0 254 {
michael@0 255 const LAllocation &parThreadContext = useRegister(ins->forkJoinContext());
michael@0 256 const LDefinition &temp1 = temp();
michael@0 257 const LDefinition &temp2 = temp();
michael@0 258
michael@0 259 LNewCallObjectPar *lir;
michael@0 260 if (ins->slots()->type() == MIRType_Slots) {
michael@0 261 const LAllocation &slots = useRegister(ins->slots());
michael@0 262 lir = LNewCallObjectPar::NewWithSlots(alloc(), parThreadContext, slots, temp1, temp2);
michael@0 263 } else {
michael@0 264 lir = LNewCallObjectPar::NewSansSlots(alloc(), parThreadContext, temp1, temp2);
michael@0 265 }
michael@0 266
michael@0 267 return define(lir, ins);
michael@0 268 }
michael@0 269
michael@0 270 bool
michael@0 271 LIRGenerator::visitNewStringObject(MNewStringObject *ins)
michael@0 272 {
michael@0 273 JS_ASSERT(ins->input()->type() == MIRType_String);
michael@0 274
michael@0 275 LNewStringObject *lir = new(alloc()) LNewStringObject(useRegister(ins->input()), temp());
michael@0 276 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 277 }
michael@0 278
michael@0 279 bool
michael@0 280 LIRGenerator::visitAbortPar(MAbortPar *ins)
michael@0 281 {
michael@0 282 LAbortPar *lir = new(alloc()) LAbortPar();
michael@0 283 return add(lir, ins);
michael@0 284 }
michael@0 285
michael@0 286 bool
michael@0 287 LIRGenerator::visitInitElem(MInitElem *ins)
michael@0 288 {
michael@0 289 LInitElem *lir = new(alloc()) LInitElem(useRegisterAtStart(ins->getObject()));
michael@0 290 if (!useBoxAtStart(lir, LInitElem::IdIndex, ins->getId()))
michael@0 291 return false;
michael@0 292 if (!useBoxAtStart(lir, LInitElem::ValueIndex, ins->getValue()))
michael@0 293 return false;
michael@0 294
michael@0 295 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 296 }
michael@0 297
michael@0 298 bool
michael@0 299 LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter *ins)
michael@0 300 {
michael@0 301 LInitElemGetterSetter *lir =
michael@0 302 new(alloc()) LInitElemGetterSetter(useRegisterAtStart(ins->object()),
michael@0 303 useRegisterAtStart(ins->value()));
michael@0 304 if (!useBoxAtStart(lir, LInitElemGetterSetter::IdIndex, ins->idValue()))
michael@0 305 return false;
michael@0 306
michael@0 307 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 308 }
michael@0 309
michael@0 310 bool
michael@0 311 LIRGenerator::visitMutateProto(MMutateProto *ins)
michael@0 312 {
michael@0 313 LMutateProto *lir = new(alloc()) LMutateProto(useRegisterAtStart(ins->getObject()));
michael@0 314 if (!useBoxAtStart(lir, LMutateProto::ValueIndex, ins->getValue()))
michael@0 315 return false;
michael@0 316
michael@0 317 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 318 }
michael@0 319
michael@0 320 bool
michael@0 321 LIRGenerator::visitInitProp(MInitProp *ins)
michael@0 322 {
michael@0 323 LInitProp *lir = new(alloc()) LInitProp(useRegisterAtStart(ins->getObject()));
michael@0 324 if (!useBoxAtStart(lir, LInitProp::ValueIndex, ins->getValue()))
michael@0 325 return false;
michael@0 326
michael@0 327 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 328 }
michael@0 329
michael@0 330 bool
michael@0 331 LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter *ins)
michael@0 332 {
michael@0 333 LInitPropGetterSetter *lir =
michael@0 334 new(alloc()) LInitPropGetterSetter(useRegisterAtStart(ins->object()),
michael@0 335 useRegisterAtStart(ins->value()));
michael@0 336 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 337 }
michael@0 338
michael@0 339 bool
michael@0 340 LIRGenerator::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins)
michael@0 341 {
michael@0 342 LCreateThisWithTemplate *lir = new(alloc()) LCreateThisWithTemplate(temp());
michael@0 343 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 344 }
michael@0 345
michael@0 346 bool
michael@0 347 LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto *ins)
michael@0 348 {
michael@0 349 LCreateThisWithProto *lir =
michael@0 350 new(alloc()) LCreateThisWithProto(useRegisterOrConstantAtStart(ins->getCallee()),
michael@0 351 useRegisterOrConstantAtStart(ins->getPrototype()));
michael@0 352 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 353 }
michael@0 354
michael@0 355 bool
michael@0 356 LIRGenerator::visitCreateThis(MCreateThis *ins)
michael@0 357 {
michael@0 358 LCreateThis *lir = new(alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->getCallee()));
michael@0 359 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 360 }
michael@0 361
michael@0 362 bool
michael@0 363 LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject *ins)
michael@0 364 {
michael@0 365 // LAllocation callObj = useRegisterAtStart(ins->getCallObject());
michael@0 366 LAllocation callObj = useFixed(ins->getCallObject(), CallTempReg0);
michael@0 367 LCreateArgumentsObject *lir = new(alloc()) LCreateArgumentsObject(callObj, tempFixed(CallTempReg1));
michael@0 368 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 369 }
michael@0 370
michael@0 371 bool
michael@0 372 LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg *ins)
michael@0 373 {
michael@0 374 LAllocation argsObj = useRegister(ins->getArgsObject());
michael@0 375 LGetArgumentsObjectArg *lir = new(alloc()) LGetArgumentsObjectArg(argsObj, temp());
michael@0 376 return defineBox(lir, ins);
michael@0 377 }
michael@0 378
michael@0 379 bool
michael@0 380 LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg *ins)
michael@0 381 {
michael@0 382 LAllocation argsObj = useRegister(ins->getArgsObject());
michael@0 383 LSetArgumentsObjectArg *lir = new(alloc()) LSetArgumentsObjectArg(argsObj, temp());
michael@0 384 if (!useBox(lir, LSetArgumentsObjectArg::ValueIndex, ins->getValue()))
michael@0 385 return false;
michael@0 386
michael@0 387 return add(lir, ins);
michael@0 388 }
michael@0 389
michael@0 390 bool
michael@0 391 LIRGenerator::visitReturnFromCtor(MReturnFromCtor *ins)
michael@0 392 {
michael@0 393 LReturnFromCtor *lir = new(alloc()) LReturnFromCtor(useRegister(ins->getObject()));
michael@0 394 if (!useBox(lir, LReturnFromCtor::ValueIndex, ins->getValue()))
michael@0 395 return false;
michael@0 396
michael@0 397 return define(lir, ins);
michael@0 398 }
michael@0 399
michael@0 400 bool
michael@0 401 LIRGenerator::visitComputeThis(MComputeThis *ins)
michael@0 402 {
michael@0 403 JS_ASSERT(ins->type() == MIRType_Object);
michael@0 404 JS_ASSERT(ins->input()->type() == MIRType_Value);
michael@0 405
michael@0 406 LComputeThis *lir = new(alloc()) LComputeThis();
michael@0 407
michael@0 408 // Don't use useBoxAtStart because ComputeThis has a safepoint and needs to
michael@0 409 // have its inputs in different registers than its return value so that
michael@0 410 // they aren't clobbered.
michael@0 411 if (!useBox(lir, LComputeThis::ValueIndex, ins->input()))
michael@0 412 return false;
michael@0 413
michael@0 414 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 415 }
michael@0 416
michael@0 417 bool
michael@0 418 LIRGenerator::visitLoadArrowThis(MLoadArrowThis *ins)
michael@0 419 {
michael@0 420 JS_ASSERT(ins->type() == MIRType_Value);
michael@0 421 JS_ASSERT(ins->callee()->type() == MIRType_Object);
michael@0 422
michael@0 423 LLoadArrowThis *lir = new(alloc()) LLoadArrowThis(useRegister(ins->callee()));
michael@0 424 return defineBox(lir, ins);
michael@0 425 }
michael@0 426
michael@0 427 bool
michael@0 428 LIRGenerator::lowerCallArguments(MCall *call)
michael@0 429 {
michael@0 430 uint32_t argc = call->numStackArgs();
michael@0 431 if (argc > maxargslots_)
michael@0 432 maxargslots_ = argc;
michael@0 433
michael@0 434 for (size_t i = 0; i < argc; i++) {
michael@0 435 MDefinition *arg = call->getArg(i);
michael@0 436 uint32_t argslot = argc - i;
michael@0 437
michael@0 438 // Values take a slow path.
michael@0 439 if (arg->type() == MIRType_Value) {
michael@0 440 LStackArgV *stack = new(alloc()) LStackArgV(argslot);
michael@0 441 if (!useBox(stack, 0, arg) || !add(stack))
michael@0 442 return false;
michael@0 443 } else {
michael@0 444 // Known types can move constant types and/or payloads.
michael@0 445 LStackArgT *stack = new(alloc()) LStackArgT(argslot, arg->type(), useRegisterOrConstant(arg));
michael@0 446 if (!add(stack))
michael@0 447 return false;
michael@0 448 }
michael@0 449 }
michael@0 450
michael@0 451 return true;
michael@0 452 }
michael@0 453
michael@0 454 bool
michael@0 455 LIRGenerator::visitCall(MCall *call)
michael@0 456 {
michael@0 457 JS_ASSERT(CallTempReg0 != CallTempReg1);
michael@0 458 JS_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
michael@0 459 JS_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
michael@0 460 JS_ASSERT(call->getFunction()->type() == MIRType_Object);
michael@0 461
michael@0 462 if (!lowerCallArguments(call))
michael@0 463 return false;
michael@0 464
michael@0 465 // Height of the current argument vector.
michael@0 466 JSFunction *target = call->getSingleTarget();
michael@0 467
michael@0 468 // Call DOM functions.
michael@0 469 if (call->isCallDOMNative()) {
michael@0 470 JS_ASSERT(target && target->isNative());
michael@0 471 Register cxReg, objReg, privReg, argsReg;
michael@0 472 GetTempRegForIntArg(0, 0, &cxReg);
michael@0 473 GetTempRegForIntArg(1, 0, &objReg);
michael@0 474 GetTempRegForIntArg(2, 0, &privReg);
michael@0 475 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &argsReg);
michael@0 476 MOZ_ASSERT(ok, "How can we not have four temp registers?");
michael@0 477 LCallDOMNative *lir = new(alloc()) LCallDOMNative(tempFixed(cxReg), tempFixed(objReg),
michael@0 478 tempFixed(privReg), tempFixed(argsReg));
michael@0 479 return defineReturn(lir, call) && assignSafepoint(lir, call);
michael@0 480 }
michael@0 481
michael@0 482 // Call known functions.
michael@0 483 if (target) {
michael@0 484 if (target->isNative()) {
michael@0 485 Register cxReg, numReg, vpReg, tmpReg;
michael@0 486 GetTempRegForIntArg(0, 0, &cxReg);
michael@0 487 GetTempRegForIntArg(1, 0, &numReg);
michael@0 488 GetTempRegForIntArg(2, 0, &vpReg);
michael@0 489
michael@0 490 // Even though this is just a temp reg, use the same API to avoid
michael@0 491 // register collisions.
michael@0 492 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
michael@0 493 MOZ_ASSERT(ok, "How can we not have four temp registers?");
michael@0 494
michael@0 495 LCallNative *lir = new(alloc()) LCallNative(tempFixed(cxReg), tempFixed(numReg),
michael@0 496 tempFixed(vpReg), tempFixed(tmpReg));
michael@0 497 return defineReturn(lir, call) && assignSafepoint(lir, call);
michael@0 498 }
michael@0 499
michael@0 500 LCallKnown *lir = new(alloc()) LCallKnown(useFixed(call->getFunction(), CallTempReg0),
michael@0 501 tempFixed(CallTempReg2));
michael@0 502 return defineReturn(lir, call) && assignSafepoint(lir, call);
michael@0 503 }
michael@0 504
michael@0 505 // Call anything, using the most generic code.
michael@0 506 LCallGeneric *lir = new(alloc()) LCallGeneric(useFixed(call->getFunction(), CallTempReg0),
michael@0 507 tempFixed(ArgumentsRectifierReg),
michael@0 508 tempFixed(CallTempReg2));
michael@0 509 return defineReturn(lir, call) && assignSafepoint(lir, call);
michael@0 510 }
michael@0 511
michael@0 512 bool
michael@0 513 LIRGenerator::visitApplyArgs(MApplyArgs *apply)
michael@0 514 {
michael@0 515 JS_ASSERT(apply->getFunction()->type() == MIRType_Object);
michael@0 516
michael@0 517 // Assert if we cannot build a rectifier frame.
michael@0 518 JS_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
michael@0 519 JS_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
michael@0 520
michael@0 521 // Assert if the return value is already erased.
michael@0 522 JS_ASSERT(CallTempReg2 != JSReturnReg_Type);
michael@0 523 JS_ASSERT(CallTempReg2 != JSReturnReg_Data);
michael@0 524
michael@0 525 LApplyArgsGeneric *lir = new(alloc()) LApplyArgsGeneric(
michael@0 526 useFixed(apply->getFunction(), CallTempReg3),
michael@0 527 useFixed(apply->getArgc(), CallTempReg0),
michael@0 528 tempFixed(CallTempReg1), // object register
michael@0 529 tempFixed(CallTempReg2)); // copy register
michael@0 530
michael@0 531 MDefinition *self = apply->getThis();
michael@0 532 if (!useBoxFixed(lir, LApplyArgsGeneric::ThisIndex, self, CallTempReg4, CallTempReg5))
michael@0 533 return false;
michael@0 534
michael@0 535 // Bailout is only needed in the case of possible non-JSFunction callee.
michael@0 536 if (!apply->getSingleTarget() && !assignSnapshot(lir))
michael@0 537 return false;
michael@0 538
michael@0 539 if (!defineReturn(lir, apply))
michael@0 540 return false;
michael@0 541 if (!assignSafepoint(lir, apply))
michael@0 542 return false;
michael@0 543 return true;
michael@0 544 }
michael@0 545
michael@0 546 bool
michael@0 547 LIRGenerator::visitBail(MBail *bail)
michael@0 548 {
michael@0 549 LBail *lir = new(alloc()) LBail();
michael@0 550 return assignSnapshot(lir) && add(lir, bail);
michael@0 551 }
michael@0 552
michael@0 553 bool
michael@0 554 LIRGenerator::visitAssertFloat32(MAssertFloat32 *assertion)
michael@0 555 {
michael@0 556 MIRType type = assertion->input()->type();
michael@0 557 DebugOnly<bool> checkIsFloat32 = assertion->mustBeFloat32();
michael@0 558
michael@0 559 if (!allowFloat32Optimizations())
michael@0 560 return true;
michael@0 561
michael@0 562 if (type != MIRType_Value && !js_JitOptions.eagerCompilation) {
michael@0 563 JS_ASSERT_IF(checkIsFloat32, type == MIRType_Float32);
michael@0 564 JS_ASSERT_IF(!checkIsFloat32, type != MIRType_Float32);
michael@0 565 }
michael@0 566 return true;
michael@0 567 }
michael@0 568
michael@0 569 bool
michael@0 570 LIRGenerator::visitArraySplice(MArraySplice *ins)
michael@0 571 {
michael@0 572 LArraySplice *lir = new(alloc()) LArraySplice(useRegisterAtStart(ins->object()),
michael@0 573 useRegisterAtStart(ins->start()),
michael@0 574 useRegisterAtStart(ins->deleteCount()));
michael@0 575 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 576 }
michael@0 577
michael@0 578 bool
michael@0 579 LIRGenerator::visitGetDynamicName(MGetDynamicName *ins)
michael@0 580 {
michael@0 581 MDefinition *scopeChain = ins->getScopeChain();
michael@0 582 JS_ASSERT(scopeChain->type() == MIRType_Object);
michael@0 583
michael@0 584 MDefinition *name = ins->getName();
michael@0 585 JS_ASSERT(name->type() == MIRType_String);
michael@0 586
michael@0 587 LGetDynamicName *lir = new(alloc()) LGetDynamicName(useFixed(scopeChain, CallTempReg0),
michael@0 588 useFixed(name, CallTempReg1),
michael@0 589 tempFixed(CallTempReg2),
michael@0 590 tempFixed(CallTempReg3),
michael@0 591 tempFixed(CallTempReg4));
michael@0 592
michael@0 593 return assignSnapshot(lir) && defineReturn(lir, ins);
michael@0 594 }
michael@0 595
michael@0 596 bool
michael@0 597 LIRGenerator::visitFilterArgumentsOrEval(MFilterArgumentsOrEval *ins)
michael@0 598 {
michael@0 599 MDefinition *string = ins->getString();
michael@0 600 MOZ_ASSERT(string->type() == MIRType_String || string->type() == MIRType_Value);
michael@0 601
michael@0 602 LInstruction *lir;
michael@0 603 if (string->type() == MIRType_String) {
michael@0 604 lir = new(alloc()) LFilterArgumentsOrEvalS(useFixed(string, CallTempReg0),
michael@0 605 tempFixed(CallTempReg1),
michael@0 606 tempFixed(CallTempReg2));
michael@0 607 } else {
michael@0 608 lir = new(alloc()) LFilterArgumentsOrEvalV(tempFixed(CallTempReg0),
michael@0 609 tempFixed(CallTempReg1),
michael@0 610 tempFixed(CallTempReg2));
michael@0 611 if (!useBoxFixed(lir, LFilterArgumentsOrEvalV::Input, string,
michael@0 612 CallTempReg3, CallTempReg4))
michael@0 613 {
michael@0 614 return false;
michael@0 615 }
michael@0 616 }
michael@0 617
michael@0 618 return assignSnapshot(lir) && add(lir, ins) && assignSafepoint(lir, ins);
michael@0 619 }
michael@0 620
michael@0 621 bool
michael@0 622 LIRGenerator::visitCallDirectEval(MCallDirectEval *ins)
michael@0 623 {
michael@0 624 MDefinition *scopeChain = ins->getScopeChain();
michael@0 625 JS_ASSERT(scopeChain->type() == MIRType_Object);
michael@0 626
michael@0 627 MDefinition *string = ins->getString();
michael@0 628 JS_ASSERT(string->type() == MIRType_String || string->type() == MIRType_Value);
michael@0 629
michael@0 630 MDefinition *thisValue = ins->getThisValue();
michael@0 631
michael@0 632
michael@0 633 LInstruction *lir;
michael@0 634 if (string->type() == MIRType_String) {
michael@0 635 lir = new(alloc()) LCallDirectEvalS(useRegisterAtStart(scopeChain),
michael@0 636 useRegisterAtStart(string));
michael@0 637 } else {
michael@0 638 lir = new(alloc()) LCallDirectEvalV(useRegisterAtStart(scopeChain));
michael@0 639 if (!useBoxAtStart(lir, LCallDirectEvalV::Argument, string))
michael@0 640 return false;
michael@0 641 }
michael@0 642
michael@0 643 if (string->type() == MIRType_String) {
michael@0 644 if (!useBoxAtStart(lir, LCallDirectEvalS::ThisValue, thisValue))
michael@0 645 return false;
michael@0 646 } else {
michael@0 647 if (!useBoxAtStart(lir, LCallDirectEvalV::ThisValue, thisValue))
michael@0 648 return false;
michael@0 649 }
michael@0 650
michael@0 651 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 652 }
michael@0 653
michael@0 654 static JSOp
michael@0 655 ReorderComparison(JSOp op, MDefinition **lhsp, MDefinition **rhsp)
michael@0 656 {
michael@0 657 MDefinition *lhs = *lhsp;
michael@0 658 MDefinition *rhs = *rhsp;
michael@0 659
michael@0 660 if (lhs->isConstant()) {
michael@0 661 *rhsp = lhs;
michael@0 662 *lhsp = rhs;
michael@0 663 return ReverseCompareOp(op);
michael@0 664 }
michael@0 665 return op;
michael@0 666 }
michael@0 667
michael@0 668 static void
michael@0 669 ReorderCommutative(MDefinition **lhsp, MDefinition **rhsp)
michael@0 670 {
michael@0 671 MDefinition *lhs = *lhsp;
michael@0 672 MDefinition *rhs = *rhsp;
michael@0 673
michael@0 674 // Ensure that if there is a constant, then it is in rhs.
michael@0 675 // In addition, since clobbering binary operations clobber the left
michael@0 676 // operand, prefer a non-constant lhs operand with no further uses.
michael@0 677
michael@0 678 if (rhs->isConstant())
michael@0 679 return;
michael@0 680
michael@0 681 // lhs and rhs are used by the commutative operator. If they have any
michael@0 682 // *other* uses besides, try to reorder to avoid clobbering them. To
michael@0 683 // be fully precise, we should check whether this is the *last* use,
michael@0 684 // but checking hasOneDefUse() is a decent approximation which doesn't
michael@0 685 // require any extra analysis.
michael@0 686 JS_ASSERT(lhs->defUseCount() > 0);
michael@0 687 JS_ASSERT(rhs->defUseCount() > 0);
michael@0 688 if (lhs->isConstant() || (rhs->hasOneDefUse() && !lhs->hasOneDefUse())) {
michael@0 689 *rhsp = lhs;
michael@0 690 *lhsp = rhs;
michael@0 691 }
michael@0 692 }
michael@0 693
michael@0 694 bool
michael@0 695 LIRGenerator::visitTest(MTest *test)
michael@0 696 {
michael@0 697 MDefinition *opd = test->getOperand(0);
michael@0 698 MBasicBlock *ifTrue = test->ifTrue();
michael@0 699 MBasicBlock *ifFalse = test->ifFalse();
michael@0 700
michael@0 701 // String is converted to length of string in the type analysis phase (see
michael@0 702 // TestPolicy).
michael@0 703 JS_ASSERT(opd->type() != MIRType_String);
michael@0 704
michael@0 705 if (opd->type() == MIRType_Value) {
michael@0 706 LDefinition temp0, temp1;
michael@0 707 if (test->operandMightEmulateUndefined()) {
michael@0 708 temp0 = temp();
michael@0 709 temp1 = temp();
michael@0 710 } else {
michael@0 711 temp0 = LDefinition::BogusTemp();
michael@0 712 temp1 = LDefinition::BogusTemp();
michael@0 713 }
michael@0 714 LTestVAndBranch *lir = new(alloc()) LTestVAndBranch(ifTrue, ifFalse, tempDouble(), temp0, temp1);
michael@0 715 if (!useBox(lir, LTestVAndBranch::Input, opd))
michael@0 716 return false;
michael@0 717 return add(lir, test);
michael@0 718 }
michael@0 719
michael@0 720 if (opd->type() == MIRType_Object) {
michael@0 721 // If the object might emulate undefined, we have to test for that.
michael@0 722 if (test->operandMightEmulateUndefined())
michael@0 723 return add(new(alloc()) LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp()), test);
michael@0 724
michael@0 725 // Otherwise we know it's truthy.
michael@0 726 return add(new(alloc()) LGoto(ifTrue));
michael@0 727 }
michael@0 728
michael@0 729 // These must be explicitly sniffed out since they are constants and have
michael@0 730 // no payload.
michael@0 731 if (opd->type() == MIRType_Undefined || opd->type() == MIRType_Null)
michael@0 732 return add(new(alloc()) LGoto(ifFalse));
michael@0 733
michael@0 734 // Constant Double operand.
michael@0 735 if (opd->type() == MIRType_Double && opd->isConstant()) {
michael@0 736 bool result = opd->toConstant()->valueToBoolean();
michael@0 737 return add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
michael@0 738 }
michael@0 739
michael@0 740 // Constant Float32 operand.
michael@0 741 if (opd->type() == MIRType_Float32 && opd->isConstant()) {
michael@0 742 bool result = opd->toConstant()->valueToBoolean();
michael@0 743 return add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
michael@0 744 }
michael@0 745
michael@0 746 // Constant Int32 operand.
michael@0 747 if (opd->type() == MIRType_Int32 && opd->isConstant()) {
michael@0 748 int32_t num = opd->toConstant()->value().toInt32();
michael@0 749 return add(new(alloc()) LGoto(num ? ifTrue : ifFalse));
michael@0 750 }
michael@0 751
michael@0 752 // Constant Boolean operand.
michael@0 753 if (opd->type() == MIRType_Boolean && opd->isConstant()) {
michael@0 754 bool result = opd->toConstant()->value().toBoolean();
michael@0 755 return add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
michael@0 756 }
michael@0 757
michael@0 758 // Check if the operand for this test is a compare operation. If it is, we want
michael@0 759 // to emit an LCompare*AndBranch rather than an LTest*AndBranch, to fuse the
michael@0 760 // compare and jump instructions.
michael@0 761 if (opd->isCompare() && opd->isEmittedAtUses()) {
michael@0 762 MCompare *comp = opd->toCompare();
michael@0 763 MDefinition *left = comp->lhs();
michael@0 764 MDefinition *right = comp->rhs();
michael@0 765
michael@0 766 // Try to fold the comparison so that we don't have to handle all cases.
michael@0 767 bool result;
michael@0 768 if (comp->tryFold(&result))
michael@0 769 return add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
michael@0 770
michael@0 771 // Emit LCompare*AndBranch.
michael@0 772
michael@0 773 // Compare and branch null/undefined.
michael@0 774 // The second operand has known null/undefined type,
michael@0 775 // so just test the first operand.
michael@0 776 if (comp->compareType() == MCompare::Compare_Null ||
michael@0 777 comp->compareType() == MCompare::Compare_Undefined)
michael@0 778 {
michael@0 779 if (left->type() == MIRType_Object) {
michael@0 780 MOZ_ASSERT(comp->operandMightEmulateUndefined(),
michael@0 781 "MCompare::tryFold should handle the never-emulates-undefined case");
michael@0 782
michael@0 783 LEmulatesUndefinedAndBranch *lir =
michael@0 784 new(alloc()) LEmulatesUndefinedAndBranch(comp, useRegister(left),
michael@0 785 ifTrue, ifFalse, temp());
michael@0 786 return add(lir, test);
michael@0 787 }
michael@0 788
michael@0 789 LDefinition tmp, tmpToUnbox;
michael@0 790 if (comp->operandMightEmulateUndefined()) {
michael@0 791 tmp = temp();
michael@0 792 tmpToUnbox = tempToUnbox();
michael@0 793 } else {
michael@0 794 tmp = LDefinition::BogusTemp();
michael@0 795 tmpToUnbox = LDefinition::BogusTemp();
michael@0 796 }
michael@0 797
michael@0 798 LIsNullOrLikeUndefinedAndBranch *lir =
michael@0 799 new(alloc()) LIsNullOrLikeUndefinedAndBranch(comp, ifTrue, ifFalse,
michael@0 800 tmp, tmpToUnbox);
michael@0 801 if (!useBox(lir, LIsNullOrLikeUndefinedAndBranch::Value, left))
michael@0 802 return false;
michael@0 803 return add(lir, test);
michael@0 804 }
michael@0 805
michael@0 806 // Compare and branch booleans.
michael@0 807 if (comp->compareType() == MCompare::Compare_Boolean) {
michael@0 808 JS_ASSERT(left->type() == MIRType_Value);
michael@0 809 JS_ASSERT(right->type() == MIRType_Boolean);
michael@0 810
michael@0 811 LAllocation rhs = useRegisterOrConstant(right);
michael@0 812 LCompareBAndBranch *lir = new(alloc()) LCompareBAndBranch(comp, rhs, ifTrue, ifFalse);
michael@0 813 if (!useBox(lir, LCompareBAndBranch::Lhs, left))
michael@0 814 return false;
michael@0 815 return add(lir, test);
michael@0 816 }
michael@0 817
michael@0 818 // Compare and branch Int32 or Object pointers.
michael@0 819 if (comp->isInt32Comparison() ||
michael@0 820 comp->compareType() == MCompare::Compare_UInt32 ||
michael@0 821 comp->compareType() == MCompare::Compare_Object)
michael@0 822 {
michael@0 823 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
michael@0 824 LAllocation lhs = useRegister(left);
michael@0 825 LAllocation rhs;
michael@0 826 if (comp->isInt32Comparison() || comp->compareType() == MCompare::Compare_UInt32)
michael@0 827 rhs = useAnyOrConstant(right);
michael@0 828 else
michael@0 829 rhs = useRegister(right);
michael@0 830 LCompareAndBranch *lir = new(alloc()) LCompareAndBranch(comp, op, lhs, rhs,
michael@0 831 ifTrue, ifFalse);
michael@0 832 return add(lir, test);
michael@0 833 }
michael@0 834
michael@0 835 // Compare and branch doubles.
michael@0 836 if (comp->isDoubleComparison()) {
michael@0 837 LAllocation lhs = useRegister(left);
michael@0 838 LAllocation rhs = useRegister(right);
michael@0 839 LCompareDAndBranch *lir = new(alloc()) LCompareDAndBranch(comp, lhs, rhs,
michael@0 840 ifTrue, ifFalse);
michael@0 841 return add(lir, test);
michael@0 842 }
michael@0 843
michael@0 844 // Compare and branch floats.
michael@0 845 if (comp->isFloat32Comparison()) {
michael@0 846 LAllocation lhs = useRegister(left);
michael@0 847 LAllocation rhs = useRegister(right);
michael@0 848 LCompareFAndBranch *lir = new(alloc()) LCompareFAndBranch(comp, lhs, rhs,
michael@0 849 ifTrue, ifFalse);
michael@0 850 return add(lir, test);
michael@0 851 }
michael@0 852
michael@0 853 // Compare values.
michael@0 854 if (comp->compareType() == MCompare::Compare_Value) {
michael@0 855 LCompareVAndBranch *lir = new(alloc()) LCompareVAndBranch(comp, ifTrue, ifFalse);
michael@0 856 if (!useBoxAtStart(lir, LCompareVAndBranch::LhsInput, left))
michael@0 857 return false;
michael@0 858 if (!useBoxAtStart(lir, LCompareVAndBranch::RhsInput, right))
michael@0 859 return false;
michael@0 860 return add(lir, test);
michael@0 861 }
michael@0 862 }
michael@0 863
michael@0 864 // Check if the operand for this test is a bitand operation. If it is, we want
michael@0 865 // to emit an LBitAndAndBranch rather than an LTest*AndBranch.
michael@0 866 if (opd->isBitAnd() && opd->isEmittedAtUses()) {
michael@0 867 MDefinition *lhs = opd->getOperand(0);
michael@0 868 MDefinition *rhs = opd->getOperand(1);
michael@0 869 if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
michael@0 870 ReorderCommutative(&lhs, &rhs);
michael@0 871 return lowerForBitAndAndBranch(new(alloc()) LBitAndAndBranch(ifTrue, ifFalse), test, lhs, rhs);
michael@0 872 }
michael@0 873 }
michael@0 874
michael@0 875 if (opd->type() == MIRType_Double)
michael@0 876 return add(new(alloc()) LTestDAndBranch(useRegister(opd), ifTrue, ifFalse));
michael@0 877
michael@0 878 if (opd->type() == MIRType_Float32)
michael@0 879 return add(new(alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse));
michael@0 880
michael@0 881 JS_ASSERT(opd->type() == MIRType_Int32 || opd->type() == MIRType_Boolean);
michael@0 882 return add(new(alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse));
michael@0 883 }
michael@0 884
michael@0 885 bool
michael@0 886 LIRGenerator::visitFunctionDispatch(MFunctionDispatch *ins)
michael@0 887 {
michael@0 888 LFunctionDispatch *lir = new(alloc()) LFunctionDispatch(useRegister(ins->input()));
michael@0 889 return add(lir, ins);
michael@0 890 }
michael@0 891
michael@0 892 bool
michael@0 893 LIRGenerator::visitTypeObjectDispatch(MTypeObjectDispatch *ins)
michael@0 894 {
michael@0 895 LTypeObjectDispatch *lir = new(alloc()) LTypeObjectDispatch(useRegister(ins->input()), temp());
michael@0 896 return add(lir, ins);
michael@0 897 }
michael@0 898
michael@0 899 static inline bool
michael@0 900 CanEmitCompareAtUses(MInstruction *ins)
michael@0 901 {
michael@0 902 if (!ins->canEmitAtUses())
michael@0 903 return false;
michael@0 904
michael@0 905 bool foundTest = false;
michael@0 906 for (MUseIterator iter(ins->usesBegin()); iter != ins->usesEnd(); iter++) {
michael@0 907 MNode *node = iter->consumer();
michael@0 908 if (!node->isDefinition())
michael@0 909 return false;
michael@0 910 if (!node->toDefinition()->isTest())
michael@0 911 return false;
michael@0 912 if (foundTest)
michael@0 913 return false;
michael@0 914 foundTest = true;
michael@0 915 }
michael@0 916 return true;
michael@0 917 }
michael@0 918
michael@0 919 bool
michael@0 920 LIRGenerator::visitCompare(MCompare *comp)
michael@0 921 {
michael@0 922 MDefinition *left = comp->lhs();
michael@0 923 MDefinition *right = comp->rhs();
michael@0 924
michael@0 925 // Try to fold the comparison so that we don't have to handle all cases.
michael@0 926 bool result;
michael@0 927 if (comp->tryFold(&result))
michael@0 928 return define(new(alloc()) LInteger(result), comp);
michael@0 929
michael@0 930 // Move below the emitAtUses call if we ever implement
michael@0 931 // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't
michael@0 932 // make sense and avoids confusion.
michael@0 933 if (comp->compareType() == MCompare::Compare_String) {
michael@0 934 LCompareS *lir = new(alloc()) LCompareS(useRegister(left), useRegister(right), temp());
michael@0 935 if (!define(lir, comp))
michael@0 936 return false;
michael@0 937 return assignSafepoint(lir, comp);
michael@0 938 }
michael@0 939
michael@0 940 // Strict compare between value and string
michael@0 941 if (comp->compareType() == MCompare::Compare_StrictString) {
michael@0 942 JS_ASSERT(left->type() == MIRType_Value);
michael@0 943 JS_ASSERT(right->type() == MIRType_String);
michael@0 944
michael@0 945 LCompareStrictS *lir = new(alloc()) LCompareStrictS(useRegister(right), temp(), tempToUnbox());
michael@0 946 if (!useBox(lir, LCompareStrictS::Lhs, left))
michael@0 947 return false;
michael@0 948 if (!define(lir, comp))
michael@0 949 return false;
michael@0 950 return assignSafepoint(lir, comp);
michael@0 951 }
michael@0 952
michael@0 953 // Unknown/unspecialized compare use a VM call.
michael@0 954 if (comp->compareType() == MCompare::Compare_Unknown) {
michael@0 955 LCompareVM *lir = new(alloc()) LCompareVM();
michael@0 956 if (!useBoxAtStart(lir, LCompareVM::LhsInput, left))
michael@0 957 return false;
michael@0 958 if (!useBoxAtStart(lir, LCompareVM::RhsInput, right))
michael@0 959 return false;
michael@0 960 return defineReturn(lir, comp) && assignSafepoint(lir, comp);
michael@0 961 }
michael@0 962
michael@0 963 // Sniff out if the output of this compare is used only for a branching.
michael@0 964 // If it is, then we will emit an LCompare*AndBranch instruction in place
michael@0 965 // of this compare and any test that uses this compare. Thus, we can
michael@0 966 // ignore this Compare.
michael@0 967 if (CanEmitCompareAtUses(comp))
michael@0 968 return emitAtUses(comp);
michael@0 969
michael@0 970 // Compare Null and Undefined.
michael@0 971 if (comp->compareType() == MCompare::Compare_Null ||
michael@0 972 comp->compareType() == MCompare::Compare_Undefined)
michael@0 973 {
michael@0 974 if (left->type() == MIRType_Object) {
michael@0 975 MOZ_ASSERT(comp->operandMightEmulateUndefined(),
michael@0 976 "MCompare::tryFold should have folded this away");
michael@0 977
michael@0 978 return define(new(alloc()) LEmulatesUndefined(useRegister(left)), comp);
michael@0 979 }
michael@0 980
michael@0 981 LDefinition tmp, tmpToUnbox;
michael@0 982 if (comp->operandMightEmulateUndefined()) {
michael@0 983 tmp = temp();
michael@0 984 tmpToUnbox = tempToUnbox();
michael@0 985 } else {
michael@0 986 tmp = LDefinition::BogusTemp();
michael@0 987 tmpToUnbox = LDefinition::BogusTemp();
michael@0 988 }
michael@0 989
michael@0 990 LIsNullOrLikeUndefined *lir = new(alloc()) LIsNullOrLikeUndefined(tmp, tmpToUnbox);
michael@0 991 if (!useBox(lir, LIsNullOrLikeUndefined::Value, left))
michael@0 992 return false;
michael@0 993 return define(lir, comp);
michael@0 994 }
michael@0 995
michael@0 996 // Compare booleans.
michael@0 997 if (comp->compareType() == MCompare::Compare_Boolean) {
michael@0 998 JS_ASSERT(left->type() == MIRType_Value);
michael@0 999 JS_ASSERT(right->type() == MIRType_Boolean);
michael@0 1000
michael@0 1001 LCompareB *lir = new(alloc()) LCompareB(useRegisterOrConstant(right));
michael@0 1002 if (!useBox(lir, LCompareB::Lhs, left))
michael@0 1003 return false;
michael@0 1004 return define(lir, comp);
michael@0 1005 }
michael@0 1006
michael@0 1007 // Compare Int32 or Object pointers.
michael@0 1008 if (comp->isInt32Comparison() ||
michael@0 1009 comp->compareType() == MCompare::Compare_UInt32 ||
michael@0 1010 comp->compareType() == MCompare::Compare_Object)
michael@0 1011 {
michael@0 1012 JSOp op = ReorderComparison(comp->jsop(), &left, &right);
michael@0 1013 LAllocation lhs = useRegister(left);
michael@0 1014 LAllocation rhs;
michael@0 1015 if (comp->isInt32Comparison() ||
michael@0 1016 comp->compareType() == MCompare::Compare_UInt32)
michael@0 1017 {
michael@0 1018 rhs = useAnyOrConstant(right);
michael@0 1019 } else {
michael@0 1020 rhs = useRegister(right);
michael@0 1021 }
michael@0 1022 return define(new(alloc()) LCompare(op, lhs, rhs), comp);
michael@0 1023 }
michael@0 1024
michael@0 1025 // Compare doubles.
michael@0 1026 if (comp->isDoubleComparison())
michael@0 1027 return define(new(alloc()) LCompareD(useRegister(left), useRegister(right)), comp);
michael@0 1028
michael@0 1029 // Compare float32.
michael@0 1030 if (comp->isFloat32Comparison())
michael@0 1031 return define(new(alloc()) LCompareF(useRegister(left), useRegister(right)), comp);
michael@0 1032
michael@0 1033 // Compare values.
michael@0 1034 if (comp->compareType() == MCompare::Compare_Value) {
michael@0 1035 LCompareV *lir = new(alloc()) LCompareV();
michael@0 1036 if (!useBoxAtStart(lir, LCompareV::LhsInput, left))
michael@0 1037 return false;
michael@0 1038 if (!useBoxAtStart(lir, LCompareV::RhsInput, right))
michael@0 1039 return false;
michael@0 1040 return define(lir, comp);
michael@0 1041 }
michael@0 1042
michael@0 1043 MOZ_ASSUME_UNREACHABLE("Unrecognized compare type.");
michael@0 1044 }
michael@0 1045
michael@0 1046 bool
michael@0 1047 LIRGenerator::lowerBitOp(JSOp op, MInstruction *ins)
michael@0 1048 {
michael@0 1049 MDefinition *lhs = ins->getOperand(0);
michael@0 1050 MDefinition *rhs = ins->getOperand(1);
michael@0 1051
michael@0 1052 if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
michael@0 1053 ReorderCommutative(&lhs, &rhs);
michael@0 1054 return lowerForALU(new(alloc()) LBitOpI(op), ins, lhs, rhs);
michael@0 1055 }
michael@0 1056
michael@0 1057 LBitOpV *lir = new(alloc()) LBitOpV(op);
michael@0 1058 if (!useBoxAtStart(lir, LBitOpV::LhsInput, lhs))
michael@0 1059 return false;
michael@0 1060 if (!useBoxAtStart(lir, LBitOpV::RhsInput, rhs))
michael@0 1061 return false;
michael@0 1062
michael@0 1063 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 1064 }
michael@0 1065
michael@0 1066 bool
michael@0 1067 LIRGenerator::visitTypeOf(MTypeOf *ins)
michael@0 1068 {
michael@0 1069 MDefinition *opd = ins->input();
michael@0 1070 JS_ASSERT(opd->type() == MIRType_Value);
michael@0 1071
michael@0 1072 LTypeOfV *lir = new(alloc()) LTypeOfV(tempToUnbox());
michael@0 1073 if (!useBox(lir, LTypeOfV::Input, opd))
michael@0 1074 return false;
michael@0 1075 return define(lir, ins);
michael@0 1076 }
michael@0 1077
michael@0 1078 bool
michael@0 1079 LIRGenerator::visitToId(MToId *ins)
michael@0 1080 {
michael@0 1081 LToIdV *lir = new(alloc()) LToIdV(tempDouble());
michael@0 1082 if (!useBox(lir, LToIdV::Object, ins->lhs()))
michael@0 1083 return false;
michael@0 1084 if (!useBox(lir, LToIdV::Index, ins->rhs()))
michael@0 1085 return false;
michael@0 1086 return defineBox(lir, ins) && assignSafepoint(lir, ins);
michael@0 1087 }
michael@0 1088
michael@0 1089 bool
michael@0 1090 LIRGenerator::visitBitNot(MBitNot *ins)
michael@0 1091 {
michael@0 1092 MDefinition *input = ins->getOperand(0);
michael@0 1093
michael@0 1094 if (input->type() == MIRType_Int32)
michael@0 1095 return lowerForALU(new(alloc()) LBitNotI(), ins, input);
michael@0 1096
michael@0 1097 LBitNotV *lir = new(alloc()) LBitNotV;
michael@0 1098 if (!useBoxAtStart(lir, LBitNotV::Input, input))
michael@0 1099 return false;
michael@0 1100 if (!defineReturn(lir, ins))
michael@0 1101 return false;
michael@0 1102 return assignSafepoint(lir, ins);
michael@0 1103 }
michael@0 1104
michael@0 1105 static bool
michael@0 1106 CanEmitBitAndAtUses(MInstruction *ins)
michael@0 1107 {
michael@0 1108 if (!ins->canEmitAtUses())
michael@0 1109 return false;
michael@0 1110
michael@0 1111 if (ins->getOperand(0)->type() != MIRType_Int32 || ins->getOperand(1)->type() != MIRType_Int32)
michael@0 1112 return false;
michael@0 1113
michael@0 1114 MUseIterator iter(ins->usesBegin());
michael@0 1115 if (iter == ins->usesEnd())
michael@0 1116 return false;
michael@0 1117
michael@0 1118 MNode *node = iter->consumer();
michael@0 1119 if (!node->isDefinition())
michael@0 1120 return false;
michael@0 1121
michael@0 1122 if (!node->toDefinition()->isTest())
michael@0 1123 return false;
michael@0 1124
michael@0 1125 iter++;
michael@0 1126 return iter == ins->usesEnd();
michael@0 1127 }
michael@0 1128
michael@0 1129 bool
michael@0 1130 LIRGenerator::visitBitAnd(MBitAnd *ins)
michael@0 1131 {
michael@0 1132 // Sniff out if the output of this bitand is used only for a branching.
michael@0 1133 // If it is, then we will emit an LBitAndAndBranch instruction in place
michael@0 1134 // of this bitand and any test that uses this bitand. Thus, we can
michael@0 1135 // ignore this BitAnd.
michael@0 1136 if (CanEmitBitAndAtUses(ins))
michael@0 1137 return emitAtUses(ins);
michael@0 1138
michael@0 1139 return lowerBitOp(JSOP_BITAND, ins);
michael@0 1140 }
michael@0 1141
michael@0 1142 bool
michael@0 1143 LIRGenerator::visitBitOr(MBitOr *ins)
michael@0 1144 {
michael@0 1145 return lowerBitOp(JSOP_BITOR, ins);
michael@0 1146 }
michael@0 1147
michael@0 1148 bool
michael@0 1149 LIRGenerator::visitBitXor(MBitXor *ins)
michael@0 1150 {
michael@0 1151 return lowerBitOp(JSOP_BITXOR, ins);
michael@0 1152 }
michael@0 1153
michael@0 1154 bool
michael@0 1155 LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction *ins)
michael@0 1156 {
michael@0 1157 MDefinition *lhs = ins->getOperand(0);
michael@0 1158 MDefinition *rhs = ins->getOperand(1);
michael@0 1159
michael@0 1160 if (lhs->type() == MIRType_Int32 && rhs->type() == MIRType_Int32) {
michael@0 1161 if (ins->type() == MIRType_Double) {
michael@0 1162 JS_ASSERT(op == JSOP_URSH);
michael@0 1163 return lowerUrshD(ins->toUrsh());
michael@0 1164 }
michael@0 1165
michael@0 1166 LShiftI *lir = new(alloc()) LShiftI(op);
michael@0 1167 if (op == JSOP_URSH) {
michael@0 1168 if (ins->toUrsh()->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
michael@0 1169 return false;
michael@0 1170 }
michael@0 1171 return lowerForShift(lir, ins, lhs, rhs);
michael@0 1172 }
michael@0 1173
michael@0 1174 JS_ASSERT(ins->specialization() == MIRType_None);
michael@0 1175
michael@0 1176 if (op == JSOP_URSH) {
michael@0 1177 // Result is either int32 or double so we have to use BinaryV.
michael@0 1178 return lowerBinaryV(JSOP_URSH, ins);
michael@0 1179 }
michael@0 1180
michael@0 1181 LBitOpV *lir = new(alloc()) LBitOpV(op);
michael@0 1182 if (!useBoxAtStart(lir, LBitOpV::LhsInput, lhs))
michael@0 1183 return false;
michael@0 1184 if (!useBoxAtStart(lir, LBitOpV::RhsInput, rhs))
michael@0 1185 return false;
michael@0 1186 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 1187 }
michael@0 1188
michael@0 1189 bool
michael@0 1190 LIRGenerator::visitLsh(MLsh *ins)
michael@0 1191 {
michael@0 1192 return lowerShiftOp(JSOP_LSH, ins);
michael@0 1193 }
michael@0 1194
michael@0 1195 bool
michael@0 1196 LIRGenerator::visitRsh(MRsh *ins)
michael@0 1197 {
michael@0 1198 return lowerShiftOp(JSOP_RSH, ins);
michael@0 1199 }
michael@0 1200
michael@0 1201 bool
michael@0 1202 LIRGenerator::visitUrsh(MUrsh *ins)
michael@0 1203 {
michael@0 1204 return lowerShiftOp(JSOP_URSH, ins);
michael@0 1205 }
michael@0 1206
michael@0 1207 bool
michael@0 1208 LIRGenerator::visitFloor(MFloor *ins)
michael@0 1209 {
michael@0 1210 MIRType type = ins->num()->type();
michael@0 1211 JS_ASSERT(IsFloatingPointType(type));
michael@0 1212
michael@0 1213 if (type == MIRType_Double) {
michael@0 1214 LFloor *lir = new(alloc()) LFloor(useRegister(ins->num()));
michael@0 1215 if (!assignSnapshot(lir))
michael@0 1216 return false;
michael@0 1217 return define(lir, ins);
michael@0 1218 }
michael@0 1219
michael@0 1220 LFloorF *lir = new(alloc()) LFloorF(useRegister(ins->num()));
michael@0 1221 if (!assignSnapshot(lir))
michael@0 1222 return false;
michael@0 1223 return define(lir, ins);
michael@0 1224 }
michael@0 1225
michael@0 1226 bool
michael@0 1227 LIRGenerator::visitRound(MRound *ins)
michael@0 1228 {
michael@0 1229 MIRType type = ins->num()->type();
michael@0 1230 JS_ASSERT(IsFloatingPointType(type));
michael@0 1231
michael@0 1232 if (type == MIRType_Double) {
michael@0 1233 LRound *lir = new (alloc()) LRound(useRegister(ins->num()), tempDouble());
michael@0 1234 if (!assignSnapshot(lir))
michael@0 1235 return false;
michael@0 1236 return define(lir, ins);
michael@0 1237 }
michael@0 1238
michael@0 1239 LRoundF *lir = new (alloc()) LRoundF(useRegister(ins->num()), tempDouble());
michael@0 1240 if (!assignSnapshot(lir))
michael@0 1241 return false;
michael@0 1242 return define(lir, ins);
michael@0 1243 }
michael@0 1244
michael@0 1245 bool
michael@0 1246 LIRGenerator::visitMinMax(MMinMax *ins)
michael@0 1247 {
michael@0 1248 MDefinition *first = ins->getOperand(0);
michael@0 1249 MDefinition *second = ins->getOperand(1);
michael@0 1250
michael@0 1251 ReorderCommutative(&first, &second);
michael@0 1252
michael@0 1253 if (ins->specialization() == MIRType_Int32) {
michael@0 1254 LMinMaxI *lir = new(alloc()) LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
michael@0 1255 return defineReuseInput(lir, ins, 0);
michael@0 1256 }
michael@0 1257
michael@0 1258 LMinMaxD *lir = new(alloc()) LMinMaxD(useRegisterAtStart(first), useRegister(second));
michael@0 1259 return defineReuseInput(lir, ins, 0);
michael@0 1260 }
michael@0 1261
michael@0 1262 bool
michael@0 1263 LIRGenerator::visitAbs(MAbs *ins)
michael@0 1264 {
michael@0 1265 MDefinition *num = ins->num();
michael@0 1266 JS_ASSERT(IsNumberType(num->type()));
michael@0 1267
michael@0 1268 if (num->type() == MIRType_Int32) {
michael@0 1269 LAbsI *lir = new(alloc()) LAbsI(useRegisterAtStart(num));
michael@0 1270 // needed to handle abs(INT32_MIN)
michael@0 1271 if (ins->fallible() && !assignSnapshot(lir))
michael@0 1272 return false;
michael@0 1273 return defineReuseInput(lir, ins, 0);
michael@0 1274 }
michael@0 1275 if (num->type() == MIRType_Float32) {
michael@0 1276 LAbsF *lir = new(alloc()) LAbsF(useRegisterAtStart(num));
michael@0 1277 return defineReuseInput(lir, ins, 0);
michael@0 1278 }
michael@0 1279
michael@0 1280 LAbsD *lir = new(alloc()) LAbsD(useRegisterAtStart(num));
michael@0 1281 return defineReuseInput(lir, ins, 0);
michael@0 1282 }
michael@0 1283
michael@0 1284 bool
michael@0 1285 LIRGenerator::visitSqrt(MSqrt *ins)
michael@0 1286 {
michael@0 1287 MDefinition *num = ins->num();
michael@0 1288 JS_ASSERT(IsFloatingPointType(num->type()));
michael@0 1289 if (num->type() == MIRType_Double) {
michael@0 1290 LSqrtD *lir = new(alloc()) LSqrtD(useRegisterAtStart(num));
michael@0 1291 return define(lir, ins);
michael@0 1292 }
michael@0 1293
michael@0 1294 LSqrtF *lir = new(alloc()) LSqrtF(useRegisterAtStart(num));
michael@0 1295 return define(lir, ins);
michael@0 1296 }
michael@0 1297
michael@0 1298 bool
michael@0 1299 LIRGenerator::visitAtan2(MAtan2 *ins)
michael@0 1300 {
michael@0 1301 MDefinition *y = ins->y();
michael@0 1302 JS_ASSERT(y->type() == MIRType_Double);
michael@0 1303
michael@0 1304 MDefinition *x = ins->x();
michael@0 1305 JS_ASSERT(x->type() == MIRType_Double);
michael@0 1306
michael@0 1307 LAtan2D *lir = new(alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x), tempFixed(CallTempReg0));
michael@0 1308 return defineReturn(lir, ins);
michael@0 1309 }
michael@0 1310
michael@0 1311 bool
michael@0 1312 LIRGenerator::visitHypot(MHypot *ins)
michael@0 1313 {
michael@0 1314 MDefinition *x = ins->x();
michael@0 1315 JS_ASSERT(x->type() == MIRType_Double);
michael@0 1316
michael@0 1317 MDefinition *y = ins->y();
michael@0 1318 JS_ASSERT(y->type() == MIRType_Double);
michael@0 1319
michael@0 1320 LHypot *lir = new(alloc()) LHypot(useRegisterAtStart(x), useRegisterAtStart(y), tempFixed(CallTempReg0));
michael@0 1321 return defineReturn(lir, ins);
michael@0 1322 }
michael@0 1323
michael@0 1324 bool
michael@0 1325 LIRGenerator::visitPow(MPow *ins)
michael@0 1326 {
michael@0 1327 MDefinition *input = ins->input();
michael@0 1328 JS_ASSERT(input->type() == MIRType_Double);
michael@0 1329
michael@0 1330 MDefinition *power = ins->power();
michael@0 1331 JS_ASSERT(power->type() == MIRType_Int32 || power->type() == MIRType_Double);
michael@0 1332
michael@0 1333 if (power->type() == MIRType_Int32) {
michael@0 1334 // Note: useRegisterAtStart here is safe, the temp is a GP register so
michael@0 1335 // it will never get the same register.
michael@0 1336 LPowI *lir = new(alloc()) LPowI(useRegisterAtStart(input), useFixed(power, CallTempReg1),
michael@0 1337 tempFixed(CallTempReg0));
michael@0 1338 return defineReturn(lir, ins);
michael@0 1339 }
michael@0 1340
michael@0 1341 LPowD *lir = new(alloc()) LPowD(useRegisterAtStart(input), useRegisterAtStart(power),
michael@0 1342 tempFixed(CallTempReg0));
michael@0 1343 return defineReturn(lir, ins);
michael@0 1344 }
michael@0 1345
michael@0 1346 bool
michael@0 1347 LIRGenerator::visitRandom(MRandom *ins)
michael@0 1348 {
michael@0 1349 LRandom *lir = new(alloc()) LRandom(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
michael@0 1350 return defineReturn(lir, ins);
michael@0 1351 }
michael@0 1352
michael@0 1353 bool
michael@0 1354 LIRGenerator::visitMathFunction(MMathFunction *ins)
michael@0 1355 {
michael@0 1356 JS_ASSERT(IsFloatingPointType(ins->type()));
michael@0 1357 JS_ASSERT_IF(ins->type() == MIRType_Double, ins->input()->type() == MIRType_Double);
michael@0 1358 JS_ASSERT_IF(ins->type() == MIRType_Float32, ins->input()->type() == MIRType_Float32);
michael@0 1359
michael@0 1360 if (ins->type() == MIRType_Double) {
michael@0 1361 // Note: useRegisterAtStart is safe here, the temp is not a FP register.
michael@0 1362 LMathFunctionD *lir = new(alloc()) LMathFunctionD(useRegisterAtStart(ins->input()),
michael@0 1363 tempFixed(CallTempReg0));
michael@0 1364 return defineReturn(lir, ins);
michael@0 1365 }
michael@0 1366
michael@0 1367 LMathFunctionF *lir = new(alloc()) LMathFunctionF(useRegisterAtStart(ins->input()),
michael@0 1368 tempFixed(CallTempReg0));
michael@0 1369 return defineReturn(lir, ins);
michael@0 1370 }
michael@0 1371
michael@0 1372 // Try to mark an add or sub instruction as able to recover its input when
michael@0 1373 // bailing out.
michael@0 1374 template <typename S, typename T>
michael@0 1375 static void
michael@0 1376 MaybeSetRecoversInput(S *mir, T *lir)
michael@0 1377 {
michael@0 1378 JS_ASSERT(lir->mirRaw() == mir);
michael@0 1379 if (!mir->fallible())
michael@0 1380 return;
michael@0 1381
michael@0 1382 if (lir->output()->policy() != LDefinition::MUST_REUSE_INPUT)
michael@0 1383 return;
michael@0 1384
michael@0 1385 // The original operands to an add or sub can't be recovered if they both
michael@0 1386 // use the same register.
michael@0 1387 if (lir->lhs()->isUse() && lir->rhs()->isUse() &&
michael@0 1388 lir->lhs()->toUse()->virtualRegister() == lir->rhs()->toUse()->virtualRegister())
michael@0 1389 {
michael@0 1390 return;
michael@0 1391 }
michael@0 1392
michael@0 1393 // Add instructions that are on two different values can recover
michael@0 1394 // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy
michael@0 1395 // of that input does not need to be kept alive in the snapshot
michael@0 1396 // for the instruction.
michael@0 1397
michael@0 1398 lir->setRecoversInput();
michael@0 1399
michael@0 1400 const LUse *input = lir->getOperand(lir->output()->getReusedInput())->toUse();
michael@0 1401 lir->snapshot()->rewriteRecoveredInput(*input);
michael@0 1402 }
michael@0 1403
michael@0 1404 bool
michael@0 1405 LIRGenerator::visitAdd(MAdd *ins)
michael@0 1406 {
michael@0 1407 MDefinition *lhs = ins->getOperand(0);
michael@0 1408 MDefinition *rhs = ins->getOperand(1);
michael@0 1409
michael@0 1410 JS_ASSERT(lhs->type() == rhs->type());
michael@0 1411
michael@0 1412 if (ins->specialization() == MIRType_Int32) {
michael@0 1413 JS_ASSERT(lhs->type() == MIRType_Int32);
michael@0 1414 ReorderCommutative(&lhs, &rhs);
michael@0 1415 LAddI *lir = new(alloc()) LAddI;
michael@0 1416
michael@0 1417 if (ins->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
michael@0 1418 return false;
michael@0 1419
michael@0 1420 if (!lowerForALU(lir, ins, lhs, rhs))
michael@0 1421 return false;
michael@0 1422
michael@0 1423 MaybeSetRecoversInput(ins, lir);
michael@0 1424 return true;
michael@0 1425 }
michael@0 1426
michael@0 1427 if (ins->specialization() == MIRType_Double) {
michael@0 1428 JS_ASSERT(lhs->type() == MIRType_Double);
michael@0 1429 ReorderCommutative(&lhs, &rhs);
michael@0 1430 return lowerForFPU(new(alloc()) LMathD(JSOP_ADD), ins, lhs, rhs);
michael@0 1431 }
michael@0 1432
michael@0 1433 if (ins->specialization() == MIRType_Float32) {
michael@0 1434 JS_ASSERT(lhs->type() == MIRType_Float32);
michael@0 1435 ReorderCommutative(&lhs, &rhs);
michael@0 1436 return lowerForFPU(new(alloc()) LMathF(JSOP_ADD), ins, lhs, rhs);
michael@0 1437 }
michael@0 1438
michael@0 1439 return lowerBinaryV(JSOP_ADD, ins);
michael@0 1440 }
michael@0 1441
michael@0 1442 bool
michael@0 1443 LIRGenerator::visitSub(MSub *ins)
michael@0 1444 {
michael@0 1445 MDefinition *lhs = ins->lhs();
michael@0 1446 MDefinition *rhs = ins->rhs();
michael@0 1447
michael@0 1448 JS_ASSERT(lhs->type() == rhs->type());
michael@0 1449
michael@0 1450 if (ins->specialization() == MIRType_Int32) {
michael@0 1451 JS_ASSERT(lhs->type() == MIRType_Int32);
michael@0 1452
michael@0 1453 LSubI *lir = new(alloc()) LSubI;
michael@0 1454 if (ins->fallible() && !assignSnapshot(lir))
michael@0 1455 return false;
michael@0 1456
michael@0 1457 if (!lowerForALU(lir, ins, lhs, rhs))
michael@0 1458 return false;
michael@0 1459
michael@0 1460 MaybeSetRecoversInput(ins, lir);
michael@0 1461 return true;
michael@0 1462 }
michael@0 1463 if (ins->specialization() == MIRType_Double) {
michael@0 1464 JS_ASSERT(lhs->type() == MIRType_Double);
michael@0 1465 return lowerForFPU(new(alloc()) LMathD(JSOP_SUB), ins, lhs, rhs);
michael@0 1466 }
michael@0 1467 if (ins->specialization() == MIRType_Float32) {
michael@0 1468 JS_ASSERT(lhs->type() == MIRType_Float32);
michael@0 1469 return lowerForFPU(new(alloc()) LMathF(JSOP_SUB), ins, lhs, rhs);
michael@0 1470 }
michael@0 1471
michael@0 1472 return lowerBinaryV(JSOP_SUB, ins);
michael@0 1473 }
michael@0 1474
michael@0 1475 bool
michael@0 1476 LIRGenerator::visitMul(MMul *ins)
michael@0 1477 {
michael@0 1478 MDefinition *lhs = ins->lhs();
michael@0 1479 MDefinition *rhs = ins->rhs();
michael@0 1480 JS_ASSERT(lhs->type() == rhs->type());
michael@0 1481
michael@0 1482 if (ins->specialization() == MIRType_Int32) {
michael@0 1483 JS_ASSERT(lhs->type() == MIRType_Int32);
michael@0 1484 ReorderCommutative(&lhs, &rhs);
michael@0 1485
michael@0 1486 // If our RHS is a constant -1 and we don't have to worry about
michael@0 1487 // overflow, we can optimize to an LNegI.
michael@0 1488 if (!ins->fallible() && rhs->isConstant() && rhs->toConstant()->value() == Int32Value(-1))
michael@0 1489 return defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(lhs)), ins, 0);
michael@0 1490
michael@0 1491 return lowerMulI(ins, lhs, rhs);
michael@0 1492 }
michael@0 1493 if (ins->specialization() == MIRType_Double) {
michael@0 1494 JS_ASSERT(lhs->type() == MIRType_Double);
michael@0 1495 ReorderCommutative(&lhs, &rhs);
michael@0 1496
michael@0 1497 // If our RHS is a constant -1.0, we can optimize to an LNegD.
michael@0 1498 if (rhs->isConstant() && rhs->toConstant()->value() == DoubleValue(-1.0))
michael@0 1499 return defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0);
michael@0 1500
michael@0 1501 return lowerForFPU(new(alloc()) LMathD(JSOP_MUL), ins, lhs, rhs);
michael@0 1502 }
michael@0 1503 if (ins->specialization() == MIRType_Float32) {
michael@0 1504 JS_ASSERT(lhs->type() == MIRType_Float32);
michael@0 1505 ReorderCommutative(&lhs, &rhs);
michael@0 1506
michael@0 1507 // We apply the same optimizations as for doubles
michael@0 1508 if (rhs->isConstant() && rhs->toConstant()->value() == Float32Value(-1.0f))
michael@0 1509 return defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0);
michael@0 1510
michael@0 1511 return lowerForFPU(new(alloc()) LMathF(JSOP_MUL), ins, lhs, rhs);
michael@0 1512 }
michael@0 1513
michael@0 1514 return lowerBinaryV(JSOP_MUL, ins);
michael@0 1515 }
michael@0 1516
michael@0 1517 bool
michael@0 1518 LIRGenerator::visitDiv(MDiv *ins)
michael@0 1519 {
michael@0 1520 MDefinition *lhs = ins->lhs();
michael@0 1521 MDefinition *rhs = ins->rhs();
michael@0 1522 JS_ASSERT(lhs->type() == rhs->type());
michael@0 1523
michael@0 1524 if (ins->specialization() == MIRType_Int32) {
michael@0 1525 JS_ASSERT(lhs->type() == MIRType_Int32);
michael@0 1526 return lowerDivI(ins);
michael@0 1527 }
michael@0 1528 if (ins->specialization() == MIRType_Double) {
michael@0 1529 JS_ASSERT(lhs->type() == MIRType_Double);
michael@0 1530 return lowerForFPU(new(alloc()) LMathD(JSOP_DIV), ins, lhs, rhs);
michael@0 1531 }
michael@0 1532 if (ins->specialization() == MIRType_Float32) {
michael@0 1533 JS_ASSERT(lhs->type() == MIRType_Float32);
michael@0 1534 return lowerForFPU(new(alloc()) LMathF(JSOP_DIV), ins, lhs, rhs);
michael@0 1535 }
michael@0 1536
michael@0 1537 return lowerBinaryV(JSOP_DIV, ins);
michael@0 1538 }
michael@0 1539
michael@0 1540 bool
michael@0 1541 LIRGenerator::visitMod(MMod *ins)
michael@0 1542 {
michael@0 1543 JS_ASSERT(ins->lhs()->type() == ins->rhs()->type());
michael@0 1544
michael@0 1545 if (ins->specialization() == MIRType_Int32) {
michael@0 1546 JS_ASSERT(ins->type() == MIRType_Int32);
michael@0 1547 JS_ASSERT(ins->lhs()->type() == MIRType_Int32);
michael@0 1548 return lowerModI(ins);
michael@0 1549 }
michael@0 1550
michael@0 1551 if (ins->specialization() == MIRType_Double) {
michael@0 1552 JS_ASSERT(ins->type() == MIRType_Double);
michael@0 1553 JS_ASSERT(ins->lhs()->type() == MIRType_Double);
michael@0 1554 JS_ASSERT(ins->rhs()->type() == MIRType_Double);
michael@0 1555
michael@0 1556 // Note: useRegisterAtStart is safe here, the temp is not a FP register.
michael@0 1557 LModD *lir = new(alloc()) LModD(useRegisterAtStart(ins->lhs()), useRegisterAtStart(ins->rhs()),
michael@0 1558 tempFixed(CallTempReg0));
michael@0 1559 return defineReturn(lir, ins);
michael@0 1560 }
michael@0 1561
michael@0 1562 return lowerBinaryV(JSOP_MOD, ins);
michael@0 1563 }
michael@0 1564
michael@0 1565 bool
michael@0 1566 LIRGenerator::lowerBinaryV(JSOp op, MBinaryInstruction *ins)
michael@0 1567 {
michael@0 1568 MDefinition *lhs = ins->getOperand(0);
michael@0 1569 MDefinition *rhs = ins->getOperand(1);
michael@0 1570
michael@0 1571 JS_ASSERT(lhs->type() == MIRType_Value);
michael@0 1572 JS_ASSERT(rhs->type() == MIRType_Value);
michael@0 1573
michael@0 1574 LBinaryV *lir = new(alloc()) LBinaryV(op);
michael@0 1575 if (!useBoxAtStart(lir, LBinaryV::LhsInput, lhs))
michael@0 1576 return false;
michael@0 1577 if (!useBoxAtStart(lir, LBinaryV::RhsInput, rhs))
michael@0 1578 return false;
michael@0 1579 if (!defineReturn(lir, ins))
michael@0 1580 return false;
michael@0 1581 return assignSafepoint(lir, ins);
michael@0 1582 }
michael@0 1583
michael@0 1584 bool
michael@0 1585 LIRGenerator::visitConcat(MConcat *ins)
michael@0 1586 {
michael@0 1587 MDefinition *lhs = ins->getOperand(0);
michael@0 1588 MDefinition *rhs = ins->getOperand(1);
michael@0 1589
michael@0 1590 JS_ASSERT(lhs->type() == MIRType_String);
michael@0 1591 JS_ASSERT(rhs->type() == MIRType_String);
michael@0 1592 JS_ASSERT(ins->type() == MIRType_String);
michael@0 1593
michael@0 1594 LConcat *lir = new(alloc()) LConcat(useFixedAtStart(lhs, CallTempReg0),
michael@0 1595 useFixedAtStart(rhs, CallTempReg1),
michael@0 1596 tempFixed(CallTempReg0),
michael@0 1597 tempFixed(CallTempReg1),
michael@0 1598 tempFixed(CallTempReg2),
michael@0 1599 tempFixed(CallTempReg3),
michael@0 1600 tempFixed(CallTempReg4));
michael@0 1601 if (!defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5))))
michael@0 1602 return false;
michael@0 1603 return assignSafepoint(lir, ins);
michael@0 1604 }
michael@0 1605
michael@0 1606 bool
michael@0 1607 LIRGenerator::visitConcatPar(MConcatPar *ins)
michael@0 1608 {
michael@0 1609 MDefinition *cx = ins->forkJoinContext();
michael@0 1610 MDefinition *lhs = ins->lhs();
michael@0 1611 MDefinition *rhs = ins->rhs();
michael@0 1612
michael@0 1613 JS_ASSERT(lhs->type() == MIRType_String);
michael@0 1614 JS_ASSERT(rhs->type() == MIRType_String);
michael@0 1615 JS_ASSERT(ins->type() == MIRType_String);
michael@0 1616
michael@0 1617 LConcatPar *lir = new(alloc()) LConcatPar(useFixed(cx, CallTempReg4),
michael@0 1618 useFixedAtStart(lhs, CallTempReg0),
michael@0 1619 useFixedAtStart(rhs, CallTempReg1),
michael@0 1620 tempFixed(CallTempReg0),
michael@0 1621 tempFixed(CallTempReg1),
michael@0 1622 tempFixed(CallTempReg2),
michael@0 1623 tempFixed(CallTempReg3));
michael@0 1624 if (!defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5))))
michael@0 1625 return false;
michael@0 1626 return assignSafepoint(lir, ins);
michael@0 1627 }
michael@0 1628
michael@0 1629 bool
michael@0 1630 LIRGenerator::visitCharCodeAt(MCharCodeAt *ins)
michael@0 1631 {
michael@0 1632 MDefinition *str = ins->getOperand(0);
michael@0 1633 MDefinition *idx = ins->getOperand(1);
michael@0 1634
michael@0 1635 JS_ASSERT(str->type() == MIRType_String);
michael@0 1636 JS_ASSERT(idx->type() == MIRType_Int32);
michael@0 1637
michael@0 1638 LCharCodeAt *lir = new(alloc()) LCharCodeAt(useRegister(str), useRegister(idx));
michael@0 1639 if (!define(lir, ins))
michael@0 1640 return false;
michael@0 1641 return assignSafepoint(lir, ins);
michael@0 1642 }
michael@0 1643
michael@0 1644 bool
michael@0 1645 LIRGenerator::visitFromCharCode(MFromCharCode *ins)
michael@0 1646 {
michael@0 1647 MDefinition *code = ins->getOperand(0);
michael@0 1648
michael@0 1649 JS_ASSERT(code->type() == MIRType_Int32);
michael@0 1650
michael@0 1651 LFromCharCode *lir = new(alloc()) LFromCharCode(useRegister(code));
michael@0 1652 if (!define(lir, ins))
michael@0 1653 return false;
michael@0 1654 return assignSafepoint(lir, ins);
michael@0 1655 }
michael@0 1656
michael@0 1657 bool
michael@0 1658 LIRGenerator::visitStart(MStart *start)
michael@0 1659 {
michael@0 1660 // Create a snapshot that captures the initial state of the function.
michael@0 1661 LStart *lir = new(alloc()) LStart;
michael@0 1662 if (!assignSnapshot(lir))
michael@0 1663 return false;
michael@0 1664
michael@0 1665 if (start->startType() == MStart::StartType_Default)
michael@0 1666 lirGraph_.setEntrySnapshot(lir->snapshot());
michael@0 1667 return add(lir);
michael@0 1668 }
michael@0 1669
michael@0 1670 bool
michael@0 1671 LIRGenerator::visitNop(MNop *nop)
michael@0 1672 {
michael@0 1673 return true;
michael@0 1674 }
michael@0 1675
michael@0 1676 bool
michael@0 1677 LIRGenerator::visitOsrEntry(MOsrEntry *entry)
michael@0 1678 {
michael@0 1679 LOsrEntry *lir = new(alloc()) LOsrEntry;
michael@0 1680 return defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg)));
michael@0 1681 }
michael@0 1682
michael@0 1683 bool
michael@0 1684 LIRGenerator::visitOsrValue(MOsrValue *value)
michael@0 1685 {
michael@0 1686 LOsrValue *lir = new(alloc()) LOsrValue(useRegister(value->entry()));
michael@0 1687 return defineBox(lir, value);
michael@0 1688 }
michael@0 1689
michael@0 1690 bool
michael@0 1691 LIRGenerator::visitOsrReturnValue(MOsrReturnValue *value)
michael@0 1692 {
michael@0 1693 LOsrReturnValue *lir = new(alloc()) LOsrReturnValue(useRegister(value->entry()));
michael@0 1694 return defineBox(lir, value);
michael@0 1695 }
michael@0 1696
michael@0 1697 bool
michael@0 1698 LIRGenerator::visitOsrScopeChain(MOsrScopeChain *object)
michael@0 1699 {
michael@0 1700 LOsrScopeChain *lir = new(alloc()) LOsrScopeChain(useRegister(object->entry()));
michael@0 1701 return define(lir, object);
michael@0 1702 }
michael@0 1703
michael@0 1704 bool
michael@0 1705 LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject *object)
michael@0 1706 {
michael@0 1707 LOsrArgumentsObject *lir = new(alloc()) LOsrArgumentsObject(useRegister(object->entry()));
michael@0 1708 return define(lir, object);
michael@0 1709 }
michael@0 1710
michael@0 1711 bool
michael@0 1712 LIRGenerator::visitToDouble(MToDouble *convert)
michael@0 1713 {
michael@0 1714 MDefinition *opd = convert->input();
michael@0 1715 mozilla::DebugOnly<MToDouble::ConversionKind> conversion = convert->conversion();
michael@0 1716
michael@0 1717 switch (opd->type()) {
michael@0 1718 case MIRType_Value:
michael@0 1719 {
michael@0 1720 LValueToDouble *lir = new(alloc()) LValueToDouble();
michael@0 1721 if (!useBox(lir, LValueToDouble::Input, opd))
michael@0 1722 return false;
michael@0 1723 return assignSnapshot(lir) && define(lir, convert);
michael@0 1724 }
michael@0 1725
michael@0 1726 case MIRType_Null:
michael@0 1727 JS_ASSERT(conversion != MToDouble::NumbersOnly && conversion != MToDouble::NonNullNonStringPrimitives);
michael@0 1728 return lowerConstantDouble(0, convert);
michael@0 1729
michael@0 1730 case MIRType_Undefined:
michael@0 1731 JS_ASSERT(conversion != MToDouble::NumbersOnly);
michael@0 1732 return lowerConstantDouble(GenericNaN(), convert);
michael@0 1733
michael@0 1734 case MIRType_Boolean:
michael@0 1735 JS_ASSERT(conversion != MToDouble::NumbersOnly);
michael@0 1736 /* FALLTHROUGH */
michael@0 1737
michael@0 1738 case MIRType_Int32:
michael@0 1739 {
michael@0 1740 LInt32ToDouble *lir = new(alloc()) LInt32ToDouble(useRegister(opd));
michael@0 1741 return define(lir, convert);
michael@0 1742 }
michael@0 1743
michael@0 1744 case MIRType_Float32:
michael@0 1745 {
michael@0 1746 LFloat32ToDouble *lir = new(alloc()) LFloat32ToDouble(useRegisterAtStart(opd));
michael@0 1747 return define(lir, convert);
michael@0 1748 }
michael@0 1749
michael@0 1750 case MIRType_Double:
michael@0 1751 return redefine(convert, opd);
michael@0 1752
michael@0 1753 default:
michael@0 1754 // Objects might be effectful.
michael@0 1755 // Strings are complicated - we don't handle them yet.
michael@0 1756 MOZ_ASSUME_UNREACHABLE("unexpected type");
michael@0 1757 }
michael@0 1758 }
michael@0 1759
michael@0 1760 bool
michael@0 1761 LIRGenerator::visitToFloat32(MToFloat32 *convert)
michael@0 1762 {
michael@0 1763 MDefinition *opd = convert->input();
michael@0 1764 mozilla::DebugOnly<MToFloat32::ConversionKind> conversion = convert->conversion();
michael@0 1765
michael@0 1766 switch (opd->type()) {
michael@0 1767 case MIRType_Value:
michael@0 1768 {
michael@0 1769 LValueToFloat32 *lir = new(alloc()) LValueToFloat32();
michael@0 1770 if (!useBox(lir, LValueToFloat32::Input, opd))
michael@0 1771 return false;
michael@0 1772 return assignSnapshot(lir) && define(lir, convert);
michael@0 1773 }
michael@0 1774
michael@0 1775 case MIRType_Null:
michael@0 1776 JS_ASSERT(conversion != MToFloat32::NonStringPrimitives);
michael@0 1777 return lowerConstantFloat32(0, convert);
michael@0 1778
michael@0 1779 case MIRType_Undefined:
michael@0 1780 JS_ASSERT(conversion != MToFloat32::NumbersOnly);
michael@0 1781 return lowerConstantFloat32(GenericNaN(), convert);
michael@0 1782
michael@0 1783 case MIRType_Boolean:
michael@0 1784 JS_ASSERT(conversion != MToFloat32::NumbersOnly);
michael@0 1785 /* FALLTHROUGH */
michael@0 1786
michael@0 1787 case MIRType_Int32:
michael@0 1788 {
michael@0 1789 LInt32ToFloat32 *lir = new(alloc()) LInt32ToFloat32(useRegister(opd));
michael@0 1790 return define(lir, convert);
michael@0 1791 }
michael@0 1792
michael@0 1793 case MIRType_Double:
michael@0 1794 {
michael@0 1795 LDoubleToFloat32 *lir = new(alloc()) LDoubleToFloat32(useRegister(opd));
michael@0 1796 return define(lir, convert);
michael@0 1797 }
michael@0 1798
michael@0 1799 case MIRType_Float32:
michael@0 1800 return redefine(convert, opd);
michael@0 1801
michael@0 1802 default:
michael@0 1803 // Objects might be effectful.
michael@0 1804 // Strings are complicated - we don't handle them yet.
michael@0 1805 MOZ_ASSUME_UNREACHABLE("unexpected type");
michael@0 1806 return false;
michael@0 1807 }
michael@0 1808 }
michael@0 1809
michael@0 1810 bool
michael@0 1811 LIRGenerator::visitToInt32(MToInt32 *convert)
michael@0 1812 {
michael@0 1813 MDefinition *opd = convert->input();
michael@0 1814
michael@0 1815 switch (opd->type()) {
michael@0 1816 case MIRType_Value:
michael@0 1817 {
michael@0 1818 LValueToInt32 *lir = new(alloc()) LValueToInt32(tempDouble(), temp(), LValueToInt32::NORMAL);
michael@0 1819 if (!useBox(lir, LValueToInt32::Input, opd))
michael@0 1820 return false;
michael@0 1821 return assignSnapshot(lir) && define(lir, convert) && assignSafepoint(lir, convert);
michael@0 1822 }
michael@0 1823
michael@0 1824 case MIRType_Null:
michael@0 1825 return define(new(alloc()) LInteger(0), convert);
michael@0 1826
michael@0 1827 case MIRType_Int32:
michael@0 1828 case MIRType_Boolean:
michael@0 1829 return redefine(convert, opd);
michael@0 1830
michael@0 1831 case MIRType_Float32:
michael@0 1832 {
michael@0 1833 LFloat32ToInt32 *lir = new(alloc()) LFloat32ToInt32(useRegister(opd));
michael@0 1834 return assignSnapshot(lir) && define(lir, convert);
michael@0 1835 }
michael@0 1836
michael@0 1837 case MIRType_Double:
michael@0 1838 {
michael@0 1839 LDoubleToInt32 *lir = new(alloc()) LDoubleToInt32(useRegister(opd));
michael@0 1840 return assignSnapshot(lir) && define(lir, convert);
michael@0 1841 }
michael@0 1842
michael@0 1843 case MIRType_String:
michael@0 1844 case MIRType_Object:
michael@0 1845 case MIRType_Undefined:
michael@0 1846 // Objects might be effectful. Undefined coerces to NaN, not int32.
michael@0 1847 MOZ_ASSUME_UNREACHABLE("ToInt32 invalid input type");
michael@0 1848 return false;
michael@0 1849
michael@0 1850 default:
michael@0 1851 MOZ_ASSUME_UNREACHABLE("unexpected type");
michael@0 1852 }
michael@0 1853 }
michael@0 1854
michael@0 1855 bool
michael@0 1856 LIRGenerator::visitTruncateToInt32(MTruncateToInt32 *truncate)
michael@0 1857 {
michael@0 1858 MDefinition *opd = truncate->input();
michael@0 1859
michael@0 1860 switch (opd->type()) {
michael@0 1861 case MIRType_Value:
michael@0 1862 {
michael@0 1863 LValueToInt32 *lir = new(alloc()) LValueToInt32(tempDouble(), temp(), LValueToInt32::TRUNCATE);
michael@0 1864 if (!useBox(lir, LValueToInt32::Input, opd))
michael@0 1865 return false;
michael@0 1866 return assignSnapshot(lir) && define(lir, truncate) && assignSafepoint(lir, truncate);
michael@0 1867 }
michael@0 1868
michael@0 1869 case MIRType_Null:
michael@0 1870 case MIRType_Undefined:
michael@0 1871 return define(new(alloc()) LInteger(0), truncate);
michael@0 1872
michael@0 1873 case MIRType_Int32:
michael@0 1874 case MIRType_Boolean:
michael@0 1875 return redefine(truncate, opd);
michael@0 1876
michael@0 1877 case MIRType_Double:
michael@0 1878 return lowerTruncateDToInt32(truncate);
michael@0 1879
michael@0 1880 case MIRType_Float32:
michael@0 1881 return lowerTruncateFToInt32(truncate);
michael@0 1882
michael@0 1883 default:
michael@0 1884 // Objects might be effectful.
michael@0 1885 // Strings are complicated - we don't handle them yet.
michael@0 1886 MOZ_ASSUME_UNREACHABLE("unexpected type");
michael@0 1887 }
michael@0 1888 }
michael@0 1889
michael@0 1890 bool
michael@0 1891 LIRGenerator::visitToString(MToString *ins)
michael@0 1892 {
michael@0 1893 MDefinition *opd = ins->input();
michael@0 1894
michael@0 1895 switch (opd->type()) {
michael@0 1896 case MIRType_Null: {
michael@0 1897 const JSAtomState &names = GetIonContext()->runtime->names();
michael@0 1898 LPointer *lir = new(alloc()) LPointer(names.null);
michael@0 1899 return define(lir, ins);
michael@0 1900 }
michael@0 1901
michael@0 1902 case MIRType_Undefined: {
michael@0 1903 const JSAtomState &names = GetIonContext()->runtime->names();
michael@0 1904 LPointer *lir = new(alloc()) LPointer(names.undefined);
michael@0 1905 return define(lir, ins);
michael@0 1906 }
michael@0 1907
michael@0 1908 case MIRType_Boolean: {
michael@0 1909 LBooleanToString *lir = new(alloc()) LBooleanToString(useRegister(opd));
michael@0 1910 return define(lir, ins);
michael@0 1911 }
michael@0 1912
michael@0 1913 case MIRType_Double: {
michael@0 1914 LDoubleToString *lir = new(alloc()) LDoubleToString(useRegister(opd), temp());
michael@0 1915
michael@0 1916 if (!define(lir, ins))
michael@0 1917 return false;
michael@0 1918 return assignSafepoint(lir, ins);
michael@0 1919 }
michael@0 1920
michael@0 1921 case MIRType_Int32: {
michael@0 1922 LIntToString *lir = new(alloc()) LIntToString(useRegister(opd));
michael@0 1923
michael@0 1924 if (!define(lir, ins))
michael@0 1925 return false;
michael@0 1926 return assignSafepoint(lir, ins);
michael@0 1927 }
michael@0 1928
michael@0 1929 case MIRType_Value: {
michael@0 1930 JS_ASSERT(!opd->mightBeType(MIRType_Object));
michael@0 1931 LPrimitiveToString *lir = new(alloc()) LPrimitiveToString(tempToUnbox());
michael@0 1932 if (!useBox(lir, LPrimitiveToString::Input, opd))
michael@0 1933 return false;
michael@0 1934 if (!define(lir, ins))
michael@0 1935 return false;
michael@0 1936 return assignSafepoint(lir, ins);
michael@0 1937 }
michael@0 1938
michael@0 1939 default:
michael@0 1940 // Objects might be effectful. (see ToPrimitive)
michael@0 1941 MOZ_ASSUME_UNREACHABLE("unexpected type");
michael@0 1942 }
michael@0 1943 }
michael@0 1944
michael@0 1945 static bool
michael@0 1946 MustCloneRegExpForCall(MCall *call, uint32_t useIndex)
michael@0 1947 {
michael@0 1948 // We have a regex literal flowing into a call. Return |false| iff
michael@0 1949 // this is a native call that does not let the regex escape.
michael@0 1950
michael@0 1951 JSFunction *target = call->getSingleTarget();
michael@0 1952 if (!target || !target->isNative())
michael@0 1953 return true;
michael@0 1954
michael@0 1955 if (useIndex == MCall::IndexOfThis() &&
michael@0 1956 (target->native() == regexp_exec || target->native() == regexp_test))
michael@0 1957 {
michael@0 1958 return false;
michael@0 1959 }
michael@0 1960
michael@0 1961 if (useIndex == MCall::IndexOfArgument(0) &&
michael@0 1962 (target->native() == str_split ||
michael@0 1963 target->native() == str_replace ||
michael@0 1964 target->native() == str_match ||
michael@0 1965 target->native() == str_search))
michael@0 1966 {
michael@0 1967 return false;
michael@0 1968 }
michael@0 1969
michael@0 1970 return true;
michael@0 1971 }
michael@0 1972
michael@0 1973
michael@0 1974 static bool
michael@0 1975 MustCloneRegExp(MRegExp *regexp)
michael@0 1976 {
michael@0 1977 if (regexp->mustClone())
michael@0 1978 return true;
michael@0 1979
michael@0 1980 // If this regex literal only flows into known natives that don't let
michael@0 1981 // it escape, we don't have to clone it.
michael@0 1982
michael@0 1983 for (MUseIterator iter(regexp->usesBegin()); iter != regexp->usesEnd(); iter++) {
michael@0 1984 MNode *node = iter->consumer();
michael@0 1985 if (!node->isDefinition())
michael@0 1986 return true;
michael@0 1987
michael@0 1988 MDefinition *def = node->toDefinition();
michael@0 1989 if (def->isRegExpTest() && iter->index() == 1) {
michael@0 1990 // Optimized RegExp.prototype.test.
michael@0 1991 JS_ASSERT(def->toRegExpTest()->regexp() == regexp);
michael@0 1992 continue;
michael@0 1993 }
michael@0 1994
michael@0 1995 if (def->isCall() && !MustCloneRegExpForCall(def->toCall(), iter->index()))
michael@0 1996 continue;
michael@0 1997
michael@0 1998 return true;
michael@0 1999 }
michael@0 2000 return false;
michael@0 2001 }
michael@0 2002
michael@0 2003 bool
michael@0 2004 LIRGenerator::visitRegExp(MRegExp *ins)
michael@0 2005 {
michael@0 2006 if (!MustCloneRegExp(ins)) {
michael@0 2007 RegExpObject *source = ins->source();
michael@0 2008 return define(new(alloc()) LPointer(source), ins);
michael@0 2009 }
michael@0 2010
michael@0 2011 LRegExp *lir = new(alloc()) LRegExp();
michael@0 2012 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 2013 }
michael@0 2014
michael@0 2015 bool
michael@0 2016 LIRGenerator::visitRegExpExec(MRegExpExec *ins)
michael@0 2017 {
michael@0 2018 JS_ASSERT(ins->regexp()->type() == MIRType_Object);
michael@0 2019 JS_ASSERT(ins->string()->type() == MIRType_String);
michael@0 2020
michael@0 2021 LRegExpExec *lir = new(alloc()) LRegExpExec(useRegisterAtStart(ins->regexp()),
michael@0 2022 useRegisterAtStart(ins->string()));
michael@0 2023 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 2024 }
michael@0 2025
michael@0 2026 bool
michael@0 2027 LIRGenerator::visitRegExpTest(MRegExpTest *ins)
michael@0 2028 {
michael@0 2029 JS_ASSERT(ins->regexp()->type() == MIRType_Object);
michael@0 2030 JS_ASSERT(ins->string()->type() == MIRType_String);
michael@0 2031
michael@0 2032 LRegExpTest *lir = new(alloc()) LRegExpTest(useRegisterAtStart(ins->regexp()),
michael@0 2033 useRegisterAtStart(ins->string()));
michael@0 2034 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 2035 }
michael@0 2036
michael@0 2037 bool
michael@0 2038 LIRGenerator::visitRegExpReplace(MRegExpReplace *ins)
michael@0 2039 {
michael@0 2040 JS_ASSERT(ins->pattern()->type() == MIRType_Object);
michael@0 2041 JS_ASSERT(ins->string()->type() == MIRType_String);
michael@0 2042 JS_ASSERT(ins->replacement()->type() == MIRType_String);
michael@0 2043
michael@0 2044 LRegExpReplace *lir = new(alloc()) LRegExpReplace(useRegisterOrConstantAtStart(ins->string()),
michael@0 2045 useRegisterAtStart(ins->pattern()),
michael@0 2046 useRegisterOrConstantAtStart(ins->replacement()));
michael@0 2047 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 2048 }
michael@0 2049
michael@0 2050 bool
michael@0 2051 LIRGenerator::visitStringReplace(MStringReplace *ins)
michael@0 2052 {
michael@0 2053 JS_ASSERT(ins->pattern()->type() == MIRType_String);
michael@0 2054 JS_ASSERT(ins->string()->type() == MIRType_String);
michael@0 2055 JS_ASSERT(ins->replacement()->type() == MIRType_String);
michael@0 2056
michael@0 2057 LStringReplace *lir = new(alloc()) LStringReplace(useRegisterOrConstantAtStart(ins->string()),
michael@0 2058 useRegisterAtStart(ins->pattern()),
michael@0 2059 useRegisterOrConstantAtStart(ins->replacement()));
michael@0 2060 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 2061 }
michael@0 2062
michael@0 2063 bool
michael@0 2064 LIRGenerator::visitLambda(MLambda *ins)
michael@0 2065 {
michael@0 2066 if (ins->info().singletonType || ins->info().useNewTypeForClone) {
michael@0 2067 // If the function has a singleton type, this instruction will only be
michael@0 2068 // executed once so we don't bother inlining it.
michael@0 2069 //
michael@0 2070 // If UseNewTypeForClone is true, we will assign a singleton type to
michael@0 2071 // the clone and we have to clone the script, we can't do that inline.
michael@0 2072 LLambdaForSingleton *lir = new(alloc()) LLambdaForSingleton(useRegisterAtStart(ins->scopeChain()));
michael@0 2073 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 2074 }
michael@0 2075
michael@0 2076 LLambda *lir = new(alloc()) LLambda(useRegister(ins->scopeChain()), temp());
michael@0 2077 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 2078 }
michael@0 2079
michael@0 2080 bool
michael@0 2081 LIRGenerator::visitLambdaArrow(MLambdaArrow *ins)
michael@0 2082 {
michael@0 2083 MOZ_ASSERT(ins->scopeChain()->type() == MIRType_Object);
michael@0 2084 MOZ_ASSERT(ins->thisDef()->type() == MIRType_Value);
michael@0 2085
michael@0 2086 LLambdaArrow *lir = new(alloc()) LLambdaArrow(useRegister(ins->scopeChain()), temp());
michael@0 2087 if (!useBox(lir, LLambdaArrow::ThisValue, ins->thisDef()))
michael@0 2088 return false;
michael@0 2089 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 2090 }
michael@0 2091
michael@0 2092 bool
michael@0 2093 LIRGenerator::visitLambdaPar(MLambdaPar *ins)
michael@0 2094 {
michael@0 2095 JS_ASSERT(!ins->info().singletonType);
michael@0 2096 JS_ASSERT(!ins->info().useNewTypeForClone);
michael@0 2097 LLambdaPar *lir = new(alloc()) LLambdaPar(useRegister(ins->forkJoinContext()),
michael@0 2098 useRegister(ins->scopeChain()),
michael@0 2099 temp(), temp());
michael@0 2100 return define(lir, ins);
michael@0 2101 }
michael@0 2102
michael@0 2103 bool
michael@0 2104 LIRGenerator::visitImplicitThis(MImplicitThis *ins)
michael@0 2105 {
michael@0 2106 JS_ASSERT(ins->callee()->type() == MIRType_Object);
michael@0 2107
michael@0 2108 LImplicitThis *lir = new(alloc()) LImplicitThis(useRegister(ins->callee()));
michael@0 2109 return assignSnapshot(lir) && defineBox(lir, ins);
michael@0 2110 }
michael@0 2111
michael@0 2112 bool
michael@0 2113 LIRGenerator::visitSlots(MSlots *ins)
michael@0 2114 {
michael@0 2115 return define(new(alloc()) LSlots(useRegisterAtStart(ins->object())), ins);
michael@0 2116 }
michael@0 2117
michael@0 2118 bool
michael@0 2119 LIRGenerator::visitElements(MElements *ins)
michael@0 2120 {
michael@0 2121 return define(new(alloc()) LElements(useRegisterAtStart(ins->object())), ins);
michael@0 2122 }
michael@0 2123
michael@0 2124 bool
michael@0 2125 LIRGenerator::visitConstantElements(MConstantElements *ins)
michael@0 2126 {
michael@0 2127 return define(new(alloc()) LPointer(ins->value(), LPointer::NON_GC_THING), ins);
michael@0 2128 }
michael@0 2129
michael@0 2130 bool
michael@0 2131 LIRGenerator::visitConvertElementsToDoubles(MConvertElementsToDoubles *ins)
michael@0 2132 {
michael@0 2133 LInstruction *check = new(alloc()) LConvertElementsToDoubles(useRegister(ins->elements()));
michael@0 2134 return add(check, ins) && assignSafepoint(check, ins);
michael@0 2135 }
michael@0 2136
michael@0 2137 bool
michael@0 2138 LIRGenerator::visitMaybeToDoubleElement(MMaybeToDoubleElement *ins)
michael@0 2139 {
michael@0 2140 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2141 JS_ASSERT(ins->value()->type() == MIRType_Int32);
michael@0 2142
michael@0 2143 LMaybeToDoubleElement *lir = new(alloc()) LMaybeToDoubleElement(useRegisterAtStart(ins->elements()),
michael@0 2144 useRegisterAtStart(ins->value()),
michael@0 2145 tempDouble());
michael@0 2146 return defineBox(lir, ins);
michael@0 2147 }
michael@0 2148
michael@0 2149 bool
michael@0 2150 LIRGenerator::visitLoadSlot(MLoadSlot *ins)
michael@0 2151 {
michael@0 2152 switch (ins->type()) {
michael@0 2153 case MIRType_Value:
michael@0 2154 return defineBox(new(alloc()) LLoadSlotV(useRegister(ins->slots())), ins);
michael@0 2155
michael@0 2156 case MIRType_Undefined:
michael@0 2157 case MIRType_Null:
michael@0 2158 MOZ_ASSUME_UNREACHABLE("typed load must have a payload");
michael@0 2159
michael@0 2160 default:
michael@0 2161 return define(new(alloc()) LLoadSlotT(useRegister(ins->slots())), ins);
michael@0 2162 }
michael@0 2163 }
michael@0 2164
michael@0 2165 bool
michael@0 2166 LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment *ins)
michael@0 2167 {
michael@0 2168 return define(new(alloc()) LFunctionEnvironment(useRegisterAtStart(ins->function())), ins);
michael@0 2169 }
michael@0 2170
michael@0 2171 bool
michael@0 2172 LIRGenerator::visitForkJoinContext(MForkJoinContext *ins)
michael@0 2173 {
michael@0 2174 LForkJoinContext *lir = new(alloc()) LForkJoinContext(tempFixed(CallTempReg0));
michael@0 2175 return defineReturn(lir, ins);
michael@0 2176 }
michael@0 2177
michael@0 2178 bool
michael@0 2179 LIRGenerator::visitGuardThreadExclusive(MGuardThreadExclusive *ins)
michael@0 2180 {
michael@0 2181 // FIXME (Bug 956281) -- For now, we always generate the most
michael@0 2182 // general form of write guard check. we could employ TI feedback
michael@0 2183 // to optimize this if we know that the object being tested is a
michael@0 2184 // typed object or know that it is definitely NOT a typed object.
michael@0 2185 LGuardThreadExclusive *lir =
michael@0 2186 new(alloc()) LGuardThreadExclusive(useFixed(ins->forkJoinContext(), CallTempReg0),
michael@0 2187 useFixed(ins->object(), CallTempReg1),
michael@0 2188 tempFixed(CallTempReg2));
michael@0 2189 lir->setMir(ins);
michael@0 2190 return add(lir, ins);
michael@0 2191 }
michael@0 2192
michael@0 2193 bool
michael@0 2194 LIRGenerator::visitInterruptCheck(MInterruptCheck *ins)
michael@0 2195 {
michael@0 2196 // Implicit interrupt checks require asm.js signal handlers to be
michael@0 2197 // installed. ARM does not yet use implicit interrupt checks, see
michael@0 2198 // bug 864220.
michael@0 2199 #ifndef JS_CODEGEN_ARM
michael@0 2200 if (GetIonContext()->runtime->signalHandlersInstalled()) {
michael@0 2201 LInterruptCheckImplicit *lir = new(alloc()) LInterruptCheckImplicit();
michael@0 2202 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 2203 }
michael@0 2204 #endif
michael@0 2205
michael@0 2206 LInterruptCheck *lir = new(alloc()) LInterruptCheck();
michael@0 2207 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 2208 }
michael@0 2209
michael@0 2210 bool
michael@0 2211 LIRGenerator::visitInterruptCheckPar(MInterruptCheckPar *ins)
michael@0 2212 {
michael@0 2213 LInterruptCheckPar *lir =
michael@0 2214 new(alloc()) LInterruptCheckPar(useRegister(ins->forkJoinContext()), temp());
michael@0 2215 if (!add(lir, ins))
michael@0 2216 return false;
michael@0 2217 if (!assignSafepoint(lir, ins))
michael@0 2218 return false;
michael@0 2219 return true;
michael@0 2220 }
michael@0 2221
michael@0 2222 bool
michael@0 2223 LIRGenerator::visitNewPar(MNewPar *ins)
michael@0 2224 {
michael@0 2225 LNewPar *lir = new(alloc()) LNewPar(useRegister(ins->forkJoinContext()), temp(), temp());
michael@0 2226 return define(lir, ins);
michael@0 2227 }
michael@0 2228
michael@0 2229 bool
michael@0 2230 LIRGenerator::visitNewDenseArrayPar(MNewDenseArrayPar *ins)
michael@0 2231 {
michael@0 2232 LNewDenseArrayPar *lir =
michael@0 2233 new(alloc()) LNewDenseArrayPar(useFixed(ins->forkJoinContext(), CallTempReg0),
michael@0 2234 useFixed(ins->length(), CallTempReg1),
michael@0 2235 tempFixed(CallTempReg2),
michael@0 2236 tempFixed(CallTempReg3),
michael@0 2237 tempFixed(CallTempReg4));
michael@0 2238 return defineReturn(lir, ins);
michael@0 2239 }
michael@0 2240
michael@0 2241 bool
michael@0 2242 LIRGenerator::visitStoreSlot(MStoreSlot *ins)
michael@0 2243 {
michael@0 2244 LInstruction *lir;
michael@0 2245
michael@0 2246 switch (ins->value()->type()) {
michael@0 2247 case MIRType_Value:
michael@0 2248 lir = new(alloc()) LStoreSlotV(useRegister(ins->slots()));
michael@0 2249 if (!useBox(lir, LStoreSlotV::Value, ins->value()))
michael@0 2250 return false;
michael@0 2251 return add(lir, ins);
michael@0 2252
michael@0 2253 case MIRType_Double:
michael@0 2254 return add(new(alloc()) LStoreSlotT(useRegister(ins->slots()), useRegister(ins->value())), ins);
michael@0 2255
michael@0 2256 case MIRType_Float32:
michael@0 2257 MOZ_ASSUME_UNREACHABLE("Float32 shouldn't be stored in a slot.");
michael@0 2258
michael@0 2259 default:
michael@0 2260 return add(new(alloc()) LStoreSlotT(useRegister(ins->slots()), useRegisterOrConstant(ins->value())),
michael@0 2261 ins);
michael@0 2262 }
michael@0 2263
michael@0 2264 return true;
michael@0 2265 }
michael@0 2266
michael@0 2267 bool
michael@0 2268 LIRGenerator::visitFilterTypeSet(MFilterTypeSet *ins)
michael@0 2269 {
michael@0 2270 return redefine(ins, ins->input());
michael@0 2271 }
michael@0 2272
michael@0 2273 bool
michael@0 2274 LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
michael@0 2275 {
michael@0 2276 // Requesting a non-GC pointer is safe here since we never re-enter C++
michael@0 2277 // from inside a type barrier test.
michael@0 2278
michael@0 2279 const types::TemporaryTypeSet *types = ins->resultTypeSet();
michael@0 2280 bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
michael@0 2281
michael@0 2282 MIRType inputType = ins->getOperand(0)->type();
michael@0 2283 DebugOnly<MIRType> outputType = ins->type();
michael@0 2284
michael@0 2285 JS_ASSERT(inputType == outputType);
michael@0 2286
michael@0 2287 // Handle typebarrier that will always bail.
michael@0 2288 // (Emit LBail for visibility).
michael@0 2289 if (ins->alwaysBails()) {
michael@0 2290 LBail *bail = new(alloc()) LBail();
michael@0 2291 if (!assignSnapshot(bail))
michael@0 2292 return false;
michael@0 2293 return redefine(ins, ins->input()) && add(bail, ins);
michael@0 2294 }
michael@0 2295
michael@0 2296 // Handle typebarrier with Value as input.
michael@0 2297 if (inputType == MIRType_Value) {
michael@0 2298 LDefinition tmp = needTemp ? temp() : tempToUnbox();
michael@0 2299 LTypeBarrierV *barrier = new(alloc()) LTypeBarrierV(tmp);
michael@0 2300 if (!useBox(barrier, LTypeBarrierV::Input, ins->input()))
michael@0 2301 return false;
michael@0 2302 if (!assignSnapshot(barrier))
michael@0 2303 return false;
michael@0 2304 return redefine(ins, ins->input()) && add(barrier, ins);
michael@0 2305 }
michael@0 2306
michael@0 2307 // Handle typebarrier with specific TypeObject/SingleObjects.
michael@0 2308 if (inputType == MIRType_Object && !types->hasType(types::Type::AnyObjectType()))
michael@0 2309 {
michael@0 2310 LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp();
michael@0 2311 LTypeBarrierO *barrier = new(alloc()) LTypeBarrierO(useRegister(ins->getOperand(0)), tmp);
michael@0 2312 if (!assignSnapshot(barrier))
michael@0 2313 return false;
michael@0 2314 return redefine(ins, ins->getOperand(0)) && add(barrier, ins);
michael@0 2315 }
michael@0 2316
michael@0 2317 // Handle remaining cases: No-op, unbox did everything.
michael@0 2318 return redefine(ins, ins->getOperand(0));
michael@0 2319 }
michael@0 2320
michael@0 2321 bool
michael@0 2322 LIRGenerator::visitMonitorTypes(MMonitorTypes *ins)
michael@0 2323 {
michael@0 2324 // Requesting a non-GC pointer is safe here since we never re-enter C++
michael@0 2325 // from inside a type check.
michael@0 2326
michael@0 2327 const types::TemporaryTypeSet *types = ins->typeSet();
michael@0 2328 bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
michael@0 2329 LDefinition tmp = needTemp ? temp() : tempToUnbox();
michael@0 2330
michael@0 2331 LMonitorTypes *lir = new(alloc()) LMonitorTypes(tmp);
michael@0 2332 if (!useBox(lir, LMonitorTypes::Input, ins->input()))
michael@0 2333 return false;
michael@0 2334 return assignSnapshot(lir, Bailout_Normal) && add(lir, ins);
michael@0 2335 }
michael@0 2336
michael@0 2337 bool
michael@0 2338 LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier *ins)
michael@0 2339 {
michael@0 2340 #ifdef JSGC_GENERATIONAL
michael@0 2341 switch (ins->value()->type()) {
michael@0 2342 case MIRType_Object: {
michael@0 2343 LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
michael@0 2344 LPostWriteBarrierO *lir =
michael@0 2345 new(alloc()) LPostWriteBarrierO(useRegisterOrConstant(ins->object()),
michael@0 2346 useRegister(ins->value()), tmp);
michael@0 2347 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 2348 }
michael@0 2349 case MIRType_Value: {
michael@0 2350 LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
michael@0 2351 LPostWriteBarrierV *lir =
michael@0 2352 new(alloc()) LPostWriteBarrierV(useRegisterOrConstant(ins->object()), tmp);
michael@0 2353 if (!useBox(lir, LPostWriteBarrierV::Input, ins->value()))
michael@0 2354 return false;
michael@0 2355 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 2356 }
michael@0 2357 default:
michael@0 2358 // Currently, only objects can be in the nursery. Other instruction
michael@0 2359 // types cannot hold nursery pointers.
michael@0 2360 return true;
michael@0 2361 }
michael@0 2362 #endif // JSGC_GENERATIONAL
michael@0 2363 return true;
michael@0 2364 }
michael@0 2365
michael@0 2366 bool
michael@0 2367 LIRGenerator::visitArrayLength(MArrayLength *ins)
michael@0 2368 {
michael@0 2369 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2370 return define(new(alloc()) LArrayLength(useRegisterAtStart(ins->elements())), ins);
michael@0 2371 }
michael@0 2372
michael@0 2373 bool
michael@0 2374 LIRGenerator::visitSetArrayLength(MSetArrayLength *ins)
michael@0 2375 {
michael@0 2376 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2377 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2378
michael@0 2379 JS_ASSERT(ins->index()->isConstant());
michael@0 2380 return add(new(alloc()) LSetArrayLength(useRegister(ins->elements()),
michael@0 2381 useRegisterOrConstant(ins->index())), ins);
michael@0 2382 }
michael@0 2383
michael@0 2384 bool
michael@0 2385 LIRGenerator::visitTypedArrayLength(MTypedArrayLength *ins)
michael@0 2386 {
michael@0 2387 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 2388 return define(new(alloc()) LTypedArrayLength(useRegisterAtStart(ins->object())), ins);
michael@0 2389 }
michael@0 2390
michael@0 2391 bool
michael@0 2392 LIRGenerator::visitTypedArrayElements(MTypedArrayElements *ins)
michael@0 2393 {
michael@0 2394 JS_ASSERT(ins->type() == MIRType_Elements);
michael@0 2395 return define(new(alloc()) LTypedArrayElements(useRegisterAtStart(ins->object())), ins);
michael@0 2396 }
michael@0 2397
michael@0 2398 bool
michael@0 2399 LIRGenerator::visitTypedObjectElements(MTypedObjectElements *ins)
michael@0 2400 {
michael@0 2401 JS_ASSERT(ins->type() == MIRType_Elements);
michael@0 2402 return define(new(alloc()) LTypedObjectElements(useRegisterAtStart(ins->object())), ins);
michael@0 2403 }
michael@0 2404
michael@0 2405 bool
michael@0 2406 LIRGenerator::visitSetTypedObjectOffset(MSetTypedObjectOffset *ins)
michael@0 2407 {
michael@0 2408 return add(new(alloc()) LSetTypedObjectOffset(
michael@0 2409 useRegister(ins->object()),
michael@0 2410 useRegister(ins->offset()),
michael@0 2411 temp()),
michael@0 2412 ins);
michael@0 2413 }
michael@0 2414
michael@0 2415 bool
michael@0 2416 LIRGenerator::visitInitializedLength(MInitializedLength *ins)
michael@0 2417 {
michael@0 2418 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2419 return define(new(alloc()) LInitializedLength(useRegisterAtStart(ins->elements())), ins);
michael@0 2420 }
michael@0 2421
michael@0 2422 bool
michael@0 2423 LIRGenerator::visitSetInitializedLength(MSetInitializedLength *ins)
michael@0 2424 {
michael@0 2425 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2426 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2427
michael@0 2428 JS_ASSERT(ins->index()->isConstant());
michael@0 2429 return add(new(alloc()) LSetInitializedLength(useRegister(ins->elements()),
michael@0 2430 useRegisterOrConstant(ins->index())), ins);
michael@0 2431 }
michael@0 2432
michael@0 2433 bool
michael@0 2434 LIRGenerator::visitNot(MNot *ins)
michael@0 2435 {
michael@0 2436 MDefinition *op = ins->operand();
michael@0 2437
michael@0 2438 // String is converted to length of string in the type analysis phase (see
michael@0 2439 // TestPolicy).
michael@0 2440 JS_ASSERT(op->type() != MIRType_String);
michael@0 2441
michael@0 2442 // - boolean: x xor 1
michael@0 2443 // - int32: LCompare(x, 0)
michael@0 2444 // - double: LCompare(x, 0)
michael@0 2445 // - null or undefined: true
michael@0 2446 // - object: false if it never emulates undefined, else LNotO(x)
michael@0 2447 switch (op->type()) {
michael@0 2448 case MIRType_Boolean: {
michael@0 2449 MConstant *cons = MConstant::New(alloc(), Int32Value(1));
michael@0 2450 ins->block()->insertBefore(ins, cons);
michael@0 2451 return lowerForALU(new(alloc()) LBitOpI(JSOP_BITXOR), ins, op, cons);
michael@0 2452 }
michael@0 2453 case MIRType_Int32: {
michael@0 2454 return define(new(alloc()) LNotI(useRegisterAtStart(op)), ins);
michael@0 2455 }
michael@0 2456 case MIRType_Double:
michael@0 2457 return define(new(alloc()) LNotD(useRegister(op)), ins);
michael@0 2458 case MIRType_Float32:
michael@0 2459 return define(new(alloc()) LNotF(useRegister(op)), ins);
michael@0 2460 case MIRType_Undefined:
michael@0 2461 case MIRType_Null:
michael@0 2462 return define(new(alloc()) LInteger(1), ins);
michael@0 2463 case MIRType_Object: {
michael@0 2464 // Objects that don't emulate undefined can be constant-folded.
michael@0 2465 if (!ins->operandMightEmulateUndefined())
michael@0 2466 return define(new(alloc()) LInteger(0), ins);
michael@0 2467 // All others require further work.
michael@0 2468 return define(new(alloc()) LNotO(useRegister(op)), ins);
michael@0 2469 }
michael@0 2470 case MIRType_Value: {
michael@0 2471 LDefinition temp0, temp1;
michael@0 2472 if (ins->operandMightEmulateUndefined()) {
michael@0 2473 temp0 = temp();
michael@0 2474 temp1 = temp();
michael@0 2475 } else {
michael@0 2476 temp0 = LDefinition::BogusTemp();
michael@0 2477 temp1 = LDefinition::BogusTemp();
michael@0 2478 }
michael@0 2479
michael@0 2480 LNotV *lir = new(alloc()) LNotV(tempDouble(), temp0, temp1);
michael@0 2481 if (!useBox(lir, LNotV::Input, op))
michael@0 2482 return false;
michael@0 2483 return define(lir, ins);
michael@0 2484 }
michael@0 2485
michael@0 2486 default:
michael@0 2487 MOZ_ASSUME_UNREACHABLE("Unexpected MIRType.");
michael@0 2488 }
michael@0 2489 }
michael@0 2490
michael@0 2491 bool
michael@0 2492 LIRGenerator::visitNeuterCheck(MNeuterCheck *ins)
michael@0 2493 {
michael@0 2494 LNeuterCheck *chk = new(alloc()) LNeuterCheck(useRegister(ins->object()),
michael@0 2495 temp());
michael@0 2496 if (!assignSnapshot(chk, Bailout_BoundsCheck))
michael@0 2497 return false;
michael@0 2498 return redefine(ins, ins->input()) && add(chk, ins);
michael@0 2499 }
michael@0 2500
michael@0 2501 bool
michael@0 2502 LIRGenerator::visitBoundsCheck(MBoundsCheck *ins)
michael@0 2503 {
michael@0 2504 LInstruction *check;
michael@0 2505 if (ins->minimum() || ins->maximum()) {
michael@0 2506 check = new(alloc()) LBoundsCheckRange(useRegisterOrConstant(ins->index()),
michael@0 2507 useAny(ins->length()),
michael@0 2508 temp());
michael@0 2509 } else {
michael@0 2510 check = new(alloc()) LBoundsCheck(useRegisterOrConstant(ins->index()),
michael@0 2511 useAnyOrConstant(ins->length()));
michael@0 2512 }
michael@0 2513 return assignSnapshot(check, Bailout_BoundsCheck) && add(check, ins);
michael@0 2514 }
michael@0 2515
michael@0 2516 bool
michael@0 2517 LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower *ins)
michael@0 2518 {
michael@0 2519 if (!ins->fallible())
michael@0 2520 return true;
michael@0 2521
michael@0 2522 LInstruction *check = new(alloc()) LBoundsCheckLower(useRegister(ins->index()));
michael@0 2523 return assignSnapshot(check, Bailout_BoundsCheck) && add(check, ins);
michael@0 2524 }
michael@0 2525
michael@0 2526 bool
michael@0 2527 LIRGenerator::visitInArray(MInArray *ins)
michael@0 2528 {
michael@0 2529 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2530 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2531 JS_ASSERT(ins->initLength()->type() == MIRType_Int32);
michael@0 2532 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 2533 JS_ASSERT(ins->type() == MIRType_Boolean);
michael@0 2534
michael@0 2535 LAllocation object;
michael@0 2536 if (ins->needsNegativeIntCheck())
michael@0 2537 object = useRegister(ins->object());
michael@0 2538 else
michael@0 2539 object = LConstantIndex::Bogus();
michael@0 2540
michael@0 2541 LInArray *lir = new(alloc()) LInArray(useRegister(ins->elements()),
michael@0 2542 useRegisterOrConstant(ins->index()),
michael@0 2543 useRegister(ins->initLength()),
michael@0 2544 object);
michael@0 2545 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 2546 }
michael@0 2547
michael@0 2548 bool
michael@0 2549 LIRGenerator::visitLoadElement(MLoadElement *ins)
michael@0 2550 {
michael@0 2551 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2552 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2553
michael@0 2554 switch (ins->type()) {
michael@0 2555 case MIRType_Value:
michael@0 2556 {
michael@0 2557 LLoadElementV *lir = new(alloc()) LLoadElementV(useRegister(ins->elements()),
michael@0 2558 useRegisterOrConstant(ins->index()));
michael@0 2559 if (ins->fallible() && !assignSnapshot(lir))
michael@0 2560 return false;
michael@0 2561 return defineBox(lir, ins);
michael@0 2562 }
michael@0 2563 case MIRType_Undefined:
michael@0 2564 case MIRType_Null:
michael@0 2565 MOZ_ASSUME_UNREACHABLE("typed load must have a payload");
michael@0 2566
michael@0 2567 default:
michael@0 2568 {
michael@0 2569 LLoadElementT *lir = new(alloc()) LLoadElementT(useRegister(ins->elements()),
michael@0 2570 useRegisterOrConstant(ins->index()));
michael@0 2571 if (ins->fallible() && !assignSnapshot(lir))
michael@0 2572 return false;
michael@0 2573 return define(lir, ins);
michael@0 2574 }
michael@0 2575 }
michael@0 2576 }
michael@0 2577
michael@0 2578 bool
michael@0 2579 LIRGenerator::visitLoadElementHole(MLoadElementHole *ins)
michael@0 2580 {
michael@0 2581 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2582 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2583 JS_ASSERT(ins->initLength()->type() == MIRType_Int32);
michael@0 2584 JS_ASSERT(ins->type() == MIRType_Value);
michael@0 2585
michael@0 2586 LLoadElementHole *lir = new(alloc()) LLoadElementHole(useRegister(ins->elements()),
michael@0 2587 useRegisterOrConstant(ins->index()),
michael@0 2588 useRegister(ins->initLength()));
michael@0 2589 if (ins->needsNegativeIntCheck() && !assignSnapshot(lir))
michael@0 2590 return false;
michael@0 2591 return defineBox(lir, ins);
michael@0 2592 }
michael@0 2593
michael@0 2594 bool
michael@0 2595 LIRGenerator::visitStoreElement(MStoreElement *ins)
michael@0 2596 {
michael@0 2597 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2598 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2599
michael@0 2600 const LUse elements = useRegister(ins->elements());
michael@0 2601 const LAllocation index = useRegisterOrConstant(ins->index());
michael@0 2602
michael@0 2603 switch (ins->value()->type()) {
michael@0 2604 case MIRType_Value:
michael@0 2605 {
michael@0 2606 LInstruction *lir = new(alloc()) LStoreElementV(elements, index);
michael@0 2607 if (ins->fallible() && !assignSnapshot(lir))
michael@0 2608 return false;
michael@0 2609 if (!useBox(lir, LStoreElementV::Value, ins->value()))
michael@0 2610 return false;
michael@0 2611 return add(lir, ins);
michael@0 2612 }
michael@0 2613
michael@0 2614 default:
michael@0 2615 {
michael@0 2616 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
michael@0 2617 LInstruction *lir = new(alloc()) LStoreElementT(elements, index, value);
michael@0 2618 if (ins->fallible() && !assignSnapshot(lir))
michael@0 2619 return false;
michael@0 2620 return add(lir, ins);
michael@0 2621 }
michael@0 2622 }
michael@0 2623 }
michael@0 2624
michael@0 2625 bool
michael@0 2626 LIRGenerator::visitStoreElementHole(MStoreElementHole *ins)
michael@0 2627 {
michael@0 2628 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2629 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2630
michael@0 2631 const LUse object = useRegister(ins->object());
michael@0 2632 const LUse elements = useRegister(ins->elements());
michael@0 2633 const LAllocation index = useRegisterOrConstant(ins->index());
michael@0 2634
michael@0 2635 LInstruction *lir;
michael@0 2636 switch (ins->value()->type()) {
michael@0 2637 case MIRType_Value:
michael@0 2638 lir = new(alloc()) LStoreElementHoleV(object, elements, index);
michael@0 2639 if (!useBox(lir, LStoreElementHoleV::Value, ins->value()))
michael@0 2640 return false;
michael@0 2641 break;
michael@0 2642
michael@0 2643 default:
michael@0 2644 {
michael@0 2645 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
michael@0 2646 lir = new(alloc()) LStoreElementHoleT(object, elements, index, value);
michael@0 2647 break;
michael@0 2648 }
michael@0 2649 }
michael@0 2650
michael@0 2651 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 2652 }
michael@0 2653
michael@0 2654 bool
michael@0 2655 LIRGenerator::visitEffectiveAddress(MEffectiveAddress *ins)
michael@0 2656 {
michael@0 2657 return define(new(alloc()) LEffectiveAddress(useRegister(ins->base()), useRegister(ins->index())), ins);
michael@0 2658 }
michael@0 2659
michael@0 2660 bool
michael@0 2661 LIRGenerator::visitArrayPopShift(MArrayPopShift *ins)
michael@0 2662 {
michael@0 2663 LUse object = useRegister(ins->object());
michael@0 2664
michael@0 2665 switch (ins->type()) {
michael@0 2666 case MIRType_Value:
michael@0 2667 {
michael@0 2668 LArrayPopShiftV *lir = new(alloc()) LArrayPopShiftV(object, temp(), temp());
michael@0 2669 return defineBox(lir, ins) && assignSafepoint(lir, ins);
michael@0 2670 }
michael@0 2671 case MIRType_Undefined:
michael@0 2672 case MIRType_Null:
michael@0 2673 MOZ_ASSUME_UNREACHABLE("typed load must have a payload");
michael@0 2674
michael@0 2675 default:
michael@0 2676 {
michael@0 2677 LArrayPopShiftT *lir = new(alloc()) LArrayPopShiftT(object, temp(), temp());
michael@0 2678 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 2679 }
michael@0 2680 }
michael@0 2681 }
michael@0 2682
michael@0 2683 bool
michael@0 2684 LIRGenerator::visitArrayPush(MArrayPush *ins)
michael@0 2685 {
michael@0 2686 JS_ASSERT(ins->type() == MIRType_Int32);
michael@0 2687
michael@0 2688 LUse object = useRegister(ins->object());
michael@0 2689
michael@0 2690 switch (ins->value()->type()) {
michael@0 2691 case MIRType_Value:
michael@0 2692 {
michael@0 2693 LArrayPushV *lir = new(alloc()) LArrayPushV(object, temp());
michael@0 2694 if (!useBox(lir, LArrayPushV::Value, ins->value()))
michael@0 2695 return false;
michael@0 2696 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 2697 }
michael@0 2698
michael@0 2699 default:
michael@0 2700 {
michael@0 2701 const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
michael@0 2702 LArrayPushT *lir = new(alloc()) LArrayPushT(object, value, temp());
michael@0 2703 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 2704 }
michael@0 2705 }
michael@0 2706 }
michael@0 2707
michael@0 2708 bool
michael@0 2709 LIRGenerator::visitArrayConcat(MArrayConcat *ins)
michael@0 2710 {
michael@0 2711 JS_ASSERT(ins->type() == MIRType_Object);
michael@0 2712 JS_ASSERT(ins->lhs()->type() == MIRType_Object);
michael@0 2713 JS_ASSERT(ins->rhs()->type() == MIRType_Object);
michael@0 2714
michael@0 2715 LArrayConcat *lir = new(alloc()) LArrayConcat(useFixed(ins->lhs(), CallTempReg1),
michael@0 2716 useFixed(ins->rhs(), CallTempReg2),
michael@0 2717 tempFixed(CallTempReg3),
michael@0 2718 tempFixed(CallTempReg4));
michael@0 2719 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 2720 }
michael@0 2721
michael@0 2722 bool
michael@0 2723 LIRGenerator::visitStringSplit(MStringSplit *ins)
michael@0 2724 {
michael@0 2725 JS_ASSERT(ins->type() == MIRType_Object);
michael@0 2726 JS_ASSERT(ins->string()->type() == MIRType_String);
michael@0 2727 JS_ASSERT(ins->separator()->type() == MIRType_String);
michael@0 2728
michael@0 2729 LStringSplit *lir = new(alloc()) LStringSplit(useRegisterAtStart(ins->string()),
michael@0 2730 useRegisterAtStart(ins->separator()));
michael@0 2731 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 2732 }
michael@0 2733
michael@0 2734 bool
michael@0 2735 LIRGenerator::visitLoadTypedArrayElement(MLoadTypedArrayElement *ins)
michael@0 2736 {
michael@0 2737 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2738 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2739
michael@0 2740 const LUse elements = useRegister(ins->elements());
michael@0 2741 const LAllocation index = useRegisterOrConstant(ins->index());
michael@0 2742
michael@0 2743 JS_ASSERT(IsNumberType(ins->type()));
michael@0 2744
michael@0 2745 // We need a temp register for Uint32Array with known double result.
michael@0 2746 LDefinition tempDef = LDefinition::BogusTemp();
michael@0 2747 if (ins->arrayType() == ScalarTypeDescr::TYPE_UINT32 && IsFloatingPointType(ins->type()))
michael@0 2748 tempDef = temp();
michael@0 2749
michael@0 2750 LLoadTypedArrayElement *lir = new(alloc()) LLoadTypedArrayElement(elements, index, tempDef);
michael@0 2751 if (ins->fallible() && !assignSnapshot(lir))
michael@0 2752 return false;
michael@0 2753 return define(lir, ins);
michael@0 2754 }
michael@0 2755
michael@0 2756 bool
michael@0 2757 LIRGenerator::visitClampToUint8(MClampToUint8 *ins)
michael@0 2758 {
michael@0 2759 MDefinition *in = ins->input();
michael@0 2760
michael@0 2761 switch (in->type()) {
michael@0 2762 case MIRType_Boolean:
michael@0 2763 return redefine(ins, in);
michael@0 2764
michael@0 2765 case MIRType_Int32:
michael@0 2766 return defineReuseInput(new(alloc()) LClampIToUint8(useRegisterAtStart(in)), ins, 0);
michael@0 2767
michael@0 2768 case MIRType_Double:
michael@0 2769 return define(new(alloc()) LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)), ins);
michael@0 2770
michael@0 2771 case MIRType_Value:
michael@0 2772 {
michael@0 2773 LClampVToUint8 *lir = new(alloc()) LClampVToUint8(tempDouble());
michael@0 2774 if (!useBox(lir, LClampVToUint8::Input, in))
michael@0 2775 return false;
michael@0 2776 return assignSnapshot(lir) && define(lir, ins) && assignSafepoint(lir, ins);
michael@0 2777 }
michael@0 2778
michael@0 2779 default:
michael@0 2780 MOZ_ASSUME_UNREACHABLE("unexpected type");
michael@0 2781 }
michael@0 2782 }
michael@0 2783
michael@0 2784 bool
michael@0 2785 LIRGenerator::visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole *ins)
michael@0 2786 {
michael@0 2787 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 2788 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2789
michael@0 2790 JS_ASSERT(ins->type() == MIRType_Value);
michael@0 2791
michael@0 2792 const LUse object = useRegister(ins->object());
michael@0 2793 const LAllocation index = useRegisterOrConstant(ins->index());
michael@0 2794
michael@0 2795 LLoadTypedArrayElementHole *lir = new(alloc()) LLoadTypedArrayElementHole(object, index);
michael@0 2796 if (ins->fallible() && !assignSnapshot(lir))
michael@0 2797 return false;
michael@0 2798 return defineBox(lir, ins) && assignSafepoint(lir, ins);
michael@0 2799 }
michael@0 2800
michael@0 2801 bool
michael@0 2802 LIRGenerator::visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic *ins)
michael@0 2803 {
michael@0 2804 LLoadTypedArrayElementStatic *lir =
michael@0 2805 new(alloc()) LLoadTypedArrayElementStatic(useRegisterAtStart(ins->ptr()));
michael@0 2806
michael@0 2807 if (ins->fallible() && !assignSnapshot(lir))
michael@0 2808 return false;
michael@0 2809 return define(lir, ins);
michael@0 2810 }
michael@0 2811
michael@0 2812 bool
michael@0 2813 LIRGenerator::visitStoreTypedArrayElement(MStoreTypedArrayElement *ins)
michael@0 2814 {
michael@0 2815 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2816 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2817
michael@0 2818 if (ins->isFloatArray()) {
michael@0 2819 DebugOnly<bool> optimizeFloat32 = allowFloat32Optimizations();
michael@0 2820 JS_ASSERT_IF(optimizeFloat32 && ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT32,
michael@0 2821 ins->value()->type() == MIRType_Float32);
michael@0 2822 JS_ASSERT_IF(!optimizeFloat32 || ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT64,
michael@0 2823 ins->value()->type() == MIRType_Double);
michael@0 2824 } else {
michael@0 2825 JS_ASSERT(ins->value()->type() == MIRType_Int32);
michael@0 2826 }
michael@0 2827
michael@0 2828 LUse elements = useRegister(ins->elements());
michael@0 2829 LAllocation index = useRegisterOrConstant(ins->index());
michael@0 2830 LAllocation value;
michael@0 2831
michael@0 2832 // For byte arrays, the value has to be in a byte register on x86.
michael@0 2833 if (ins->isByteArray())
michael@0 2834 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
michael@0 2835 else
michael@0 2836 value = useRegisterOrNonDoubleConstant(ins->value());
michael@0 2837 return add(new(alloc()) LStoreTypedArrayElement(elements, index, value), ins);
michael@0 2838 }
michael@0 2839
michael@0 2840 bool
michael@0 2841 LIRGenerator::visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole *ins)
michael@0 2842 {
michael@0 2843 JS_ASSERT(ins->elements()->type() == MIRType_Elements);
michael@0 2844 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2845 JS_ASSERT(ins->length()->type() == MIRType_Int32);
michael@0 2846
michael@0 2847 if (ins->isFloatArray()) {
michael@0 2848 DebugOnly<bool> optimizeFloat32 = allowFloat32Optimizations();
michael@0 2849 JS_ASSERT_IF(optimizeFloat32 && ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT32,
michael@0 2850 ins->value()->type() == MIRType_Float32);
michael@0 2851 JS_ASSERT_IF(!optimizeFloat32 || ins->arrayType() == ScalarTypeDescr::TYPE_FLOAT64,
michael@0 2852 ins->value()->type() == MIRType_Double);
michael@0 2853 } else {
michael@0 2854 JS_ASSERT(ins->value()->type() == MIRType_Int32);
michael@0 2855 }
michael@0 2856
michael@0 2857 LUse elements = useRegister(ins->elements());
michael@0 2858 LAllocation length = useAnyOrConstant(ins->length());
michael@0 2859 LAllocation index = useRegisterOrConstant(ins->index());
michael@0 2860 LAllocation value;
michael@0 2861
michael@0 2862 // For byte arrays, the value has to be in a byte register on x86.
michael@0 2863 if (ins->isByteArray())
michael@0 2864 value = useByteOpRegisterOrNonDoubleConstant(ins->value());
michael@0 2865 else
michael@0 2866 value = useRegisterOrNonDoubleConstant(ins->value());
michael@0 2867 return add(new(alloc()) LStoreTypedArrayElementHole(elements, length, index, value), ins);
michael@0 2868 }
michael@0 2869
michael@0 2870 bool
michael@0 2871 LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot *ins)
michael@0 2872 {
michael@0 2873 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 2874
michael@0 2875 if (ins->type() == MIRType_Value) {
michael@0 2876 LLoadFixedSlotV *lir = new(alloc()) LLoadFixedSlotV(useRegister(ins->object()));
michael@0 2877 return defineBox(lir, ins);
michael@0 2878 }
michael@0 2879
michael@0 2880 LLoadFixedSlotT *lir = new(alloc()) LLoadFixedSlotT(useRegister(ins->object()));
michael@0 2881 return define(lir, ins);
michael@0 2882 }
michael@0 2883
michael@0 2884 bool
michael@0 2885 LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot *ins)
michael@0 2886 {
michael@0 2887 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 2888
michael@0 2889 if (ins->value()->type() == MIRType_Value) {
michael@0 2890 LStoreFixedSlotV *lir = new(alloc()) LStoreFixedSlotV(useRegister(ins->object()));
michael@0 2891
michael@0 2892 if (!useBox(lir, LStoreFixedSlotV::Value, ins->value()))
michael@0 2893 return false;
michael@0 2894 return add(lir, ins);
michael@0 2895 }
michael@0 2896
michael@0 2897 LStoreFixedSlotT *lir = new(alloc()) LStoreFixedSlotT(useRegister(ins->object()),
michael@0 2898 useRegisterOrConstant(ins->value()));
michael@0 2899 return add(lir, ins);
michael@0 2900 }
michael@0 2901
michael@0 2902 bool
michael@0 2903 LIRGenerator::visitGetNameCache(MGetNameCache *ins)
michael@0 2904 {
michael@0 2905 JS_ASSERT(ins->scopeObj()->type() == MIRType_Object);
michael@0 2906
michael@0 2907 LGetNameCache *lir = new(alloc()) LGetNameCache(useRegister(ins->scopeObj()));
michael@0 2908 if (!defineBox(lir, ins))
michael@0 2909 return false;
michael@0 2910 return assignSafepoint(lir, ins);
michael@0 2911 }
michael@0 2912
michael@0 2913 bool
michael@0 2914 LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue *ins)
michael@0 2915 {
michael@0 2916 LCallGetIntrinsicValue *lir = new(alloc()) LCallGetIntrinsicValue();
michael@0 2917 if (!defineReturn(lir, ins))
michael@0 2918 return false;
michael@0 2919 return assignSafepoint(lir, ins);
michael@0 2920 }
michael@0 2921
michael@0 2922 bool
michael@0 2923 LIRGenerator::visitCallsiteCloneCache(MCallsiteCloneCache *ins)
michael@0 2924 {
michael@0 2925 JS_ASSERT(ins->callee()->type() == MIRType_Object);
michael@0 2926
michael@0 2927 LCallsiteCloneCache *lir = new(alloc()) LCallsiteCloneCache(useRegister(ins->callee()));
michael@0 2928 if (!define(lir, ins))
michael@0 2929 return false;
michael@0 2930 return assignSafepoint(lir, ins);
michael@0 2931 }
michael@0 2932
michael@0 2933 bool
michael@0 2934 LIRGenerator::visitGetPropertyCache(MGetPropertyCache *ins)
michael@0 2935 {
michael@0 2936 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 2937 if (ins->type() == MIRType_Value) {
michael@0 2938 LGetPropertyCacheV *lir = new(alloc()) LGetPropertyCacheV(useRegister(ins->object()));
michael@0 2939 if (!defineBox(lir, ins))
michael@0 2940 return false;
michael@0 2941 return assignSafepoint(lir, ins);
michael@0 2942 }
michael@0 2943
michael@0 2944 LGetPropertyCacheT *lir = new(alloc()) LGetPropertyCacheT(useRegister(ins->object()),
michael@0 2945 tempForDispatchCache(ins->type()));
michael@0 2946 if (!define(lir, ins))
michael@0 2947 return false;
michael@0 2948 return assignSafepoint(lir, ins);
michael@0 2949 }
michael@0 2950
michael@0 2951 bool
michael@0 2952 LIRGenerator::visitGetPropertyPolymorphic(MGetPropertyPolymorphic *ins)
michael@0 2953 {
michael@0 2954 JS_ASSERT(ins->obj()->type() == MIRType_Object);
michael@0 2955
michael@0 2956 if (ins->type() == MIRType_Value) {
michael@0 2957 LGetPropertyPolymorphicV *lir = new(alloc()) LGetPropertyPolymorphicV(useRegister(ins->obj()));
michael@0 2958 return assignSnapshot(lir, Bailout_ShapeGuard) && defineBox(lir, ins);
michael@0 2959 }
michael@0 2960
michael@0 2961 LDefinition maybeTemp = (ins->type() == MIRType_Double) ? temp() : LDefinition::BogusTemp();
michael@0 2962 LGetPropertyPolymorphicT *lir = new(alloc()) LGetPropertyPolymorphicT(useRegister(ins->obj()), maybeTemp);
michael@0 2963 return assignSnapshot(lir, Bailout_ShapeGuard) && define(lir, ins);
michael@0 2964 }
michael@0 2965
michael@0 2966 bool
michael@0 2967 LIRGenerator::visitSetPropertyPolymorphic(MSetPropertyPolymorphic *ins)
michael@0 2968 {
michael@0 2969 JS_ASSERT(ins->obj()->type() == MIRType_Object);
michael@0 2970
michael@0 2971 if (ins->value()->type() == MIRType_Value) {
michael@0 2972 LSetPropertyPolymorphicV *lir = new(alloc()) LSetPropertyPolymorphicV(useRegister(ins->obj()), temp());
michael@0 2973 if (!useBox(lir, LSetPropertyPolymorphicV::Value, ins->value()))
michael@0 2974 return false;
michael@0 2975 return assignSnapshot(lir, Bailout_ShapeGuard) && add(lir, ins);
michael@0 2976 }
michael@0 2977
michael@0 2978 LAllocation value = useRegisterOrConstant(ins->value());
michael@0 2979 LSetPropertyPolymorphicT *lir =
michael@0 2980 new(alloc()) LSetPropertyPolymorphicT(useRegister(ins->obj()), value, ins->value()->type(), temp());
michael@0 2981 return assignSnapshot(lir, Bailout_ShapeGuard) && add(lir, ins);
michael@0 2982 }
michael@0 2983
michael@0 2984 bool
michael@0 2985 LIRGenerator::visitGetElementCache(MGetElementCache *ins)
michael@0 2986 {
michael@0 2987 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 2988
michael@0 2989 if (ins->type() == MIRType_Value) {
michael@0 2990 JS_ASSERT(ins->index()->type() == MIRType_Value);
michael@0 2991 LGetElementCacheV *lir = new(alloc()) LGetElementCacheV(useRegister(ins->object()));
michael@0 2992 if (!useBox(lir, LGetElementCacheV::Index, ins->index()))
michael@0 2993 return false;
michael@0 2994 return defineBox(lir, ins) && assignSafepoint(lir, ins);
michael@0 2995 }
michael@0 2996
michael@0 2997 JS_ASSERT(ins->index()->type() == MIRType_Int32);
michael@0 2998 LGetElementCacheT *lir = new(alloc()) LGetElementCacheT(useRegister(ins->object()),
michael@0 2999 useRegister(ins->index()),
michael@0 3000 tempForDispatchCache(ins->type()));
michael@0 3001 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 3002 }
michael@0 3003
michael@0 3004 bool
michael@0 3005 LIRGenerator::visitBindNameCache(MBindNameCache *ins)
michael@0 3006 {
michael@0 3007 JS_ASSERT(ins->scopeChain()->type() == MIRType_Object);
michael@0 3008 JS_ASSERT(ins->type() == MIRType_Object);
michael@0 3009
michael@0 3010 LBindNameCache *lir = new(alloc()) LBindNameCache(useRegister(ins->scopeChain()));
michael@0 3011 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 3012 }
michael@0 3013
michael@0 3014 bool
michael@0 3015 LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity *ins)
michael@0 3016 {
michael@0 3017 LGuardObjectIdentity *guard = new(alloc()) LGuardObjectIdentity(useRegister(ins->obj()));
michael@0 3018 return assignSnapshot(guard) && add(guard, ins) && redefine(ins, ins->obj());
michael@0 3019 }
michael@0 3020
michael@0 3021 bool
michael@0 3022 LIRGenerator::visitGuardClass(MGuardClass *ins)
michael@0 3023 {
michael@0 3024 LDefinition t = temp();
michael@0 3025 LGuardClass *guard = new(alloc()) LGuardClass(useRegister(ins->obj()), t);
michael@0 3026 return assignSnapshot(guard) && add(guard, ins);
michael@0 3027 }
michael@0 3028
michael@0 3029 bool
michael@0 3030 LIRGenerator::visitGuardObject(MGuardObject *ins)
michael@0 3031 {
michael@0 3032 // The type policy does all the work, so at this point the input
michael@0 3033 // is guaranteed to be an object.
michael@0 3034 JS_ASSERT(ins->input()->type() == MIRType_Object);
michael@0 3035 return redefine(ins, ins->input());
michael@0 3036 }
michael@0 3037
michael@0 3038 bool
michael@0 3039 LIRGenerator::visitGuardString(MGuardString *ins)
michael@0 3040 {
michael@0 3041 // The type policy does all the work, so at this point the input
michael@0 3042 // is guaranteed to be a string.
michael@0 3043 JS_ASSERT(ins->input()->type() == MIRType_String);
michael@0 3044 return redefine(ins, ins->input());
michael@0 3045 }
michael@0 3046
michael@0 3047 bool
michael@0 3048 LIRGenerator::visitAssertRange(MAssertRange *ins)
michael@0 3049 {
michael@0 3050 MDefinition *input = ins->input();
michael@0 3051 LInstruction *lir = nullptr;
michael@0 3052
michael@0 3053 switch (input->type()) {
michael@0 3054 case MIRType_Boolean:
michael@0 3055 case MIRType_Int32:
michael@0 3056 lir = new(alloc()) LAssertRangeI(useRegisterAtStart(input));
michael@0 3057 break;
michael@0 3058
michael@0 3059 case MIRType_Double:
michael@0 3060 lir = new(alloc()) LAssertRangeD(useRegister(input), tempDouble());
michael@0 3061 break;
michael@0 3062
michael@0 3063 case MIRType_Float32:
michael@0 3064 lir = new(alloc()) LAssertRangeF(useRegister(input), tempFloat32());
michael@0 3065 break;
michael@0 3066
michael@0 3067 case MIRType_Value:
michael@0 3068 lir = new(alloc()) LAssertRangeV(tempToUnbox(), tempDouble(), tempDouble());
michael@0 3069 if (!useBox(lir, LAssertRangeV::Input, input))
michael@0 3070 return false;
michael@0 3071 break;
michael@0 3072
michael@0 3073 default:
michael@0 3074 MOZ_ASSUME_UNREACHABLE("Unexpected Range for MIRType");
michael@0 3075 break;
michael@0 3076 }
michael@0 3077
michael@0 3078 lir->setMir(ins);
michael@0 3079 return add(lir);
michael@0 3080 }
michael@0 3081
michael@0 3082 bool
michael@0 3083 LIRGenerator::visitCallGetProperty(MCallGetProperty *ins)
michael@0 3084 {
michael@0 3085 LCallGetProperty *lir = new(alloc()) LCallGetProperty();
michael@0 3086 if (!useBoxAtStart(lir, LCallGetProperty::Value, ins->value()))
michael@0 3087 return false;
michael@0 3088 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 3089 }
michael@0 3090
michael@0 3091 bool
michael@0 3092 LIRGenerator::visitCallGetElement(MCallGetElement *ins)
michael@0 3093 {
michael@0 3094 JS_ASSERT(ins->lhs()->type() == MIRType_Value);
michael@0 3095 JS_ASSERT(ins->rhs()->type() == MIRType_Value);
michael@0 3096
michael@0 3097 LCallGetElement *lir = new(alloc()) LCallGetElement();
michael@0 3098 if (!useBoxAtStart(lir, LCallGetElement::LhsInput, ins->lhs()))
michael@0 3099 return false;
michael@0 3100 if (!useBoxAtStart(lir, LCallGetElement::RhsInput, ins->rhs()))
michael@0 3101 return false;
michael@0 3102 if (!defineReturn(lir, ins))
michael@0 3103 return false;
michael@0 3104 return assignSafepoint(lir, ins);
michael@0 3105 }
michael@0 3106
michael@0 3107 bool
michael@0 3108 LIRGenerator::visitCallSetProperty(MCallSetProperty *ins)
michael@0 3109 {
michael@0 3110 LInstruction *lir = new(alloc()) LCallSetProperty(useRegisterAtStart(ins->object()));
michael@0 3111 if (!useBoxAtStart(lir, LCallSetProperty::Value, ins->value()))
michael@0 3112 return false;
michael@0 3113 if (!add(lir, ins))
michael@0 3114 return false;
michael@0 3115 return assignSafepoint(lir, ins);
michael@0 3116 }
michael@0 3117
michael@0 3118 bool
michael@0 3119 LIRGenerator::visitDeleteProperty(MDeleteProperty *ins)
michael@0 3120 {
michael@0 3121 LCallDeleteProperty *lir = new(alloc()) LCallDeleteProperty();
michael@0 3122 if(!useBoxAtStart(lir, LCallDeleteProperty::Value, ins->value()))
michael@0 3123 return false;
michael@0 3124 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 3125 }
michael@0 3126
michael@0 3127 bool
michael@0 3128 LIRGenerator::visitDeleteElement(MDeleteElement *ins)
michael@0 3129 {
michael@0 3130 LCallDeleteElement *lir = new(alloc()) LCallDeleteElement();
michael@0 3131 if(!useBoxAtStart(lir, LCallDeleteElement::Value, ins->value()))
michael@0 3132 return false;
michael@0 3133 if(!useBoxAtStart(lir, LCallDeleteElement::Index, ins->index()))
michael@0 3134 return false;
michael@0 3135 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 3136 }
michael@0 3137
michael@0 3138 bool
michael@0 3139 LIRGenerator::visitSetPropertyCache(MSetPropertyCache *ins)
michael@0 3140 {
michael@0 3141 LUse obj = useRegisterAtStart(ins->object());
michael@0 3142 LDefinition slots = tempCopy(ins->object(), 0);
michael@0 3143 LDefinition dispatchTemp = tempForDispatchCache();
michael@0 3144
michael@0 3145 LInstruction *lir;
michael@0 3146 if (ins->value()->type() == MIRType_Value) {
michael@0 3147 lir = new(alloc()) LSetPropertyCacheV(obj, slots, dispatchTemp);
michael@0 3148 if (!useBox(lir, LSetPropertyCacheV::Value, ins->value()))
michael@0 3149 return false;
michael@0 3150 } else {
michael@0 3151 LAllocation value = useRegisterOrConstant(ins->value());
michael@0 3152 lir = new(alloc()) LSetPropertyCacheT(obj, slots, value, dispatchTemp, ins->value()->type());
michael@0 3153 }
michael@0 3154
michael@0 3155 if (!add(lir, ins))
michael@0 3156 return false;
michael@0 3157
michael@0 3158 return assignSafepoint(lir, ins);
michael@0 3159 }
michael@0 3160
michael@0 3161 bool
michael@0 3162 LIRGenerator::visitSetElementCache(MSetElementCache *ins)
michael@0 3163 {
michael@0 3164 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 3165 JS_ASSERT(ins->index()->type() == MIRType_Value);
michael@0 3166
michael@0 3167 // Due to lack of registers on x86, we reuse the object register as a
michael@0 3168 // temporary. This register may be used in a 1-byte store, which on x86
michael@0 3169 // again has constraints; thus the use of |useByteOpRegister| over
michael@0 3170 // |useRegister| below.
michael@0 3171 LInstruction *lir;
michael@0 3172 if (ins->value()->type() == MIRType_Value) {
michael@0 3173 lir = new(alloc()) LSetElementCacheV(useByteOpRegister(ins->object()), tempToUnbox(),
michael@0 3174 temp(), tempDouble());
michael@0 3175
michael@0 3176 if (!useBox(lir, LSetElementCacheV::Index, ins->index()))
michael@0 3177 return false;
michael@0 3178 if (!useBox(lir, LSetElementCacheV::Value, ins->value()))
michael@0 3179 return false;
michael@0 3180 } else {
michael@0 3181 lir = new(alloc()) LSetElementCacheT(useByteOpRegister(ins->object()),
michael@0 3182 useRegisterOrConstant(ins->value()),
michael@0 3183 tempToUnbox(), temp(), tempDouble());
michael@0 3184
michael@0 3185 if (!useBox(lir, LSetElementCacheT::Index, ins->index()))
michael@0 3186 return false;
michael@0 3187 }
michael@0 3188
michael@0 3189 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 3190 }
michael@0 3191
michael@0 3192 bool
michael@0 3193 LIRGenerator::visitCallSetElement(MCallSetElement *ins)
michael@0 3194 {
michael@0 3195 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 3196 JS_ASSERT(ins->index()->type() == MIRType_Value);
michael@0 3197 JS_ASSERT(ins->value()->type() == MIRType_Value);
michael@0 3198
michael@0 3199 LCallSetElement *lir = new(alloc()) LCallSetElement();
michael@0 3200 lir->setOperand(0, useRegisterAtStart(ins->object()));
michael@0 3201 if (!useBoxAtStart(lir, LCallSetElement::Index, ins->index()))
michael@0 3202 return false;
michael@0 3203 if (!useBoxAtStart(lir, LCallSetElement::Value, ins->value()))
michael@0 3204 return false;
michael@0 3205 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 3206 }
michael@0 3207
michael@0 3208 bool
michael@0 3209 LIRGenerator::visitCallInitElementArray(MCallInitElementArray *ins)
michael@0 3210 {
michael@0 3211 LCallInitElementArray *lir = new(alloc()) LCallInitElementArray();
michael@0 3212 lir->setOperand(0, useRegisterAtStart(ins->object()));
michael@0 3213 if (!useBoxAtStart(lir, LCallInitElementArray::Value, ins->value()))
michael@0 3214 return false;
michael@0 3215 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 3216 }
michael@0 3217
michael@0 3218 bool
michael@0 3219 LIRGenerator::visitIteratorStart(MIteratorStart *ins)
michael@0 3220 {
michael@0 3221 // Call a stub if this is not a simple for-in loop.
michael@0 3222 if (ins->flags() != JSITER_ENUMERATE) {
michael@0 3223 LCallIteratorStart *lir = new(alloc()) LCallIteratorStart(useRegisterAtStart(ins->object()));
michael@0 3224 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 3225 }
michael@0 3226
michael@0 3227 LIteratorStart *lir = new(alloc()) LIteratorStart(useRegister(ins->object()), temp(), temp(), temp());
michael@0 3228 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 3229 }
michael@0 3230
michael@0 3231 bool
michael@0 3232 LIRGenerator::visitIteratorNext(MIteratorNext *ins)
michael@0 3233 {
michael@0 3234 LIteratorNext *lir = new(alloc()) LIteratorNext(useRegister(ins->iterator()), temp());
michael@0 3235 return defineBox(lir, ins) && assignSafepoint(lir, ins);
michael@0 3236 }
michael@0 3237
michael@0 3238 bool
michael@0 3239 LIRGenerator::visitIteratorMore(MIteratorMore *ins)
michael@0 3240 {
michael@0 3241 LIteratorMore *lir = new(alloc()) LIteratorMore(useRegister(ins->iterator()), temp());
michael@0 3242 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 3243 }
michael@0 3244
michael@0 3245 bool
michael@0 3246 LIRGenerator::visitIteratorEnd(MIteratorEnd *ins)
michael@0 3247 {
michael@0 3248 LIteratorEnd *lir = new(alloc()) LIteratorEnd(useRegister(ins->iterator()), temp(), temp(), temp());
michael@0 3249 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 3250 }
michael@0 3251
michael@0 3252 bool
michael@0 3253 LIRGenerator::visitStringLength(MStringLength *ins)
michael@0 3254 {
michael@0 3255 JS_ASSERT(ins->string()->type() == MIRType_String);
michael@0 3256 return define(new(alloc()) LStringLength(useRegisterAtStart(ins->string())), ins);
michael@0 3257 }
michael@0 3258
michael@0 3259 bool
michael@0 3260 LIRGenerator::visitArgumentsLength(MArgumentsLength *ins)
michael@0 3261 {
michael@0 3262 return define(new(alloc()) LArgumentsLength(), ins);
michael@0 3263 }
michael@0 3264
michael@0 3265 bool
michael@0 3266 LIRGenerator::visitGetFrameArgument(MGetFrameArgument *ins)
michael@0 3267 {
michael@0 3268 LGetFrameArgument *lir = new(alloc()) LGetFrameArgument(useRegisterOrConstant(ins->index()));
michael@0 3269 return defineBox(lir, ins);
michael@0 3270 }
michael@0 3271
michael@0 3272 bool
michael@0 3273 LIRGenerator::visitSetFrameArgument(MSetFrameArgument *ins)
michael@0 3274 {
michael@0 3275 MDefinition *input = ins->input();
michael@0 3276
michael@0 3277 if (input->type() == MIRType_Value) {
michael@0 3278 LSetFrameArgumentV *lir = new(alloc()) LSetFrameArgumentV();
michael@0 3279 if (!useBox(lir, LSetFrameArgumentV::Input, input))
michael@0 3280 return false;
michael@0 3281 return add(lir, ins);
michael@0 3282 }
michael@0 3283
michael@0 3284 if (input->type() == MIRType_Undefined || input->type() == MIRType_Null) {
michael@0 3285 Value val = input->type() == MIRType_Undefined ? UndefinedValue() : NullValue();
michael@0 3286 LSetFrameArgumentC *lir = new(alloc()) LSetFrameArgumentC(val);
michael@0 3287 return add(lir, ins);
michael@0 3288 }
michael@0 3289
michael@0 3290 LSetFrameArgumentT *lir = new(alloc()) LSetFrameArgumentT(useRegister(input));
michael@0 3291 return add(lir, ins);
michael@0 3292 }
michael@0 3293
michael@0 3294 bool
michael@0 3295 LIRGenerator::visitRunOncePrologue(MRunOncePrologue *ins)
michael@0 3296 {
michael@0 3297 LRunOncePrologue *lir = new(alloc()) LRunOncePrologue;
michael@0 3298 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 3299 }
michael@0 3300
michael@0 3301 bool
michael@0 3302 LIRGenerator::visitRest(MRest *ins)
michael@0 3303 {
michael@0 3304 JS_ASSERT(ins->numActuals()->type() == MIRType_Int32);
michael@0 3305
michael@0 3306 LRest *lir = new(alloc()) LRest(useFixed(ins->numActuals(), CallTempReg0),
michael@0 3307 tempFixed(CallTempReg1),
michael@0 3308 tempFixed(CallTempReg2),
michael@0 3309 tempFixed(CallTempReg3));
michael@0 3310 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 3311 }
michael@0 3312
michael@0 3313 bool
michael@0 3314 LIRGenerator::visitRestPar(MRestPar *ins)
michael@0 3315 {
michael@0 3316 JS_ASSERT(ins->numActuals()->type() == MIRType_Int32);
michael@0 3317
michael@0 3318 LRestPar *lir = new(alloc()) LRestPar(useFixed(ins->forkJoinContext(), CallTempReg0),
michael@0 3319 useFixed(ins->numActuals(), CallTempReg1),
michael@0 3320 tempFixed(CallTempReg2),
michael@0 3321 tempFixed(CallTempReg3),
michael@0 3322 tempFixed(CallTempReg4));
michael@0 3323 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 3324 }
michael@0 3325
michael@0 3326 bool
michael@0 3327 LIRGenerator::visitThrow(MThrow *ins)
michael@0 3328 {
michael@0 3329 MDefinition *value = ins->getOperand(0);
michael@0 3330 JS_ASSERT(value->type() == MIRType_Value);
michael@0 3331
michael@0 3332 LThrow *lir = new(alloc()) LThrow;
michael@0 3333 if (!useBoxAtStart(lir, LThrow::Value, value))
michael@0 3334 return false;
michael@0 3335 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 3336 }
michael@0 3337
michael@0 3338 bool
michael@0 3339 LIRGenerator::visitIn(MIn *ins)
michael@0 3340 {
michael@0 3341 MDefinition *lhs = ins->lhs();
michael@0 3342 MDefinition *rhs = ins->rhs();
michael@0 3343
michael@0 3344 JS_ASSERT(lhs->type() == MIRType_Value);
michael@0 3345 JS_ASSERT(rhs->type() == MIRType_Object);
michael@0 3346
michael@0 3347 LIn *lir = new(alloc()) LIn(useRegisterAtStart(rhs));
michael@0 3348 if (!useBoxAtStart(lir, LIn::LHS, lhs))
michael@0 3349 return false;
michael@0 3350 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 3351 }
michael@0 3352
michael@0 3353 bool
michael@0 3354 LIRGenerator::visitInstanceOf(MInstanceOf *ins)
michael@0 3355 {
michael@0 3356 MDefinition *lhs = ins->getOperand(0);
michael@0 3357
michael@0 3358 JS_ASSERT(lhs->type() == MIRType_Value || lhs->type() == MIRType_Object);
michael@0 3359
michael@0 3360 if (lhs->type() == MIRType_Object) {
michael@0 3361 LInstanceOfO *lir = new(alloc()) LInstanceOfO(useRegister(lhs));
michael@0 3362 return define(lir, ins) && assignSafepoint(lir, ins);
michael@0 3363 }
michael@0 3364
michael@0 3365 LInstanceOfV *lir = new(alloc()) LInstanceOfV();
michael@0 3366 return useBox(lir, LInstanceOfV::LHS, lhs) && define(lir, ins) && assignSafepoint(lir, ins);
michael@0 3367 }
michael@0 3368
michael@0 3369 bool
michael@0 3370 LIRGenerator::visitCallInstanceOf(MCallInstanceOf *ins)
michael@0 3371 {
michael@0 3372 MDefinition *lhs = ins->lhs();
michael@0 3373 MDefinition *rhs = ins->rhs();
michael@0 3374
michael@0 3375 JS_ASSERT(lhs->type() == MIRType_Value);
michael@0 3376 JS_ASSERT(rhs->type() == MIRType_Object);
michael@0 3377
michael@0 3378 LCallInstanceOf *lir = new(alloc()) LCallInstanceOf(useRegisterAtStart(rhs));
michael@0 3379 if (!useBoxAtStart(lir, LCallInstanceOf::LHS, lhs))
michael@0 3380 return false;
michael@0 3381 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 3382 }
michael@0 3383
michael@0 3384 bool
michael@0 3385 LIRGenerator::visitProfilerStackOp(MProfilerStackOp *ins)
michael@0 3386 {
michael@0 3387 LProfilerStackOp *lir = new(alloc()) LProfilerStackOp(temp());
michael@0 3388 if (!add(lir, ins))
michael@0 3389 return false;
michael@0 3390 // If slow assertions are enabled, then this node will result in a callVM
michael@0 3391 // out to a C++ function for the assertions, so we will need a safepoint.
michael@0 3392 return !gen->options.spsSlowAssertionsEnabled() || assignSafepoint(lir, ins);
michael@0 3393 }
michael@0 3394
michael@0 3395 bool
michael@0 3396 LIRGenerator::visitIsCallable(MIsCallable *ins)
michael@0 3397 {
michael@0 3398 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 3399 JS_ASSERT(ins->type() == MIRType_Boolean);
michael@0 3400 return define(new(alloc()) LIsCallable(useRegister(ins->object())), ins);
michael@0 3401 }
michael@0 3402
michael@0 3403 bool
michael@0 3404 LIRGenerator::visitHaveSameClass(MHaveSameClass *ins)
michael@0 3405 {
michael@0 3406 MDefinition *lhs = ins->lhs();
michael@0 3407 MDefinition *rhs = ins->rhs();
michael@0 3408
michael@0 3409 JS_ASSERT(lhs->type() == MIRType_Object);
michael@0 3410 JS_ASSERT(rhs->type() == MIRType_Object);
michael@0 3411
michael@0 3412 return define(new(alloc()) LHaveSameClass(useRegister(lhs), useRegister(rhs), temp()), ins);
michael@0 3413 }
michael@0 3414
michael@0 3415 bool
michael@0 3416 LIRGenerator::visitHasClass(MHasClass *ins)
michael@0 3417 {
michael@0 3418 JS_ASSERT(ins->object()->type() == MIRType_Object);
michael@0 3419 JS_ASSERT(ins->type() == MIRType_Boolean);
michael@0 3420 return define(new(alloc()) LHasClass(useRegister(ins->object())), ins);
michael@0 3421 }
michael@0 3422
michael@0 3423 bool
michael@0 3424 LIRGenerator::visitAsmJSLoadGlobalVar(MAsmJSLoadGlobalVar *ins)
michael@0 3425 {
michael@0 3426 return define(new(alloc()) LAsmJSLoadGlobalVar, ins);
michael@0 3427 }
michael@0 3428
michael@0 3429 bool
michael@0 3430 LIRGenerator::visitAsmJSStoreGlobalVar(MAsmJSStoreGlobalVar *ins)
michael@0 3431 {
michael@0 3432 return add(new(alloc()) LAsmJSStoreGlobalVar(useRegisterAtStart(ins->value())), ins);
michael@0 3433 }
michael@0 3434
michael@0 3435 bool
michael@0 3436 LIRGenerator::visitAsmJSLoadFFIFunc(MAsmJSLoadFFIFunc *ins)
michael@0 3437 {
michael@0 3438 return define(new(alloc()) LAsmJSLoadFFIFunc, ins);
michael@0 3439 }
michael@0 3440
michael@0 3441 bool
michael@0 3442 LIRGenerator::visitAsmJSParameter(MAsmJSParameter *ins)
michael@0 3443 {
michael@0 3444 ABIArg abi = ins->abi();
michael@0 3445 if (abi.argInRegister())
michael@0 3446 return defineFixed(new(alloc()) LAsmJSParameter, ins, LAllocation(abi.reg()));
michael@0 3447
michael@0 3448 JS_ASSERT(IsNumberType(ins->type()));
michael@0 3449 return defineFixed(new(alloc()) LAsmJSParameter, ins, LArgument(abi.offsetFromArgBase()));
michael@0 3450 }
michael@0 3451
michael@0 3452 bool
michael@0 3453 LIRGenerator::visitAsmJSReturn(MAsmJSReturn *ins)
michael@0 3454 {
michael@0 3455 MDefinition *rval = ins->getOperand(0);
michael@0 3456 LAsmJSReturn *lir = new(alloc()) LAsmJSReturn;
michael@0 3457 if (IsFloatingPointType(rval->type()))
michael@0 3458 lir->setOperand(0, useFixed(rval, ReturnFloatReg));
michael@0 3459 else if (rval->type() == MIRType_Int32)
michael@0 3460 lir->setOperand(0, useFixed(rval, ReturnReg));
michael@0 3461 else
michael@0 3462 MOZ_ASSUME_UNREACHABLE("Unexpected asm.js return type");
michael@0 3463 return add(lir);
michael@0 3464 }
michael@0 3465
michael@0 3466 bool
michael@0 3467 LIRGenerator::visitAsmJSVoidReturn(MAsmJSVoidReturn *ins)
michael@0 3468 {
michael@0 3469 return add(new(alloc()) LAsmJSVoidReturn);
michael@0 3470 }
michael@0 3471
michael@0 3472 bool
michael@0 3473 LIRGenerator::visitAsmJSPassStackArg(MAsmJSPassStackArg *ins)
michael@0 3474 {
michael@0 3475 if (IsFloatingPointType(ins->arg()->type())) {
michael@0 3476 JS_ASSERT(!ins->arg()->isEmittedAtUses());
michael@0 3477 return add(new(alloc()) LAsmJSPassStackArg(useRegisterAtStart(ins->arg())), ins);
michael@0 3478 }
michael@0 3479
michael@0 3480 return add(new(alloc()) LAsmJSPassStackArg(useRegisterOrConstantAtStart(ins->arg())), ins);
michael@0 3481 }
michael@0 3482
michael@0 3483 bool
michael@0 3484 LIRGenerator::visitAsmJSCall(MAsmJSCall *ins)
michael@0 3485 {
michael@0 3486 gen->setPerformsAsmJSCall();
michael@0 3487
michael@0 3488 LAllocation *args = gen->allocate<LAllocation>(ins->numOperands());
michael@0 3489 if (!args)
michael@0 3490 return false;
michael@0 3491
michael@0 3492 for (unsigned i = 0; i < ins->numArgs(); i++)
michael@0 3493 args[i] = useFixed(ins->getOperand(i), ins->registerForArg(i));
michael@0 3494
michael@0 3495 if (ins->callee().which() == MAsmJSCall::Callee::Dynamic)
michael@0 3496 args[ins->dynamicCalleeOperandIndex()] = useFixed(ins->callee().dynamic(), CallTempReg0);
michael@0 3497
michael@0 3498 LInstruction *lir = new(alloc()) LAsmJSCall(args, ins->numOperands());
michael@0 3499 if (ins->type() == MIRType_None) {
michael@0 3500 return add(lir, ins);
michael@0 3501 }
michael@0 3502 return defineReturn(lir, ins);
michael@0 3503 }
michael@0 3504
michael@0 3505 bool
michael@0 3506 LIRGenerator::visitSetDOMProperty(MSetDOMProperty *ins)
michael@0 3507 {
michael@0 3508 MDefinition *val = ins->value();
michael@0 3509
michael@0 3510 Register cxReg, objReg, privReg, valueReg;
michael@0 3511 GetTempRegForIntArg(0, 0, &cxReg);
michael@0 3512 GetTempRegForIntArg(1, 0, &objReg);
michael@0 3513 GetTempRegForIntArg(2, 0, &privReg);
michael@0 3514 GetTempRegForIntArg(3, 0, &valueReg);
michael@0 3515 LSetDOMProperty *lir = new(alloc()) LSetDOMProperty(tempFixed(cxReg),
michael@0 3516 useFixed(ins->object(), objReg),
michael@0 3517 tempFixed(privReg),
michael@0 3518 tempFixed(valueReg));
michael@0 3519
michael@0 3520 // Keep using GetTempRegForIntArg, since we want to make sure we
michael@0 3521 // don't clobber registers we're already using.
michael@0 3522 Register tempReg1, tempReg2;
michael@0 3523 GetTempRegForIntArg(4, 0, &tempReg1);
michael@0 3524 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2);
michael@0 3525 MOZ_ASSERT(ok, "How can we not have six temp registers?");
michael@0 3526 if (!useBoxFixed(lir, LSetDOMProperty::Value, val, tempReg1, tempReg2))
michael@0 3527 return false;
michael@0 3528
michael@0 3529 return add(lir, ins) && assignSafepoint(lir, ins);
michael@0 3530 }
michael@0 3531
michael@0 3532 bool
michael@0 3533 LIRGenerator::visitGetDOMProperty(MGetDOMProperty *ins)
michael@0 3534 {
michael@0 3535 Register cxReg, objReg, privReg, valueReg;
michael@0 3536 GetTempRegForIntArg(0, 0, &cxReg);
michael@0 3537 GetTempRegForIntArg(1, 0, &objReg);
michael@0 3538 GetTempRegForIntArg(2, 0, &privReg);
michael@0 3539 mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg);
michael@0 3540 MOZ_ASSERT(ok, "How can we not have four temp registers?");
michael@0 3541 LGetDOMProperty *lir = new(alloc()) LGetDOMProperty(tempFixed(cxReg),
michael@0 3542 useFixed(ins->object(), objReg),
michael@0 3543 tempFixed(privReg),
michael@0 3544 tempFixed(valueReg));
michael@0 3545
michael@0 3546 return defineReturn(lir, ins) && assignSafepoint(lir, ins);
michael@0 3547 }
michael@0 3548
michael@0 3549 bool
michael@0 3550 LIRGenerator::visitGetDOMMember(MGetDOMMember *ins)
michael@0 3551 {
michael@0 3552 MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
michael@0 3553 // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
michael@0 3554 // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
michael@0 3555 // value can in fact change as a result of DOM setters and method calls.
michael@0 3556 MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
michael@0 3557 "Member gets had better not alias the world");
michael@0 3558 LGetDOMMember *lir =
michael@0 3559 new(alloc()) LGetDOMMember(useRegister(ins->object()));
michael@0 3560 return defineBox(lir, ins);
michael@0 3561 }
michael@0 3562
michael@0 3563 bool
michael@0 3564 LIRGenerator::visitRecompileCheck(MRecompileCheck *ins)
michael@0 3565 {
michael@0 3566 LRecompileCheck *lir = new(alloc()) LRecompileCheck(temp());
michael@0 3567 if (!add(lir, ins))
michael@0 3568 return false;
michael@0 3569 return assignSafepoint(lir, ins);
michael@0 3570 }
michael@0 3571
michael@0 3572 static void
michael@0 3573 SpewResumePoint(MBasicBlock *block, MInstruction *ins, MResumePoint *resumePoint)
michael@0 3574 {
michael@0 3575 fprintf(IonSpewFile, "Current resume point %p details:\n", (void *)resumePoint);
michael@0 3576 fprintf(IonSpewFile, " frame count: %u\n", resumePoint->frameCount());
michael@0 3577
michael@0 3578 if (ins) {
michael@0 3579 fprintf(IonSpewFile, " taken after: ");
michael@0 3580 ins->printName(IonSpewFile);
michael@0 3581 } else {
michael@0 3582 fprintf(IonSpewFile, " taken at block %d entry", block->id());
michael@0 3583 }
michael@0 3584 fprintf(IonSpewFile, "\n");
michael@0 3585
michael@0 3586 fprintf(IonSpewFile, " pc: %p (script: %p, offset: %d)\n",
michael@0 3587 (void *)resumePoint->pc(),
michael@0 3588 (void *)resumePoint->block()->info().script(),
michael@0 3589 int(resumePoint->block()->info().script()->pcToOffset(resumePoint->pc())));
michael@0 3590
michael@0 3591 for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) {
michael@0 3592 MDefinition *in = resumePoint->getOperand(i);
michael@0 3593 fprintf(IonSpewFile, " slot%u: ", (unsigned)i);
michael@0 3594 in->printName(IonSpewFile);
michael@0 3595 fprintf(IonSpewFile, "\n");
michael@0 3596 }
michael@0 3597 }
michael@0 3598
michael@0 3599 bool
michael@0 3600 LIRGenerator::visitInstruction(MInstruction *ins)
michael@0 3601 {
michael@0 3602 if (!gen->ensureBallast())
michael@0 3603 return false;
michael@0 3604 if (!ins->accept(this))
michael@0 3605 return false;
michael@0 3606
michael@0 3607 if (ins->possiblyCalls())
michael@0 3608 gen->setPerformsCall();
michael@0 3609
michael@0 3610 if (ins->resumePoint())
michael@0 3611 updateResumeState(ins);
michael@0 3612
michael@0 3613 if (gen->errored())
michael@0 3614 return false;
michael@0 3615 #ifdef DEBUG
michael@0 3616 ins->setInWorklistUnchecked();
michael@0 3617 #endif
michael@0 3618
michael@0 3619 // If no safepoint was created, there's no need for an OSI point.
michael@0 3620 if (LOsiPoint *osiPoint = popOsiPoint()) {
michael@0 3621 if (!add(osiPoint))
michael@0 3622 return false;
michael@0 3623 }
michael@0 3624
michael@0 3625 return true;
michael@0 3626 }
michael@0 3627
michael@0 3628 bool
michael@0 3629 LIRGenerator::definePhis()
michael@0 3630 {
michael@0 3631 size_t lirIndex = 0;
michael@0 3632 MBasicBlock *block = current->mir();
michael@0 3633 for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
michael@0 3634 if (phi->type() == MIRType_Value) {
michael@0 3635 if (!defineUntypedPhi(*phi, lirIndex))
michael@0 3636 return false;
michael@0 3637 lirIndex += BOX_PIECES;
michael@0 3638 } else {
michael@0 3639 if (!defineTypedPhi(*phi, lirIndex))
michael@0 3640 return false;
michael@0 3641 lirIndex += 1;
michael@0 3642 }
michael@0 3643 }
michael@0 3644 return true;
michael@0 3645 }
michael@0 3646
michael@0 3647 void
michael@0 3648 LIRGenerator::updateResumeState(MInstruction *ins)
michael@0 3649 {
michael@0 3650 lastResumePoint_ = ins->resumePoint();
michael@0 3651 if (IonSpewEnabled(IonSpew_Snapshots) && lastResumePoint_)
michael@0 3652 SpewResumePoint(nullptr, ins, lastResumePoint_);
michael@0 3653 }
michael@0 3654
michael@0 3655 void
michael@0 3656 LIRGenerator::updateResumeState(MBasicBlock *block)
michael@0 3657 {
michael@0 3658 lastResumePoint_ = block->entryResumePoint();
michael@0 3659 if (IonSpewEnabled(IonSpew_Snapshots) && lastResumePoint_)
michael@0 3660 SpewResumePoint(block, nullptr, lastResumePoint_);
michael@0 3661 }
michael@0 3662
michael@0 3663 bool
michael@0 3664 LIRGenerator::visitBlock(MBasicBlock *block)
michael@0 3665 {
michael@0 3666 current = block->lir();
michael@0 3667 updateResumeState(block);
michael@0 3668
michael@0 3669 if (!definePhis())
michael@0 3670 return false;
michael@0 3671
michael@0 3672 if (gen->optimizationInfo().registerAllocator() == RegisterAllocator_LSRA) {
michael@0 3673 if (!add(new(alloc()) LLabel()))
michael@0 3674 return false;
michael@0 3675 }
michael@0 3676
michael@0 3677 for (MInstructionIterator iter = block->begin(); *iter != block->lastIns(); iter++) {
michael@0 3678 if (!visitInstruction(*iter))
michael@0 3679 return false;
michael@0 3680 }
michael@0 3681
michael@0 3682 if (block->successorWithPhis()) {
michael@0 3683 // If we have a successor with phis, lower the phi input now that we
michael@0 3684 // are approaching the join point.
michael@0 3685 MBasicBlock *successor = block->successorWithPhis();
michael@0 3686 uint32_t position = block->positionInPhiSuccessor();
michael@0 3687 size_t lirIndex = 0;
michael@0 3688 for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd(); phi++) {
michael@0 3689 MDefinition *opd = phi->getOperand(position);
michael@0 3690 if (!ensureDefined(opd))
michael@0 3691 return false;
michael@0 3692
michael@0 3693 JS_ASSERT(opd->type() == phi->type());
michael@0 3694
michael@0 3695 if (phi->type() == MIRType_Value) {
michael@0 3696 lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex);
michael@0 3697 lirIndex += BOX_PIECES;
michael@0 3698 } else {
michael@0 3699 lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex);
michael@0 3700 lirIndex += 1;
michael@0 3701 }
michael@0 3702 }
michael@0 3703 }
michael@0 3704
michael@0 3705 // Now emit the last instruction, which is some form of branch.
michael@0 3706 if (!visitInstruction(block->lastIns()))
michael@0 3707 return false;
michael@0 3708
michael@0 3709 return true;
michael@0 3710 }
michael@0 3711
michael@0 3712 bool
michael@0 3713 LIRGenerator::precreatePhi(LBlock *block, MPhi *phi)
michael@0 3714 {
michael@0 3715 LPhi *lir = LPhi::New(gen, phi);
michael@0 3716 if (!lir)
michael@0 3717 return false;
michael@0 3718 if (!block->addPhi(lir))
michael@0 3719 return false;
michael@0 3720 return true;
michael@0 3721 }
michael@0 3722
michael@0 3723 bool
michael@0 3724 LIRGenerator::generate()
michael@0 3725 {
michael@0 3726 // Create all blocks and prep all phis beforehand.
michael@0 3727 for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
michael@0 3728 if (gen->shouldCancel("Lowering (preparation loop)"))
michael@0 3729 return false;
michael@0 3730
michael@0 3731 current = LBlock::New(alloc(), *block);
michael@0 3732 if (!current)
michael@0 3733 return false;
michael@0 3734 if (!lirGraph_.addBlock(current))
michael@0 3735 return false;
michael@0 3736 block->assignLir(current);
michael@0 3737
michael@0 3738 // For each MIR phi, add LIR phis as appropriate. We'll fill in their
michael@0 3739 // operands on each incoming edge, and set their definitions at the
michael@0 3740 // start of their defining block.
michael@0 3741 for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
michael@0 3742 int numPhis = (phi->type() == MIRType_Value) ? BOX_PIECES : 1;
michael@0 3743 for (int i = 0; i < numPhis; i++) {
michael@0 3744 if (!precreatePhi(block->lir(), *phi))
michael@0 3745 return false;
michael@0 3746 }
michael@0 3747 }
michael@0 3748 }
michael@0 3749
michael@0 3750 for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
michael@0 3751 if (gen->shouldCancel("Lowering (main loop)"))
michael@0 3752 return false;
michael@0 3753
michael@0 3754 if (!visitBlock(*block))
michael@0 3755 return false;
michael@0 3756 }
michael@0 3757
michael@0 3758 if (graph.osrBlock())
michael@0 3759 lirGraph_.setOsrBlock(graph.osrBlock()->lir());
michael@0 3760
michael@0 3761 lirGraph_.setArgumentSlotCount(maxargslots_);
michael@0 3762 return true;
michael@0 3763 }

mercurial