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