Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 | } |