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