Line data Source code
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/. */
6 :
7 : #include "jit/Lowering.h"
8 :
9 : #include "mozilla/DebugOnly.h"
10 :
11 : #include "jit/JitSpewer.h"
12 : #include "jit/LIR.h"
13 : #include "jit/MIR.h"
14 : #include "jit/MIRGraph.h"
15 : #include "wasm/WasmSignalHandlers.h"
16 :
17 : #include "jsobjinlines.h"
18 : #include "jsopcodeinlines.h"
19 :
20 : #include "jit/shared/Lowering-shared-inl.h"
21 :
22 : using namespace js;
23 : using namespace jit;
24 :
25 : using mozilla::DebugOnly;
26 : using JS::GenericNaN;
27 :
28 : LBoxAllocation
29 0 : LIRGenerator::useBoxFixedAtStart(MDefinition* mir, ValueOperand op)
30 : {
31 : #if defined(JS_NUNBOX32)
32 : return useBoxFixed(mir, op.typeReg(), op.payloadReg(), true);
33 : #elif defined(JS_PUNBOX64)
34 0 : return useBoxFixed(mir, op.valueReg(), op.scratchReg(), true);
35 : #endif
36 : }
37 :
38 : LBoxAllocation
39 4 : LIRGenerator::useBoxAtStart(MDefinition* mir, LUse::Policy policy)
40 : {
41 4 : return useBox(mir, policy, /* useAtStart = */ true);
42 : }
43 :
44 : void
45 0 : LIRGenerator::visitCloneLiteral(MCloneLiteral* ins)
46 : {
47 0 : MOZ_ASSERT(ins->type() == MIRType::Object);
48 0 : MOZ_ASSERT(ins->input()->type() == MIRType::Object);
49 :
50 0 : LCloneLiteral* lir = new(alloc()) LCloneLiteral(useRegisterAtStart(ins->input()));
51 0 : defineReturn(lir, ins);
52 0 : assignSafepoint(lir, ins);
53 0 : }
54 :
55 : void
56 36 : LIRGenerator::visitParameter(MParameter* param)
57 : {
58 : ptrdiff_t offset;
59 36 : if (param->index() == MParameter::THIS_SLOT)
60 11 : offset = THIS_FRAME_ARGSLOT;
61 : else
62 25 : offset = 1 + param->index();
63 :
64 36 : LParameter* ins = new(alloc()) LParameter;
65 36 : defineBox(ins, param, LDefinition::FIXED);
66 :
67 36 : offset *= sizeof(Value);
68 : #if defined(JS_NUNBOX32)
69 : # if MOZ_BIG_ENDIAN
70 : ins->getDef(0)->setOutput(LArgument(offset));
71 : ins->getDef(1)->setOutput(LArgument(offset + 4));
72 : # else
73 : ins->getDef(0)->setOutput(LArgument(offset + 4));
74 : ins->getDef(1)->setOutput(LArgument(offset));
75 : # endif
76 : #elif defined(JS_PUNBOX64)
77 36 : ins->getDef(0)->setOutput(LArgument(offset));
78 : #endif
79 36 : }
80 :
81 : void
82 3 : LIRGenerator::visitCallee(MCallee* ins)
83 : {
84 3 : define(new(alloc()) LCallee(), ins);
85 3 : }
86 :
87 : void
88 0 : LIRGenerator::visitIsConstructing(MIsConstructing* ins)
89 : {
90 0 : define(new(alloc()) LIsConstructing(), ins);
91 0 : }
92 :
93 : static void
94 5 : TryToUseImplicitInterruptCheck(MIRGraph& graph, MBasicBlock* backedge)
95 : {
96 : // Implicit interrupt checks require wasm signal handlers to be installed.
97 5 : if (!wasm::HaveSignalHandlers() || JitOptions.ionInterruptWithoutSignals)
98 5 : return;
99 :
100 : // To avoid triggering expensive interrupts (backedge patching) in
101 : // requestMajorGC and requestMinorGC, use an implicit interrupt check only
102 : // if the loop body can not trigger GC or affect GC state like the store
103 : // buffer. We do this by checking there are no safepoints attached to LIR
104 : // instructions inside the loop.
105 :
106 5 : MBasicBlockIterator block = graph.begin(backedge->loopHeaderOfBackedge());
107 5 : LInterruptCheck* check = nullptr;
108 : while (true) {
109 18 : LBlock* lir = block->lir();
110 58 : for (LInstructionIterator iter = lir->begin(); iter != lir->end(); iter++) {
111 45 : if (iter->isInterruptCheck()) {
112 5 : if (!check) {
113 5 : MOZ_ASSERT(*block == backedge->loopHeaderOfBackedge());
114 5 : check = iter->toInterruptCheck();
115 : }
116 5 : continue;
117 : }
118 :
119 40 : MOZ_ASSERT_IF(iter->isPostWriteBarrierO() || iter->isPostWriteBarrierV(),
120 : iter->safepoint());
121 :
122 40 : if (iter->safepoint())
123 5 : return;
124 : }
125 13 : if (*block == backedge)
126 0 : break;
127 13 : block++;
128 13 : }
129 :
130 0 : check->setImplicit();
131 : }
132 :
133 : void
134 255 : LIRGenerator::visitGoto(MGoto* ins)
135 : {
136 255 : if (!gen->compilingWasm() && ins->block()->isLoopBackedge())
137 5 : TryToUseImplicitInterruptCheck(graph, ins->block());
138 :
139 255 : add(new(alloc()) LGoto(ins->target()));
140 255 : }
141 :
142 : void
143 0 : LIRGenerator::visitTableSwitch(MTableSwitch* tableswitch)
144 : {
145 0 : MDefinition* opd = tableswitch->getOperand(0);
146 :
147 : // There should be at least 1 successor. The default case!
148 0 : MOZ_ASSERT(tableswitch->numSuccessors() > 0);
149 :
150 : // If there are no cases, the default case is always taken.
151 0 : if (tableswitch->numSuccessors() == 1) {
152 0 : add(new(alloc()) LGoto(tableswitch->getDefault()));
153 0 : return;
154 : }
155 :
156 : // If we don't know the type.
157 0 : if (opd->type() == MIRType::Value) {
158 0 : LTableSwitchV* lir = newLTableSwitchV(tableswitch);
159 0 : add(lir);
160 0 : return;
161 : }
162 :
163 : // Case indices are numeric, so other types will always go to the default case.
164 0 : if (opd->type() != MIRType::Int32 && opd->type() != MIRType::Double) {
165 0 : add(new(alloc()) LGoto(tableswitch->getDefault()));
166 0 : return;
167 : }
168 :
169 : // Return an LTableSwitch, capable of handling either an integer or
170 : // floating-point index.
171 0 : LAllocation index;
172 0 : LDefinition tempInt;
173 0 : if (opd->type() == MIRType::Int32) {
174 0 : index = useRegisterAtStart(opd);
175 0 : tempInt = tempCopy(opd, 0);
176 : } else {
177 0 : index = useRegister(opd);
178 0 : tempInt = temp(LDefinition::GENERAL);
179 : }
180 0 : add(newLTableSwitch(index, tempInt, tableswitch));
181 : }
182 :
183 : void
184 8 : LIRGenerator::visitCheckOverRecursed(MCheckOverRecursed* ins)
185 : {
186 8 : LCheckOverRecursed* lir = new(alloc()) LCheckOverRecursed(temp());
187 8 : add(lir, ins);
188 8 : assignSafepoint(lir, ins);
189 8 : }
190 :
191 : void
192 0 : LIRGenerator::visitDefVar(MDefVar* ins)
193 : {
194 0 : LDefVar* lir = new(alloc()) LDefVar(useRegisterAtStart(ins->environmentChain()));
195 0 : add(lir, ins);
196 0 : assignSafepoint(lir, ins);
197 0 : }
198 :
199 : void
200 0 : LIRGenerator::visitDefLexical(MDefLexical* ins)
201 : {
202 0 : LDefLexical* lir = new(alloc()) LDefLexical();
203 0 : add(lir, ins);
204 0 : assignSafepoint(lir, ins);
205 0 : }
206 :
207 : void
208 0 : LIRGenerator::visitDefFun(MDefFun* ins)
209 : {
210 0 : MDefinition* fun = ins->fun();
211 0 : MOZ_ASSERT(fun->type() == MIRType::Object);
212 :
213 0 : LDefFun* lir = new(alloc()) LDefFun(useRegisterAtStart(fun),
214 0 : useRegisterAtStart(ins->environmentChain()));
215 0 : add(lir, ins);
216 0 : assignSafepoint(lir, ins);
217 0 : }
218 :
219 : void
220 3 : LIRGenerator::visitNewArray(MNewArray* ins)
221 : {
222 3 : LNewArray* lir = new(alloc()) LNewArray(temp());
223 3 : define(lir, ins);
224 3 : assignSafepoint(lir, ins);
225 3 : }
226 :
227 : void
228 0 : LIRGenerator::visitNewArrayCopyOnWrite(MNewArrayCopyOnWrite* ins)
229 : {
230 0 : LNewArrayCopyOnWrite* lir = new(alloc()) LNewArrayCopyOnWrite(temp());
231 0 : define(lir, ins);
232 0 : assignSafepoint(lir, ins);
233 0 : }
234 :
235 : void
236 0 : LIRGenerator::visitNewArrayDynamicLength(MNewArrayDynamicLength* ins)
237 : {
238 0 : MDefinition* length = ins->length();
239 0 : MOZ_ASSERT(length->type() == MIRType::Int32);
240 :
241 0 : LNewArrayDynamicLength* lir = new(alloc()) LNewArrayDynamicLength(useRegister(length), temp());
242 0 : define(lir, ins);
243 0 : assignSafepoint(lir, ins);
244 0 : }
245 :
246 : void
247 0 : LIRGenerator::visitNewIterator(MNewIterator* ins)
248 : {
249 0 : LNewIterator* lir = new(alloc()) LNewIterator(temp());
250 0 : define(lir, ins);
251 0 : assignSafepoint(lir, ins);
252 0 : }
253 :
254 : void
255 0 : LIRGenerator::visitNewTypedArray(MNewTypedArray* ins)
256 : {
257 0 : LNewTypedArray* lir = new(alloc()) LNewTypedArray(temp(), temp());
258 0 : define(lir, ins);
259 0 : assignSafepoint(lir, ins);
260 0 : }
261 :
262 : void
263 0 : LIRGenerator::visitNewTypedArrayDynamicLength(MNewTypedArrayDynamicLength* ins)
264 : {
265 0 : MDefinition* length = ins->length();
266 0 : MOZ_ASSERT(length->type() == MIRType::Int32);
267 :
268 0 : LNewTypedArrayDynamicLength* lir = new(alloc()) LNewTypedArrayDynamicLength(useRegister(length), temp());
269 0 : define(lir, ins);
270 0 : assignSafepoint(lir, ins);
271 0 : }
272 :
273 : void
274 1 : LIRGenerator::visitNewObject(MNewObject* ins)
275 : {
276 1 : LNewObject* lir = new(alloc()) LNewObject(temp());
277 1 : define(lir, ins);
278 1 : assignSafepoint(lir, ins);
279 1 : }
280 :
281 : void
282 0 : LIRGenerator::visitNewTypedObject(MNewTypedObject* ins)
283 : {
284 0 : LNewTypedObject* lir = new(alloc()) LNewTypedObject(temp());
285 0 : define(lir, ins);
286 0 : assignSafepoint(lir, ins);
287 0 : }
288 :
289 : void
290 0 : LIRGenerator::visitNewNamedLambdaObject(MNewNamedLambdaObject* ins)
291 : {
292 0 : LNewNamedLambdaObject* lir = new(alloc()) LNewNamedLambdaObject(temp());
293 0 : define(lir, ins);
294 0 : assignSafepoint(lir, ins);
295 0 : }
296 :
297 : void
298 2 : LIRGenerator::visitNewCallObject(MNewCallObject* ins)
299 : {
300 2 : LNewCallObject* lir = new(alloc()) LNewCallObject(temp());
301 2 : define(lir, ins);
302 2 : assignSafepoint(lir, ins);
303 2 : }
304 :
305 : void
306 0 : LIRGenerator::visitNewSingletonCallObject(MNewSingletonCallObject* ins)
307 : {
308 0 : LNewSingletonCallObject* lir = new(alloc()) LNewSingletonCallObject(temp());
309 0 : define(lir, ins);
310 0 : assignSafepoint(lir, ins);
311 0 : }
312 :
313 : void
314 0 : LIRGenerator::visitNewDerivedTypedObject(MNewDerivedTypedObject* ins)
315 : {
316 : LNewDerivedTypedObject* lir =
317 0 : new(alloc()) LNewDerivedTypedObject(useRegisterAtStart(ins->type()),
318 0 : useRegisterAtStart(ins->owner()),
319 0 : useRegisterAtStart(ins->offset()));
320 0 : defineReturn(lir, ins);
321 0 : assignSafepoint(lir, ins);
322 0 : }
323 :
324 : void
325 0 : LIRGenerator::visitNewStringObject(MNewStringObject* ins)
326 : {
327 0 : MOZ_ASSERT(ins->input()->type() == MIRType::String);
328 :
329 0 : LNewStringObject* lir = new(alloc()) LNewStringObject(useRegister(ins->input()), temp());
330 0 : define(lir, ins);
331 0 : assignSafepoint(lir, ins);
332 0 : }
333 :
334 : void
335 0 : LIRGenerator::visitInitElem(MInitElem* ins)
336 : {
337 0 : LInitElem* lir = new(alloc()) LInitElem(useRegisterAtStart(ins->getObject()),
338 0 : useBoxAtStart(ins->getId()),
339 0 : useBoxAtStart(ins->getValue()));
340 0 : add(lir, ins);
341 0 : assignSafepoint(lir, ins);
342 0 : }
343 :
344 : void
345 0 : LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter* ins)
346 : {
347 : LInitElemGetterSetter* lir =
348 0 : new(alloc()) LInitElemGetterSetter(useRegisterAtStart(ins->object()),
349 0 : useBoxAtStart(ins->idValue()),
350 0 : useRegisterAtStart(ins->value()));
351 0 : add(lir, ins);
352 0 : assignSafepoint(lir, ins);
353 0 : }
354 :
355 : void
356 0 : LIRGenerator::visitMutateProto(MMutateProto* ins)
357 : {
358 0 : LMutateProto* lir = new(alloc()) LMutateProto(useRegisterAtStart(ins->getObject()),
359 0 : useBoxAtStart(ins->getValue()));
360 0 : add(lir, ins);
361 0 : assignSafepoint(lir, ins);
362 0 : }
363 :
364 : void
365 0 : LIRGenerator::visitInitProp(MInitProp* ins)
366 : {
367 0 : LInitProp* lir = new(alloc()) LInitProp(useRegisterAtStart(ins->getObject()),
368 0 : useBoxAtStart(ins->getValue()));
369 0 : add(lir, ins);
370 0 : assignSafepoint(lir, ins);
371 0 : }
372 :
373 : void
374 0 : LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter* ins)
375 : {
376 : LInitPropGetterSetter* lir =
377 0 : new(alloc()) LInitPropGetterSetter(useRegisterAtStart(ins->object()),
378 0 : useRegisterAtStart(ins->value()));
379 0 : add(lir, ins);
380 0 : assignSafepoint(lir, ins);
381 0 : }
382 :
383 : void
384 0 : LIRGenerator::visitCreateThisWithTemplate(MCreateThisWithTemplate* ins)
385 : {
386 0 : LCreateThisWithTemplate* lir = new(alloc()) LCreateThisWithTemplate(temp());
387 0 : define(lir, ins);
388 0 : assignSafepoint(lir, ins);
389 0 : }
390 :
391 : void
392 0 : LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto* ins)
393 : {
394 : LCreateThisWithProto* lir =
395 0 : new(alloc()) LCreateThisWithProto(useRegisterOrConstantAtStart(ins->getCallee()),
396 0 : useRegisterOrConstantAtStart(ins->getNewTarget()),
397 0 : useRegisterOrConstantAtStart(ins->getPrototype()));
398 0 : defineReturn(lir, ins);
399 0 : assignSafepoint(lir, ins);
400 0 : }
401 :
402 : void
403 4 : LIRGenerator::visitCreateThis(MCreateThis* ins)
404 : {
405 12 : LCreateThis* lir = new(alloc()) LCreateThis(useRegisterOrConstantAtStart(ins->getCallee()),
406 8 : useRegisterOrConstantAtStart(ins->getNewTarget()));
407 4 : defineReturn(lir, ins);
408 4 : assignSafepoint(lir, ins);
409 4 : }
410 :
411 : void
412 0 : LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject* ins)
413 : {
414 0 : LAllocation callObj = useFixedAtStart(ins->getCallObject(), CallTempReg0);
415 0 : LCreateArgumentsObject* lir = new(alloc()) LCreateArgumentsObject(callObj, tempFixed(CallTempReg1),
416 0 : tempFixed(CallTempReg2),
417 0 : tempFixed(CallTempReg3));
418 0 : defineReturn(lir, ins);
419 0 : assignSafepoint(lir, ins);
420 0 : }
421 :
422 : void
423 0 : LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg* ins)
424 : {
425 0 : LAllocation argsObj = useRegister(ins->getArgsObject());
426 0 : LGetArgumentsObjectArg* lir = new(alloc()) LGetArgumentsObjectArg(argsObj, temp());
427 0 : defineBox(lir, ins);
428 0 : }
429 :
430 : void
431 0 : LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg* ins)
432 : {
433 0 : LAllocation argsObj = useRegister(ins->getArgsObject());
434 : LSetArgumentsObjectArg* lir =
435 0 : new(alloc()) LSetArgumentsObjectArg(argsObj, useBox(ins->getValue()), temp());
436 0 : add(lir, ins);
437 0 : }
438 :
439 : void
440 0 : LIRGenerator::visitReturnFromCtor(MReturnFromCtor* ins)
441 : {
442 0 : LReturnFromCtor* lir = new(alloc()) LReturnFromCtor(useBox(ins->getValue()),
443 0 : useRegister(ins->getObject()));
444 0 : define(lir, ins);
445 0 : }
446 :
447 : void
448 0 : LIRGenerator::visitComputeThis(MComputeThis* ins)
449 : {
450 0 : MOZ_ASSERT(ins->type() == MIRType::Value);
451 0 : MOZ_ASSERT(ins->input()->type() == MIRType::Value);
452 :
453 : // Don't use useBoxAtStart because ComputeThis has a safepoint and needs to
454 : // have its inputs in different registers than its return value so that
455 : // they aren't clobbered.
456 0 : LComputeThis* lir = new(alloc()) LComputeThis(useBox(ins->input()));
457 0 : defineBox(lir, ins);
458 0 : assignSafepoint(lir, ins);
459 0 : }
460 :
461 : void
462 0 : LIRGenerator::visitArrowNewTarget(MArrowNewTarget* ins)
463 : {
464 0 : MOZ_ASSERT(ins->type() == MIRType::Value);
465 0 : MOZ_ASSERT(ins->callee()->type() == MIRType::Object);
466 :
467 0 : LArrowNewTarget* lir = new(alloc()) LArrowNewTarget(useRegister(ins->callee()));
468 0 : defineBox(lir, ins);
469 0 : }
470 :
471 : bool
472 27 : LIRGenerator::lowerCallArguments(MCall* call)
473 : {
474 27 : uint32_t argc = call->numStackArgs();
475 :
476 : // Align the arguments of a call such that the callee would keep the same
477 : // alignment as the caller.
478 27 : uint32_t baseSlot = 0;
479 : if (JitStackValueAlignment > 1)
480 27 : baseSlot = AlignBytes(argc, JitStackValueAlignment);
481 : else
482 : baseSlot = argc;
483 :
484 : // Save the maximum number of argument, such that we can have one unique
485 : // frame size.
486 27 : if (baseSlot > maxargslots_)
487 8 : maxargslots_ = baseSlot;
488 :
489 98 : for (size_t i = 0; i < argc; i++) {
490 71 : MDefinition* arg = call->getArg(i);
491 71 : uint32_t argslot = baseSlot - i;
492 :
493 : // Values take a slow path.
494 71 : if (arg->type() == MIRType::Value) {
495 9 : LStackArgV* stack = new(alloc()) LStackArgV(argslot, useBox(arg));
496 9 : add(stack);
497 : } else {
498 : // Known types can move constant types and/or payloads.
499 62 : LStackArgT* stack = new(alloc()) LStackArgT(argslot, arg->type(), useRegisterOrConstant(arg));
500 62 : add(stack);
501 : }
502 :
503 71 : if (!alloc().ensureBallast())
504 0 : return false;
505 : }
506 27 : return true;
507 : }
508 :
509 : void
510 27 : LIRGenerator::visitCall(MCall* call)
511 : {
512 27 : MOZ_ASSERT(CallTempReg0 != CallTempReg1);
513 27 : MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
514 27 : MOZ_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
515 27 : MOZ_ASSERT(call->getFunction()->type() == MIRType::Object);
516 :
517 : // In case of oom, skip the rest of the allocations.
518 27 : if (!lowerCallArguments(call)) {
519 0 : abort(AbortReason::Alloc, "OOM: LIRGenerator::visitCall");
520 0 : return;
521 : }
522 :
523 27 : WrappedFunction* target = call->getSingleTarget();
524 :
525 : LInstruction* lir;
526 :
527 27 : if (call->isCallDOMNative()) {
528 : // Call DOM functions.
529 0 : MOZ_ASSERT(target && target->isNative());
530 0 : Register cxReg, objReg, privReg, argsReg;
531 0 : GetTempRegForIntArg(0, 0, &cxReg);
532 0 : GetTempRegForIntArg(1, 0, &objReg);
533 0 : GetTempRegForIntArg(2, 0, &privReg);
534 0 : mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &argsReg);
535 0 : MOZ_ASSERT(ok, "How can we not have four temp registers?");
536 0 : lir = new(alloc()) LCallDOMNative(tempFixed(cxReg), tempFixed(objReg),
537 0 : tempFixed(privReg), tempFixed(argsReg));
538 27 : } else if (target) {
539 : // Call known functions.
540 18 : if (target->isNative()) {
541 9 : Register cxReg, numReg, vpReg, tmpReg;
542 9 : GetTempRegForIntArg(0, 0, &cxReg);
543 9 : GetTempRegForIntArg(1, 0, &numReg);
544 9 : GetTempRegForIntArg(2, 0, &vpReg);
545 :
546 : // Even though this is just a temp reg, use the same API to avoid
547 : // register collisions.
548 18 : mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &tmpReg);
549 9 : MOZ_ASSERT(ok, "How can we not have four temp registers?");
550 :
551 45 : lir = new(alloc()) LCallNative(tempFixed(cxReg), tempFixed(numReg),
552 36 : tempFixed(vpReg), tempFixed(tmpReg));
553 : } else {
554 36 : lir = new(alloc()) LCallKnown(useFixedAtStart(call->getFunction(), CallTempReg0),
555 27 : tempFixed(CallTempReg2));
556 : }
557 : } else {
558 : // Call anything, using the most generic code.
559 36 : lir = new(alloc()) LCallGeneric(useFixedAtStart(call->getFunction(), CallTempReg0),
560 18 : tempFixed(ArgumentsRectifierReg),
561 36 : tempFixed(CallTempReg2));
562 : }
563 27 : defineReturn(lir, call);
564 27 : assignSafepoint(lir, call);
565 : }
566 :
567 : void
568 0 : LIRGenerator::visitApplyArgs(MApplyArgs* apply)
569 : {
570 0 : MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
571 :
572 : // Assert if we cannot build a rectifier frame.
573 0 : MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
574 0 : MOZ_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
575 :
576 : // Assert if the return value is already erased.
577 0 : MOZ_ASSERT(CallTempReg2 != JSReturnReg_Type);
578 0 : MOZ_ASSERT(CallTempReg2 != JSReturnReg_Data);
579 :
580 0 : LApplyArgsGeneric* lir = new(alloc()) LApplyArgsGeneric(
581 0 : useFixedAtStart(apply->getFunction(), CallTempReg3),
582 0 : useFixedAtStart(apply->getArgc(), CallTempReg0),
583 0 : useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
584 0 : tempFixed(CallTempReg1), // object register
585 0 : tempFixed(CallTempReg2)); // stack counter register
586 :
587 : // Bailout is needed in the case of possible non-JSFunction callee or too
588 : // many values in the arguments array. I'm going to use NonJSFunctionCallee
589 : // for the code even if that is not an adequate description.
590 0 : assignSnapshot(lir, Bailout_NonJSFunctionCallee);
591 :
592 0 : defineReturn(lir, apply);
593 0 : assignSafepoint(lir, apply);
594 0 : }
595 :
596 : void
597 0 : LIRGenerator::visitApplyArray(MApplyArray* apply)
598 : {
599 0 : MOZ_ASSERT(apply->getFunction()->type() == MIRType::Object);
600 :
601 : // Assert if we cannot build a rectifier frame.
602 0 : MOZ_ASSERT(CallTempReg0 != ArgumentsRectifierReg);
603 0 : MOZ_ASSERT(CallTempReg1 != ArgumentsRectifierReg);
604 :
605 : // Assert if the return value is already erased.
606 0 : MOZ_ASSERT(CallTempReg2 != JSReturnReg_Type);
607 0 : MOZ_ASSERT(CallTempReg2 != JSReturnReg_Data);
608 :
609 0 : LApplyArrayGeneric* lir = new(alloc()) LApplyArrayGeneric(
610 0 : useFixedAtStart(apply->getFunction(), CallTempReg3),
611 0 : useFixedAtStart(apply->getElements(), CallTempReg0),
612 0 : useBoxFixedAtStart(apply->getThis(), CallTempReg4, CallTempReg5),
613 0 : tempFixed(CallTempReg1), // object register
614 0 : tempFixed(CallTempReg2)); // stack counter register
615 :
616 : // Bailout is needed in the case of possible non-JSFunction callee,
617 : // too many values in the array, or empty space at the end of the
618 : // array. I'm going to use NonJSFunctionCallee for the code even
619 : // if that is not an adequate description.
620 0 : assignSnapshot(lir, Bailout_NonJSFunctionCallee);
621 :
622 0 : defineReturn(lir, apply);
623 0 : assignSafepoint(lir, apply);
624 0 : }
625 :
626 : void
627 18 : LIRGenerator::visitBail(MBail* bail)
628 : {
629 18 : LBail* lir = new(alloc()) LBail();
630 18 : assignSnapshot(lir, bail->bailoutKind());
631 18 : add(lir, bail);
632 18 : }
633 :
634 : void
635 18 : LIRGenerator::visitUnreachable(MUnreachable* unreachable)
636 : {
637 18 : LUnreachable* lir = new(alloc()) LUnreachable();
638 18 : add(lir, unreachable);
639 18 : }
640 :
641 : void
642 0 : LIRGenerator::visitEncodeSnapshot(MEncodeSnapshot* mir)
643 : {
644 0 : LEncodeSnapshot* lir = new(alloc()) LEncodeSnapshot();
645 0 : assignSnapshot(lir, Bailout_Inevitable);
646 0 : add(lir, mir);
647 0 : }
648 :
649 : void
650 0 : LIRGenerator::visitAssertFloat32(MAssertFloat32* assertion)
651 : {
652 0 : MIRType type = assertion->input()->type();
653 0 : DebugOnly<bool> checkIsFloat32 = assertion->mustBeFloat32();
654 :
655 0 : if (type != MIRType::Value && !JitOptions.eagerCompilation) {
656 0 : MOZ_ASSERT_IF(checkIsFloat32, type == MIRType::Float32);
657 0 : MOZ_ASSERT_IF(!checkIsFloat32, type != MIRType::Float32);
658 : }
659 0 : }
660 :
661 : void
662 0 : LIRGenerator::visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* assertion)
663 : {
664 0 : MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
665 : }
666 :
667 : void
668 0 : LIRGenerator::visitGetDynamicName(MGetDynamicName* ins)
669 : {
670 0 : MDefinition* envChain = ins->getEnvironmentChain();
671 0 : MOZ_ASSERT(envChain->type() == MIRType::Object);
672 :
673 0 : MDefinition* name = ins->getName();
674 0 : MOZ_ASSERT(name->type() == MIRType::String);
675 :
676 0 : LGetDynamicName* lir = new(alloc()) LGetDynamicName(useFixedAtStart(envChain, CallTempReg0),
677 0 : useFixedAtStart(name, CallTempReg1),
678 0 : tempFixed(CallTempReg2),
679 0 : tempFixed(CallTempReg3),
680 0 : tempFixed(CallTempReg4));
681 :
682 0 : assignSnapshot(lir, Bailout_DynamicNameNotFound);
683 0 : defineReturn(lir, ins);
684 0 : }
685 :
686 : void
687 0 : LIRGenerator::visitCallDirectEval(MCallDirectEval* ins)
688 : {
689 0 : MDefinition* envChain = ins->getEnvironmentChain();
690 0 : MOZ_ASSERT(envChain->type() == MIRType::Object);
691 :
692 0 : MDefinition* string = ins->getString();
693 0 : MOZ_ASSERT(string->type() == MIRType::String);
694 :
695 0 : MDefinition* newTargetValue = ins->getNewTargetValue();
696 :
697 0 : LInstruction* lir = new(alloc()) LCallDirectEval(useRegisterAtStart(envChain),
698 0 : useRegisterAtStart(string),
699 0 : useBoxAtStart(newTargetValue));
700 0 : defineReturn(lir, ins);
701 0 : assignSafepoint(lir, ins);
702 0 : }
703 :
704 : static JSOp
705 45 : ReorderComparison(JSOp op, MDefinition** lhsp, MDefinition** rhsp)
706 : {
707 45 : MDefinition* lhs = *lhsp;
708 45 : MDefinition* rhs = *rhsp;
709 :
710 45 : if (lhs->maybeConstantValue()) {
711 1 : *rhsp = lhs;
712 1 : *lhsp = rhs;
713 1 : return ReverseCompareOp(op);
714 : }
715 44 : return op;
716 : }
717 :
718 : void
719 108 : LIRGenerator::visitTest(MTest* test)
720 : {
721 108 : MDefinition* opd = test->getOperand(0);
722 108 : MBasicBlock* ifTrue = test->ifTrue();
723 108 : MBasicBlock* ifFalse = test->ifFalse();
724 :
725 : // String is converted to length of string in the type analysis phase (see
726 : // TestPolicy).
727 108 : MOZ_ASSERT(opd->type() != MIRType::String);
728 :
729 : // Testing a constant.
730 108 : if (MConstant* constant = opd->maybeConstantValue()) {
731 : bool b;
732 0 : if (constant->valueToBoolean(&b)) {
733 0 : add(new(alloc()) LGoto(b ? ifTrue : ifFalse));
734 0 : return;
735 : }
736 : }
737 :
738 108 : if (opd->type() == MIRType::Value) {
739 30 : LDefinition temp0, temp1;
740 30 : if (test->operandMightEmulateUndefined()) {
741 10 : temp0 = temp();
742 10 : temp1 = temp();
743 : } else {
744 20 : temp0 = LDefinition::BogusTemp();
745 20 : temp1 = LDefinition::BogusTemp();
746 : }
747 : LTestVAndBranch* lir =
748 30 : new(alloc()) LTestVAndBranch(ifTrue, ifFalse, useBox(opd), tempDouble(), temp0, temp1);
749 30 : add(lir, test);
750 30 : return;
751 : }
752 :
753 78 : if (opd->type() == MIRType::ObjectOrNull) {
754 0 : LDefinition temp0 = test->operandMightEmulateUndefined() ? temp() : LDefinition::BogusTemp();
755 0 : add(new(alloc()) LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp0), test);
756 0 : return;
757 : }
758 :
759 : // Objects are truthy, except if it might emulate undefined.
760 78 : if (opd->type() == MIRType::Object) {
761 0 : if (test->operandMightEmulateUndefined())
762 0 : add(new(alloc()) LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp()), test);
763 : else
764 0 : add(new(alloc()) LGoto(ifTrue));
765 0 : return;
766 : }
767 :
768 : // These must be explicitly sniffed out since they are constants and have
769 : // no payload.
770 78 : if (opd->type() == MIRType::Undefined || opd->type() == MIRType::Null) {
771 0 : add(new(alloc()) LGoto(ifFalse));
772 0 : return;
773 : }
774 :
775 : // All symbols are truthy.
776 78 : if (opd->type() == MIRType::Symbol) {
777 0 : add(new(alloc()) LGoto(ifTrue));
778 0 : return;
779 : }
780 :
781 78 : if (opd->isCompare() && opd->isEmittedAtUses()) {
782 : // Emit LBitAndBranch for cases like |if ((x & y) === 0)|.
783 23 : MCompare* comp = opd->toCompare();
784 46 : if ((comp->isInt32Comparison() ||
785 23 : comp->compareType() == MCompare::Compare_UInt32) &&
786 37 : comp->getOperand(1)->isConstant() &&
787 15 : comp->getOperand(1)->toConstant()->isInt32(0) &&
788 24 : comp->getOperand(0)->isBitAnd() &&
789 0 : comp->getOperand(0)->isEmittedAtUses())
790 : {
791 0 : MDefinition* bitAnd = opd->getOperand(0);
792 0 : MDefinition* lhs = bitAnd->getOperand(0);
793 0 : MDefinition* rhs = bitAnd->getOperand(1);
794 :
795 0 : Assembler::Condition cond = JSOpToCondition(comp->compareType(),
796 0 : comp->jsop());
797 :
798 0 : if (lhs->type() == MIRType::Int32 && rhs->type() == MIRType::Int32 &&
799 0 : (cond == Assembler::Equal || cond == Assembler::NotEqual))
800 : {
801 0 : ReorderCommutative(&lhs, &rhs, test);
802 0 : if (cond == Assembler::Equal)
803 0 : cond = Assembler::Zero;
804 0 : else if(cond == Assembler::NotEqual)
805 0 : cond = Assembler::NonZero;
806 : else
807 0 : MOZ_ASSERT_UNREACHABLE("inequality operators cannot be folded");
808 0 : lowerForBitAndAndBranch(new(alloc()) LBitAndAndBranch(ifTrue, ifFalse, cond),
809 0 : test, lhs, rhs);
810 0 : return;
811 : }
812 : }
813 : }
814 :
815 : // Check if the operand for this test is a compare operation. If it is, we want
816 : // to emit an LCompare*AndBranch rather than an LTest*AndBranch, to fuse the
817 : // compare and jump instructions.
818 78 : if (opd->isCompare() && opd->isEmittedAtUses()) {
819 23 : MCompare* comp = opd->toCompare();
820 23 : MDefinition* left = comp->lhs();
821 23 : MDefinition* right = comp->rhs();
822 :
823 : // Try to fold the comparison so that we don't have to handle all cases.
824 : bool result;
825 23 : if (comp->tryFold(&result)) {
826 0 : add(new(alloc()) LGoto(result ? ifTrue : ifFalse));
827 0 : return;
828 : }
829 :
830 : // Emit LCompare*AndBranch.
831 :
832 : // Compare and branch null/undefined.
833 : // The second operand has known null/undefined type,
834 : // so just test the first operand.
835 46 : if (comp->compareType() == MCompare::Compare_Null ||
836 23 : comp->compareType() == MCompare::Compare_Undefined)
837 : {
838 0 : if (left->type() == MIRType::Object || left->type() == MIRType::ObjectOrNull) {
839 0 : MOZ_ASSERT(left->type() == MIRType::ObjectOrNull ||
840 : comp->operandMightEmulateUndefined(),
841 : "MCompare::tryFold should handle the never-emulates-undefined case");
842 :
843 : LDefinition tmp =
844 0 : comp->operandMightEmulateUndefined() ? temp() : LDefinition::BogusTemp();
845 : LIsNullOrLikeUndefinedAndBranchT* lir =
846 0 : new(alloc()) LIsNullOrLikeUndefinedAndBranchT(comp, useRegister(left),
847 0 : ifTrue, ifFalse, tmp);
848 0 : add(lir, test);
849 0 : return;
850 : }
851 :
852 0 : LDefinition tmp, tmpToUnbox;
853 0 : if (comp->operandMightEmulateUndefined()) {
854 0 : tmp = temp();
855 0 : tmpToUnbox = tempToUnbox();
856 : } else {
857 0 : tmp = LDefinition::BogusTemp();
858 0 : tmpToUnbox = LDefinition::BogusTemp();
859 : }
860 :
861 : LIsNullOrLikeUndefinedAndBranchV* lir =
862 0 : new(alloc()) LIsNullOrLikeUndefinedAndBranchV(comp, ifTrue, ifFalse, useBox(left),
863 0 : tmp, tmpToUnbox);
864 0 : add(lir, test);
865 0 : return;
866 : }
867 :
868 : // Compare and branch booleans.
869 23 : if (comp->compareType() == MCompare::Compare_Boolean) {
870 0 : MOZ_ASSERT(left->type() == MIRType::Value);
871 0 : MOZ_ASSERT(right->type() == MIRType::Boolean);
872 :
873 0 : LCompareBAndBranch* lir = new(alloc()) LCompareBAndBranch(comp, useBox(left),
874 0 : useRegisterOrConstant(right),
875 0 : ifTrue, ifFalse);
876 0 : add(lir, test);
877 0 : return;
878 : }
879 :
880 : // Compare and branch Int32, Symbol or Object pointers.
881 46 : if (comp->isInt32Comparison() ||
882 0 : comp->compareType() == MCompare::Compare_UInt32 ||
883 23 : comp->compareType() == MCompare::Compare_Object ||
884 0 : comp->compareType() == MCompare::Compare_Symbol)
885 : {
886 23 : JSOp op = ReorderComparison(comp->jsop(), &left, &right);
887 23 : LAllocation lhs = useRegister(left);
888 23 : LAllocation rhs;
889 23 : if (comp->isInt32Comparison() || comp->compareType() == MCompare::Compare_UInt32)
890 23 : rhs = useAnyOrConstant(right);
891 : else
892 0 : rhs = useRegister(right);
893 23 : LCompareAndBranch* lir = new(alloc()) LCompareAndBranch(comp, op, lhs, rhs,
894 23 : ifTrue, ifFalse);
895 23 : add(lir, test);
896 23 : return;
897 : }
898 :
899 : // Compare and branch Int64.
900 0 : if (comp->compareType() == MCompare::Compare_Int64 ||
901 0 : comp->compareType() == MCompare::Compare_UInt64)
902 : {
903 0 : JSOp op = ReorderComparison(comp->jsop(), &left, &right);
904 0 : LCompareI64AndBranch* lir = new(alloc()) LCompareI64AndBranch(comp, op,
905 0 : useInt64Register(left),
906 0 : useInt64OrConstant(right),
907 0 : ifTrue, ifFalse);
908 0 : add(lir, test);
909 0 : return;
910 : }
911 :
912 : // Compare and branch doubles.
913 0 : if (comp->isDoubleComparison()) {
914 0 : LAllocation lhs = useRegister(left);
915 0 : LAllocation rhs = useRegister(right);
916 0 : LCompareDAndBranch* lir = new(alloc()) LCompareDAndBranch(comp, lhs, rhs,
917 0 : ifTrue, ifFalse);
918 0 : add(lir, test);
919 0 : return;
920 : }
921 :
922 : // Compare and branch floats.
923 0 : if (comp->isFloat32Comparison()) {
924 0 : LAllocation lhs = useRegister(left);
925 0 : LAllocation rhs = useRegister(right);
926 0 : LCompareFAndBranch* lir = new(alloc()) LCompareFAndBranch(comp, lhs, rhs,
927 0 : ifTrue, ifFalse);
928 0 : add(lir, test);
929 0 : return;
930 : }
931 :
932 : // Compare values.
933 0 : if (comp->compareType() == MCompare::Compare_Bitwise) {
934 : LCompareBitwiseAndBranch* lir =
935 0 : new(alloc()) LCompareBitwiseAndBranch(comp, ifTrue, ifFalse,
936 0 : useBoxAtStart(left),
937 0 : useBoxAtStart(right));
938 0 : add(lir, test);
939 0 : return;
940 : }
941 : }
942 :
943 : // Check if the operand for this test is a bitand operation. If it is, we want
944 : // to emit an LBitAndAndBranch rather than an LTest*AndBranch.
945 55 : if (opd->isBitAnd() && opd->isEmittedAtUses()) {
946 0 : MDefinition* lhs = opd->getOperand(0);
947 0 : MDefinition* rhs = opd->getOperand(1);
948 0 : if (lhs->type() == MIRType::Int32 && rhs->type() == MIRType::Int32) {
949 0 : ReorderCommutative(&lhs, &rhs, test);
950 0 : lowerForBitAndAndBranch(new(alloc()) LBitAndAndBranch(ifTrue, ifFalse), test, lhs, rhs);
951 0 : return;
952 : }
953 : }
954 :
955 55 : if (opd->isIsObject() && opd->isEmittedAtUses()) {
956 0 : MDefinition* input = opd->toIsObject()->input();
957 0 : MOZ_ASSERT(input->type() == MIRType::Value);
958 :
959 0 : LIsObjectAndBranch* lir = new(alloc()) LIsObjectAndBranch(ifTrue, ifFalse,
960 0 : useBoxAtStart(input));
961 0 : add(lir, test);
962 0 : return;
963 : }
964 :
965 55 : if (opd->isIsNoIter()) {
966 0 : MOZ_ASSERT(opd->isEmittedAtUses());
967 :
968 0 : MDefinition* input = opd->toIsNoIter()->input();
969 0 : MOZ_ASSERT(input->type() == MIRType::Value);
970 :
971 0 : LIsNoIterAndBranch* lir = new(alloc()) LIsNoIterAndBranch(ifTrue, ifFalse,
972 0 : useBox(input));
973 0 : add(lir, test);
974 0 : return;
975 : }
976 :
977 55 : switch (opd->type()) {
978 : case MIRType::Double:
979 0 : add(new(alloc()) LTestDAndBranch(useRegister(opd), ifTrue, ifFalse));
980 0 : break;
981 : case MIRType::Float32:
982 0 : add(new(alloc()) LTestFAndBranch(useRegister(opd), ifTrue, ifFalse));
983 0 : break;
984 : case MIRType::Int32:
985 : case MIRType::Boolean:
986 55 : add(new(alloc()) LTestIAndBranch(useRegister(opd), ifTrue, ifFalse));
987 55 : break;
988 : case MIRType::Int64:
989 0 : add(new(alloc()) LTestI64AndBranch(useInt64Register(opd), ifTrue, ifFalse));
990 0 : break;
991 : default:
992 0 : MOZ_CRASH("Bad type");
993 : }
994 : }
995 :
996 : void
997 1 : LIRGenerator::visitGotoWithFake(MGotoWithFake* gotoWithFake)
998 : {
999 1 : add(new(alloc()) LGoto(gotoWithFake->target()));
1000 1 : }
1001 :
1002 : void
1003 3 : LIRGenerator::visitFunctionDispatch(MFunctionDispatch* ins)
1004 : {
1005 3 : LFunctionDispatch* lir = new(alloc()) LFunctionDispatch(useRegister(ins->input()));
1006 3 : add(lir, ins);
1007 3 : }
1008 :
1009 : void
1010 0 : LIRGenerator::visitObjectGroupDispatch(MObjectGroupDispatch* ins)
1011 : {
1012 0 : LObjectGroupDispatch* lir = new(alloc()) LObjectGroupDispatch(useRegister(ins->input()), temp());
1013 0 : add(lir, ins);
1014 0 : }
1015 :
1016 : static inline bool
1017 45 : CanEmitCompareAtUses(MInstruction* ins)
1018 : {
1019 45 : if (!ins->canEmitAtUses())
1020 0 : return false;
1021 :
1022 45 : bool foundTest = false;
1023 68 : for (MUseIterator iter(ins->usesBegin()); iter != ins->usesEnd(); iter++) {
1024 45 : MNode* node = iter->consumer();
1025 45 : if (!node->isDefinition())
1026 22 : return false;
1027 45 : if (!node->toDefinition()->isTest())
1028 22 : return false;
1029 23 : if (foundTest)
1030 0 : return false;
1031 23 : foundTest = true;
1032 : }
1033 23 : return true;
1034 : }
1035 :
1036 : void
1037 45 : LIRGenerator::visitCompare(MCompare* comp)
1038 : {
1039 45 : MDefinition* left = comp->lhs();
1040 45 : MDefinition* right = comp->rhs();
1041 :
1042 : // Try to fold the comparison so that we don't have to handle all cases.
1043 : bool result;
1044 45 : if (comp->tryFold(&result)) {
1045 0 : define(new(alloc()) LInteger(result), comp);
1046 0 : return;
1047 : }
1048 :
1049 : // Move below the emitAtUses call if we ever implement
1050 : // LCompareSAndBranch. Doing this now wouldn't be wrong, but doesn't
1051 : // make sense and avoids confusion.
1052 45 : if (comp->compareType() == MCompare::Compare_String) {
1053 0 : LCompareS* lir = new(alloc()) LCompareS(useRegister(left), useRegister(right));
1054 0 : define(lir, comp);
1055 0 : assignSafepoint(lir, comp);
1056 0 : return;
1057 : }
1058 :
1059 : // Strict compare between value and string
1060 45 : if (comp->compareType() == MCompare::Compare_StrictString) {
1061 0 : MOZ_ASSERT(left->type() == MIRType::Value);
1062 0 : MOZ_ASSERT(right->type() == MIRType::String);
1063 :
1064 0 : LCompareStrictS* lir = new(alloc()) LCompareStrictS(useBox(left), useRegister(right),
1065 0 : tempToUnbox());
1066 0 : define(lir, comp);
1067 0 : assignSafepoint(lir, comp);
1068 0 : return;
1069 : }
1070 :
1071 : // Unknown/unspecialized compare use a VM call.
1072 45 : if (comp->compareType() == MCompare::Compare_Unknown) {
1073 0 : LCompareVM* lir = new(alloc()) LCompareVM(useBoxAtStart(left), useBoxAtStart(right));
1074 0 : defineReturn(lir, comp);
1075 0 : assignSafepoint(lir, comp);
1076 0 : return;
1077 : }
1078 :
1079 : // Sniff out if the output of this compare is used only for a branching.
1080 : // If it is, then we will emit an LCompare*AndBranch instruction in place
1081 : // of this compare and any test that uses this compare. Thus, we can
1082 : // ignore this Compare.
1083 45 : if (CanEmitCompareAtUses(comp)) {
1084 23 : emitAtUses(comp);
1085 23 : return;
1086 : }
1087 :
1088 : // Compare Null and Undefined.
1089 44 : if (comp->compareType() == MCompare::Compare_Null ||
1090 22 : comp->compareType() == MCompare::Compare_Undefined)
1091 : {
1092 0 : if (left->type() == MIRType::Object || left->type() == MIRType::ObjectOrNull) {
1093 0 : MOZ_ASSERT(left->type() == MIRType::ObjectOrNull ||
1094 : comp->operandMightEmulateUndefined(),
1095 : "MCompare::tryFold should have folded this away");
1096 :
1097 0 : define(new(alloc()) LIsNullOrLikeUndefinedT(useRegister(left)), comp);
1098 0 : return;
1099 : }
1100 :
1101 0 : LDefinition tmp, tmpToUnbox;
1102 0 : if (comp->operandMightEmulateUndefined()) {
1103 0 : tmp = temp();
1104 0 : tmpToUnbox = tempToUnbox();
1105 : } else {
1106 0 : tmp = LDefinition::BogusTemp();
1107 0 : tmpToUnbox = LDefinition::BogusTemp();
1108 : }
1109 :
1110 0 : LIsNullOrLikeUndefinedV* lir = new(alloc()) LIsNullOrLikeUndefinedV(useBox(left),
1111 0 : tmp, tmpToUnbox);
1112 0 : define(lir, comp);
1113 0 : return;
1114 : }
1115 :
1116 : // Compare booleans.
1117 22 : if (comp->compareType() == MCompare::Compare_Boolean) {
1118 0 : MOZ_ASSERT(left->type() == MIRType::Value);
1119 0 : MOZ_ASSERT(right->type() == MIRType::Boolean);
1120 :
1121 0 : LCompareB* lir = new(alloc()) LCompareB(useBox(left), useRegisterOrConstant(right));
1122 0 : define(lir, comp);
1123 0 : return;
1124 : }
1125 :
1126 : // Compare Int32, Symbol or Object pointers.
1127 44 : if (comp->isInt32Comparison() ||
1128 0 : comp->compareType() == MCompare::Compare_UInt32 ||
1129 22 : comp->compareType() == MCompare::Compare_Object ||
1130 0 : comp->compareType() == MCompare::Compare_Symbol)
1131 : {
1132 22 : JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1133 22 : LAllocation lhs = useRegister(left);
1134 22 : LAllocation rhs;
1135 22 : if (comp->isInt32Comparison() ||
1136 0 : comp->compareType() == MCompare::Compare_UInt32)
1137 : {
1138 22 : rhs = useAnyOrConstant(right);
1139 : } else {
1140 0 : rhs = useRegister(right);
1141 : }
1142 22 : define(new(alloc()) LCompare(op, lhs, rhs), comp);
1143 22 : return;
1144 : }
1145 :
1146 : // Compare Int64.
1147 0 : if (comp->compareType() == MCompare::Compare_Int64 ||
1148 0 : comp->compareType() == MCompare::Compare_UInt64)
1149 : {
1150 0 : JSOp op = ReorderComparison(comp->jsop(), &left, &right);
1151 0 : define(new(alloc()) LCompareI64(op, useInt64Register(left), useInt64OrConstant(right)),
1152 0 : comp);
1153 0 : return;
1154 : }
1155 :
1156 : // Compare doubles.
1157 0 : if (comp->isDoubleComparison()) {
1158 0 : define(new(alloc()) LCompareD(useRegister(left), useRegister(right)), comp);
1159 0 : return;
1160 : }
1161 :
1162 : // Compare float32.
1163 0 : if (comp->isFloat32Comparison()) {
1164 0 : define(new(alloc()) LCompareF(useRegister(left), useRegister(right)), comp);
1165 0 : return;
1166 : }
1167 :
1168 : // Compare values.
1169 0 : if (comp->compareType() == MCompare::Compare_Bitwise) {
1170 0 : LCompareBitwise* lir = new(alloc()) LCompareBitwise(useBoxAtStart(left),
1171 0 : useBoxAtStart(right));
1172 0 : define(lir, comp);
1173 0 : return;
1174 : }
1175 :
1176 0 : MOZ_CRASH("Unrecognized compare type.");
1177 : }
1178 :
1179 : void
1180 0 : LIRGenerator::lowerBitOp(JSOp op, MInstruction* ins)
1181 : {
1182 0 : MDefinition* lhs = ins->getOperand(0);
1183 0 : MDefinition* rhs = ins->getOperand(1);
1184 :
1185 0 : if (lhs->type() == MIRType::Int32) {
1186 0 : MOZ_ASSERT(rhs->type() == MIRType::Int32);
1187 0 : ReorderCommutative(&lhs, &rhs, ins);
1188 0 : lowerForALU(new(alloc()) LBitOpI(op), ins, lhs, rhs);
1189 0 : return;
1190 : }
1191 :
1192 0 : if (lhs->type() == MIRType::Int64) {
1193 0 : MOZ_ASSERT(rhs->type() == MIRType::Int64);
1194 0 : ReorderCommutative(&lhs, &rhs, ins);
1195 0 : lowerForALUInt64(new(alloc()) LBitOpI64(op), ins, lhs, rhs);
1196 0 : return;
1197 : }
1198 :
1199 0 : LBitOpV* lir = new(alloc()) LBitOpV(op, useBoxAtStart(lhs), useBoxAtStart(rhs));
1200 0 : defineReturn(lir, ins);
1201 0 : assignSafepoint(lir, ins);
1202 : }
1203 :
1204 : void
1205 0 : LIRGenerator::visitTypeOf(MTypeOf* ins)
1206 : {
1207 0 : MDefinition* opd = ins->input();
1208 0 : MOZ_ASSERT(opd->type() == MIRType::Value);
1209 :
1210 0 : LTypeOfV* lir = new(alloc()) LTypeOfV(useBox(opd), tempToUnbox());
1211 0 : define(lir, ins);
1212 0 : }
1213 :
1214 : void
1215 0 : LIRGenerator::visitToAsync(MToAsync* ins)
1216 : {
1217 0 : LToAsync* lir = new(alloc()) LToAsync(useRegisterAtStart(ins->input()));
1218 0 : defineReturn(lir, ins);
1219 0 : assignSafepoint(lir, ins);
1220 0 : }
1221 :
1222 : void
1223 0 : LIRGenerator::visitToAsyncGen(MToAsyncGen* ins)
1224 : {
1225 0 : LToAsyncGen* lir = new(alloc()) LToAsyncGen(useRegisterAtStart(ins->input()));
1226 0 : defineReturn(lir, ins);
1227 0 : assignSafepoint(lir, ins);
1228 0 : }
1229 :
1230 : void
1231 0 : LIRGenerator::visitToAsyncIter(MToAsyncIter* ins)
1232 : {
1233 0 : LToAsyncIter* lir = new(alloc()) LToAsyncIter(useRegisterAtStart(ins->input()));
1234 0 : defineReturn(lir, ins);
1235 0 : assignSafepoint(lir, ins);
1236 0 : }
1237 :
1238 : void
1239 0 : LIRGenerator::visitToId(MToId* ins)
1240 : {
1241 0 : LToIdV* lir = new(alloc()) LToIdV(useBox(ins->input()), tempDouble());
1242 0 : defineBox(lir, ins);
1243 0 : assignSafepoint(lir, ins);
1244 0 : }
1245 :
1246 : void
1247 0 : LIRGenerator::visitBitNot(MBitNot* ins)
1248 : {
1249 0 : MDefinition* input = ins->getOperand(0);
1250 :
1251 0 : if (input->type() == MIRType::Int32) {
1252 0 : lowerForALU(new(alloc()) LBitNotI(), ins, input);
1253 0 : return;
1254 : }
1255 :
1256 0 : LBitNotV* lir = new(alloc()) LBitNotV(useBoxAtStart(input));
1257 0 : defineReturn(lir, ins);
1258 0 : assignSafepoint(lir, ins);
1259 : }
1260 :
1261 : static bool
1262 0 : CanEmitBitAndAtUses(MInstruction* ins)
1263 : {
1264 0 : if (!ins->canEmitAtUses())
1265 0 : return false;
1266 :
1267 0 : if (ins->getOperand(0)->type() != MIRType::Int32 || ins->getOperand(1)->type() != MIRType::Int32)
1268 0 : return false;
1269 :
1270 0 : MUseIterator iter(ins->usesBegin());
1271 0 : if (iter == ins->usesEnd())
1272 0 : return false;
1273 :
1274 0 : MNode* node = iter->consumer();
1275 0 : if (!node->isDefinition() || !node->toDefinition()->isInstruction())
1276 0 : return false;
1277 :
1278 0 : MInstruction* use = node->toDefinition()->toInstruction();
1279 0 : if (!use->isTest() && !(use->isCompare() && CanEmitCompareAtUses(use)))
1280 0 : return false;
1281 :
1282 0 : iter++;
1283 0 : return iter == ins->usesEnd();
1284 : }
1285 :
1286 : void
1287 0 : LIRGenerator::visitBitAnd(MBitAnd* ins)
1288 : {
1289 : // Sniff out if the output of this bitand is used only for a branching.
1290 : // If it is, then we will emit an LBitAndAndBranch instruction in place
1291 : // of this bitand and any test that uses this bitand. Thus, we can
1292 : // ignore this BitAnd.
1293 0 : if (CanEmitBitAndAtUses(ins))
1294 0 : emitAtUses(ins);
1295 : else
1296 0 : lowerBitOp(JSOP_BITAND, ins);
1297 0 : }
1298 :
1299 : void
1300 0 : LIRGenerator::visitBitOr(MBitOr* ins)
1301 : {
1302 0 : lowerBitOp(JSOP_BITOR, ins);
1303 0 : }
1304 :
1305 : void
1306 0 : LIRGenerator::visitBitXor(MBitXor* ins)
1307 : {
1308 0 : lowerBitOp(JSOP_BITXOR, ins);
1309 0 : }
1310 :
1311 : void
1312 0 : LIRGenerator::lowerShiftOp(JSOp op, MShiftInstruction* ins)
1313 : {
1314 0 : MDefinition* lhs = ins->getOperand(0);
1315 0 : MDefinition* rhs = ins->getOperand(1);
1316 :
1317 0 : if (lhs->type() == MIRType::Int32) {
1318 0 : MOZ_ASSERT(rhs->type() == MIRType::Int32);
1319 :
1320 0 : if (ins->type() == MIRType::Double) {
1321 0 : MOZ_ASSERT(op == JSOP_URSH);
1322 0 : lowerUrshD(ins->toUrsh());
1323 0 : return;
1324 : }
1325 :
1326 0 : LShiftI* lir = new(alloc()) LShiftI(op);
1327 0 : if (op == JSOP_URSH) {
1328 0 : if (ins->toUrsh()->fallible())
1329 0 : assignSnapshot(lir, Bailout_OverflowInvalidate);
1330 : }
1331 0 : lowerForShift(lir, ins, lhs, rhs);
1332 0 : return;
1333 : }
1334 :
1335 0 : if (lhs->type() == MIRType::Int64) {
1336 0 : MOZ_ASSERT(rhs->type() == MIRType::Int64);
1337 0 : lowerForShiftInt64(new(alloc()) LShiftI64(op), ins, lhs, rhs);
1338 0 : return;
1339 : }
1340 :
1341 0 : MOZ_ASSERT(ins->specialization() == MIRType::None);
1342 :
1343 0 : if (op == JSOP_URSH) {
1344 : // Result is either int32 or double so we have to use BinaryV.
1345 0 : lowerBinaryV(JSOP_URSH, ins);
1346 0 : return;
1347 : }
1348 :
1349 0 : LBitOpV* lir = new(alloc()) LBitOpV(op, useBoxAtStart(lhs), useBoxAtStart(rhs));
1350 0 : defineReturn(lir, ins);
1351 0 : assignSafepoint(lir, ins);
1352 : }
1353 :
1354 : void
1355 0 : LIRGenerator::visitLsh(MLsh* ins)
1356 : {
1357 0 : lowerShiftOp(JSOP_LSH, ins);
1358 0 : }
1359 :
1360 : void
1361 0 : LIRGenerator::visitRsh(MRsh* ins)
1362 : {
1363 0 : lowerShiftOp(JSOP_RSH, ins);
1364 0 : }
1365 :
1366 : void
1367 0 : LIRGenerator::visitUrsh(MUrsh* ins)
1368 : {
1369 0 : lowerShiftOp(JSOP_URSH, ins);
1370 0 : }
1371 :
1372 : void
1373 0 : LIRGenerator::visitSignExtend(MSignExtend* ins)
1374 : {
1375 : LInstructionHelper<1, 1, 0>* lir;
1376 :
1377 0 : if (ins->mode() == MSignExtend::Byte)
1378 0 : lir = new(alloc()) LSignExtend(useByteOpRegisterAtStart(ins->input()), ins->mode());
1379 : else
1380 0 : lir = new(alloc()) LSignExtend(useRegisterAtStart(ins->input()), ins->mode());
1381 :
1382 0 : define(lir, ins);
1383 0 : }
1384 :
1385 : void
1386 0 : LIRGenerator::visitRotate(MRotate* ins)
1387 : {
1388 0 : MDefinition* input = ins->input();
1389 0 : MDefinition* count = ins->count();
1390 :
1391 0 : if (ins->type() == MIRType::Int32) {
1392 0 : auto* lir = new(alloc()) LRotate();
1393 0 : lowerForShift(lir, ins, input, count);
1394 0 : } else if (ins->type() == MIRType::Int64) {
1395 0 : auto* lir = new(alloc()) LRotateI64();
1396 0 : lowerForShiftInt64(lir, ins, input, count);
1397 : } else {
1398 0 : MOZ_CRASH("unexpected type in visitRotate");
1399 : }
1400 0 : }
1401 :
1402 : void
1403 0 : LIRGenerator::visitFloor(MFloor* ins)
1404 : {
1405 0 : MIRType type = ins->input()->type();
1406 0 : MOZ_ASSERT(IsFloatingPointType(type));
1407 :
1408 : LInstructionHelper<1, 1, 0>* lir;
1409 0 : if (type == MIRType::Double)
1410 0 : lir = new(alloc()) LFloor(useRegister(ins->input()));
1411 : else
1412 0 : lir = new(alloc()) LFloorF(useRegister(ins->input()));
1413 :
1414 0 : assignSnapshot(lir, Bailout_Round);
1415 0 : define(lir, ins);
1416 0 : }
1417 :
1418 : void
1419 0 : LIRGenerator::visitCeil(MCeil* ins)
1420 : {
1421 0 : MIRType type = ins->input()->type();
1422 0 : MOZ_ASSERT(IsFloatingPointType(type));
1423 :
1424 : LInstructionHelper<1, 1, 0>* lir;
1425 0 : if (type == MIRType::Double)
1426 0 : lir = new(alloc()) LCeil(useRegister(ins->input()));
1427 : else
1428 0 : lir = new(alloc()) LCeilF(useRegister(ins->input()));
1429 :
1430 0 : assignSnapshot(lir, Bailout_Round);
1431 0 : define(lir, ins);
1432 0 : }
1433 :
1434 : void
1435 0 : LIRGenerator::visitRound(MRound* ins)
1436 : {
1437 0 : MIRType type = ins->input()->type();
1438 0 : MOZ_ASSERT(IsFloatingPointType(type));
1439 :
1440 : LInstructionHelper<1, 1, 1>* lir;
1441 0 : if (type == MIRType::Double)
1442 0 : lir = new (alloc()) LRound(useRegister(ins->input()), tempDouble());
1443 : else
1444 0 : lir = new (alloc()) LRoundF(useRegister(ins->input()), tempFloat32());
1445 :
1446 0 : assignSnapshot(lir, Bailout_Round);
1447 0 : define(lir, ins);
1448 0 : }
1449 :
1450 : void
1451 0 : LIRGenerator::visitNearbyInt(MNearbyInt* ins)
1452 : {
1453 0 : MIRType inputType = ins->input()->type();
1454 0 : MOZ_ASSERT(IsFloatingPointType(inputType));
1455 0 : MOZ_ASSERT(ins->type() == inputType);
1456 :
1457 : LInstructionHelper<1, 1, 0>* lir;
1458 0 : if (inputType == MIRType::Double)
1459 0 : lir = new(alloc()) LNearbyInt(useRegisterAtStart(ins->input()));
1460 : else
1461 0 : lir = new(alloc()) LNearbyIntF(useRegisterAtStart(ins->input()));
1462 :
1463 0 : define(lir, ins);
1464 0 : }
1465 :
1466 : void
1467 5 : LIRGenerator::visitMinMax(MMinMax* ins)
1468 : {
1469 5 : MDefinition* first = ins->getOperand(0);
1470 5 : MDefinition* second = ins->getOperand(1);
1471 :
1472 5 : ReorderCommutative(&first, &second, ins);
1473 :
1474 : LMinMaxBase* lir;
1475 5 : switch (ins->specialization()) {
1476 : case MIRType::Int32:
1477 5 : lir = new(alloc()) LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
1478 5 : break;
1479 : case MIRType::Float32:
1480 0 : lir = new(alloc()) LMinMaxF(useRegisterAtStart(first), useRegister(second));
1481 0 : break;
1482 : case MIRType::Double:
1483 0 : lir = new(alloc()) LMinMaxD(useRegisterAtStart(first), useRegister(second));
1484 0 : break;
1485 : default:
1486 0 : MOZ_CRASH();
1487 : }
1488 :
1489 5 : defineReuseInput(lir, ins, 0);
1490 5 : }
1491 :
1492 : void
1493 0 : LIRGenerator::visitAbs(MAbs* ins)
1494 : {
1495 0 : MDefinition* num = ins->input();
1496 0 : MOZ_ASSERT(IsNumberType(num->type()));
1497 :
1498 : LInstructionHelper<1, 1, 0>* lir;
1499 0 : switch (num->type()) {
1500 : case MIRType::Int32:
1501 0 : lir = new(alloc()) LAbsI(useRegisterAtStart(num));
1502 : // needed to handle abs(INT32_MIN)
1503 0 : if (ins->fallible())
1504 0 : assignSnapshot(lir, Bailout_Overflow);
1505 0 : break;
1506 : case MIRType::Float32:
1507 0 : lir = new(alloc()) LAbsF(useRegisterAtStart(num));
1508 0 : break;
1509 : case MIRType::Double:
1510 0 : lir = new(alloc()) LAbsD(useRegisterAtStart(num));
1511 0 : break;
1512 : default:
1513 0 : MOZ_CRASH();
1514 : }
1515 :
1516 0 : defineReuseInput(lir, ins, 0);
1517 0 : }
1518 :
1519 : void
1520 0 : LIRGenerator::visitClz(MClz* ins)
1521 : {
1522 0 : MDefinition* num = ins->num();
1523 :
1524 0 : MOZ_ASSERT(IsIntType(ins->type()));
1525 :
1526 0 : if (ins->type() == MIRType::Int32) {
1527 0 : LClzI* lir = new(alloc()) LClzI(useRegisterAtStart(num));
1528 0 : define(lir, ins);
1529 0 : return;
1530 : }
1531 :
1532 0 : auto* lir = new(alloc()) LClzI64(useInt64RegisterAtStart(num));
1533 0 : defineInt64(lir, ins);
1534 : }
1535 :
1536 : void
1537 0 : LIRGenerator::visitCtz(MCtz* ins)
1538 : {
1539 0 : MDefinition* num = ins->num();
1540 :
1541 0 : MOZ_ASSERT(IsIntType(ins->type()));
1542 :
1543 0 : if (ins->type() == MIRType::Int32) {
1544 0 : LCtzI* lir = new(alloc()) LCtzI(useRegisterAtStart(num));
1545 0 : define(lir, ins);
1546 0 : return;
1547 : }
1548 :
1549 0 : auto* lir = new(alloc()) LCtzI64(useInt64RegisterAtStart(num));
1550 0 : defineInt64(lir, ins);
1551 : }
1552 :
1553 : void
1554 0 : LIRGenerator::visitPopcnt(MPopcnt* ins)
1555 : {
1556 0 : MDefinition* num = ins->num();
1557 :
1558 0 : MOZ_ASSERT(IsIntType(ins->type()));
1559 :
1560 0 : if (ins->type() == MIRType::Int32) {
1561 0 : LPopcntI* lir = new(alloc()) LPopcntI(useRegisterAtStart(num), temp());
1562 0 : define(lir, ins);
1563 0 : return;
1564 : }
1565 :
1566 0 : auto* lir = new(alloc()) LPopcntI64(useInt64RegisterAtStart(num), temp());
1567 0 : defineInt64(lir, ins);
1568 : }
1569 :
1570 : void
1571 0 : LIRGenerator::visitSqrt(MSqrt* ins)
1572 : {
1573 0 : MDefinition* num = ins->input();
1574 0 : MOZ_ASSERT(IsFloatingPointType(num->type()));
1575 :
1576 : LInstructionHelper<1, 1, 0>* lir;
1577 0 : if (num->type() == MIRType::Double)
1578 0 : lir = new(alloc()) LSqrtD(useRegisterAtStart(num));
1579 : else
1580 0 : lir = new(alloc()) LSqrtF(useRegisterAtStart(num));
1581 0 : define(lir, ins);
1582 0 : }
1583 :
1584 : void
1585 0 : LIRGenerator::visitAtan2(MAtan2* ins)
1586 : {
1587 0 : MDefinition* y = ins->y();
1588 0 : MOZ_ASSERT(y->type() == MIRType::Double);
1589 :
1590 0 : MDefinition* x = ins->x();
1591 0 : MOZ_ASSERT(x->type() == MIRType::Double);
1592 :
1593 0 : LAtan2D* lir = new(alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x),
1594 0 : tempFixed(CallTempReg0));
1595 0 : defineReturn(lir, ins);
1596 0 : }
1597 :
1598 : void
1599 0 : LIRGenerator::visitHypot(MHypot* ins)
1600 : {
1601 0 : LHypot* lir = nullptr;
1602 0 : uint32_t length = ins->numOperands();
1603 0 : for (uint32_t i = 0; i < length; ++i)
1604 0 : MOZ_ASSERT(ins->getOperand(i)->type() == MIRType::Double);
1605 :
1606 0 : switch(length) {
1607 : case 2:
1608 0 : lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1609 0 : useRegisterAtStart(ins->getOperand(1)),
1610 0 : tempFixed(CallTempReg0));
1611 0 : break;
1612 : case 3:
1613 0 : lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1614 0 : useRegisterAtStart(ins->getOperand(1)),
1615 0 : useRegisterAtStart(ins->getOperand(2)),
1616 0 : tempFixed(CallTempReg0));
1617 0 : break;
1618 : case 4:
1619 0 : lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
1620 0 : useRegisterAtStart(ins->getOperand(1)),
1621 0 : useRegisterAtStart(ins->getOperand(2)),
1622 0 : useRegisterAtStart(ins->getOperand(3)),
1623 0 : tempFixed(CallTempReg0));
1624 0 : break;
1625 : default:
1626 0 : MOZ_CRASH("Unexpected number of arguments to LHypot.");
1627 : }
1628 :
1629 0 : defineReturn(lir, ins);
1630 0 : }
1631 :
1632 : void
1633 0 : LIRGenerator::visitPow(MPow* ins)
1634 : {
1635 0 : MDefinition* input = ins->input();
1636 0 : MDefinition* power = ins->power();
1637 : LInstruction* lir;
1638 :
1639 0 : if (ins->specialization() == MIRType::None) {
1640 0 : MOZ_ASSERT(input->type() == MIRType::Value);
1641 0 : MOZ_ASSERT(power->type() == MIRType::Value);
1642 :
1643 0 : lir = new(alloc()) LPowV(useBoxAtStart(input), useBoxAtStart(power));
1644 0 : defineReturn(lir, ins);
1645 0 : assignSafepoint(lir, ins);
1646 0 : return;
1647 : }
1648 :
1649 0 : MOZ_ASSERT(input->type() == MIRType::Double);
1650 0 : MOZ_ASSERT(power->type() == MIRType::Int32 || power->type() == MIRType::Double);
1651 :
1652 0 : if (power->type() == MIRType::Int32) {
1653 : // Note: useRegisterAtStart here is safe, the temp is a GP register so
1654 : // it will never get the same register.
1655 0 : lir = new(alloc()) LPowI(useRegisterAtStart(input), useFixedAtStart(power, CallTempReg1),
1656 0 : tempFixed(CallTempReg0));
1657 : } else {
1658 0 : lir = new(alloc()) LPowD(useRegisterAtStart(input), useRegisterAtStart(power),
1659 0 : tempFixed(CallTempReg0));
1660 : }
1661 0 : defineReturn(lir, ins);
1662 : }
1663 :
1664 : void
1665 0 : LIRGenerator::visitMathFunction(MMathFunction* ins)
1666 : {
1667 0 : MOZ_ASSERT(IsFloatingPointType(ins->type()));
1668 0 : MOZ_ASSERT_IF(ins->input()->type() != MIRType::SinCosDouble,
1669 : ins->type() == ins->input()->type());
1670 :
1671 0 : if (ins->input()->type() == MIRType::SinCosDouble) {
1672 0 : MOZ_ASSERT(ins->type() == MIRType::Double);
1673 0 : redefine(ins, ins->input(), ins->function());
1674 0 : return;
1675 : }
1676 :
1677 : LInstruction* lir;
1678 0 : if (ins->type() == MIRType::Double) {
1679 : // Note: useRegisterAtStart is safe here, the temp is not a FP register.
1680 0 : lir = new(alloc()) LMathFunctionD(useRegisterAtStart(ins->input()),
1681 0 : tempFixed(CallTempReg0));
1682 : } else {
1683 0 : lir = new(alloc()) LMathFunctionF(useRegisterAtStart(ins->input()),
1684 0 : tempFixed(CallTempReg0));
1685 : }
1686 0 : defineReturn(lir, ins);
1687 : }
1688 :
1689 : // Try to mark an add or sub instruction as able to recover its input when
1690 : // bailing out.
1691 : template <typename S, typename T>
1692 : static void
1693 8 : MaybeSetRecoversInput(S* mir, T* lir)
1694 : {
1695 8 : MOZ_ASSERT(lir->mirRaw() == mir);
1696 8 : if (!mir->fallible() || !lir->snapshot())
1697 7 : return;
1698 :
1699 1 : if (lir->output()->policy() != LDefinition::MUST_REUSE_INPUT)
1700 0 : return;
1701 :
1702 : // The original operands to an add or sub can't be recovered if they both
1703 : // use the same register.
1704 1 : if (lir->lhs()->isUse() && lir->rhs()->isUse() &&
1705 0 : lir->lhs()->toUse()->virtualRegister() == lir->rhs()->toUse()->virtualRegister())
1706 : {
1707 0 : return;
1708 : }
1709 :
1710 : // Add instructions that are on two different values can recover
1711 : // the input they clobbered via MUST_REUSE_INPUT. Thus, a copy
1712 : // of that input does not need to be kept alive in the snapshot
1713 : // for the instruction.
1714 :
1715 1 : lir->setRecoversInput();
1716 :
1717 1 : const LUse* input = lir->getOperand(lir->output()->getReusedInput())->toUse();
1718 1 : lir->snapshot()->rewriteRecoveredInput(*input);
1719 : }
1720 :
1721 : void
1722 8 : LIRGenerator::visitAdd(MAdd* ins)
1723 : {
1724 8 : MDefinition* lhs = ins->getOperand(0);
1725 8 : MDefinition* rhs = ins->getOperand(1);
1726 :
1727 8 : MOZ_ASSERT(lhs->type() == rhs->type());
1728 :
1729 8 : if (ins->specialization() == MIRType::Int32) {
1730 8 : MOZ_ASSERT(lhs->type() == MIRType::Int32);
1731 8 : ReorderCommutative(&lhs, &rhs, ins);
1732 8 : LAddI* lir = new(alloc()) LAddI;
1733 :
1734 8 : if (ins->fallible())
1735 1 : assignSnapshot(lir, Bailout_OverflowInvalidate);
1736 :
1737 8 : lowerForALU(lir, ins, lhs, rhs);
1738 8 : MaybeSetRecoversInput(ins, lir);
1739 8 : return;
1740 : }
1741 :
1742 0 : if (ins->specialization() == MIRType::Int64) {
1743 0 : MOZ_ASSERT(lhs->type() == MIRType::Int64);
1744 0 : ReorderCommutative(&lhs, &rhs, ins);
1745 0 : LAddI64* lir = new(alloc()) LAddI64;
1746 0 : lowerForALUInt64(lir, ins, lhs, rhs);
1747 0 : return;
1748 : }
1749 :
1750 0 : if (ins->specialization() == MIRType::Double) {
1751 0 : MOZ_ASSERT(lhs->type() == MIRType::Double);
1752 0 : ReorderCommutative(&lhs, &rhs, ins);
1753 0 : lowerForFPU(new(alloc()) LMathD(JSOP_ADD), ins, lhs, rhs);
1754 0 : return;
1755 : }
1756 :
1757 0 : if (ins->specialization() == MIRType::Float32) {
1758 0 : MOZ_ASSERT(lhs->type() == MIRType::Float32);
1759 0 : ReorderCommutative(&lhs, &rhs, ins);
1760 0 : lowerForFPU(new(alloc()) LMathF(JSOP_ADD), ins, lhs, rhs);
1761 0 : return;
1762 : }
1763 :
1764 0 : lowerBinaryV(JSOP_ADD, ins);
1765 : }
1766 :
1767 : void
1768 0 : LIRGenerator::visitSub(MSub* ins)
1769 : {
1770 0 : MDefinition* lhs = ins->lhs();
1771 0 : MDefinition* rhs = ins->rhs();
1772 :
1773 0 : MOZ_ASSERT(lhs->type() == rhs->type());
1774 :
1775 0 : if (ins->specialization() == MIRType::Int32) {
1776 0 : MOZ_ASSERT(lhs->type() == MIRType::Int32);
1777 :
1778 0 : LSubI* lir = new(alloc()) LSubI;
1779 0 : if (ins->fallible())
1780 0 : assignSnapshot(lir, Bailout_Overflow);
1781 :
1782 0 : lowerForALU(lir, ins, lhs, rhs);
1783 0 : MaybeSetRecoversInput(ins, lir);
1784 0 : return;
1785 : }
1786 :
1787 0 : if (ins->specialization() == MIRType::Int64) {
1788 0 : MOZ_ASSERT(lhs->type() == MIRType::Int64);
1789 0 : LSubI64* lir = new(alloc()) LSubI64;
1790 0 : lowerForALUInt64(lir, ins, lhs, rhs);
1791 0 : return;
1792 : }
1793 :
1794 0 : if (ins->specialization() == MIRType::Double) {
1795 0 : MOZ_ASSERT(lhs->type() == MIRType::Double);
1796 0 : lowerForFPU(new(alloc()) LMathD(JSOP_SUB), ins, lhs, rhs);
1797 0 : return;
1798 : }
1799 :
1800 0 : if (ins->specialization() == MIRType::Float32) {
1801 0 : MOZ_ASSERT(lhs->type() == MIRType::Float32);
1802 0 : lowerForFPU(new(alloc()) LMathF(JSOP_SUB), ins, lhs, rhs);
1803 0 : return;
1804 : }
1805 :
1806 0 : lowerBinaryV(JSOP_SUB, ins);
1807 : }
1808 :
1809 : void
1810 0 : LIRGenerator::visitMul(MMul* ins)
1811 : {
1812 0 : MDefinition* lhs = ins->lhs();
1813 0 : MDefinition* rhs = ins->rhs();
1814 0 : MOZ_ASSERT(lhs->type() == rhs->type());
1815 :
1816 0 : if (ins->specialization() == MIRType::Int32) {
1817 0 : MOZ_ASSERT(lhs->type() == MIRType::Int32);
1818 0 : ReorderCommutative(&lhs, &rhs, ins);
1819 :
1820 : // If our RHS is a constant -1 and we don't have to worry about
1821 : // overflow, we can optimize to an LNegI.
1822 0 : if (!ins->fallible() && rhs->isConstant() && rhs->toConstant()->toInt32() == -1)
1823 0 : defineReuseInput(new(alloc()) LNegI(useRegisterAtStart(lhs)), ins, 0);
1824 : else
1825 0 : lowerMulI(ins, lhs, rhs);
1826 0 : return;
1827 : }
1828 :
1829 0 : if (ins->specialization() == MIRType::Int64) {
1830 0 : MOZ_ASSERT(lhs->type() == MIRType::Int64);
1831 0 : ReorderCommutative(&lhs, &rhs, ins);
1832 0 : LMulI64* lir = new(alloc()) LMulI64;
1833 0 : lowerForMulInt64(lir, ins, lhs, rhs);
1834 0 : return;
1835 : }
1836 :
1837 0 : if (ins->specialization() == MIRType::Double) {
1838 0 : MOZ_ASSERT(lhs->type() == MIRType::Double);
1839 0 : ReorderCommutative(&lhs, &rhs, ins);
1840 :
1841 : // If our RHS is a constant -1.0, we can optimize to an LNegD.
1842 0 : if (!ins->mustPreserveNaN() && rhs->isConstant() && rhs->toConstant()->toDouble() == -1.0)
1843 0 : defineReuseInput(new(alloc()) LNegD(useRegisterAtStart(lhs)), ins, 0);
1844 : else
1845 0 : lowerForFPU(new(alloc()) LMathD(JSOP_MUL), ins, lhs, rhs);
1846 0 : return;
1847 : }
1848 :
1849 0 : if (ins->specialization() == MIRType::Float32) {
1850 0 : MOZ_ASSERT(lhs->type() == MIRType::Float32);
1851 0 : ReorderCommutative(&lhs, &rhs, ins);
1852 :
1853 : // We apply the same optimizations as for doubles
1854 0 : if (!ins->mustPreserveNaN() && rhs->isConstant() && rhs->toConstant()->toFloat32() == -1.0f)
1855 0 : defineReuseInput(new(alloc()) LNegF(useRegisterAtStart(lhs)), ins, 0);
1856 : else
1857 0 : lowerForFPU(new(alloc()) LMathF(JSOP_MUL), ins, lhs, rhs);
1858 0 : return;
1859 : }
1860 :
1861 0 : lowerBinaryV(JSOP_MUL, ins);
1862 : }
1863 :
1864 : void
1865 0 : LIRGenerator::visitDiv(MDiv* ins)
1866 : {
1867 0 : MDefinition* lhs = ins->lhs();
1868 0 : MDefinition* rhs = ins->rhs();
1869 0 : MOZ_ASSERT(lhs->type() == rhs->type());
1870 :
1871 0 : if (ins->specialization() == MIRType::Int32) {
1872 0 : MOZ_ASSERT(lhs->type() == MIRType::Int32);
1873 0 : lowerDivI(ins);
1874 0 : return;
1875 : }
1876 :
1877 0 : if (ins->specialization() == MIRType::Int64) {
1878 0 : MOZ_ASSERT(lhs->type() == MIRType::Int64);
1879 0 : lowerDivI64(ins);
1880 0 : return;
1881 : }
1882 :
1883 0 : if (ins->specialization() == MIRType::Double) {
1884 0 : MOZ_ASSERT(lhs->type() == MIRType::Double);
1885 0 : lowerForFPU(new(alloc()) LMathD(JSOP_DIV), ins, lhs, rhs);
1886 0 : return;
1887 : }
1888 :
1889 0 : if (ins->specialization() == MIRType::Float32) {
1890 0 : MOZ_ASSERT(lhs->type() == MIRType::Float32);
1891 0 : lowerForFPU(new(alloc()) LMathF(JSOP_DIV), ins, lhs, rhs);
1892 0 : return;
1893 : }
1894 :
1895 0 : lowerBinaryV(JSOP_DIV, ins);
1896 : }
1897 :
1898 : void
1899 0 : LIRGenerator::visitMod(MMod* ins)
1900 : {
1901 0 : MOZ_ASSERT(ins->lhs()->type() == ins->rhs()->type());
1902 :
1903 0 : if (ins->specialization() == MIRType::Int32) {
1904 0 : MOZ_ASSERT(ins->type() == MIRType::Int32);
1905 0 : MOZ_ASSERT(ins->lhs()->type() == MIRType::Int32);
1906 0 : lowerModI(ins);
1907 0 : return;
1908 : }
1909 :
1910 0 : if (ins->specialization() == MIRType::Int64) {
1911 0 : MOZ_ASSERT(ins->type() == MIRType::Int64);
1912 0 : MOZ_ASSERT(ins->lhs()->type() == MIRType::Int64);
1913 0 : lowerModI64(ins);
1914 0 : return;
1915 : }
1916 :
1917 0 : if (ins->specialization() == MIRType::Double) {
1918 0 : MOZ_ASSERT(ins->type() == MIRType::Double);
1919 0 : MOZ_ASSERT(ins->lhs()->type() == MIRType::Double);
1920 0 : MOZ_ASSERT(ins->rhs()->type() == MIRType::Double);
1921 :
1922 : // Ion does an unaligned ABI call and thus needs a temp register. Wasm
1923 : // doesn't.
1924 0 : LDefinition maybeTemp = gen->compilingWasm()
1925 : ? LDefinition::BogusTemp()
1926 0 : : tempFixed(CallTempReg0);
1927 :
1928 : // Note: useRegisterAtStart is safe here, the temp is not a FP register.
1929 0 : LModD* lir = new(alloc()) LModD(useRegisterAtStart(ins->lhs()),
1930 0 : useRegisterAtStart(ins->rhs()),
1931 0 : maybeTemp);
1932 0 : defineReturn(lir, ins);
1933 0 : return;
1934 : }
1935 :
1936 0 : lowerBinaryV(JSOP_MOD, ins);
1937 : }
1938 :
1939 : void
1940 0 : LIRGenerator::lowerBinaryV(JSOp op, MBinaryInstruction* ins)
1941 : {
1942 0 : MDefinition* lhs = ins->getOperand(0);
1943 0 : MDefinition* rhs = ins->getOperand(1);
1944 :
1945 0 : MOZ_ASSERT(lhs->type() == MIRType::Value);
1946 0 : MOZ_ASSERT(rhs->type() == MIRType::Value);
1947 :
1948 0 : LBinaryV* lir = new(alloc()) LBinaryV(op, useBoxAtStart(lhs), useBoxAtStart(rhs));
1949 0 : defineReturn(lir, ins);
1950 0 : assignSafepoint(lir, ins);
1951 0 : }
1952 :
1953 : void
1954 12 : LIRGenerator::visitConcat(MConcat* ins)
1955 : {
1956 12 : MDefinition* lhs = ins->getOperand(0);
1957 12 : MDefinition* rhs = ins->getOperand(1);
1958 :
1959 12 : MOZ_ASSERT(lhs->type() == MIRType::String);
1960 12 : MOZ_ASSERT(rhs->type() == MIRType::String);
1961 12 : MOZ_ASSERT(ins->type() == MIRType::String);
1962 :
1963 36 : LConcat* lir = new(alloc()) LConcat(useFixedAtStart(lhs, CallTempReg0),
1964 24 : useFixedAtStart(rhs, CallTempReg1),
1965 24 : tempFixed(CallTempReg0),
1966 24 : tempFixed(CallTempReg1),
1967 24 : tempFixed(CallTempReg2),
1968 24 : tempFixed(CallTempReg3),
1969 84 : tempFixed(CallTempReg4));
1970 12 : defineFixed(lir, ins, LAllocation(AnyRegister(CallTempReg5)));
1971 12 : assignSafepoint(lir, ins);
1972 12 : }
1973 :
1974 : void
1975 2 : LIRGenerator::visitCharCodeAt(MCharCodeAt* ins)
1976 : {
1977 2 : MDefinition* str = ins->getOperand(0);
1978 2 : MDefinition* idx = ins->getOperand(1);
1979 :
1980 2 : MOZ_ASSERT(str->type() == MIRType::String);
1981 2 : MOZ_ASSERT(idx->type() == MIRType::Int32);
1982 :
1983 2 : LCharCodeAt* lir = new(alloc()) LCharCodeAt(useRegister(str), useRegister(idx));
1984 2 : define(lir, ins);
1985 2 : assignSafepoint(lir, ins);
1986 2 : }
1987 :
1988 : void
1989 2 : LIRGenerator::visitFromCharCode(MFromCharCode* ins)
1990 : {
1991 2 : MDefinition* code = ins->getOperand(0);
1992 :
1993 2 : MOZ_ASSERT(code->type() == MIRType::Int32);
1994 :
1995 2 : LFromCharCode* lir = new(alloc()) LFromCharCode(useRegister(code));
1996 2 : define(lir, ins);
1997 2 : assignSafepoint(lir, ins);
1998 2 : }
1999 :
2000 : void
2001 0 : LIRGenerator::visitFromCodePoint(MFromCodePoint* ins)
2002 : {
2003 0 : MDefinition* codePoint = ins->getOperand(0);
2004 :
2005 0 : MOZ_ASSERT(codePoint->type() == MIRType::Int32);
2006 :
2007 0 : LFromCodePoint* lir = new(alloc()) LFromCodePoint(useRegister(codePoint), temp(), temp());
2008 0 : assignSnapshot(lir, Bailout_BoundsCheck);
2009 0 : define(lir, ins);
2010 0 : assignSafepoint(lir, ins);
2011 0 : }
2012 :
2013 : void
2014 11 : LIRGenerator::visitStart(MStart* start)
2015 : {
2016 11 : LStart* lir = new(alloc()) LStart;
2017 :
2018 : // Create a snapshot that captures the initial state of the function.
2019 11 : assignSnapshot(lir, Bailout_ArgumentCheck);
2020 11 : if (start->block()->graph().entryBlock() == start->block())
2021 8 : lirGraph_.setEntrySnapshot(lir->snapshot());
2022 :
2023 11 : add(lir);
2024 11 : }
2025 :
2026 : void
2027 60 : LIRGenerator::visitNop(MNop* nop)
2028 : {
2029 60 : }
2030 :
2031 : void
2032 5 : LIRGenerator::visitLimitedTruncate(MLimitedTruncate* nop)
2033 : {
2034 5 : redefine(nop, nop->input());
2035 5 : }
2036 :
2037 : void
2038 3 : LIRGenerator::visitOsrEntry(MOsrEntry* entry)
2039 : {
2040 3 : LOsrEntry* lir = new(alloc()) LOsrEntry(temp());
2041 3 : defineFixed(lir, entry, LAllocation(AnyRegister(OsrFrameReg)));
2042 3 : }
2043 :
2044 : void
2045 42 : LIRGenerator::visitOsrValue(MOsrValue* value)
2046 : {
2047 42 : LOsrValue* lir = new(alloc()) LOsrValue(useRegister(value->entry()));
2048 42 : defineBox(lir, value);
2049 42 : }
2050 :
2051 : void
2052 3 : LIRGenerator::visitOsrReturnValue(MOsrReturnValue* value)
2053 : {
2054 3 : LOsrReturnValue* lir = new(alloc()) LOsrReturnValue(useRegister(value->entry()));
2055 3 : defineBox(lir, value);
2056 3 : }
2057 :
2058 : void
2059 2 : LIRGenerator::visitOsrEnvironmentChain(MOsrEnvironmentChain* object)
2060 : {
2061 2 : LOsrEnvironmentChain* lir = new(alloc()) LOsrEnvironmentChain(useRegister(object->entry()));
2062 2 : define(lir, object);
2063 2 : }
2064 :
2065 : void
2066 0 : LIRGenerator::visitOsrArgumentsObject(MOsrArgumentsObject* object)
2067 : {
2068 0 : LOsrArgumentsObject* lir = new(alloc()) LOsrArgumentsObject(useRegister(object->entry()));
2069 0 : define(lir, object);
2070 0 : }
2071 :
2072 : void
2073 0 : LIRGenerator::visitToDouble(MToDouble* convert)
2074 : {
2075 0 : MDefinition* opd = convert->input();
2076 0 : mozilla::DebugOnly<MToFPInstruction::ConversionKind> conversion = convert->conversion();
2077 :
2078 0 : switch (opd->type()) {
2079 : case MIRType::Value:
2080 : {
2081 0 : LValueToDouble* lir = new(alloc()) LValueToDouble(useBox(opd));
2082 0 : assignSnapshot(lir, Bailout_NonPrimitiveInput);
2083 0 : define(lir, convert);
2084 0 : break;
2085 : }
2086 :
2087 : case MIRType::Null:
2088 0 : MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly &&
2089 : conversion != MToFPInstruction::NonNullNonStringPrimitives);
2090 0 : lowerConstantDouble(0, convert);
2091 0 : break;
2092 :
2093 : case MIRType::Undefined:
2094 0 : MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
2095 0 : lowerConstantDouble(GenericNaN(), convert);
2096 0 : break;
2097 :
2098 : case MIRType::Boolean:
2099 0 : MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
2100 : MOZ_FALLTHROUGH;
2101 :
2102 : case MIRType::Int32:
2103 : {
2104 0 : LInt32ToDouble* lir = new(alloc()) LInt32ToDouble(useRegisterAtStart(opd));
2105 0 : define(lir, convert);
2106 0 : break;
2107 : }
2108 :
2109 : case MIRType::Float32:
2110 : {
2111 0 : LFloat32ToDouble* lir = new (alloc()) LFloat32ToDouble(useRegisterAtStart(opd));
2112 0 : define(lir, convert);
2113 0 : break;
2114 : }
2115 :
2116 : case MIRType::Double:
2117 0 : redefine(convert, opd);
2118 0 : break;
2119 :
2120 : default:
2121 : // Objects might be effectful. Symbols will throw.
2122 : // Strings are complicated - we don't handle them yet.
2123 0 : MOZ_CRASH("unexpected type");
2124 : }
2125 0 : }
2126 :
2127 : void
2128 0 : LIRGenerator::visitToFloat32(MToFloat32* convert)
2129 : {
2130 0 : MDefinition* opd = convert->input();
2131 0 : mozilla::DebugOnly<MToFloat32::ConversionKind> conversion = convert->conversion();
2132 :
2133 0 : switch (opd->type()) {
2134 : case MIRType::Value:
2135 : {
2136 0 : LValueToFloat32* lir = new(alloc()) LValueToFloat32(useBox(opd));
2137 0 : assignSnapshot(lir, Bailout_NonPrimitiveInput);
2138 0 : define(lir, convert);
2139 0 : break;
2140 : }
2141 :
2142 : case MIRType::Null:
2143 0 : MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly &&
2144 : conversion != MToFPInstruction::NonNullNonStringPrimitives);
2145 0 : lowerConstantFloat32(0, convert);
2146 0 : break;
2147 :
2148 : case MIRType::Undefined:
2149 0 : MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
2150 0 : lowerConstantFloat32(GenericNaN(), convert);
2151 0 : break;
2152 :
2153 : case MIRType::Boolean:
2154 0 : MOZ_ASSERT(conversion != MToFPInstruction::NumbersOnly);
2155 : MOZ_FALLTHROUGH;
2156 :
2157 : case MIRType::Int32:
2158 : {
2159 0 : LInt32ToFloat32* lir = new(alloc()) LInt32ToFloat32(useRegisterAtStart(opd));
2160 0 : define(lir, convert);
2161 0 : break;
2162 : }
2163 :
2164 : case MIRType::Double:
2165 : {
2166 0 : LDoubleToFloat32* lir = new(alloc()) LDoubleToFloat32(useRegisterAtStart(opd));
2167 0 : define(lir, convert);
2168 0 : break;
2169 : }
2170 :
2171 : case MIRType::Float32:
2172 0 : redefine(convert, opd);
2173 0 : break;
2174 :
2175 : default:
2176 : // Objects might be effectful. Symbols will throw.
2177 : // Strings are complicated - we don't handle them yet.
2178 0 : MOZ_CRASH("unexpected type");
2179 : }
2180 0 : }
2181 :
2182 : void
2183 1 : LIRGenerator::visitToInt32(MToInt32* convert)
2184 : {
2185 1 : MDefinition* opd = convert->input();
2186 :
2187 1 : switch (opd->type()) {
2188 : case MIRType::Value:
2189 : {
2190 : LValueToInt32* lir =
2191 1 : new(alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(), LValueToInt32::NORMAL);
2192 1 : assignSnapshot(lir, Bailout_NonPrimitiveInput);
2193 1 : define(lir, convert);
2194 1 : assignSafepoint(lir, convert);
2195 1 : break;
2196 : }
2197 :
2198 : case MIRType::Null:
2199 0 : MOZ_ASSERT(convert->conversion() == MacroAssembler::IntConversion_Any);
2200 0 : define(new(alloc()) LInteger(0), convert);
2201 0 : break;
2202 :
2203 : case MIRType::Boolean:
2204 0 : MOZ_ASSERT(convert->conversion() == MacroAssembler::IntConversion_Any ||
2205 : convert->conversion() == MacroAssembler::IntConversion_NumbersOrBoolsOnly);
2206 0 : redefine(convert, opd);
2207 0 : break;
2208 :
2209 : case MIRType::Int32:
2210 0 : redefine(convert, opd);
2211 0 : break;
2212 :
2213 : case MIRType::Float32:
2214 : {
2215 0 : LFloat32ToInt32* lir = new(alloc()) LFloat32ToInt32(useRegister(opd));
2216 0 : assignSnapshot(lir, Bailout_PrecisionLoss);
2217 0 : define(lir, convert);
2218 0 : break;
2219 : }
2220 :
2221 : case MIRType::Double:
2222 : {
2223 0 : LDoubleToInt32* lir = new(alloc()) LDoubleToInt32(useRegister(opd));
2224 0 : assignSnapshot(lir, Bailout_PrecisionLoss);
2225 0 : define(lir, convert);
2226 0 : break;
2227 : }
2228 :
2229 : case MIRType::String:
2230 : case MIRType::Symbol:
2231 : case MIRType::Object:
2232 : case MIRType::Undefined:
2233 : // Objects might be effectful. Symbols throw. Undefined coerces to NaN, not int32.
2234 0 : MOZ_CRASH("ToInt32 invalid input type");
2235 :
2236 : default:
2237 0 : MOZ_CRASH("unexpected type");
2238 : }
2239 1 : }
2240 :
2241 : void
2242 2 : LIRGenerator::visitTruncateToInt32(MTruncateToInt32* truncate)
2243 : {
2244 2 : MDefinition* opd = truncate->input();
2245 :
2246 2 : switch (opd->type()) {
2247 : case MIRType::Value: {
2248 5 : LValueToInt32* lir = new(alloc()) LValueToInt32(useBox(opd), tempDouble(), temp(),
2249 4 : LValueToInt32::TRUNCATE);
2250 1 : assignSnapshot(lir, Bailout_NonPrimitiveInput);
2251 1 : define(lir, truncate);
2252 1 : assignSafepoint(lir, truncate);
2253 1 : break;
2254 : }
2255 :
2256 : case MIRType::Null:
2257 : case MIRType::Undefined:
2258 1 : define(new(alloc()) LInteger(0), truncate);
2259 1 : break;
2260 :
2261 : case MIRType::Int32:
2262 : case MIRType::Boolean:
2263 0 : redefine(truncate, opd);
2264 0 : break;
2265 :
2266 : case MIRType::Double:
2267 : // May call into JS::ToInt32() on the slow OOL path.
2268 0 : gen->setNeedsStaticStackAlignment();
2269 0 : lowerTruncateDToInt32(truncate);
2270 0 : break;
2271 :
2272 : case MIRType::Float32:
2273 : // May call into JS::ToInt32() on the slow OOL path.
2274 0 : gen->setNeedsStaticStackAlignment();
2275 0 : lowerTruncateFToInt32(truncate);
2276 0 : break;
2277 :
2278 : default:
2279 : // Objects might be effectful. Symbols throw.
2280 : // Strings are complicated - we don't handle them yet.
2281 0 : MOZ_CRASH("unexpected type");
2282 : }
2283 2 : }
2284 :
2285 : void
2286 0 : LIRGenerator::visitWasmTruncateToInt32(MWasmTruncateToInt32* ins)
2287 : {
2288 0 : MDefinition* input = ins->input();
2289 0 : switch (input->type()) {
2290 : case MIRType::Double:
2291 : case MIRType::Float32: {
2292 0 : auto* lir = new(alloc()) LWasmTruncateToInt32(useRegisterAtStart(input));
2293 0 : define(lir, ins);
2294 0 : break;
2295 : }
2296 : default:
2297 0 : MOZ_CRASH("unexpected type in WasmTruncateToInt32");
2298 : }
2299 0 : }
2300 :
2301 : void
2302 0 : LIRGenerator::visitWrapInt64ToInt32(MWrapInt64ToInt32* ins)
2303 : {
2304 0 : define(new(alloc()) LWrapInt64ToInt32(useInt64AtStart(ins->input())), ins);
2305 0 : }
2306 :
2307 : void
2308 4 : LIRGenerator::visitToString(MToString* ins)
2309 : {
2310 4 : MDefinition* opd = ins->input();
2311 :
2312 4 : switch (opd->type()) {
2313 : case MIRType::Null: {
2314 0 : const JSAtomState& names = GetJitContext()->runtime->names();
2315 0 : LPointer* lir = new(alloc()) LPointer(names.null);
2316 0 : define(lir, ins);
2317 0 : break;
2318 : }
2319 :
2320 : case MIRType::Undefined: {
2321 0 : const JSAtomState& names = GetJitContext()->runtime->names();
2322 0 : LPointer* lir = new(alloc()) LPointer(names.undefined);
2323 0 : define(lir, ins);
2324 0 : break;
2325 : }
2326 :
2327 : case MIRType::Boolean: {
2328 0 : LBooleanToString* lir = new(alloc()) LBooleanToString(useRegister(opd));
2329 0 : define(lir, ins);
2330 0 : break;
2331 : }
2332 :
2333 : case MIRType::Double: {
2334 0 : LDoubleToString* lir = new(alloc()) LDoubleToString(useRegister(opd), temp());
2335 :
2336 0 : define(lir, ins);
2337 0 : assignSafepoint(lir, ins);
2338 0 : break;
2339 : }
2340 :
2341 : case MIRType::Int32: {
2342 0 : LIntToString* lir = new(alloc()) LIntToString(useRegister(opd));
2343 :
2344 0 : define(lir, ins);
2345 0 : assignSafepoint(lir, ins);
2346 0 : break;
2347 : }
2348 :
2349 : case MIRType::String:
2350 0 : redefine(ins, ins->input());
2351 0 : break;
2352 :
2353 : case MIRType::Value: {
2354 4 : LValueToString* lir = new(alloc()) LValueToString(useBox(opd), tempToUnbox());
2355 4 : if (ins->fallible())
2356 0 : assignSnapshot(lir, Bailout_NonPrimitiveInput);
2357 4 : define(lir, ins);
2358 4 : assignSafepoint(lir, ins);
2359 4 : break;
2360 : }
2361 :
2362 : default:
2363 : // Float32, symbols, and objects are not supported.
2364 0 : MOZ_CRASH("unexpected type");
2365 : }
2366 4 : }
2367 :
2368 : void
2369 0 : LIRGenerator::visitToObjectOrNull(MToObjectOrNull* ins)
2370 : {
2371 0 : MOZ_ASSERT(ins->input()->type() == MIRType::Value);
2372 :
2373 0 : LValueToObjectOrNull* lir = new(alloc()) LValueToObjectOrNull(useBox(ins->input()));
2374 0 : define(lir, ins);
2375 0 : assignSafepoint(lir, ins);
2376 0 : }
2377 :
2378 : void
2379 0 : LIRGenerator::visitRegExp(MRegExp* ins)
2380 : {
2381 0 : if (ins->mustClone()) {
2382 0 : LRegExp* lir = new(alloc()) LRegExp(temp());
2383 0 : define(lir, ins);
2384 0 : assignSafepoint(lir, ins);
2385 : } else {
2386 0 : RegExpObject* source = ins->source();
2387 0 : define(new(alloc()) LPointer(source), ins);
2388 : }
2389 0 : }
2390 :
2391 : void
2392 0 : LIRGenerator::visitRegExpMatcher(MRegExpMatcher* ins)
2393 : {
2394 0 : MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
2395 0 : MOZ_ASSERT(ins->string()->type() == MIRType::String);
2396 0 : MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
2397 :
2398 0 : LRegExpMatcher* lir = new(alloc()) LRegExpMatcher(useFixedAtStart(ins->regexp(), RegExpMatcherRegExpReg),
2399 0 : useFixedAtStart(ins->string(), RegExpMatcherStringReg),
2400 0 : useFixedAtStart(ins->lastIndex(), RegExpMatcherLastIndexReg));
2401 0 : defineReturn(lir, ins);
2402 0 : assignSafepoint(lir, ins);
2403 0 : }
2404 :
2405 : void
2406 0 : LIRGenerator::visitRegExpSearcher(MRegExpSearcher* ins)
2407 : {
2408 0 : MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
2409 0 : MOZ_ASSERT(ins->string()->type() == MIRType::String);
2410 0 : MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
2411 :
2412 0 : LRegExpSearcher* lir = new(alloc()) LRegExpSearcher(useFixedAtStart(ins->regexp(), RegExpTesterRegExpReg),
2413 0 : useFixedAtStart(ins->string(), RegExpTesterStringReg),
2414 0 : useFixedAtStart(ins->lastIndex(), RegExpTesterLastIndexReg));
2415 0 : defineReturn(lir, ins);
2416 0 : assignSafepoint(lir, ins);
2417 0 : }
2418 :
2419 : void
2420 0 : LIRGenerator::visitRegExpTester(MRegExpTester* ins)
2421 : {
2422 0 : MOZ_ASSERT(ins->regexp()->type() == MIRType::Object);
2423 0 : MOZ_ASSERT(ins->string()->type() == MIRType::String);
2424 0 : MOZ_ASSERT(ins->lastIndex()->type() == MIRType::Int32);
2425 :
2426 0 : LRegExpTester* lir = new(alloc()) LRegExpTester(useFixedAtStart(ins->regexp(), RegExpTesterRegExpReg),
2427 0 : useFixedAtStart(ins->string(), RegExpTesterStringReg),
2428 0 : useFixedAtStart(ins->lastIndex(), RegExpTesterLastIndexReg));
2429 0 : defineReturn(lir, ins);
2430 0 : assignSafepoint(lir, ins);
2431 0 : }
2432 :
2433 : void
2434 0 : LIRGenerator::visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins)
2435 : {
2436 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
2437 0 : MOZ_ASSERT(ins->type() == MIRType::Boolean);
2438 0 : LRegExpPrototypeOptimizable* lir = new(alloc()) LRegExpPrototypeOptimizable(useRegister(ins->object()),
2439 0 : temp());
2440 0 : define(lir, ins);
2441 0 : }
2442 :
2443 : void
2444 0 : LIRGenerator::visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins)
2445 : {
2446 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
2447 0 : MOZ_ASSERT(ins->proto()->type() == MIRType::Object);
2448 0 : MOZ_ASSERT(ins->type() == MIRType::Boolean);
2449 0 : LRegExpInstanceOptimizable* lir = new(alloc()) LRegExpInstanceOptimizable(useRegister(ins->object()),
2450 0 : useRegister(ins->proto()),
2451 0 : temp());
2452 0 : define(lir, ins);
2453 0 : }
2454 :
2455 : void
2456 0 : LIRGenerator::visitGetFirstDollarIndex(MGetFirstDollarIndex* ins)
2457 : {
2458 0 : MOZ_ASSERT(ins->str()->type() == MIRType::String);
2459 0 : MOZ_ASSERT(ins->type() == MIRType::Int32);
2460 0 : LGetFirstDollarIndex* lir = new(alloc()) LGetFirstDollarIndex(useRegister(ins->str()),
2461 0 : temp(), temp(), temp());
2462 0 : define(lir, ins);
2463 0 : assignSafepoint(lir, ins);
2464 0 : }
2465 :
2466 : void
2467 0 : LIRGenerator::visitStringReplace(MStringReplace* ins)
2468 : {
2469 0 : MOZ_ASSERT(ins->pattern()->type() == MIRType::String);
2470 0 : MOZ_ASSERT(ins->string()->type() == MIRType::String);
2471 0 : MOZ_ASSERT(ins->replacement()->type() == MIRType::String);
2472 :
2473 0 : LStringReplace* lir = new(alloc()) LStringReplace(useRegisterOrConstantAtStart(ins->string()),
2474 0 : useRegisterAtStart(ins->pattern()),
2475 0 : useRegisterOrConstantAtStart(ins->replacement()));
2476 0 : defineReturn(lir, ins);
2477 0 : assignSafepoint(lir, ins);
2478 0 : }
2479 :
2480 : void
2481 0 : LIRGenerator::visitBinarySharedStub(MBinarySharedStub* ins)
2482 : {
2483 0 : MDefinition* lhs = ins->getOperand(0);
2484 0 : MDefinition* rhs = ins->getOperand(1);
2485 :
2486 0 : MOZ_ASSERT(ins->type() == MIRType::Value);
2487 0 : MOZ_ASSERT(ins->type() == MIRType::Value);
2488 :
2489 0 : LBinarySharedStub* lir = new(alloc()) LBinarySharedStub(useBoxFixedAtStart(lhs, R0),
2490 0 : useBoxFixedAtStart(rhs, R1));
2491 0 : defineSharedStubReturn(lir, ins);
2492 0 : assignSafepoint(lir, ins);
2493 0 : }
2494 :
2495 : void
2496 0 : LIRGenerator::visitUnarySharedStub(MUnarySharedStub* ins)
2497 : {
2498 0 : MDefinition* input = ins->getOperand(0);
2499 0 : MOZ_ASSERT(ins->type() == MIRType::Value);
2500 :
2501 0 : LUnarySharedStub* lir = new(alloc()) LUnarySharedStub(useBoxFixedAtStart(input, R0));
2502 0 : defineSharedStubReturn(lir, ins);
2503 0 : assignSafepoint(lir, ins);
2504 0 : }
2505 :
2506 : void
2507 0 : LIRGenerator::visitNullarySharedStub(MNullarySharedStub* ins)
2508 : {
2509 0 : MOZ_ASSERT(ins->type() == MIRType::Value);
2510 :
2511 0 : LNullarySharedStub* lir = new(alloc()) LNullarySharedStub();
2512 :
2513 0 : defineSharedStubReturn(lir, ins);
2514 0 : assignSafepoint(lir, ins);
2515 0 : }
2516 :
2517 : void
2518 10 : LIRGenerator::visitLambda(MLambda* ins)
2519 : {
2520 10 : if (ins->info().singletonType || ins->info().useSingletonForClone) {
2521 : // If the function has a singleton type, this instruction will only be
2522 : // executed once so we don't bother inlining it.
2523 : //
2524 : // If UseSingletonForClone is true, we will assign a singleton type to
2525 : // the clone and we have to clone the script, we can't do that inline.
2526 0 : LLambdaForSingleton* lir = new(alloc())
2527 0 : LLambdaForSingleton(useRegisterAtStart(ins->environmentChain()));
2528 0 : defineReturn(lir, ins);
2529 0 : assignSafepoint(lir, ins);
2530 : } else {
2531 10 : LLambda* lir = new(alloc()) LLambda(useRegister(ins->environmentChain()), temp());
2532 10 : define(lir, ins);
2533 10 : assignSafepoint(lir, ins);
2534 : }
2535 10 : }
2536 :
2537 : void
2538 0 : LIRGenerator::visitLambdaArrow(MLambdaArrow* ins)
2539 : {
2540 0 : MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
2541 0 : MOZ_ASSERT(ins->newTargetDef()->type() == MIRType::Value);
2542 :
2543 0 : LLambdaArrow* lir = new(alloc()) LLambdaArrow(useRegister(ins->environmentChain()),
2544 0 : useBox(ins->newTargetDef()));
2545 0 : define(lir, ins);
2546 0 : assignSafepoint(lir, ins);
2547 0 : }
2548 :
2549 : void
2550 0 : LIRGenerator::visitSetFunName(MSetFunName* ins)
2551 : {
2552 0 : MOZ_ASSERT(ins->fun()->type() == MIRType::Object);
2553 0 : MOZ_ASSERT(ins->name()->type() == MIRType::Value);
2554 :
2555 0 : LSetFunName* lir = new(alloc()) LSetFunName(useRegisterAtStart(ins->fun()),
2556 0 : useBoxAtStart(ins->name()));
2557 0 : add(lir, ins);
2558 0 : assignSafepoint(lir, ins);
2559 0 : }
2560 :
2561 : void
2562 0 : LIRGenerator::visitNewLexicalEnvironmentObject(MNewLexicalEnvironmentObject* ins)
2563 : {
2564 0 : MDefinition* enclosing = ins->enclosing();
2565 0 : MOZ_ASSERT(enclosing->type() == MIRType::Object);
2566 :
2567 : LNewLexicalEnvironmentObject* lir =
2568 0 : new(alloc()) LNewLexicalEnvironmentObject(useRegisterAtStart(enclosing));
2569 :
2570 0 : defineReturn(lir, ins);
2571 0 : assignSafepoint(lir, ins);
2572 0 : }
2573 :
2574 : void
2575 0 : LIRGenerator::visitCopyLexicalEnvironmentObject(MCopyLexicalEnvironmentObject* ins)
2576 : {
2577 0 : MDefinition* env = ins->env();
2578 0 : MOZ_ASSERT(env->type() == MIRType::Object);
2579 :
2580 : LCopyLexicalEnvironmentObject* lir =
2581 0 : new(alloc()) LCopyLexicalEnvironmentObject(useRegisterAtStart(env));
2582 :
2583 0 : defineReturn(lir, ins);
2584 0 : assignSafepoint(lir, ins);
2585 0 : }
2586 :
2587 : void
2588 2 : LIRGenerator::visitKeepAliveObject(MKeepAliveObject* ins)
2589 : {
2590 2 : MDefinition* obj = ins->object();
2591 2 : MOZ_ASSERT(obj->type() == MIRType::Object);
2592 :
2593 2 : add(new(alloc()) LKeepAliveObject(useKeepalive(obj)), ins);
2594 2 : }
2595 :
2596 : void
2597 7 : LIRGenerator::visitSlots(MSlots* ins)
2598 : {
2599 7 : define(new(alloc()) LSlots(useRegisterAtStart(ins->object())), ins);
2600 7 : }
2601 :
2602 : void
2603 7 : LIRGenerator::visitElements(MElements* ins)
2604 : {
2605 7 : define(new(alloc()) LElements(useRegisterAtStart(ins->object())), ins);
2606 7 : }
2607 :
2608 : void
2609 0 : LIRGenerator::visitConstantElements(MConstantElements* ins)
2610 : {
2611 0 : define(new(alloc()) LPointer(ins->value().unwrap(/*safe - pointer does not flow back to C++*/),
2612 0 : LPointer::NON_GC_THING),
2613 0 : ins);
2614 0 : }
2615 :
2616 : void
2617 0 : LIRGenerator::visitConvertElementsToDoubles(MConvertElementsToDoubles* ins)
2618 : {
2619 0 : LInstruction* check = new(alloc()) LConvertElementsToDoubles(useRegister(ins->elements()));
2620 0 : add(check, ins);
2621 0 : assignSafepoint(check, ins);
2622 0 : }
2623 :
2624 : void
2625 0 : LIRGenerator::visitMaybeToDoubleElement(MMaybeToDoubleElement* ins)
2626 : {
2627 0 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
2628 0 : MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
2629 :
2630 0 : LMaybeToDoubleElement* lir = new(alloc()) LMaybeToDoubleElement(useRegisterAtStart(ins->elements()),
2631 0 : useRegisterAtStart(ins->value()),
2632 0 : tempDouble());
2633 0 : defineBox(lir, ins);
2634 0 : }
2635 :
2636 : void
2637 0 : LIRGenerator::visitMaybeCopyElementsForWrite(MMaybeCopyElementsForWrite* ins)
2638 : {
2639 0 : LInstruction* check = new(alloc()) LMaybeCopyElementsForWrite(useRegister(ins->object()), temp());
2640 0 : add(check, ins);
2641 0 : assignSafepoint(check, ins);
2642 0 : }
2643 :
2644 : void
2645 7 : LIRGenerator::visitLoadSlot(MLoadSlot* ins)
2646 : {
2647 7 : switch (ins->type()) {
2648 : case MIRType::Value:
2649 0 : defineBox(new(alloc()) LLoadSlotV(useRegisterAtStart(ins->slots())), ins);
2650 0 : break;
2651 :
2652 : case MIRType::Undefined:
2653 : case MIRType::Null:
2654 0 : MOZ_CRASH("typed load must have a payload");
2655 :
2656 : default:
2657 7 : define(new(alloc()) LLoadSlotT(useRegisterForTypedLoad(ins->slots(), ins->type())), ins);
2658 7 : break;
2659 : }
2660 7 : }
2661 :
2662 : void
2663 6 : LIRGenerator::visitFunctionEnvironment(MFunctionEnvironment* ins)
2664 : {
2665 6 : define(new(alloc()) LFunctionEnvironment(useRegisterAtStart(ins->function())), ins);
2666 6 : }
2667 :
2668 : void
2669 5 : LIRGenerator::visitInterruptCheck(MInterruptCheck* ins)
2670 : {
2671 5 : LInstruction* lir = new(alloc()) LInterruptCheck(temp());
2672 5 : add(lir, ins);
2673 5 : assignSafepoint(lir, ins);
2674 5 : }
2675 :
2676 : void
2677 0 : LIRGenerator::visitWasmTrap(MWasmTrap* ins)
2678 : {
2679 0 : add(new(alloc()) LWasmTrap, ins);
2680 0 : }
2681 :
2682 : void
2683 0 : LIRGenerator::visitWasmReinterpret(MWasmReinterpret* ins)
2684 : {
2685 0 : if (ins->type() == MIRType::Int64)
2686 0 : defineInt64(new(alloc()) LWasmReinterpretToI64(useRegisterAtStart(ins->input())), ins);
2687 0 : else if (ins->input()->type() == MIRType::Int64)
2688 0 : define(new(alloc()) LWasmReinterpretFromI64(useInt64RegisterAtStart(ins->input())), ins);
2689 : else
2690 0 : define(new(alloc()) LWasmReinterpret(useRegisterAtStart(ins->input())), ins);
2691 0 : }
2692 :
2693 : void
2694 0 : LIRGenerator::visitStoreSlot(MStoreSlot* ins)
2695 : {
2696 : LInstruction* lir;
2697 :
2698 0 : switch (ins->value()->type()) {
2699 : case MIRType::Value:
2700 0 : lir = new(alloc()) LStoreSlotV(useRegister(ins->slots()), useBox(ins->value()));
2701 0 : add(lir, ins);
2702 0 : break;
2703 :
2704 : case MIRType::Double:
2705 0 : add(new(alloc()) LStoreSlotT(useRegister(ins->slots()), useRegister(ins->value())), ins);
2706 0 : break;
2707 :
2708 : case MIRType::Float32:
2709 0 : MOZ_CRASH("Float32 shouldn't be stored in a slot.");
2710 :
2711 : default:
2712 0 : add(new(alloc()) LStoreSlotT(useRegister(ins->slots()),
2713 0 : useRegisterOrConstant(ins->value())), ins);
2714 0 : break;
2715 : }
2716 0 : }
2717 :
2718 : void
2719 10 : LIRGenerator::visitFilterTypeSet(MFilterTypeSet* ins)
2720 : {
2721 10 : redefine(ins, ins->input());
2722 10 : }
2723 :
2724 : void
2725 127 : LIRGenerator::visitTypeBarrier(MTypeBarrier* ins)
2726 : {
2727 : // Requesting a non-GC pointer is safe here since we never re-enter C++
2728 : // from inside a type barrier test.
2729 :
2730 127 : const TemporaryTypeSet* types = ins->resultTypeSet();
2731 127 : bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
2732 :
2733 127 : MIRType inputType = ins->getOperand(0)->type();
2734 127 : MOZ_ASSERT(inputType == ins->type());
2735 :
2736 : // Handle typebarrier that will always bail.
2737 : // (Emit LBail for visibility).
2738 127 : if (ins->alwaysBails()) {
2739 0 : LBail* bail = new(alloc()) LBail();
2740 0 : assignSnapshot(bail, Bailout_Inevitable);
2741 0 : add(bail, ins);
2742 0 : redefine(ins, ins->input());
2743 0 : return;
2744 : }
2745 :
2746 : // Handle typebarrier with Value as input.
2747 127 : if (inputType == MIRType::Value) {
2748 47 : LDefinition tmp = needTemp ? temp() : tempToUnbox();
2749 47 : LTypeBarrierV* barrier = new(alloc()) LTypeBarrierV(useBox(ins->input()), tmp);
2750 47 : assignSnapshot(barrier, Bailout_TypeBarrierV);
2751 47 : add(barrier, ins);
2752 47 : redefine(ins, ins->input());
2753 47 : return;
2754 : }
2755 :
2756 : // The payload needs to be tested if it either might be null or might have
2757 : // an object that should be excluded from the barrier.
2758 80 : bool needsObjectBarrier = false;
2759 80 : if (inputType == MIRType::ObjectOrNull)
2760 0 : needsObjectBarrier = true;
2761 101 : if (inputType == MIRType::Object && !types->hasType(TypeSet::AnyObjectType()) &&
2762 21 : ins->barrierKind() != BarrierKind::TypeTagOnly)
2763 : {
2764 21 : needsObjectBarrier = true;
2765 : }
2766 :
2767 80 : if (needsObjectBarrier) {
2768 21 : LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp();
2769 21 : LTypeBarrierO* barrier = new(alloc()) LTypeBarrierO(useRegister(ins->getOperand(0)), tmp);
2770 21 : assignSnapshot(barrier, Bailout_TypeBarrierO);
2771 21 : add(barrier, ins);
2772 21 : redefine(ins, ins->getOperand(0));
2773 21 : return;
2774 : }
2775 :
2776 : // Handle remaining cases: No-op, unbox did everything.
2777 59 : redefine(ins, ins->getOperand(0));
2778 : }
2779 :
2780 : void
2781 0 : LIRGenerator::visitMonitorTypes(MMonitorTypes* ins)
2782 : {
2783 : // Requesting a non-GC pointer is safe here since we never re-enter C++
2784 : // from inside a type check.
2785 :
2786 0 : const TemporaryTypeSet* types = ins->typeSet();
2787 0 : bool needTemp = !types->unknownObject() && types->getObjectCount() > 0;
2788 0 : LDefinition tmp = needTemp ? temp() : tempToUnbox();
2789 :
2790 0 : LMonitorTypes* lir = new(alloc()) LMonitorTypes(useBox(ins->input()), tmp);
2791 0 : assignSnapshot(lir, Bailout_MonitorTypes);
2792 0 : add(lir, ins);
2793 0 : }
2794 :
2795 : // Returns true iff |def| is a constant that's either not a GC thing or is not
2796 : // allocated in the nursery.
2797 : static bool
2798 8 : IsNonNurseryConstant(MDefinition* def)
2799 : {
2800 8 : if (!def->isConstant())
2801 6 : return false;
2802 2 : Value v = def->toConstant()->toJSValue();
2803 2 : return !v.isGCThing() || !IsInsideNursery(v.toGCThing());
2804 : }
2805 :
2806 : void
2807 2 : LIRGenerator::visitPostWriteBarrier(MPostWriteBarrier* ins)
2808 : {
2809 2 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
2810 :
2811 : // LPostWriteBarrier assumes that if it has a constant object then that
2812 : // object is tenured, and does not need to be tested for being in the
2813 : // nursery. Ensure that assumption holds by lowering constant nursery
2814 : // objects to a register.
2815 2 : bool useConstantObject = IsNonNurseryConstant(ins->object());
2816 :
2817 2 : switch (ins->value()->type()) {
2818 : case MIRType::Object:
2819 : case MIRType::ObjectOrNull: {
2820 1 : LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
2821 : LPostWriteBarrierO* lir =
2822 1 : new(alloc()) LPostWriteBarrierO(useConstantObject
2823 3 : ? useOrConstant(ins->object())
2824 3 : : useRegister(ins->object()),
2825 2 : useRegister(ins->value()), tmp);
2826 1 : add(lir, ins);
2827 1 : assignSafepoint(lir, ins);
2828 1 : break;
2829 : }
2830 : case MIRType::Value: {
2831 1 : LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
2832 : LPostWriteBarrierV* lir =
2833 1 : new(alloc()) LPostWriteBarrierV(useConstantObject
2834 3 : ? useOrConstant(ins->object())
2835 3 : : useRegister(ins->object()),
2836 2 : useBox(ins->value()),
2837 3 : tmp);
2838 1 : add(lir, ins);
2839 1 : assignSafepoint(lir, ins);
2840 1 : break;
2841 : }
2842 : default:
2843 : // Currently, only objects can be in the nursery. Other instruction
2844 : // types cannot hold nursery pointers.
2845 0 : break;
2846 : }
2847 2 : }
2848 :
2849 : void
2850 0 : LIRGenerator::visitPostWriteElementBarrier(MPostWriteElementBarrier* ins)
2851 : {
2852 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
2853 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
2854 :
2855 : // LPostWriteElementBarrier assumes that if it has a constant object then that
2856 : // object is tenured, and does not need to be tested for being in the
2857 : // nursery. Ensure that assumption holds by lowering constant nursery
2858 : // objects to a register.
2859 : bool useConstantObject =
2860 0 : ins->object()->isConstant() &&
2861 0 : !IsInsideNursery(&ins->object()->toConstant()->toObject());
2862 :
2863 0 : switch (ins->value()->type()) {
2864 : case MIRType::Object:
2865 : case MIRType::ObjectOrNull: {
2866 0 : LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
2867 : LPostWriteElementBarrierO* lir =
2868 0 : new(alloc()) LPostWriteElementBarrierO(useConstantObject
2869 0 : ? useOrConstant(ins->object())
2870 0 : : useRegister(ins->object()),
2871 0 : useRegister(ins->value()),
2872 0 : useRegister(ins->index()),
2873 0 : tmp);
2874 0 : add(lir, ins);
2875 0 : assignSafepoint(lir, ins);
2876 0 : break;
2877 : }
2878 : case MIRType::Value: {
2879 0 : LDefinition tmp = needTempForPostBarrier() ? temp() : LDefinition::BogusTemp();
2880 : LPostWriteElementBarrierV* lir =
2881 0 : new(alloc()) LPostWriteElementBarrierV(useConstantObject
2882 0 : ? useOrConstant(ins->object())
2883 0 : : useRegister(ins->object()),
2884 0 : useRegister(ins->index()),
2885 0 : useBox(ins->value()),
2886 0 : tmp);
2887 0 : add(lir, ins);
2888 0 : assignSafepoint(lir, ins);
2889 0 : break;
2890 : }
2891 : default:
2892 : // Currently, only objects can be in the nursery. Other instruction
2893 : // types cannot hold nursery pointers.
2894 0 : break;
2895 : }
2896 0 : }
2897 :
2898 : void
2899 2 : LIRGenerator::visitArrayLength(MArrayLength* ins)
2900 : {
2901 2 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
2902 2 : define(new(alloc()) LArrayLength(useRegisterAtStart(ins->elements())), ins);
2903 2 : }
2904 :
2905 : void
2906 0 : LIRGenerator::visitSetArrayLength(MSetArrayLength* ins)
2907 : {
2908 0 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
2909 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
2910 :
2911 0 : MOZ_ASSERT(ins->index()->isConstant());
2912 0 : add(new(alloc()) LSetArrayLength(useRegister(ins->elements()),
2913 0 : useRegisterOrConstant(ins->index())), ins);
2914 0 : }
2915 :
2916 : void
2917 0 : LIRGenerator::visitGetNextEntryForIterator(MGetNextEntryForIterator* ins)
2918 : {
2919 0 : MOZ_ASSERT(ins->iter()->type() == MIRType::Object);
2920 0 : MOZ_ASSERT(ins->result()->type() == MIRType::Object);
2921 0 : auto lir = new(alloc()) LGetNextEntryForIterator(useRegister(ins->iter()),
2922 0 : useRegister(ins->result()),
2923 0 : temp(), temp(), temp());
2924 0 : define(lir, ins);
2925 0 : assignSafepoint(lir, ins);
2926 0 : }
2927 :
2928 : void
2929 0 : LIRGenerator::visitTypedArrayLength(MTypedArrayLength* ins)
2930 : {
2931 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
2932 0 : define(new(alloc()) LTypedArrayLength(useRegisterAtStart(ins->object())), ins);
2933 0 : }
2934 :
2935 : void
2936 0 : LIRGenerator::visitTypedArrayElements(MTypedArrayElements* ins)
2937 : {
2938 0 : MOZ_ASSERT(ins->type() == MIRType::Elements);
2939 0 : define(new(alloc()) LTypedArrayElements(useRegisterAtStart(ins->object())), ins);
2940 0 : }
2941 :
2942 : void
2943 0 : LIRGenerator::visitSetDisjointTypedElements(MSetDisjointTypedElements* ins)
2944 : {
2945 0 : MOZ_ASSERT(ins->type() == MIRType::None);
2946 :
2947 0 : MDefinition* target = ins->target();
2948 0 : MOZ_ASSERT(target->type() == MIRType::Object);
2949 :
2950 0 : MDefinition* targetOffset = ins->targetOffset();
2951 0 : MOZ_ASSERT(targetOffset->type() == MIRType::Int32);
2952 :
2953 0 : MDefinition* source = ins->source();
2954 0 : MOZ_ASSERT(source->type() == MIRType::Object);
2955 :
2956 0 : auto lir = new(alloc()) LSetDisjointTypedElements(useRegister(target),
2957 0 : useRegister(targetOffset),
2958 0 : useRegister(source),
2959 0 : temp());
2960 0 : add(lir, ins);
2961 0 : }
2962 :
2963 : void
2964 0 : LIRGenerator::visitTypedObjectDescr(MTypedObjectDescr* ins)
2965 : {
2966 0 : MOZ_ASSERT(ins->type() == MIRType::Object);
2967 0 : define(new(alloc()) LTypedObjectDescr(useRegisterAtStart(ins->object())), ins);
2968 0 : }
2969 :
2970 : void
2971 0 : LIRGenerator::visitTypedObjectElements(MTypedObjectElements* ins)
2972 : {
2973 0 : MOZ_ASSERT(ins->type() == MIRType::Elements);
2974 0 : define(new(alloc()) LTypedObjectElements(useRegister(ins->object())), ins);
2975 0 : }
2976 :
2977 : void
2978 0 : LIRGenerator::visitSetTypedObjectOffset(MSetTypedObjectOffset* ins)
2979 : {
2980 0 : add(new(alloc()) LSetTypedObjectOffset(useRegister(ins->object()),
2981 0 : useRegister(ins->offset()),
2982 0 : temp(), temp()),
2983 0 : ins);
2984 0 : }
2985 :
2986 : void
2987 1 : LIRGenerator::visitInitializedLength(MInitializedLength* ins)
2988 : {
2989 1 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
2990 1 : define(new(alloc()) LInitializedLength(useRegisterAtStart(ins->elements())), ins);
2991 1 : }
2992 :
2993 : void
2994 4 : LIRGenerator::visitSetInitializedLength(MSetInitializedLength* ins)
2995 : {
2996 4 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
2997 4 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
2998 :
2999 4 : MOZ_ASSERT(ins->index()->isConstant());
3000 16 : add(new(alloc()) LSetInitializedLength(useRegister(ins->elements()),
3001 12 : useRegisterOrConstant(ins->index())), ins);
3002 4 : }
3003 :
3004 : void
3005 0 : LIRGenerator::visitUnboxedArrayLength(MUnboxedArrayLength* ins)
3006 : {
3007 0 : define(new(alloc()) LUnboxedArrayLength(useRegisterAtStart(ins->object())), ins);
3008 0 : }
3009 :
3010 : void
3011 0 : LIRGenerator::visitUnboxedArrayInitializedLength(MUnboxedArrayInitializedLength* ins)
3012 : {
3013 0 : define(new(alloc()) LUnboxedArrayInitializedLength(useRegisterAtStart(ins->object())), ins);
3014 0 : }
3015 :
3016 : void
3017 0 : LIRGenerator::visitIncrementUnboxedArrayInitializedLength(MIncrementUnboxedArrayInitializedLength* ins)
3018 : {
3019 0 : add(new(alloc()) LIncrementUnboxedArrayInitializedLength(useRegister(ins->object())), ins);
3020 0 : }
3021 :
3022 : void
3023 0 : LIRGenerator::visitSetUnboxedArrayInitializedLength(MSetUnboxedArrayInitializedLength* ins)
3024 : {
3025 0 : add(new(alloc()) LSetUnboxedArrayInitializedLength(useRegister(ins->object()),
3026 0 : useRegisterOrConstant(ins->length()),
3027 0 : temp()), ins);
3028 0 : }
3029 :
3030 : void
3031 2 : LIRGenerator::visitNot(MNot* ins)
3032 : {
3033 2 : MDefinition* op = ins->input();
3034 :
3035 : // String is converted to length of string in the type analysis phase (see
3036 : // TestPolicy).
3037 2 : MOZ_ASSERT(op->type() != MIRType::String);
3038 :
3039 : // - boolean: x xor 1
3040 : // - int32: LCompare(x, 0)
3041 : // - double: LCompare(x, 0)
3042 : // - null or undefined: true
3043 : // - object: false if it never emulates undefined, else LNotO(x)
3044 2 : switch (op->type()) {
3045 : case MIRType::Boolean: {
3046 0 : MConstant* cons = MConstant::New(alloc(), Int32Value(1));
3047 0 : ins->block()->insertBefore(ins, cons);
3048 0 : lowerForALU(new(alloc()) LBitOpI(JSOP_BITXOR), ins, op, cons);
3049 0 : break;
3050 : }
3051 : case MIRType::Int32:
3052 0 : define(new(alloc()) LNotI(useRegisterAtStart(op)), ins);
3053 0 : break;
3054 : case MIRType::Int64:
3055 0 : define(new(alloc()) LNotI64(useInt64RegisterAtStart(op)), ins);
3056 0 : break;
3057 : case MIRType::Double:
3058 0 : define(new(alloc()) LNotD(useRegister(op)), ins);
3059 0 : break;
3060 : case MIRType::Float32:
3061 0 : define(new(alloc()) LNotF(useRegister(op)), ins);
3062 0 : break;
3063 : case MIRType::Undefined:
3064 : case MIRType::Null:
3065 0 : define(new(alloc()) LInteger(1), ins);
3066 0 : break;
3067 : case MIRType::Symbol:
3068 0 : define(new(alloc()) LInteger(0), ins);
3069 0 : break;
3070 : case MIRType::Object:
3071 0 : if (!ins->operandMightEmulateUndefined()) {
3072 : // Objects that don't emulate undefined can be constant-folded.
3073 0 : define(new(alloc()) LInteger(0), ins);
3074 : } else {
3075 : // All others require further work.
3076 0 : define(new(alloc()) LNotO(useRegister(op)), ins);
3077 : }
3078 0 : break;
3079 : case MIRType::Value: {
3080 2 : LDefinition temp0, temp1;
3081 2 : if (ins->operandMightEmulateUndefined()) {
3082 0 : temp0 = temp();
3083 0 : temp1 = temp();
3084 : } else {
3085 2 : temp0 = LDefinition::BogusTemp();
3086 2 : temp1 = LDefinition::BogusTemp();
3087 : }
3088 :
3089 2 : LNotV* lir = new(alloc()) LNotV(useBox(op), tempDouble(), temp0, temp1);
3090 2 : define(lir, ins);
3091 2 : break;
3092 : }
3093 :
3094 : default:
3095 0 : MOZ_CRASH("Unexpected MIRType.");
3096 : }
3097 2 : }
3098 :
3099 : void
3100 2 : LIRGenerator::visitBoundsCheck(MBoundsCheck* ins)
3101 : {
3102 2 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3103 2 : MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
3104 2 : MOZ_ASSERT(ins->type() == MIRType::Int32);
3105 :
3106 2 : if (!ins->fallible())
3107 1 : return;
3108 :
3109 : LInstruction* check;
3110 1 : if (ins->minimum() || ins->maximum()) {
3111 0 : check = new(alloc()) LBoundsCheckRange(useRegisterOrConstant(ins->index()),
3112 0 : useAny(ins->length()),
3113 0 : temp());
3114 : } else {
3115 4 : check = new(alloc()) LBoundsCheck(useRegisterOrConstant(ins->index()),
3116 3 : useAnyOrConstant(ins->length()));
3117 : }
3118 1 : assignSnapshot(check, Bailout_BoundsCheck);
3119 1 : add(check, ins);
3120 : }
3121 :
3122 : void
3123 2 : LIRGenerator::visitBoundsCheckLower(MBoundsCheckLower* ins)
3124 : {
3125 2 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3126 :
3127 2 : if (!ins->fallible())
3128 0 : return;
3129 :
3130 2 : LInstruction* check = new(alloc()) LBoundsCheckLower(useRegister(ins->index()));
3131 2 : assignSnapshot(check, Bailout_BoundsCheck);
3132 2 : add(check, ins);
3133 : }
3134 :
3135 : void
3136 0 : LIRGenerator::visitInArray(MInArray* ins)
3137 : {
3138 0 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3139 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3140 0 : MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
3141 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3142 0 : MOZ_ASSERT(ins->type() == MIRType::Boolean);
3143 :
3144 0 : LAllocation object;
3145 0 : if (ins->needsNegativeIntCheck())
3146 0 : object = useRegister(ins->object());
3147 :
3148 0 : LInArray* lir = new(alloc()) LInArray(useRegister(ins->elements()),
3149 0 : useRegisterOrConstant(ins->index()),
3150 0 : useRegister(ins->initLength()),
3151 0 : object);
3152 0 : define(lir, ins);
3153 0 : assignSafepoint(lir, ins);
3154 0 : }
3155 :
3156 : void
3157 1 : LIRGenerator::visitLoadElement(MLoadElement* ins)
3158 : {
3159 1 : MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
3160 1 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3161 :
3162 1 : switch (ins->type()) {
3163 : case MIRType::Value:
3164 : {
3165 0 : LLoadElementV* lir = new(alloc()) LLoadElementV(useRegister(ins->elements()),
3166 0 : useRegisterOrConstant(ins->index()));
3167 0 : if (ins->fallible())
3168 0 : assignSnapshot(lir, Bailout_Hole);
3169 0 : defineBox(lir, ins);
3170 0 : break;
3171 : }
3172 : case MIRType::Undefined:
3173 : case MIRType::Null:
3174 0 : MOZ_CRASH("typed load must have a payload");
3175 :
3176 : default:
3177 : {
3178 3 : LLoadElementT* lir = new(alloc()) LLoadElementT(useRegister(ins->elements()),
3179 2 : useRegisterOrConstant(ins->index()));
3180 1 : if (ins->fallible())
3181 0 : assignSnapshot(lir, Bailout_Hole);
3182 1 : define(lir, ins);
3183 1 : break;
3184 : }
3185 : }
3186 1 : }
3187 :
3188 : void
3189 0 : LIRGenerator::visitLoadElementHole(MLoadElementHole* ins)
3190 : {
3191 0 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3192 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3193 0 : MOZ_ASSERT(ins->initLength()->type() == MIRType::Int32);
3194 0 : MOZ_ASSERT(ins->type() == MIRType::Value);
3195 :
3196 0 : LLoadElementHole* lir = new(alloc()) LLoadElementHole(useRegister(ins->elements()),
3197 0 : useRegisterOrConstant(ins->index()),
3198 0 : useRegister(ins->initLength()));
3199 0 : if (ins->needsNegativeIntCheck())
3200 0 : assignSnapshot(lir, Bailout_NegativeIndex);
3201 0 : defineBox(lir, ins);
3202 0 : }
3203 :
3204 : void
3205 0 : LIRGenerator::visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins)
3206 : {
3207 0 : MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
3208 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3209 :
3210 0 : if (ins->type() == MIRType::Object || ins->type() == MIRType::ObjectOrNull) {
3211 0 : LLoadUnboxedPointerT* lir = new(alloc()) LLoadUnboxedPointerT(useRegister(ins->elements()),
3212 0 : useRegisterOrConstant(ins->index()));
3213 0 : if (ins->nullBehavior() == MLoadUnboxedObjectOrNull::BailOnNull)
3214 0 : assignSnapshot(lir, Bailout_TypeBarrierO);
3215 0 : define(lir, ins);
3216 : } else {
3217 0 : MOZ_ASSERT(ins->type() == MIRType::Value);
3218 0 : MOZ_ASSERT(ins->nullBehavior() != MLoadUnboxedObjectOrNull::BailOnNull);
3219 :
3220 0 : LLoadUnboxedPointerV* lir = new(alloc()) LLoadUnboxedPointerV(useRegister(ins->elements()),
3221 0 : useRegisterOrConstant(ins->index()));
3222 0 : defineBox(lir, ins);
3223 : }
3224 0 : }
3225 :
3226 : void
3227 0 : LIRGenerator::visitLoadUnboxedString(MLoadUnboxedString* ins)
3228 : {
3229 0 : MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
3230 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3231 0 : MOZ_ASSERT(ins->type() == MIRType::String);
3232 :
3233 0 : LLoadUnboxedPointerT* lir = new(alloc()) LLoadUnboxedPointerT(useRegister(ins->elements()),
3234 0 : useRegisterOrConstant(ins->index()));
3235 0 : define(lir, ins);
3236 0 : }
3237 :
3238 : void
3239 4 : LIRGenerator::visitStoreElement(MStoreElement* ins)
3240 : {
3241 4 : MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
3242 4 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3243 :
3244 4 : const LUse elements = useRegister(ins->elements());
3245 4 : const LAllocation index = useRegisterOrConstant(ins->index());
3246 :
3247 4 : switch (ins->value()->type()) {
3248 : case MIRType::Value:
3249 : {
3250 0 : LInstruction* lir = new(alloc()) LStoreElementV(elements, index, useBox(ins->value()));
3251 0 : if (ins->fallible())
3252 0 : assignSnapshot(lir, Bailout_Hole);
3253 0 : add(lir, ins);
3254 0 : break;
3255 : }
3256 :
3257 : default:
3258 : {
3259 4 : const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
3260 4 : LInstruction* lir = new(alloc()) LStoreElementT(elements, index, value);
3261 4 : if (ins->fallible())
3262 0 : assignSnapshot(lir, Bailout_Hole);
3263 4 : add(lir, ins);
3264 4 : break;
3265 : }
3266 : }
3267 4 : }
3268 :
3269 : void
3270 1 : LIRGenerator::visitStoreElementHole(MStoreElementHole* ins)
3271 : {
3272 1 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3273 1 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3274 :
3275 1 : const LUse object = useRegister(ins->object());
3276 1 : const LUse elements = useRegister(ins->elements());
3277 1 : const LAllocation index = useRegisterOrConstant(ins->index());
3278 :
3279 : // Use a temp register when adding new elements to unboxed arrays.
3280 1 : LDefinition tempDef = LDefinition::BogusTemp();
3281 1 : if (ins->unboxedType() != JSVAL_TYPE_MAGIC)
3282 0 : tempDef = temp();
3283 :
3284 : LInstruction* lir;
3285 1 : switch (ins->value()->type()) {
3286 : case MIRType::Value:
3287 0 : lir = new(alloc()) LStoreElementHoleV(object, elements, index, useBox(ins->value()),
3288 0 : tempDef);
3289 0 : break;
3290 :
3291 : default:
3292 : {
3293 1 : const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
3294 1 : lir = new(alloc()) LStoreElementHoleT(object, elements, index, value, tempDef);
3295 1 : break;
3296 : }
3297 : }
3298 :
3299 1 : add(lir, ins);
3300 1 : assignSafepoint(lir, ins);
3301 1 : }
3302 :
3303 : void
3304 0 : LIRGenerator::visitFallibleStoreElement(MFallibleStoreElement* ins)
3305 : {
3306 0 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3307 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3308 :
3309 0 : const LUse object = useRegister(ins->object());
3310 0 : const LUse elements = useRegister(ins->elements());
3311 0 : const LAllocation index = useRegisterOrConstant(ins->index());
3312 :
3313 : // Use a temp register when adding new elements to unboxed arrays.
3314 0 : LDefinition tempDef = LDefinition::BogusTemp();
3315 0 : if (ins->unboxedType() != JSVAL_TYPE_MAGIC)
3316 0 : tempDef = temp();
3317 :
3318 : LInstruction* lir;
3319 0 : switch (ins->value()->type()) {
3320 : case MIRType::Value:
3321 0 : lir = new(alloc()) LFallibleStoreElementV(object, elements, index, useBox(ins->value()),
3322 0 : tempDef);
3323 0 : break;
3324 : default:
3325 0 : const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
3326 0 : lir = new(alloc()) LFallibleStoreElementT(object, elements, index, value, tempDef);
3327 0 : break;
3328 : }
3329 :
3330 0 : add(lir, ins);
3331 0 : assignSafepoint(lir, ins);
3332 0 : }
3333 :
3334 :
3335 : void
3336 0 : LIRGenerator::visitStoreUnboxedObjectOrNull(MStoreUnboxedObjectOrNull* ins)
3337 : {
3338 0 : MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
3339 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3340 0 : MOZ_ASSERT(ins->value()->type() == MIRType::Object ||
3341 : ins->value()->type() == MIRType::Null ||
3342 : ins->value()->type() == MIRType::ObjectOrNull);
3343 :
3344 0 : const LUse elements = useRegister(ins->elements());
3345 0 : const LAllocation index = useRegisterOrNonDoubleConstant(ins->index());
3346 0 : const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
3347 :
3348 0 : LInstruction* lir = new(alloc()) LStoreUnboxedPointer(elements, index, value);
3349 0 : add(lir, ins);
3350 0 : }
3351 :
3352 : void
3353 0 : LIRGenerator::visitStoreUnboxedString(MStoreUnboxedString* ins)
3354 : {
3355 0 : MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
3356 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3357 0 : MOZ_ASSERT(ins->value()->type() == MIRType::String);
3358 :
3359 0 : const LUse elements = useRegister(ins->elements());
3360 0 : const LAllocation index = useRegisterOrConstant(ins->index());
3361 0 : const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
3362 :
3363 0 : LInstruction* lir = new(alloc()) LStoreUnboxedPointer(elements, index, value);
3364 0 : add(lir, ins);
3365 0 : }
3366 :
3367 : void
3368 0 : LIRGenerator::visitConvertUnboxedObjectToNative(MConvertUnboxedObjectToNative* ins)
3369 : {
3370 0 : LInstruction* check = new(alloc()) LConvertUnboxedObjectToNative(useRegister(ins->object()));
3371 0 : add(check, ins);
3372 0 : assignSafepoint(check, ins);
3373 0 : }
3374 :
3375 : void
3376 0 : LIRGenerator::visitEffectiveAddress(MEffectiveAddress* ins)
3377 : {
3378 0 : define(new(alloc()) LEffectiveAddress(useRegister(ins->base()), useRegister(ins->index())), ins);
3379 0 : }
3380 :
3381 : void
3382 0 : LIRGenerator::visitArrayPopShift(MArrayPopShift* ins)
3383 : {
3384 0 : LUse object = useRegister(ins->object());
3385 :
3386 0 : switch (ins->type()) {
3387 : case MIRType::Value:
3388 : {
3389 0 : LArrayPopShiftV* lir = new(alloc()) LArrayPopShiftV(object, temp(), temp());
3390 0 : defineBox(lir, ins);
3391 0 : assignSafepoint(lir, ins);
3392 0 : break;
3393 : }
3394 : case MIRType::Undefined:
3395 : case MIRType::Null:
3396 0 : MOZ_CRASH("typed load must have a payload");
3397 :
3398 : default:
3399 : {
3400 0 : LArrayPopShiftT* lir = new(alloc()) LArrayPopShiftT(object, temp(), temp());
3401 0 : define(lir, ins);
3402 0 : assignSafepoint(lir, ins);
3403 0 : break;
3404 : }
3405 : }
3406 0 : }
3407 :
3408 : void
3409 1 : LIRGenerator::visitArrayPush(MArrayPush* ins)
3410 : {
3411 1 : MOZ_ASSERT(ins->type() == MIRType::Int32);
3412 :
3413 1 : LUse object = useRegister(ins->object());
3414 :
3415 1 : switch (ins->value()->type()) {
3416 : case MIRType::Value:
3417 : {
3418 0 : LArrayPushV* lir = new(alloc()) LArrayPushV(object, useBox(ins->value()), temp());
3419 0 : define(lir, ins);
3420 0 : assignSafepoint(lir, ins);
3421 0 : break;
3422 : }
3423 :
3424 : default:
3425 : {
3426 1 : const LAllocation value = useRegisterOrNonDoubleConstant(ins->value());
3427 1 : LArrayPushT* lir = new(alloc()) LArrayPushT(object, value, temp());
3428 1 : define(lir, ins);
3429 1 : assignSafepoint(lir, ins);
3430 1 : break;
3431 : }
3432 : }
3433 1 : }
3434 :
3435 : void
3436 0 : LIRGenerator::visitArraySlice(MArraySlice* ins)
3437 : {
3438 0 : MOZ_ASSERT(ins->type() == MIRType::Object);
3439 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3440 0 : MOZ_ASSERT(ins->begin()->type() == MIRType::Int32);
3441 0 : MOZ_ASSERT(ins->end()->type() == MIRType::Int32);
3442 :
3443 0 : LArraySlice* lir = new(alloc()) LArraySlice(useFixedAtStart(ins->object(), CallTempReg0),
3444 0 : useFixedAtStart(ins->begin(), CallTempReg1),
3445 0 : useFixedAtStart(ins->end(), CallTempReg2),
3446 0 : tempFixed(CallTempReg3),
3447 0 : tempFixed(CallTempReg4));
3448 0 : defineReturn(lir, ins);
3449 0 : assignSafepoint(lir, ins);
3450 0 : }
3451 :
3452 : void
3453 1 : LIRGenerator::visitArrayJoin(MArrayJoin* ins)
3454 : {
3455 1 : MOZ_ASSERT(ins->type() == MIRType::String);
3456 1 : MOZ_ASSERT(ins->array()->type() == MIRType::Object);
3457 1 : MOZ_ASSERT(ins->sep()->type() == MIRType::String);
3458 :
3459 3 : LArrayJoin* lir = new(alloc()) LArrayJoin(useRegisterAtStart(ins->array()),
3460 2 : useRegisterAtStart(ins->sep()));
3461 1 : defineReturn(lir, ins);
3462 1 : assignSafepoint(lir, ins);
3463 1 : }
3464 :
3465 : void
3466 0 : LIRGenerator::visitSinCos(MSinCos *ins)
3467 : {
3468 0 : MOZ_ASSERT(ins->type() == MIRType::SinCosDouble);
3469 0 : MOZ_ASSERT(ins->input()->type() == MIRType::Double ||
3470 : ins->input()->type() == MIRType::Float32 ||
3471 : ins->input()->type() == MIRType::Int32);
3472 :
3473 0 : LSinCos *lir = new (alloc()) LSinCos(useRegisterAtStart(ins->input()),
3474 0 : tempFixed(CallTempReg0),
3475 0 : temp());
3476 0 : defineSinCos(lir, ins);
3477 0 : }
3478 :
3479 : void
3480 0 : LIRGenerator::visitStringSplit(MStringSplit* ins)
3481 : {
3482 0 : MOZ_ASSERT(ins->type() == MIRType::Object);
3483 0 : MOZ_ASSERT(ins->string()->type() == MIRType::String);
3484 0 : MOZ_ASSERT(ins->separator()->type() == MIRType::String);
3485 :
3486 0 : LStringSplit* lir = new(alloc()) LStringSplit(useRegisterAtStart(ins->string()),
3487 0 : useRegisterAtStart(ins->separator()));
3488 0 : defineReturn(lir, ins);
3489 0 : assignSafepoint(lir, ins);
3490 0 : }
3491 :
3492 : void
3493 0 : LIRGenerator::visitLoadUnboxedScalar(MLoadUnboxedScalar* ins)
3494 : {
3495 0 : MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
3496 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3497 :
3498 0 : const LUse elements = useRegister(ins->elements());
3499 0 : const LAllocation index = useRegisterOrConstant(ins->index());
3500 :
3501 0 : MOZ_ASSERT(IsNumberType(ins->type()) || IsSimdType(ins->type()) ||
3502 : ins->type() == MIRType::Boolean);
3503 :
3504 : // We need a temp register for Uint32Array with known double result.
3505 0 : LDefinition tempDef = LDefinition::BogusTemp();
3506 0 : if (ins->readType() == Scalar::Uint32 && IsFloatingPointType(ins->type()))
3507 0 : tempDef = temp();
3508 :
3509 0 : if (ins->requiresMemoryBarrier()) {
3510 0 : LMemoryBarrier* fence = new(alloc()) LMemoryBarrier(MembarBeforeLoad);
3511 0 : add(fence, ins);
3512 : }
3513 0 : LLoadUnboxedScalar* lir = new(alloc()) LLoadUnboxedScalar(elements, index, tempDef);
3514 0 : if (ins->fallible())
3515 0 : assignSnapshot(lir, Bailout_Overflow);
3516 0 : define(lir, ins);
3517 0 : if (ins->requiresMemoryBarrier()) {
3518 0 : LMemoryBarrier* fence = new(alloc()) LMemoryBarrier(MembarAfterLoad);
3519 0 : add(fence, ins);
3520 : }
3521 0 : }
3522 :
3523 : void
3524 0 : LIRGenerator::visitClampToUint8(MClampToUint8* ins)
3525 : {
3526 0 : MDefinition* in = ins->input();
3527 :
3528 0 : switch (in->type()) {
3529 : case MIRType::Boolean:
3530 0 : redefine(ins, in);
3531 0 : break;
3532 :
3533 : case MIRType::Int32:
3534 0 : defineReuseInput(new(alloc()) LClampIToUint8(useRegisterAtStart(in)), ins, 0);
3535 0 : break;
3536 :
3537 : case MIRType::Double:
3538 : // LClampDToUint8 clobbers its input register. Making it available as
3539 : // a temp copy describes this behavior to the register allocator.
3540 0 : define(new(alloc()) LClampDToUint8(useRegisterAtStart(in), tempCopy(in, 0)), ins);
3541 0 : break;
3542 :
3543 : case MIRType::Value:
3544 : {
3545 0 : LClampVToUint8* lir = new(alloc()) LClampVToUint8(useBox(in), tempDouble());
3546 0 : assignSnapshot(lir, Bailout_NonPrimitiveInput);
3547 0 : define(lir, ins);
3548 0 : assignSafepoint(lir, ins);
3549 0 : break;
3550 : }
3551 :
3552 : default:
3553 0 : MOZ_CRASH("unexpected type");
3554 : }
3555 0 : }
3556 :
3557 : void
3558 0 : LIRGenerator::visitLoadTypedArrayElementHole(MLoadTypedArrayElementHole* ins)
3559 : {
3560 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3561 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3562 :
3563 0 : MOZ_ASSERT(ins->type() == MIRType::Value);
3564 :
3565 0 : const LUse object = useRegister(ins->object());
3566 0 : const LAllocation index = useRegisterOrConstant(ins->index());
3567 :
3568 0 : LLoadTypedArrayElementHole* lir = new(alloc()) LLoadTypedArrayElementHole(object, index);
3569 0 : if (ins->fallible())
3570 0 : assignSnapshot(lir, Bailout_Overflow);
3571 0 : defineBox(lir, ins);
3572 0 : assignSafepoint(lir, ins);
3573 0 : }
3574 :
3575 : void
3576 0 : LIRGenerator::visitLoadTypedArrayElementStatic(MLoadTypedArrayElementStatic* ins)
3577 : {
3578 : LLoadTypedArrayElementStatic* lir =
3579 0 : new(alloc()) LLoadTypedArrayElementStatic(useRegisterAtStart(ins->ptr()));
3580 :
3581 : // In case of out of bounds, may bail out, or may jump to ool code.
3582 0 : if (ins->fallible())
3583 0 : assignSnapshot(lir, Bailout_BoundsCheck);
3584 0 : define(lir, ins);
3585 0 : }
3586 :
3587 : void
3588 0 : LIRGenerator::visitStoreUnboxedScalar(MStoreUnboxedScalar* ins)
3589 : {
3590 0 : MOZ_ASSERT(IsValidElementsType(ins->elements(), ins->offsetAdjustment()));
3591 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3592 :
3593 0 : if (ins->isSimdWrite()) {
3594 0 : MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32x4, ins->value()->type() == MIRType::Float32x4);
3595 0 : MOZ_ASSERT_IF(ins->writeType() == Scalar::Int8x16, ins->value()->type() == MIRType::Int8x16);
3596 0 : MOZ_ASSERT_IF(ins->writeType() == Scalar::Int16x8, ins->value()->type() == MIRType::Int16x8);
3597 0 : MOZ_ASSERT_IF(ins->writeType() == Scalar::Int32x4, ins->value()->type() == MIRType::Int32x4);
3598 0 : } else if (ins->isFloatWrite()) {
3599 0 : MOZ_ASSERT_IF(ins->writeType() == Scalar::Float32, ins->value()->type() == MIRType::Float32);
3600 0 : MOZ_ASSERT_IF(ins->writeType() == Scalar::Float64, ins->value()->type() == MIRType::Double);
3601 : } else {
3602 0 : MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
3603 : }
3604 :
3605 0 : LUse elements = useRegister(ins->elements());
3606 0 : LAllocation index = useRegisterOrConstant(ins->index());
3607 0 : LAllocation value;
3608 :
3609 : // For byte arrays, the value has to be in a byte register on x86.
3610 0 : if (ins->isByteWrite())
3611 0 : value = useByteOpRegisterOrNonDoubleConstant(ins->value());
3612 : else
3613 0 : value = useRegisterOrNonDoubleConstant(ins->value());
3614 :
3615 : // Optimization opportunity for atomics: on some platforms there
3616 : // is a store instruction that incorporates the necessary
3617 : // barriers, and we could use that instead of separate barrier and
3618 : // store instructions. See bug #1077027.
3619 0 : if (ins->requiresMemoryBarrier()) {
3620 0 : LMemoryBarrier* fence = new(alloc()) LMemoryBarrier(MembarBeforeStore);
3621 0 : add(fence, ins);
3622 : }
3623 0 : add(new(alloc()) LStoreUnboxedScalar(elements, index, value), ins);
3624 0 : if (ins->requiresMemoryBarrier()) {
3625 0 : LMemoryBarrier* fence = new(alloc()) LMemoryBarrier(MembarAfterStore);
3626 0 : add(fence, ins);
3627 : }
3628 0 : }
3629 :
3630 : void
3631 0 : LIRGenerator::visitStoreTypedArrayElementHole(MStoreTypedArrayElementHole* ins)
3632 : {
3633 0 : MOZ_ASSERT(ins->elements()->type() == MIRType::Elements);
3634 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
3635 0 : MOZ_ASSERT(ins->length()->type() == MIRType::Int32);
3636 :
3637 0 : if (ins->isFloatWrite()) {
3638 0 : MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float32, ins->value()->type() == MIRType::Float32);
3639 0 : MOZ_ASSERT_IF(ins->arrayType() == Scalar::Float64, ins->value()->type() == MIRType::Double);
3640 : } else {
3641 0 : MOZ_ASSERT(ins->value()->type() == MIRType::Int32);
3642 : }
3643 :
3644 0 : LUse elements = useRegister(ins->elements());
3645 0 : LAllocation length = useAnyOrConstant(ins->length());
3646 0 : LAllocation index = useRegisterOrConstant(ins->index());
3647 0 : LAllocation value;
3648 :
3649 : // For byte arrays, the value has to be in a byte register on x86.
3650 0 : if (ins->isByteWrite())
3651 0 : value = useByteOpRegisterOrNonDoubleConstant(ins->value());
3652 : else
3653 0 : value = useRegisterOrNonDoubleConstant(ins->value());
3654 0 : add(new(alloc()) LStoreTypedArrayElementHole(elements, length, index, value), ins);
3655 0 : }
3656 :
3657 : void
3658 34 : LIRGenerator::visitLoadFixedSlot(MLoadFixedSlot* ins)
3659 : {
3660 34 : MDefinition* obj = ins->object();
3661 34 : MOZ_ASSERT(obj->type() == MIRType::Object);
3662 :
3663 34 : MIRType type = ins->type();
3664 :
3665 34 : if (type == MIRType::Value) {
3666 29 : LLoadFixedSlotV* lir = new(alloc()) LLoadFixedSlotV(useRegisterAtStart(obj));
3667 29 : defineBox(lir, ins);
3668 : } else {
3669 5 : LLoadFixedSlotT* lir = new(alloc()) LLoadFixedSlotT(useRegisterForTypedLoad(obj, type));
3670 5 : define(lir, ins);
3671 : }
3672 34 : }
3673 :
3674 : void
3675 1 : LIRGenerator::visitLoadFixedSlotAndUnbox(MLoadFixedSlotAndUnbox* ins)
3676 : {
3677 1 : MDefinition* obj = ins->object();
3678 1 : MOZ_ASSERT(obj->type() == MIRType::Object);
3679 :
3680 1 : LLoadFixedSlotAndUnbox* lir = new(alloc()) LLoadFixedSlotAndUnbox(useRegisterAtStart(obj));
3681 1 : if (ins->fallible())
3682 1 : assignSnapshot(lir, ins->bailoutKind());
3683 :
3684 1 : define(lir, ins);
3685 1 : }
3686 :
3687 : void
3688 32 : LIRGenerator::visitStoreFixedSlot(MStoreFixedSlot* ins)
3689 : {
3690 32 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3691 :
3692 32 : if (ins->value()->type() == MIRType::Value) {
3693 3 : LStoreFixedSlotV* lir = new(alloc()) LStoreFixedSlotV(useRegister(ins->object()),
3694 2 : useBox(ins->value()));
3695 1 : add(lir, ins);
3696 : } else {
3697 93 : LStoreFixedSlotT* lir = new(alloc()) LStoreFixedSlotT(useRegister(ins->object()),
3698 62 : useRegisterOrConstant(ins->value()));
3699 31 : add(lir, ins);
3700 : }
3701 32 : }
3702 :
3703 : void
3704 4 : LIRGenerator::visitGetNameCache(MGetNameCache* ins)
3705 : {
3706 4 : MOZ_ASSERT(ins->envObj()->type() == MIRType::Object);
3707 :
3708 : // Emit an overrecursed check: this is necessary because the cache can
3709 : // attach a scripted getter stub that calls this script recursively.
3710 4 : gen->setNeedsOverrecursedCheck();
3711 :
3712 4 : LGetNameCache* lir = new(alloc()) LGetNameCache(useRegister(ins->envObj()), temp());
3713 4 : defineBox(lir, ins);
3714 4 : assignSafepoint(lir, ins);
3715 4 : }
3716 :
3717 : void
3718 1 : LIRGenerator::visitCallGetIntrinsicValue(MCallGetIntrinsicValue* ins)
3719 : {
3720 1 : LCallGetIntrinsicValue* lir = new(alloc()) LCallGetIntrinsicValue();
3721 1 : defineReturn(lir, ins);
3722 1 : assignSafepoint(lir, ins);
3723 1 : }
3724 :
3725 : void
3726 23 : LIRGenerator::visitGetPropertyCache(MGetPropertyCache* ins)
3727 : {
3728 23 : MDefinition* value = ins->value();
3729 23 : MOZ_ASSERT(value->type() == MIRType::Object || value->type() == MIRType::Value);
3730 :
3731 23 : MDefinition* id = ins->idval();
3732 23 : MOZ_ASSERT(id->type() == MIRType::String ||
3733 : id->type() == MIRType::Symbol ||
3734 : id->type() == MIRType::Int32 ||
3735 : id->type() == MIRType::Value);
3736 :
3737 23 : if (ins->monitoredResult()) {
3738 : // Emit an overrecursed check: this is necessary because the cache can
3739 : // attach a scripted getter stub that calls this script recursively.
3740 17 : gen->setNeedsOverrecursedCheck();
3741 : }
3742 :
3743 : // If this is a GETPROP, the id is a constant string. Allow passing it as a
3744 : // constant to reduce register allocation pressure.
3745 23 : bool useConstId = id->type() == MIRType::String || id->type() == MIRType::Symbol;
3746 :
3747 : // We need a temp register if we can't use the output register as scratch.
3748 : // See IonIC::scratchRegisterForEntryJump.
3749 23 : LDefinition maybeTemp = LDefinition::BogusTemp();
3750 23 : if (ins->type() == MIRType::Double)
3751 1 : maybeTemp = temp();
3752 :
3753 23 : if (ins->type() == MIRType::Value) {
3754 : LGetPropertyCacheV* lir =
3755 51 : new(alloc()) LGetPropertyCacheV(useBoxOrTyped(value),
3756 34 : useBoxOrTypedOrConstant(id, useConstId),
3757 51 : maybeTemp);
3758 17 : defineBox(lir, ins);
3759 17 : assignSafepoint(lir, ins);
3760 : } else {
3761 : LGetPropertyCacheT* lir =
3762 18 : new(alloc()) LGetPropertyCacheT(useBoxOrTyped(value),
3763 12 : useBoxOrTypedOrConstant(id, useConstId),
3764 18 : maybeTemp);
3765 6 : define(lir, ins);
3766 6 : assignSafepoint(lir, ins);
3767 : }
3768 23 : }
3769 :
3770 : void
3771 0 : LIRGenerator::visitGetPropertyPolymorphic(MGetPropertyPolymorphic* ins)
3772 : {
3773 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3774 :
3775 0 : if (ins->type() == MIRType::Value) {
3776 : LGetPropertyPolymorphicV* lir =
3777 0 : new(alloc()) LGetPropertyPolymorphicV(useRegister(ins->object()));
3778 0 : assignSnapshot(lir, Bailout_ShapeGuard);
3779 0 : defineBox(lir, ins);
3780 : } else {
3781 0 : LDefinition maybeTemp = (ins->type() == MIRType::Double) ? temp() : LDefinition::BogusTemp();
3782 : LGetPropertyPolymorphicT* lir =
3783 0 : new(alloc()) LGetPropertyPolymorphicT(useRegister(ins->object()), maybeTemp);
3784 0 : assignSnapshot(lir, Bailout_ShapeGuard);
3785 0 : define(lir, ins);
3786 : }
3787 0 : }
3788 :
3789 : void
3790 0 : LIRGenerator::visitSetPropertyPolymorphic(MSetPropertyPolymorphic* ins)
3791 : {
3792 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3793 :
3794 0 : if (ins->value()->type() == MIRType::Value) {
3795 : LSetPropertyPolymorphicV* lir =
3796 0 : new(alloc()) LSetPropertyPolymorphicV(useRegister(ins->object()),
3797 0 : useBox(ins->value()),
3798 0 : temp());
3799 0 : assignSnapshot(lir, Bailout_ShapeGuard);
3800 0 : add(lir, ins);
3801 : } else {
3802 0 : LAllocation value = useRegisterOrConstant(ins->value());
3803 : LSetPropertyPolymorphicT* lir =
3804 0 : new(alloc()) LSetPropertyPolymorphicT(useRegister(ins->object()), value,
3805 0 : ins->value()->type(), temp());
3806 0 : assignSnapshot(lir, Bailout_ShapeGuard);
3807 0 : add(lir, ins);
3808 : }
3809 0 : }
3810 :
3811 : void
3812 0 : LIRGenerator::visitBindNameCache(MBindNameCache* ins)
3813 : {
3814 0 : MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3815 0 : MOZ_ASSERT(ins->type() == MIRType::Object);
3816 :
3817 0 : LBindNameCache* lir = new(alloc()) LBindNameCache(useRegister(ins->environmentChain()), temp());
3818 0 : define(lir, ins);
3819 0 : assignSafepoint(lir, ins);
3820 0 : }
3821 :
3822 : void
3823 0 : LIRGenerator::visitCallBindVar(MCallBindVar* ins)
3824 : {
3825 0 : MOZ_ASSERT(ins->environmentChain()->type() == MIRType::Object);
3826 0 : MOZ_ASSERT(ins->type() == MIRType::Object);
3827 :
3828 0 : LCallBindVar* lir = new(alloc()) LCallBindVar(useRegister(ins->environmentChain()));
3829 0 : define(lir, ins);
3830 0 : }
3831 :
3832 : void
3833 0 : LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins)
3834 : {
3835 0 : LGuardObjectIdentity* guard = new(alloc()) LGuardObjectIdentity(useRegister(ins->object()),
3836 0 : useRegister(ins->expected()));
3837 0 : assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
3838 0 : add(guard, ins);
3839 0 : redefine(ins, ins->object());
3840 0 : }
3841 :
3842 : void
3843 0 : LIRGenerator::visitGuardClass(MGuardClass* ins)
3844 : {
3845 0 : LDefinition t = temp();
3846 0 : LGuardClass* guard = new(alloc()) LGuardClass(useRegister(ins->object()), t);
3847 0 : assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
3848 0 : add(guard, ins);
3849 0 : }
3850 :
3851 : void
3852 0 : LIRGenerator::visitGuardObject(MGuardObject* ins)
3853 : {
3854 : // The type policy does all the work, so at this point the input
3855 : // is guaranteed to be an object.
3856 0 : MOZ_ASSERT(ins->input()->type() == MIRType::Object);
3857 0 : redefine(ins, ins->input());
3858 0 : }
3859 :
3860 : void
3861 0 : LIRGenerator::visitGuardString(MGuardString* ins)
3862 : {
3863 : // The type policy does all the work, so at this point the input
3864 : // is guaranteed to be a string.
3865 0 : MOZ_ASSERT(ins->input()->type() == MIRType::String);
3866 0 : redefine(ins, ins->input());
3867 0 : }
3868 :
3869 : void
3870 0 : LIRGenerator::visitGuardSharedTypedArray(MGuardSharedTypedArray* ins)
3871 : {
3872 0 : MOZ_ASSERT(ins->input()->type() == MIRType::Object);
3873 : LGuardSharedTypedArray* guard =
3874 0 : new(alloc()) LGuardSharedTypedArray(useRegister(ins->object()), temp());
3875 0 : assignSnapshot(guard, Bailout_NonSharedTypedArrayInput);
3876 0 : add(guard, ins);
3877 0 : }
3878 :
3879 : void
3880 3 : LIRGenerator::visitPolyInlineGuard(MPolyInlineGuard* ins)
3881 : {
3882 3 : MOZ_ASSERT(ins->input()->type() == MIRType::Object);
3883 3 : redefine(ins, ins->input());
3884 3 : }
3885 :
3886 : void
3887 0 : LIRGenerator::visitGuardReceiverPolymorphic(MGuardReceiverPolymorphic* ins)
3888 : {
3889 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
3890 0 : MOZ_ASSERT(ins->type() == MIRType::Object);
3891 :
3892 : LGuardReceiverPolymorphic* guard =
3893 0 : new(alloc()) LGuardReceiverPolymorphic(useRegister(ins->object()), temp());
3894 0 : assignSnapshot(guard, Bailout_ShapeGuard);
3895 0 : add(guard, ins);
3896 0 : redefine(ins, ins->object());
3897 0 : }
3898 :
3899 : void
3900 0 : LIRGenerator::visitGuardUnboxedExpando(MGuardUnboxedExpando* ins)
3901 : {
3902 : LGuardUnboxedExpando* guard =
3903 0 : new(alloc()) LGuardUnboxedExpando(useRegister(ins->object()));
3904 0 : assignSnapshot(guard, ins->bailoutKind());
3905 0 : add(guard, ins);
3906 0 : redefine(ins, ins->object());
3907 0 : }
3908 :
3909 : void
3910 0 : LIRGenerator::visitLoadUnboxedExpando(MLoadUnboxedExpando* ins)
3911 : {
3912 : LLoadUnboxedExpando* lir =
3913 0 : new(alloc()) LLoadUnboxedExpando(useRegisterAtStart(ins->object()));
3914 0 : define(lir, ins);
3915 0 : }
3916 :
3917 : void
3918 0 : LIRGenerator::visitAssertRange(MAssertRange* ins)
3919 : {
3920 0 : MDefinition* input = ins->input();
3921 0 : LInstruction* lir = nullptr;
3922 :
3923 0 : switch (input->type()) {
3924 : case MIRType::Boolean:
3925 : case MIRType::Int32:
3926 0 : lir = new(alloc()) LAssertRangeI(useRegisterAtStart(input));
3927 0 : break;
3928 :
3929 : case MIRType::Double:
3930 0 : lir = new(alloc()) LAssertRangeD(useRegister(input), tempDouble());
3931 0 : break;
3932 :
3933 : case MIRType::Float32:
3934 0 : lir = new(alloc()) LAssertRangeF(useRegister(input), tempDouble(), tempDouble());
3935 0 : break;
3936 :
3937 : case MIRType::Value:
3938 0 : lir = new(alloc()) LAssertRangeV(useBox(input), tempToUnbox(), tempDouble(), tempDouble());
3939 0 : break;
3940 :
3941 : default:
3942 0 : MOZ_CRASH("Unexpected Range for MIRType");
3943 : break;
3944 : }
3945 :
3946 0 : lir->setMir(ins);
3947 0 : add(lir);
3948 0 : }
3949 :
3950 : void
3951 3 : LIRGenerator::visitCallGetProperty(MCallGetProperty* ins)
3952 : {
3953 3 : LCallGetProperty* lir = new(alloc()) LCallGetProperty(useBoxAtStart(ins->value()));
3954 3 : defineReturn(lir, ins);
3955 3 : assignSafepoint(lir, ins);
3956 3 : }
3957 :
3958 : void
3959 0 : LIRGenerator::visitCallGetElement(MCallGetElement* ins)
3960 : {
3961 0 : MOZ_ASSERT(ins->lhs()->type() == MIRType::Value);
3962 0 : MOZ_ASSERT(ins->rhs()->type() == MIRType::Value);
3963 :
3964 0 : LCallGetElement* lir = new(alloc()) LCallGetElement(useBoxAtStart(ins->lhs()),
3965 0 : useBoxAtStart(ins->rhs()));
3966 0 : defineReturn(lir, ins);
3967 0 : assignSafepoint(lir, ins);
3968 0 : }
3969 :
3970 : void
3971 0 : LIRGenerator::visitCallSetProperty(MCallSetProperty* ins)
3972 : {
3973 0 : LInstruction* lir = new(alloc()) LCallSetProperty(useRegisterAtStart(ins->object()),
3974 0 : useBoxAtStart(ins->value()));
3975 0 : add(lir, ins);
3976 0 : assignSafepoint(lir, ins);
3977 0 : }
3978 :
3979 : void
3980 0 : LIRGenerator::visitDeleteProperty(MDeleteProperty* ins)
3981 : {
3982 0 : LCallDeleteProperty* lir = new(alloc()) LCallDeleteProperty(useBoxAtStart(ins->value()));
3983 0 : defineReturn(lir, ins);
3984 0 : assignSafepoint(lir, ins);
3985 0 : }
3986 :
3987 : void
3988 0 : LIRGenerator::visitDeleteElement(MDeleteElement* ins)
3989 : {
3990 0 : LCallDeleteElement* lir = new(alloc()) LCallDeleteElement(useBoxAtStart(ins->value()),
3991 0 : useBoxAtStart(ins->index()));
3992 0 : defineReturn(lir, ins);
3993 0 : assignSafepoint(lir, ins);
3994 0 : }
3995 :
3996 : void
3997 6 : LIRGenerator::visitSetPropertyCache(MSetPropertyCache* ins)
3998 : {
3999 6 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4000 :
4001 6 : MDefinition* id = ins->idval();
4002 6 : MOZ_ASSERT(id->type() == MIRType::String ||
4003 : id->type() == MIRType::Symbol ||
4004 : id->type() == MIRType::Int32 ||
4005 : id->type() == MIRType::Value);
4006 :
4007 : // If this is a SETPROP, the id is a constant string. Allow passing it as a
4008 : // constant to reduce register allocation pressure.
4009 6 : bool useConstId = id->type() == MIRType::String || id->type() == MIRType::Symbol;
4010 6 : bool useConstValue = IsNonNurseryConstant(ins->value());
4011 :
4012 : // Emit an overrecursed check: this is necessary because the cache can
4013 : // attach a scripted setter stub that calls this script recursively.
4014 6 : gen->setNeedsOverrecursedCheck();
4015 :
4016 : // We need a double/float32 temp register for typed array stubs if this is
4017 : // a SETELEM or INITELEM op.
4018 6 : LDefinition tempD = LDefinition::BogusTemp();
4019 6 : LDefinition tempF32 = LDefinition::BogusTemp();
4020 6 : if (IsElemPC(ins->resumePoint()->pc())) {
4021 6 : tempD = tempDouble();
4022 6 : tempF32 = hasUnaliasedDouble() ? tempFloat32() : LDefinition::BogusTemp();
4023 : }
4024 :
4025 : LInstruction* lir =
4026 18 : new(alloc()) LSetPropertyCache(useRegister(ins->object()),
4027 12 : useBoxOrTypedOrConstant(id, useConstId),
4028 12 : useBoxOrTypedOrConstant(ins->value(), useConstValue),
4029 24 : temp(), tempD, tempF32);
4030 6 : add(lir, ins);
4031 6 : assignSafepoint(lir, ins);
4032 6 : }
4033 :
4034 : void
4035 0 : LIRGenerator::visitCallSetElement(MCallSetElement* ins)
4036 : {
4037 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4038 0 : MOZ_ASSERT(ins->index()->type() == MIRType::Value);
4039 0 : MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4040 :
4041 0 : LCallSetElement* lir = new(alloc()) LCallSetElement(useRegisterAtStart(ins->object()),
4042 0 : useBoxAtStart(ins->index()),
4043 0 : useBoxAtStart(ins->value()));
4044 0 : add(lir, ins);
4045 0 : assignSafepoint(lir, ins);
4046 0 : }
4047 :
4048 : void
4049 0 : LIRGenerator::visitCallInitElementArray(MCallInitElementArray* ins)
4050 : {
4051 : LCallInitElementArray* lir =
4052 0 : new(alloc()) LCallInitElementArray(useRegisterAtStart(ins->object()),
4053 0 : useRegisterOrConstantAtStart(ins->index()),
4054 0 : useBoxAtStart(ins->value()));
4055 0 : add(lir, ins);
4056 0 : assignSafepoint(lir, ins);
4057 0 : }
4058 :
4059 : void
4060 0 : LIRGenerator::visitIteratorStart(MIteratorStart* ins)
4061 : {
4062 0 : if (ins->object()->type() == MIRType::Value) {
4063 0 : LCallIteratorStartV* lir = new(alloc()) LCallIteratorStartV(useBoxAtStart(ins->object()));
4064 0 : defineReturn(lir, ins);
4065 0 : assignSafepoint(lir, ins);
4066 0 : return;
4067 : }
4068 :
4069 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4070 :
4071 : // Call a stub if this is not a simple for-in loop.
4072 0 : if (ins->flags() != JSITER_ENUMERATE) {
4073 0 : LCallIteratorStartO* lir = new(alloc()) LCallIteratorStartO(useRegisterAtStart(ins->object()));
4074 0 : defineReturn(lir, ins);
4075 0 : assignSafepoint(lir, ins);
4076 : } else {
4077 0 : LIteratorStartO* lir = new(alloc()) LIteratorStartO(useRegister(ins->object()), temp(), temp(), temp());
4078 0 : define(lir, ins);
4079 0 : assignSafepoint(lir, ins);
4080 : }
4081 : }
4082 :
4083 : void
4084 0 : LIRGenerator::visitIteratorMore(MIteratorMore* ins)
4085 : {
4086 0 : LIteratorMore* lir = new(alloc()) LIteratorMore(useRegister(ins->iterator()), temp());
4087 0 : defineBox(lir, ins);
4088 0 : assignSafepoint(lir, ins);
4089 0 : }
4090 :
4091 : void
4092 0 : LIRGenerator::visitIsNoIter(MIsNoIter* ins)
4093 : {
4094 0 : MOZ_ASSERT(ins->hasOneUse());
4095 0 : emitAtUses(ins);
4096 0 : }
4097 :
4098 : void
4099 0 : LIRGenerator::visitIteratorEnd(MIteratorEnd* ins)
4100 : {
4101 0 : LIteratorEnd* lir = new(alloc()) LIteratorEnd(useRegister(ins->iterator()), temp(), temp(), temp());
4102 0 : add(lir, ins);
4103 0 : assignSafepoint(lir, ins);
4104 0 : }
4105 :
4106 : void
4107 8 : LIRGenerator::visitStringLength(MStringLength* ins)
4108 : {
4109 8 : MOZ_ASSERT(ins->string()->type() == MIRType::String);
4110 8 : define(new(alloc()) LStringLength(useRegisterAtStart(ins->string())), ins);
4111 8 : }
4112 :
4113 : void
4114 2 : LIRGenerator::visitArgumentsLength(MArgumentsLength* ins)
4115 : {
4116 2 : define(new(alloc()) LArgumentsLength(), ins);
4117 2 : }
4118 :
4119 : void
4120 1 : LIRGenerator::visitGetFrameArgument(MGetFrameArgument* ins)
4121 : {
4122 1 : LGetFrameArgument* lir = new(alloc()) LGetFrameArgument(useRegisterOrConstant(ins->index()));
4123 1 : defineBox(lir, ins);
4124 1 : }
4125 :
4126 : void
4127 0 : LIRGenerator::visitNewTarget(MNewTarget* ins)
4128 : {
4129 0 : LNewTarget* lir = new(alloc()) LNewTarget();
4130 0 : defineBox(lir, ins);
4131 0 : }
4132 :
4133 : void
4134 0 : LIRGenerator::visitSetFrameArgument(MSetFrameArgument* ins)
4135 : {
4136 0 : MDefinition* input = ins->input();
4137 :
4138 0 : if (input->type() == MIRType::Value) {
4139 0 : LSetFrameArgumentV* lir = new(alloc()) LSetFrameArgumentV(useBox(input));
4140 0 : add(lir, ins);
4141 0 : } else if (input->type() == MIRType::Undefined || input->type() == MIRType::Null) {
4142 0 : Value val = input->type() == MIRType::Undefined ? UndefinedValue() : NullValue();
4143 0 : LSetFrameArgumentC* lir = new(alloc()) LSetFrameArgumentC(val);
4144 0 : add(lir, ins);
4145 : } else {
4146 0 : LSetFrameArgumentT* lir = new(alloc()) LSetFrameArgumentT(useRegister(input));
4147 0 : add(lir, ins);
4148 : }
4149 0 : }
4150 :
4151 : void
4152 0 : LIRGenerator::visitRunOncePrologue(MRunOncePrologue* ins)
4153 : {
4154 0 : LRunOncePrologue* lir = new(alloc()) LRunOncePrologue;
4155 0 : add(lir, ins);
4156 0 : assignSafepoint(lir, ins);
4157 0 : }
4158 :
4159 : void
4160 1 : LIRGenerator::visitRest(MRest* ins)
4161 : {
4162 1 : MOZ_ASSERT(ins->numActuals()->type() == MIRType::Int32);
4163 :
4164 3 : LRest* lir = new(alloc()) LRest(useFixedAtStart(ins->numActuals(), CallTempReg0),
4165 2 : tempFixed(CallTempReg1),
4166 2 : tempFixed(CallTempReg2),
4167 4 : tempFixed(CallTempReg3));
4168 1 : defineReturn(lir, ins);
4169 1 : assignSafepoint(lir, ins);
4170 1 : }
4171 :
4172 : void
4173 1 : LIRGenerator::visitThrow(MThrow* ins)
4174 : {
4175 1 : MDefinition* value = ins->getOperand(0);
4176 1 : MOZ_ASSERT(value->type() == MIRType::Value);
4177 :
4178 1 : LThrow* lir = new(alloc()) LThrow(useBoxAtStart(value));
4179 1 : add(lir, ins);
4180 1 : assignSafepoint(lir, ins);
4181 1 : }
4182 :
4183 : void
4184 2 : LIRGenerator::visitInCache(MInCache* ins)
4185 : {
4186 2 : MDefinition* lhs = ins->lhs();
4187 2 : MDefinition* rhs = ins->rhs();
4188 :
4189 2 : MOZ_ASSERT(lhs->type() == MIRType::String ||
4190 : lhs->type() == MIRType::Symbol ||
4191 : lhs->type() == MIRType::Int32 ||
4192 : lhs->type() == MIRType::Value);
4193 2 : MOZ_ASSERT(rhs->type() == MIRType::Object);
4194 :
4195 2 : LInCache* lir = new(alloc()) LInCache(useBoxOrTyped(lhs), useRegister(rhs), temp());
4196 2 : define(lir, ins);
4197 2 : assignSafepoint(lir, ins);
4198 2 : }
4199 :
4200 : void
4201 0 : LIRGenerator::visitHasOwnCache(MHasOwnCache* ins)
4202 : {
4203 0 : MDefinition* value = ins->value();
4204 0 : MOZ_ASSERT(value->type() == MIRType::Object || value->type() == MIRType::Value);
4205 :
4206 0 : MDefinition* id = ins->idval();
4207 0 : MOZ_ASSERT(id->type() == MIRType::String ||
4208 : id->type() == MIRType::Symbol ||
4209 : id->type() == MIRType::Int32 ||
4210 : id->type() == MIRType::Value);
4211 :
4212 : // Emit an overrecursed check: this is necessary because the cache can
4213 : // attach a scripted getter stub that calls this script recursively.
4214 0 : gen->setNeedsOverrecursedCheck();
4215 :
4216 0 : LHasOwnCache* lir = new(alloc()) LHasOwnCache(useBoxOrTyped(value), useBoxOrTyped(id));
4217 0 : define(lir, ins);
4218 0 : assignSafepoint(lir, ins);
4219 0 : }
4220 :
4221 : void
4222 0 : LIRGenerator::visitInstanceOf(MInstanceOf* ins)
4223 : {
4224 0 : MDefinition* lhs = ins->getOperand(0);
4225 :
4226 0 : MOZ_ASSERT(lhs->type() == MIRType::Value || lhs->type() == MIRType::Object);
4227 :
4228 0 : if (lhs->type() == MIRType::Object) {
4229 0 : LInstanceOfO* lir = new(alloc()) LInstanceOfO(useRegister(lhs));
4230 0 : define(lir, ins);
4231 0 : assignSafepoint(lir, ins);
4232 : } else {
4233 0 : LInstanceOfV* lir = new(alloc()) LInstanceOfV(useBox(lhs));
4234 0 : define(lir, ins);
4235 0 : assignSafepoint(lir, ins);
4236 : }
4237 0 : }
4238 :
4239 : void
4240 0 : LIRGenerator::visitCallInstanceOf(MCallInstanceOf* ins)
4241 : {
4242 0 : MDefinition* lhs = ins->lhs();
4243 0 : MDefinition* rhs = ins->rhs();
4244 :
4245 0 : MOZ_ASSERT(lhs->type() == MIRType::Value);
4246 0 : MOZ_ASSERT(rhs->type() == MIRType::Object);
4247 :
4248 0 : LCallInstanceOf* lir = new(alloc()) LCallInstanceOf(useBoxAtStart(lhs),
4249 0 : useRegisterAtStart(rhs));
4250 0 : defineReturn(lir, ins);
4251 0 : assignSafepoint(lir, ins);
4252 0 : }
4253 :
4254 : void
4255 0 : LIRGenerator::visitIsArray(MIsArray* ins)
4256 : {
4257 0 : MOZ_ASSERT(ins->type() == MIRType::Boolean);
4258 :
4259 0 : if (ins->value()->type() == MIRType::Object) {
4260 0 : LIsArrayO* lir = new(alloc()) LIsArrayO(useRegister(ins->value()));
4261 0 : define(lir, ins);
4262 0 : assignSafepoint(lir, ins);
4263 : } else {
4264 0 : MOZ_ASSERT(ins->value()->type() == MIRType::Value);
4265 0 : LIsArrayV* lir = new(alloc()) LIsArrayV(useBox(ins->value()), temp());
4266 0 : define(lir, ins);
4267 0 : assignSafepoint(lir, ins);
4268 : }
4269 0 : }
4270 :
4271 : void
4272 0 : LIRGenerator::visitIsCallable(MIsCallable* ins)
4273 : {
4274 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4275 0 : MOZ_ASSERT(ins->type() == MIRType::Boolean);
4276 0 : define(new(alloc()) LIsCallable(useRegister(ins->object())), ins);
4277 0 : }
4278 :
4279 : void
4280 0 : LIRGenerator::visitIsConstructor(MIsConstructor* ins)
4281 : {
4282 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4283 0 : MOZ_ASSERT(ins->type() == MIRType::Boolean);
4284 0 : define(new(alloc()) LIsConstructor(useRegister(ins->object())), ins);
4285 0 : }
4286 :
4287 : static bool
4288 0 : CanEmitIsObjectAtUses(MInstruction* ins)
4289 : {
4290 0 : if (!ins->canEmitAtUses())
4291 0 : return false;
4292 :
4293 0 : MUseIterator iter(ins->usesBegin());
4294 0 : if (iter == ins->usesEnd())
4295 0 : return false;
4296 :
4297 0 : MNode* node = iter->consumer();
4298 0 : if (!node->isDefinition())
4299 0 : return false;
4300 :
4301 0 : if (!node->toDefinition()->isTest())
4302 0 : return false;
4303 :
4304 0 : iter++;
4305 0 : return iter == ins->usesEnd();
4306 : }
4307 :
4308 : void
4309 0 : LIRGenerator::visitIsObject(MIsObject* ins)
4310 : {
4311 0 : if (CanEmitIsObjectAtUses(ins)) {
4312 0 : emitAtUses(ins);
4313 0 : return;
4314 : }
4315 :
4316 0 : MDefinition* opd = ins->input();
4317 0 : MOZ_ASSERT(opd->type() == MIRType::Value);
4318 0 : LIsObject* lir = new(alloc()) LIsObject(useBoxAtStart(opd));
4319 0 : define(lir, ins);
4320 : }
4321 :
4322 : void
4323 0 : LIRGenerator::visitHasClass(MHasClass* ins)
4324 : {
4325 0 : MOZ_ASSERT(ins->object()->type() == MIRType::Object);
4326 0 : MOZ_ASSERT(ins->type() == MIRType::Boolean);
4327 0 : define(new(alloc()) LHasClass(useRegister(ins->object())), ins);
4328 0 : }
4329 :
4330 : void
4331 0 : LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins)
4332 : {
4333 0 : MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
4334 0 : MOZ_ASSERT(ins->type() == MIRType::Int32);
4335 0 : define(new(alloc()) LWasmAddOffset(useRegisterAtStart(ins->base())), ins);
4336 0 : }
4337 :
4338 : void
4339 0 : LIRGenerator::visitWasmLoadTls(MWasmLoadTls* ins)
4340 : {
4341 : #ifdef WASM_HUGE_MEMORY
4342 : // This will disappear once we remove HeapReg and replace it with a load
4343 : // from Tls, but in the mean time it keeps us sane.
4344 0 : MOZ_CRASH("No WasmLoadTls here at the moment");
4345 : #endif
4346 : auto* lir = new(alloc()) LWasmLoadTls(useRegisterAtStart(ins->tlsPtr()));
4347 : define(lir, ins);
4348 : }
4349 :
4350 : void
4351 0 : LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins)
4352 : {
4353 : #ifdef WASM_HUGE_MEMORY
4354 0 : MOZ_CRASH("No bounds checking on huge memory");
4355 : #else
4356 : MOZ_ASSERT(!ins->isRedundant());
4357 :
4358 : MDefinition* index = ins->index();
4359 : MOZ_ASSERT(index->type() == MIRType::Int32);
4360 :
4361 : MDefinition* boundsCheckLimit = ins->boundsCheckLimit();
4362 : MOZ_ASSERT(boundsCheckLimit->type() == MIRType::Int32);
4363 :
4364 : auto* lir = new(alloc()) LWasmBoundsCheck(useRegisterAtStart(index),
4365 : useRegisterAtStart(boundsCheckLimit));
4366 : add(lir, ins);
4367 : #endif
4368 : }
4369 :
4370 : void
4371 0 : LIRGenerator::visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins)
4372 : {
4373 0 : if (ins->type() == MIRType::Int64) {
4374 : #ifdef JS_PUNBOX64
4375 0 : LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
4376 : #else
4377 : LAllocation tlsPtr = useRegister(ins->tlsPtr());
4378 : #endif
4379 0 : defineInt64(new(alloc()) LWasmLoadGlobalVarI64(tlsPtr), ins);
4380 : } else {
4381 0 : LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
4382 0 : define(new(alloc()) LWasmLoadGlobalVar(tlsPtr), ins);
4383 : }
4384 0 : }
4385 :
4386 : void
4387 0 : LIRGenerator::visitWasmStoreGlobalVar(MWasmStoreGlobalVar* ins)
4388 : {
4389 0 : MDefinition* value = ins->value();
4390 0 : if (value->type() == MIRType::Int64) {
4391 : #ifdef JS_PUNBOX64
4392 0 : LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
4393 0 : LInt64Allocation valueAlloc = useInt64RegisterAtStart(value);
4394 : #else
4395 : LAllocation tlsPtr = useRegister(ins->tlsPtr());
4396 : LInt64Allocation valueAlloc = useInt64Register(value);
4397 : #endif
4398 0 : add(new(alloc()) LWasmStoreGlobalVarI64(valueAlloc, tlsPtr), ins);
4399 : } else {
4400 0 : LAllocation tlsPtr = useRegisterAtStart(ins->tlsPtr());
4401 0 : LAllocation valueAlloc = useRegisterAtStart(value);
4402 0 : add(new(alloc()) LWasmStoreGlobalVar(valueAlloc, tlsPtr), ins);
4403 : }
4404 0 : }
4405 :
4406 : void
4407 0 : LIRGenerator::visitWasmParameter(MWasmParameter* ins)
4408 : {
4409 0 : ABIArg abi = ins->abi();
4410 0 : if (abi.argInRegister()) {
4411 : #if defined(JS_NUNBOX32)
4412 : if (abi.isGeneralRegPair()) {
4413 : defineInt64Fixed(new(alloc()) LWasmParameterI64, ins,
4414 : LInt64Allocation(LAllocation(AnyRegister(abi.gpr64().high)),
4415 : LAllocation(AnyRegister(abi.gpr64().low))));
4416 : return;
4417 : }
4418 : #endif
4419 0 : defineFixed(new(alloc()) LWasmParameter, ins, LAllocation(abi.reg()));
4420 0 : return;
4421 : }
4422 0 : if (ins->type() == MIRType::Int64) {
4423 0 : MOZ_ASSERT(!abi.argInRegister());
4424 0 : defineInt64Fixed(new(alloc()) LWasmParameterI64, ins,
4425 : #if defined(JS_NUNBOX32)
4426 : LInt64Allocation(LArgument(abi.offsetFromArgBase() + INT64HIGH_OFFSET),
4427 : LArgument(abi.offsetFromArgBase() + INT64LOW_OFFSET))
4428 : #else
4429 0 : LInt64Allocation(LArgument(abi.offsetFromArgBase()))
4430 : #endif
4431 0 : );
4432 : } else {
4433 0 : MOZ_ASSERT(IsNumberType(ins->type()) || IsSimdType(ins->type()));
4434 0 : defineFixed(new(alloc()) LWasmParameter, ins, LArgument(abi.offsetFromArgBase()));
4435 : }
4436 : }
4437 :
4438 : void
4439 0 : LIRGenerator::visitWasmReturn(MWasmReturn* ins)
4440 : {
4441 0 : MDefinition* rval = ins->getOperand(0);
4442 :
4443 0 : if (rval->type() == MIRType::Int64) {
4444 0 : add(new(alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64)));
4445 0 : return;
4446 : }
4447 :
4448 0 : LWasmReturn* lir = new(alloc()) LWasmReturn;
4449 0 : if (rval->type() == MIRType::Float32)
4450 0 : lir->setOperand(0, useFixed(rval, ReturnFloat32Reg));
4451 0 : else if (rval->type() == MIRType::Double)
4452 0 : lir->setOperand(0, useFixed(rval, ReturnDoubleReg));
4453 0 : else if (IsSimdType(rval->type()))
4454 0 : lir->setOperand(0, useFixed(rval, ReturnSimd128Reg));
4455 0 : else if (rval->type() == MIRType::Int32)
4456 0 : lir->setOperand(0, useFixed(rval, ReturnReg));
4457 : else
4458 0 : MOZ_CRASH("Unexpected wasm return type");
4459 :
4460 0 : add(lir);
4461 : }
4462 :
4463 : void
4464 0 : LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid* ins)
4465 : {
4466 0 : add(new(alloc()) LWasmReturnVoid);
4467 0 : }
4468 :
4469 : void
4470 0 : LIRGenerator::visitWasmStackArg(MWasmStackArg* ins)
4471 : {
4472 0 : if (ins->arg()->type() == MIRType::Int64) {
4473 0 : add(new(alloc()) LWasmStackArgI64(useInt64RegisterOrConstantAtStart(ins->arg())), ins);
4474 0 : } else if (IsFloatingPointType(ins->arg()->type()) || IsSimdType(ins->arg()->type())) {
4475 0 : MOZ_ASSERT(!ins->arg()->isEmittedAtUses());
4476 0 : add(new(alloc()) LWasmStackArg(useRegisterAtStart(ins->arg())), ins);
4477 : } else {
4478 0 : add(new(alloc()) LWasmStackArg(useRegisterOrConstantAtStart(ins->arg())), ins);
4479 : }
4480 0 : }
4481 :
4482 : void
4483 0 : LIRGenerator::visitWasmCall(MWasmCall* ins)
4484 : {
4485 0 : LAllocation* args = gen->allocate<LAllocation>(ins->numOperands());
4486 0 : if (!args) {
4487 0 : abort(AbortReason::Alloc, "Couldn't allocate for MWasmCall");
4488 0 : return;
4489 : }
4490 :
4491 0 : for (unsigned i = 0; i < ins->numArgs(); i++)
4492 0 : args[i] = useFixedAtStart(ins->getOperand(i), ins->registerForArg(i));
4493 :
4494 0 : bool needsBoundsCheck = true;
4495 0 : if (ins->callee().isTable()) {
4496 0 : MDefinition* index = ins->getOperand(ins->numArgs());
4497 :
4498 0 : if (ins->callee().which() == wasm::CalleeDesc::WasmTable && index->isConstant()) {
4499 0 : if (uint32_t(index->toConstant()->toInt32()) < ins->callee().wasmTableMinLength())
4500 0 : needsBoundsCheck = false;
4501 : }
4502 :
4503 0 : args[ins->numArgs()] = useFixedAtStart(index, WasmTableCallIndexReg);
4504 : }
4505 :
4506 : LInstruction* lir;
4507 0 : if (ins->type() == MIRType::Int64)
4508 0 : lir = new(alloc()) LWasmCallI64(args, ins->numOperands(), needsBoundsCheck);
4509 : else
4510 0 : lir = new(alloc()) LWasmCall(args, ins->numOperands(), needsBoundsCheck);
4511 :
4512 0 : if (ins->type() == MIRType::None)
4513 0 : add(lir, ins);
4514 : else
4515 0 : defineReturn(lir, ins);
4516 : }
4517 :
4518 : void
4519 0 : LIRGenerator::visitSetDOMProperty(MSetDOMProperty* ins)
4520 : {
4521 0 : MDefinition* val = ins->value();
4522 :
4523 0 : Register cxReg, objReg, privReg, valueReg;
4524 0 : GetTempRegForIntArg(0, 0, &cxReg);
4525 0 : GetTempRegForIntArg(1, 0, &objReg);
4526 0 : GetTempRegForIntArg(2, 0, &privReg);
4527 0 : GetTempRegForIntArg(3, 0, &valueReg);
4528 :
4529 : // Keep using GetTempRegForIntArg, since we want to make sure we
4530 : // don't clobber registers we're already using.
4531 0 : Register tempReg1, tempReg2;
4532 0 : GetTempRegForIntArg(4, 0, &tempReg1);
4533 0 : mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(5, 0, &tempReg2);
4534 0 : MOZ_ASSERT(ok, "How can we not have six temp registers?");
4535 :
4536 0 : LSetDOMProperty* lir = new(alloc()) LSetDOMProperty(tempFixed(cxReg),
4537 0 : useFixedAtStart(ins->object(), objReg),
4538 0 : useBoxFixedAtStart(val, tempReg1, tempReg2),
4539 0 : tempFixed(privReg),
4540 0 : tempFixed(valueReg));
4541 0 : add(lir, ins);
4542 0 : assignSafepoint(lir, ins);
4543 0 : }
4544 :
4545 : void
4546 0 : LIRGenerator::visitGetDOMProperty(MGetDOMProperty* ins)
4547 : {
4548 0 : Register cxReg, objReg, privReg, valueReg;
4549 0 : GetTempRegForIntArg(0, 0, &cxReg);
4550 0 : GetTempRegForIntArg(1, 0, &objReg);
4551 0 : GetTempRegForIntArg(2, 0, &privReg);
4552 0 : mozilla::DebugOnly<bool> ok = GetTempRegForIntArg(3, 0, &valueReg);
4553 0 : MOZ_ASSERT(ok, "How can we not have four temp registers?");
4554 0 : LGetDOMProperty* lir = new(alloc()) LGetDOMProperty(tempFixed(cxReg),
4555 0 : useFixedAtStart(ins->object(), objReg),
4556 0 : tempFixed(privReg),
4557 0 : tempFixed(valueReg));
4558 :
4559 0 : defineReturn(lir, ins);
4560 0 : assignSafepoint(lir, ins);
4561 0 : }
4562 :
4563 : void
4564 0 : LIRGenerator::visitGetDOMMember(MGetDOMMember* ins)
4565 : {
4566 0 : MOZ_ASSERT(ins->isDomMovable(), "Members had better be movable");
4567 : // We wish we could assert that ins->domAliasSet() == JSJitInfo::AliasNone,
4568 : // but some MGetDOMMembers are for [Pure], not [Constant] properties, whose
4569 : // value can in fact change as a result of DOM setters and method calls.
4570 0 : MOZ_ASSERT(ins->domAliasSet() != JSJitInfo::AliasEverything,
4571 : "Member gets had better not alias the world");
4572 :
4573 0 : MDefinition* obj = ins->object();
4574 0 : MOZ_ASSERT(obj->type() == MIRType::Object);
4575 :
4576 0 : MIRType type = ins->type();
4577 :
4578 0 : if (type == MIRType::Value) {
4579 0 : LGetDOMMemberV* lir = new(alloc()) LGetDOMMemberV(useRegisterAtStart(obj));
4580 0 : defineBox(lir, ins);
4581 : } else {
4582 0 : LGetDOMMemberT* lir = new(alloc()) LGetDOMMemberT(useRegisterForTypedLoad(obj, type));
4583 0 : define(lir, ins);
4584 : }
4585 0 : }
4586 :
4587 : void
4588 6 : LIRGenerator::visitRecompileCheck(MRecompileCheck* ins)
4589 : {
4590 6 : LRecompileCheck* lir = new(alloc()) LRecompileCheck(temp());
4591 6 : add(lir, ins);
4592 6 : assignSafepoint(lir, ins);
4593 6 : }
4594 :
4595 : void
4596 0 : LIRGenerator::visitSimdBox(MSimdBox* ins)
4597 : {
4598 0 : MOZ_ASSERT(IsSimdType(ins->input()->type()));
4599 0 : LUse in = useRegister(ins->input());
4600 0 : LSimdBox* lir = new(alloc()) LSimdBox(in, temp());
4601 0 : define(lir, ins);
4602 0 : assignSafepoint(lir, ins);
4603 0 : }
4604 :
4605 : void
4606 0 : LIRGenerator::visitSimdUnbox(MSimdUnbox* ins)
4607 : {
4608 0 : MOZ_ASSERT(ins->input()->type() == MIRType::Object);
4609 0 : MOZ_ASSERT(IsSimdType(ins->type()));
4610 0 : LUse in = useRegister(ins->input());
4611 0 : LSimdUnbox* lir = new(alloc()) LSimdUnbox(in, temp());
4612 0 : assignSnapshot(lir, Bailout_UnexpectedSimdInput);
4613 0 : define(lir, ins);
4614 0 : }
4615 :
4616 : void
4617 0 : LIRGenerator::visitSimdConstant(MSimdConstant* ins)
4618 : {
4619 0 : MOZ_ASSERT(IsSimdType(ins->type()));
4620 :
4621 0 : switch (ins->type()) {
4622 : case MIRType::Int8x16:
4623 : case MIRType::Int16x8:
4624 : case MIRType::Int32x4:
4625 : case MIRType::Bool8x16:
4626 : case MIRType::Bool16x8:
4627 : case MIRType::Bool32x4:
4628 0 : define(new(alloc()) LSimd128Int(), ins);
4629 0 : break;
4630 : case MIRType::Float32x4:
4631 0 : define(new(alloc()) LSimd128Float(), ins);
4632 0 : break;
4633 : default:
4634 0 : MOZ_CRASH("Unknown SIMD kind when generating constant");
4635 : }
4636 0 : }
4637 :
4638 : void
4639 0 : LIRGenerator::visitSimdConvert(MSimdConvert* ins)
4640 : {
4641 0 : MOZ_ASSERT(IsSimdType(ins->type()));
4642 0 : MDefinition* input = ins->input();
4643 0 : LUse use = useRegister(input);
4644 0 : if (ins->type() == MIRType::Int32x4) {
4645 0 : MOZ_ASSERT(input->type() == MIRType::Float32x4);
4646 0 : switch (ins->signedness()) {
4647 : case SimdSign::Signed: {
4648 0 : LFloat32x4ToInt32x4* lir = new(alloc()) LFloat32x4ToInt32x4(use, temp());
4649 0 : if (!gen->compilingWasm())
4650 0 : assignSnapshot(lir, Bailout_BoundsCheck);
4651 0 : define(lir, ins);
4652 0 : break;
4653 : }
4654 : case SimdSign::Unsigned: {
4655 : LFloat32x4ToUint32x4* lir =
4656 0 : new (alloc()) LFloat32x4ToUint32x4(use, temp(), temp(LDefinition::SIMD128INT));
4657 0 : if (!gen->compilingWasm())
4658 0 : assignSnapshot(lir, Bailout_BoundsCheck);
4659 0 : define(lir, ins);
4660 0 : break;
4661 : }
4662 : default:
4663 0 : MOZ_CRASH("Unexpected SimdConvert sign");
4664 : }
4665 0 : } else if (ins->type() == MIRType::Float32x4) {
4666 0 : MOZ_ASSERT(input->type() == MIRType::Int32x4);
4667 0 : MOZ_ASSERT(ins->signedness() == SimdSign::Signed, "Unexpected SimdConvert sign");
4668 0 : define(new(alloc()) LInt32x4ToFloat32x4(use), ins);
4669 : } else {
4670 0 : MOZ_CRASH("Unknown SIMD kind when generating constant");
4671 : }
4672 0 : }
4673 :
4674 : void
4675 0 : LIRGenerator::visitSimdReinterpretCast(MSimdReinterpretCast* ins)
4676 : {
4677 0 : MOZ_ASSERT(IsSimdType(ins->type()) && IsSimdType(ins->input()->type()));
4678 0 : MDefinition* input = ins->input();
4679 0 : LUse use = useRegisterAtStart(input);
4680 : // :TODO: (Bug 1132894) We have to allocate a different register as redefine
4681 : // and/or defineReuseInput are not yet capable of reusing the same register
4682 : // with a different register type.
4683 0 : define(new(alloc()) LSimdReinterpretCast(use), ins);
4684 0 : }
4685 :
4686 : void
4687 0 : LIRGenerator::visitSimdAllTrue(MSimdAllTrue* ins)
4688 : {
4689 0 : MDefinition* input = ins->input();
4690 0 : MOZ_ASSERT(IsBooleanSimdType(input->type()));
4691 :
4692 0 : LUse use = useRegisterAtStart(input);
4693 0 : define(new(alloc()) LSimdAllTrue(use), ins);
4694 0 : }
4695 :
4696 : void
4697 0 : LIRGenerator::visitSimdAnyTrue(MSimdAnyTrue* ins)
4698 : {
4699 0 : MDefinition* input = ins->input();
4700 0 : MOZ_ASSERT(IsBooleanSimdType(input->type()));
4701 :
4702 0 : LUse use = useRegisterAtStart(input);
4703 0 : define(new(alloc()) LSimdAnyTrue(use), ins);
4704 0 : }
4705 :
4706 : void
4707 0 : LIRGenerator::visitSimdUnaryArith(MSimdUnaryArith* ins)
4708 : {
4709 0 : MOZ_ASSERT(IsSimdType(ins->input()->type()));
4710 0 : MOZ_ASSERT(IsSimdType(ins->type()));
4711 :
4712 : // Cannot be at start, as the ouput is used as a temporary to store values.
4713 0 : LUse in = use(ins->input());
4714 :
4715 0 : switch (ins->type()) {
4716 : case MIRType::Int8x16:
4717 : case MIRType::Bool8x16:
4718 0 : define(new (alloc()) LSimdUnaryArithIx16(in), ins);
4719 0 : break;
4720 : case MIRType::Int16x8:
4721 : case MIRType::Bool16x8:
4722 0 : define(new (alloc()) LSimdUnaryArithIx8(in), ins);
4723 0 : break;
4724 : case MIRType::Int32x4:
4725 : case MIRType::Bool32x4:
4726 0 : define(new (alloc()) LSimdUnaryArithIx4(in), ins);
4727 0 : break;
4728 : case MIRType::Float32x4:
4729 0 : define(new (alloc()) LSimdUnaryArithFx4(in), ins);
4730 0 : break;
4731 : default:
4732 0 : MOZ_CRASH("Unknown SIMD kind for unary operation");
4733 : }
4734 0 : }
4735 :
4736 : void
4737 0 : LIRGenerator::visitSimdBinaryComp(MSimdBinaryComp* ins)
4738 : {
4739 0 : MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
4740 0 : MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
4741 0 : MOZ_ASSERT(IsBooleanSimdType(ins->type()));
4742 :
4743 0 : if (ShouldReorderCommutative(ins->lhs(), ins->rhs(), ins))
4744 0 : ins->reverse();
4745 :
4746 0 : switch (ins->specialization()) {
4747 : case MIRType::Int8x16: {
4748 0 : MOZ_ASSERT(ins->signedness() == SimdSign::Signed);
4749 0 : LSimdBinaryCompIx16* add = new (alloc()) LSimdBinaryCompIx16();
4750 0 : lowerForFPU(add, ins, ins->lhs(), ins->rhs());
4751 0 : return;
4752 : }
4753 : case MIRType::Int16x8: {
4754 0 : MOZ_ASSERT(ins->signedness() == SimdSign::Signed);
4755 0 : LSimdBinaryCompIx8* add = new (alloc()) LSimdBinaryCompIx8();
4756 0 : lowerForFPU(add, ins, ins->lhs(), ins->rhs());
4757 0 : return;
4758 : }
4759 : case MIRType::Int32x4: {
4760 0 : MOZ_ASSERT(ins->signedness() == SimdSign::Signed);
4761 0 : LSimdBinaryCompIx4* add = new (alloc()) LSimdBinaryCompIx4();
4762 0 : lowerForCompIx4(add, ins, ins->lhs(), ins->rhs());
4763 0 : return;
4764 : }
4765 : case MIRType::Float32x4: {
4766 0 : MOZ_ASSERT(ins->signedness() == SimdSign::NotApplicable);
4767 0 : LSimdBinaryCompFx4* add = new (alloc()) LSimdBinaryCompFx4();
4768 0 : lowerForCompFx4(add, ins, ins->lhs(), ins->rhs());
4769 0 : return;
4770 : }
4771 : default:
4772 0 : MOZ_CRASH("Unknown compare type when comparing values");
4773 : }
4774 : }
4775 :
4776 : void
4777 0 : LIRGenerator::visitSimdBinaryBitwise(MSimdBinaryBitwise* ins)
4778 : {
4779 0 : MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
4780 0 : MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
4781 0 : MOZ_ASSERT(IsSimdType(ins->type()));
4782 :
4783 0 : MDefinition* lhs = ins->lhs();
4784 0 : MDefinition* rhs = ins->rhs();
4785 0 : ReorderCommutative(&lhs, &rhs, ins);
4786 0 : LSimdBinaryBitwise* lir = new(alloc()) LSimdBinaryBitwise;
4787 0 : lowerForFPU(lir, ins, lhs, rhs);
4788 0 : }
4789 :
4790 : void
4791 0 : LIRGenerator::visitSimdShift(MSimdShift* ins)
4792 : {
4793 0 : MOZ_ASSERT(IsIntegerSimdType(ins->type()));
4794 0 : MOZ_ASSERT(ins->lhs()->type() == ins->type());
4795 0 : MOZ_ASSERT(ins->rhs()->type() == MIRType::Int32);
4796 :
4797 0 : LUse vector = useRegisterAtStart(ins->lhs());
4798 0 : LAllocation value = useRegisterOrConstant(ins->rhs());
4799 : // We need a temp register to mask the shift amount, but not if the shift
4800 : // amount is a constant.
4801 0 : LDefinition tempReg = value.isConstant() ? LDefinition::BogusTemp() : temp();
4802 0 : LSimdShift* lir = new(alloc()) LSimdShift(vector, value, tempReg);
4803 0 : defineReuseInput(lir, ins, 0);
4804 0 : }
4805 :
4806 : void
4807 0 : LIRGenerator::visitLexicalCheck(MLexicalCheck* ins)
4808 : {
4809 0 : MDefinition* input = ins->input();
4810 0 : MOZ_ASSERT(input->type() == MIRType::Value);
4811 0 : LLexicalCheck* lir = new(alloc()) LLexicalCheck(useBox(input));
4812 0 : assignSnapshot(lir, ins->bailoutKind());
4813 0 : add(lir, ins);
4814 0 : redefine(ins, input);
4815 0 : }
4816 :
4817 : void
4818 0 : LIRGenerator::visitThrowRuntimeLexicalError(MThrowRuntimeLexicalError* ins)
4819 : {
4820 0 : LThrowRuntimeLexicalError* lir = new(alloc()) LThrowRuntimeLexicalError();
4821 0 : add(lir, ins);
4822 0 : assignSafepoint(lir, ins);
4823 0 : }
4824 :
4825 : void
4826 0 : LIRGenerator::visitGlobalNameConflictsCheck(MGlobalNameConflictsCheck* ins)
4827 : {
4828 0 : LGlobalNameConflictsCheck* lir = new(alloc()) LGlobalNameConflictsCheck();
4829 0 : add(lir, ins);
4830 0 : assignSafepoint(lir, ins);
4831 0 : }
4832 :
4833 : void
4834 0 : LIRGenerator::visitDebugger(MDebugger* ins)
4835 : {
4836 0 : LDebugger* lir = new(alloc()) LDebugger(tempFixed(CallTempReg0), tempFixed(CallTempReg1));
4837 0 : assignSnapshot(lir, Bailout_Debugger);
4838 0 : add(lir, ins);
4839 0 : }
4840 :
4841 : void
4842 0 : LIRGenerator::visitAtomicIsLockFree(MAtomicIsLockFree* ins)
4843 : {
4844 0 : define(new(alloc()) LAtomicIsLockFree(useRegister(ins->input())), ins);
4845 0 : }
4846 :
4847 : void
4848 0 : LIRGenerator::visitCheckReturn(MCheckReturn* ins)
4849 : {
4850 0 : MDefinition* retVal = ins->returnValue();
4851 0 : MDefinition* thisVal = ins->thisValue();
4852 0 : MOZ_ASSERT(retVal->type() == MIRType::Value);
4853 0 : MOZ_ASSERT(thisVal->type() == MIRType::Value);
4854 :
4855 0 : LCheckReturn* lir = new(alloc()) LCheckReturn(useBoxAtStart(retVal), useBoxAtStart(thisVal));
4856 0 : assignSnapshot(lir, Bailout_BadDerivedConstructorReturn);
4857 0 : add(lir, ins);
4858 0 : redefine(ins, retVal);
4859 0 : }
4860 :
4861 : void
4862 0 : LIRGenerator::visitCheckIsObj(MCheckIsObj* ins)
4863 : {
4864 0 : MDefinition* checkVal = ins->checkValue();
4865 0 : MOZ_ASSERT(checkVal->type() == MIRType::Value);
4866 :
4867 0 : LCheckIsObj* lir = new(alloc()) LCheckIsObj(useBoxAtStart(checkVal));
4868 0 : redefine(ins, checkVal);
4869 0 : add(lir, ins);
4870 0 : assignSafepoint(lir, ins);
4871 0 : }
4872 :
4873 : void
4874 0 : LIRGenerator::visitCheckIsCallable(MCheckIsCallable* ins)
4875 : {
4876 0 : MDefinition* checkVal = ins->checkValue();
4877 0 : MOZ_ASSERT(checkVal->type() == MIRType::Value);
4878 :
4879 0 : LCheckIsCallable* lir = new(alloc()) LCheckIsCallable(useBox(checkVal),
4880 0 : temp());
4881 0 : redefine(ins, checkVal);
4882 0 : add(lir, ins);
4883 0 : assignSafepoint(lir, ins);
4884 0 : }
4885 :
4886 : void
4887 0 : LIRGenerator::visitCheckObjCoercible(MCheckObjCoercible* ins)
4888 : {
4889 0 : MDefinition* checkVal = ins->checkValue();
4890 0 : MOZ_ASSERT(checkVal->type() == MIRType::Value);
4891 :
4892 0 : LCheckObjCoercible* lir = new(alloc()) LCheckObjCoercible(useBoxAtStart(checkVal));
4893 0 : redefine(ins, checkVal);
4894 0 : add(lir, ins);
4895 0 : assignSafepoint(lir, ins);
4896 0 : }
4897 :
4898 : void
4899 0 : LIRGenerator::visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins)
4900 : {
4901 0 : MDefinition* checkVal = ins->checkValue();
4902 0 : MOZ_ASSERT(checkVal->type() == MIRType::Value);
4903 :
4904 0 : LDebugCheckSelfHosted* lir = new (alloc()) LDebugCheckSelfHosted(useBoxAtStart(checkVal));
4905 0 : redefine(ins, checkVal);
4906 0 : add(lir, ins);
4907 0 : assignSafepoint(lir, ins);
4908 0 : }
4909 :
4910 : void
4911 0 : LIRGenerator::visitFinishBoundFunctionInit(MFinishBoundFunctionInit* ins)
4912 : {
4913 0 : auto lir = new(alloc()) LFinishBoundFunctionInit(useRegister(ins->bound()),
4914 0 : useRegister(ins->target()),
4915 0 : useRegister(ins->argCount()),
4916 0 : temp(), temp());
4917 0 : add(lir, ins);
4918 0 : assignSafepoint(lir, ins);
4919 0 : }
4920 :
4921 : static void
4922 0 : SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
4923 : {
4924 0 : Fprinter& out = JitSpewPrinter();
4925 0 : out.printf("Current resume point %p details:\n", (void*)resumePoint);
4926 0 : out.printf(" frame count: %u\n", resumePoint->frameCount());
4927 :
4928 0 : if (ins) {
4929 0 : out.printf(" taken after: ");
4930 0 : ins->printName(out);
4931 : } else {
4932 0 : out.printf(" taken at block %d entry", block->id());
4933 : }
4934 0 : out.printf("\n");
4935 :
4936 0 : out.printf(" pc: %p (script: %p, offset: %d)\n",
4937 0 : (void*)resumePoint->pc(),
4938 0 : (void*)resumePoint->block()->info().script(),
4939 0 : int(resumePoint->block()->info().script()->pcToOffset(resumePoint->pc())));
4940 :
4941 0 : for (size_t i = 0, e = resumePoint->numOperands(); i < e; i++) {
4942 0 : MDefinition* in = resumePoint->getOperand(i);
4943 0 : out.printf(" slot%u: ", (unsigned)i);
4944 0 : in->printName(out);
4945 0 : out.printf("\n");
4946 : }
4947 0 : }
4948 :
4949 : bool
4950 1474 : LIRGenerator::visitInstruction(MInstruction* ins)
4951 : {
4952 1474 : if (ins->isRecoveredOnBailout()) {
4953 63 : MOZ_ASSERT(!JitOptions.disableRecoverIns);
4954 63 : return true;
4955 : }
4956 :
4957 1411 : if (!gen->ensureBallast())
4958 0 : return false;
4959 1411 : ins->accept(this);
4960 :
4961 1411 : if (ins->possiblyCalls()) {
4962 38 : gen->setNeedsStaticStackAlignment();
4963 38 : gen->setNeedsOverrecursedCheck();
4964 : }
4965 :
4966 1411 : if (ins->resumePoint())
4967 259 : updateResumeState(ins);
4968 :
4969 : #ifdef DEBUG
4970 1411 : ins->setInWorklistUnchecked();
4971 : #endif
4972 :
4973 : // If no safepoint was created, there's no need for an OSI point.
4974 1411 : if (LOsiPoint* osiPoint = popOsiPoint())
4975 134 : add(osiPoint);
4976 :
4977 1411 : return !errored();
4978 : }
4979 :
4980 : void
4981 403 : LIRGenerator::definePhis()
4982 : {
4983 403 : size_t lirIndex = 0;
4984 403 : MBasicBlock* block = current->mir();
4985 578 : for (MPhiIterator phi(block->phisBegin()); phi != block->phisEnd(); phi++) {
4986 175 : if (phi->type() == MIRType::Value) {
4987 86 : defineUntypedPhi(*phi, lirIndex);
4988 86 : lirIndex += BOX_PIECES;
4989 89 : } else if (phi->type() == MIRType::Int64) {
4990 0 : defineInt64Phi(*phi, lirIndex);
4991 0 : lirIndex += INT64_PIECES;
4992 : } else {
4993 89 : defineTypedPhi(*phi, lirIndex);
4994 89 : lirIndex += 1;
4995 : }
4996 : }
4997 403 : }
4998 :
4999 : void
5000 259 : LIRGenerator::updateResumeState(MInstruction* ins)
5001 : {
5002 259 : lastResumePoint_ = ins->resumePoint();
5003 259 : if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_)
5004 0 : SpewResumePoint(nullptr, ins, lastResumePoint_);
5005 259 : }
5006 :
5007 : void
5008 403 : LIRGenerator::updateResumeState(MBasicBlock* block)
5009 : {
5010 : // As Value Numbering phase can remove edges from the entry basic block to a
5011 : // code paths reachable from the OSR entry point, we have to add fixup
5012 : // blocks to keep the dominator tree organized the same way. These fixup
5013 : // blocks are flaged as unreachable, and should only exist iff the graph has
5014 : // an OSR block.
5015 : //
5016 : // Note: RangeAnalysis can flag blocks as unreachable, but they are only
5017 : // removed iff GVN (including UCE) is enabled.
5018 403 : MOZ_ASSERT_IF(!mir()->compilingWasm() && !block->unreachable(), block->entryResumePoint());
5019 403 : MOZ_ASSERT_IF(block->unreachable(), block->graph().osrBlock() ||
5020 : !mir()->optimizationInfo().gvnEnabled());
5021 403 : lastResumePoint_ = block->entryResumePoint();
5022 403 : if (JitSpewEnabled(JitSpew_IonSnapshots) && lastResumePoint_)
5023 0 : SpewResumePoint(block, nullptr, lastResumePoint_);
5024 403 : }
5025 :
5026 : bool
5027 403 : LIRGenerator::visitBlock(MBasicBlock* block)
5028 : {
5029 403 : current = block->lir();
5030 403 : updateResumeState(block);
5031 :
5032 403 : definePhis();
5033 :
5034 : // See fixup blocks added by Value Numbering, to keep the dominator relation
5035 : // modified by the presence of the OSR block.
5036 403 : MOZ_ASSERT_IF(block->unreachable(), *block->begin() == block->lastIns() ||
5037 : !mir()->optimizationInfo().gvnEnabled());
5038 403 : MOZ_ASSERT_IF(block->unreachable(), block->graph().osrBlock() ||
5039 : !mir()->optimizationInfo().gvnEnabled());
5040 1474 : for (MInstructionIterator iter = block->begin(); *iter != block->lastIns(); iter++) {
5041 1071 : if (!visitInstruction(*iter))
5042 0 : return false;
5043 : }
5044 :
5045 403 : if (block->successorWithPhis()) {
5046 : // If we have a successor with phis, lower the phi input now that we
5047 : // are approaching the join point.
5048 134 : MBasicBlock* successor = block->successorWithPhis();
5049 134 : uint32_t position = block->positionInPhiSuccessor();
5050 134 : size_t lirIndex = 0;
5051 564 : for (MPhiIterator phi(successor->phisBegin()); phi != successor->phisEnd(); phi++) {
5052 430 : if (!gen->ensureBallast())
5053 0 : return false;
5054 :
5055 430 : MDefinition* opd = phi->getOperand(position);
5056 430 : ensureDefined(opd);
5057 :
5058 430 : MOZ_ASSERT(opd->type() == phi->type());
5059 :
5060 430 : if (phi->type() == MIRType::Value) {
5061 222 : lowerUntypedPhiInput(*phi, position, successor->lir(), lirIndex);
5062 222 : lirIndex += BOX_PIECES;
5063 208 : } else if (phi->type() == MIRType::Int64) {
5064 0 : lowerInt64PhiInput(*phi, position, successor->lir(), lirIndex);
5065 0 : lirIndex += INT64_PIECES;
5066 : } else {
5067 208 : lowerTypedPhiInput(*phi, position, successor->lir(), lirIndex);
5068 208 : lirIndex += 1;
5069 : }
5070 : }
5071 : }
5072 :
5073 : // Now emit the last instruction, which is some form of branch.
5074 403 : if (!visitInstruction(block->lastIns()))
5075 0 : return false;
5076 :
5077 403 : return true;
5078 : }
5079 :
5080 : void
5081 0 : LIRGenerator::visitNaNToZero(MNaNToZero *ins)
5082 : {
5083 0 : MDefinition* input = ins->input();
5084 :
5085 0 : if (ins->operandIsNeverNaN() && ins->operandIsNeverNegativeZero()) {
5086 0 : redefine(ins, input);
5087 0 : return;
5088 : }
5089 0 : LNaNToZero* lir = new(alloc()) LNaNToZero(useRegisterAtStart(input), tempDouble());
5090 0 : defineReuseInput(lir, ins, 0);
5091 : }
5092 :
5093 : bool
5094 8 : LIRGenerator::generate()
5095 : {
5096 : // Create all blocks and prep all phis beforehand.
5097 411 : for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
5098 403 : if (gen->shouldCancel("Lowering (preparation loop)"))
5099 0 : return false;
5100 :
5101 403 : if (!lirGraph_.initBlock(*block))
5102 0 : return false;
5103 : }
5104 :
5105 822 : for (ReversePostorderIterator block(graph.rpoBegin()); block != graph.rpoEnd(); block++) {
5106 403 : if (gen->shouldCancel("Lowering (main loop)"))
5107 0 : return false;
5108 :
5109 403 : if (!visitBlock(*block))
5110 0 : return false;
5111 : }
5112 :
5113 8 : lirGraph_.setArgumentSlotCount(maxargslots_);
5114 8 : return true;
5115 : }
5116 :
5117 : void
5118 0 : LIRGenerator::visitPhi(MPhi* phi)
5119 : {
5120 : // Phi nodes are not lowered because they are only meaningful for the register allocator.
5121 0 : MOZ_CRASH("Unexpected Phi node during Lowering.");
5122 : }
5123 :
5124 : void
5125 0 : LIRGenerator::visitBeta(MBeta* beta)
5126 : {
5127 : // Beta nodes are supposed to be removed before because they are
5128 : // only used to carry the range information for Range analysis
5129 0 : MOZ_CRASH("Unexpected Beta node during Lowering.");
5130 : }
5131 :
5132 : void
5133 0 : LIRGenerator::visitObjectState(MObjectState* objState)
5134 : {
5135 : // ObjectState nodes are always recovered on bailouts
5136 0 : MOZ_CRASH("Unexpected ObjectState node during Lowering.");
5137 : }
5138 :
5139 : void
5140 0 : LIRGenerator::visitArrayState(MArrayState* objState)
5141 : {
5142 : // ArrayState nodes are always recovered on bailouts
5143 0 : MOZ_CRASH("Unexpected ArrayState node during Lowering.");
5144 : }
5145 :
5146 : void
5147 0 : LIRGenerator::visitUnknownValue(MUnknownValue* ins)
5148 : {
5149 0 : MOZ_CRASH("Can not lower unknown value.");
5150 : }
|