1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #ifndef DFGJITCodeGenerator_h
27 #define DFGJITCodeGenerator_h
28 
29 #if ENABLE(DFG_JIT)
30 
31 #include "CodeBlock.h"
32 #include <dfg/DFGGenerationInfo.h>
33 #include <dfg/DFGGraph.h>
34 #include <dfg/DFGJITCompiler.h>
35 #include <dfg/DFGOperations.h>
36 #include <dfg/DFGRegisterBank.h>
37 
38 namespace JSC { namespace DFG {
39 
40 class SpeculateIntegerOperand;
41 class SpeculateStrictInt32Operand;
42 class SpeculateCellOperand;
43 
44 
45 // === JITCodeGenerator ===
46 //
47 // This class provides common infrastructure used by the speculative &
48 // non-speculative JITs. Provides common mechanisms for virtual and
49 // physical register management, calls out from JIT code to helper
50 // functions, etc.
51 class JITCodeGenerator {
52 protected:
53     typedef MacroAssembler::TrustedImm32 TrustedImm32;
54     typedef MacroAssembler::Imm32 Imm32;
55 
56     // These constants are used to set priorities for spill order for
57     // the register allocator.
58     enum SpillOrder {
59         SpillOrderConstant = 1, // no spill, and cheap fill
60         SpillOrderSpilled = 2,  // no spill
61         SpillOrderJS = 4,       // needs spill
62         SpillOrderCell = 4,     // needs spill
63         SpillOrderInteger = 5,  // needs spill and box
64         SpillOrderDouble = 6,   // needs spill and convert
65     };
66 
67 
68 public:
69     GPRReg fillInteger(NodeIndex, DataFormat& returnFormat);
70     FPRReg fillDouble(NodeIndex);
71     GPRReg fillJSValue(NodeIndex);
72 
73     // lock and unlock GPR & FPR registers.
lock(GPRReg reg)74     void lock(GPRReg reg)
75     {
76         m_gprs.lock(reg);
77     }
lock(FPRReg reg)78     void lock(FPRReg reg)
79     {
80         m_fprs.lock(reg);
81     }
unlock(GPRReg reg)82     void unlock(GPRReg reg)
83     {
84         m_gprs.unlock(reg);
85     }
unlock(FPRReg reg)86     void unlock(FPRReg reg)
87     {
88         m_fprs.unlock(reg);
89     }
90 
91     // Used to check whether a child node is on its last use,
92     // and its machine registers may be reused.
canReuse(NodeIndex nodeIndex)93     bool canReuse(NodeIndex nodeIndex)
94     {
95         VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
96         GenerationInfo& info = m_generationInfo[virtualRegister];
97         return info.canReuse();
98     }
reuse(GPRReg reg)99     GPRReg reuse(GPRReg reg)
100     {
101         m_gprs.lock(reg);
102         return reg;
103     }
reuse(FPRReg reg)104     FPRReg reuse(FPRReg reg)
105     {
106         m_fprs.lock(reg);
107         return reg;
108     }
109 
110     // Allocate a gpr/fpr.
allocate()111     GPRReg allocate()
112     {
113         VirtualRegister spillMe;
114         GPRReg gpr = m_gprs.allocate(spillMe);
115         if (spillMe != InvalidVirtualRegister)
116             spill(spillMe);
117         return gpr;
118     }
fprAllocate()119     FPRReg fprAllocate()
120     {
121         VirtualRegister spillMe;
122         FPRReg fpr = m_fprs.allocate(spillMe);
123         if (spillMe != InvalidVirtualRegister)
124             spill(spillMe);
125         return fpr;
126     }
127 
128     // Check whether a VirtualRegsiter is currently in a machine register.
129     // We use this when filling operands to fill those that are already in
130     // machine registers first (by locking VirtualRegsiters that are already
131     // in machine register before filling those that are not we attempt to
132     // avoid spilling values we will need immediately).
isFilled(NodeIndex nodeIndex)133     bool isFilled(NodeIndex nodeIndex)
134     {
135         VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
136         GenerationInfo& info = m_generationInfo[virtualRegister];
137         return info.registerFormat() != DataFormatNone;
138     }
isFilledDouble(NodeIndex nodeIndex)139     bool isFilledDouble(NodeIndex nodeIndex)
140     {
141         VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
142         GenerationInfo& info = m_generationInfo[virtualRegister];
143         return info.registerFormat() == DataFormatDouble;
144     }
145 
146 protected:
JITCodeGenerator(JITCompiler & jit,bool isSpeculative)147     JITCodeGenerator(JITCompiler& jit, bool isSpeculative)
148         : m_jit(jit)
149         , m_isSpeculative(isSpeculative)
150         , m_compileIndex(0)
151         , m_generationInfo(m_jit.codeBlock()->m_numCalleeRegisters)
152         , m_blockHeads(jit.graph().m_blocks.size())
153     {
154     }
155 
156     // These methods convert between doubles, and doubles boxed and JSValues.
boxDouble(FPRReg fpr,GPRReg gpr)157     GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
158     {
159         m_jit.moveDoubleToPtr(fpr, gpr);
160         m_jit.subPtr(GPRInfo::tagTypeNumberRegister, gpr);
161         return gpr;
162     }
unboxDouble(GPRReg gpr,FPRReg fpr)163     FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
164     {
165         m_jit.addPtr(GPRInfo::tagTypeNumberRegister, gpr);
166         m_jit.movePtrToDouble(gpr, fpr);
167         return fpr;
168     }
boxDouble(FPRReg fpr)169     GPRReg boxDouble(FPRReg fpr)
170     {
171         return boxDouble(fpr, allocate());
172     }
unboxDouble(GPRReg gpr)173     FPRReg unboxDouble(GPRReg gpr)
174     {
175         return unboxDouble(gpr, fprAllocate());
176     }
177 
178     // Called on an operand once it has been consumed by a parent node.
use(NodeIndex nodeIndex)179     void use(NodeIndex nodeIndex)
180     {
181         VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
182         GenerationInfo& info = m_generationInfo[virtualRegister];
183 
184         // use() returns true when the value becomes dead, and any
185         // associated resources may be freed.
186         if (!info.use())
187             return;
188 
189         // Release the associated machine registers.
190         DataFormat registerFormat = info.registerFormat();
191         if (registerFormat == DataFormatDouble)
192             m_fprs.release(info.fpr());
193         else if (registerFormat != DataFormatNone)
194             m_gprs.release(info.gpr());
195     }
196 
197     // Spill a VirtualRegister to the RegisterFile.
spill(VirtualRegister spillMe)198     void spill(VirtualRegister spillMe)
199     {
200         GenerationInfo& info = m_generationInfo[spillMe];
201 
202         // Check the GenerationInfo to see if this value need writing
203         // to the RegisterFile - if not, mark it as spilled & return.
204         if (!info.needsSpill()) {
205             info.setSpilled();
206             return;
207         }
208 
209         DataFormat spillFormat = info.registerFormat();
210         if (spillFormat == DataFormatDouble) {
211             // All values are spilled as JSValues, so box the double via a temporary gpr.
212             GPRReg gpr = boxDouble(info.fpr());
213             m_jit.storePtr(gpr, JITCompiler::addressFor(spillMe));
214             unlock(gpr);
215             info.spill(DataFormatJSDouble);
216             return;
217         }
218 
219         // The following code handles JSValues, int32s, and cells.
220         ASSERT(spillFormat == DataFormatInteger || spillFormat == DataFormatCell || spillFormat & DataFormatJS);
221 
222         GPRReg reg = info.gpr();
223         // We need to box int32 and cell values ...
224         // but on JSVALUE64 boxing a cell is a no-op!
225         if (spillFormat == DataFormatInteger)
226             m_jit.orPtr(GPRInfo::tagTypeNumberRegister, reg);
227 
228         // Spill the value, and record it as spilled in its boxed form.
229         m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
230         info.spill((DataFormat)(spillFormat | DataFormatJS));
231     }
232 
233     // Checks/accessors for constant values.
isConstant(NodeIndex nodeIndex)234     bool isConstant(NodeIndex nodeIndex) { return m_jit.isConstant(nodeIndex); }
isInt32Constant(NodeIndex nodeIndex)235     bool isInt32Constant(NodeIndex nodeIndex) { return m_jit.isInt32Constant(nodeIndex); }
isDoubleConstant(NodeIndex nodeIndex)236     bool isDoubleConstant(NodeIndex nodeIndex) { return m_jit.isDoubleConstant(nodeIndex); }
isJSConstant(NodeIndex nodeIndex)237     bool isJSConstant(NodeIndex nodeIndex) { return m_jit.isJSConstant(nodeIndex); }
valueOfInt32Constant(NodeIndex nodeIndex)238     int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); }
valueOfDoubleConstant(NodeIndex nodeIndex)239     double valueOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.valueOfDoubleConstant(nodeIndex); }
valueOfJSConstant(NodeIndex nodeIndex)240     JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(nodeIndex); }
241 
identifier(unsigned index)242     Identifier* identifier(unsigned index)
243     {
244         return &m_jit.codeBlock()->identifier(index);
245     }
246 
247     // Spill all VirtualRegisters back to the RegisterFile.
flushRegisters()248     void flushRegisters()
249     {
250         for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
251             if (iter.name() != InvalidVirtualRegister) {
252                 spill(iter.name());
253                 iter.release();
254             }
255         }
256         for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
257             if (iter.name() != InvalidVirtualRegister) {
258                 spill(iter.name());
259                 iter.release();
260             }
261         }
262     }
263 
264 #ifndef NDEBUG
265     // Used to ASSERT flushRegisters() has been called prior to
266     // calling out from JIT code to a C helper function.
isFlushed()267     bool isFlushed()
268     {
269         for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
270             if (iter.name() != InvalidVirtualRegister)
271                 return false;
272         }
273         for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
274             if (iter.name() != InvalidVirtualRegister)
275                 return false;
276         }
277         return true;
278     }
279 #endif
280 
281     // Get the JSValue representation of a constant.
constantAsJSValue(NodeIndex nodeIndex)282     JSValue constantAsJSValue(NodeIndex nodeIndex)
283     {
284         Node& node = m_jit.graph()[nodeIndex];
285         if (isInt32Constant(nodeIndex))
286             return jsNumber(node.int32Constant());
287         if (isDoubleConstant(nodeIndex))
288             return JSValue(JSValue::EncodeAsDouble, node.numericConstant());
289         ASSERT(isJSConstant(nodeIndex));
290         return valueOfJSConstant(nodeIndex);
291     }
constantAsJSValueAsImmPtr(NodeIndex nodeIndex)292     MacroAssembler::ImmPtr constantAsJSValueAsImmPtr(NodeIndex nodeIndex)
293     {
294         return MacroAssembler::ImmPtr(JSValue::encode(constantAsJSValue(nodeIndex)));
295     }
296 
297     // Helper functions to enable code sharing in implementations of bit/shift ops.
bitOp(NodeType op,int32_t imm,GPRReg op1,GPRReg result)298     void bitOp(NodeType op, int32_t imm, GPRReg op1, GPRReg result)
299     {
300         switch (op) {
301         case BitAnd:
302             m_jit.and32(Imm32(imm), op1, result);
303             break;
304         case BitOr:
305             m_jit.or32(Imm32(imm), op1, result);
306             break;
307         case BitXor:
308             m_jit.xor32(Imm32(imm), op1, result);
309             break;
310         default:
311             ASSERT_NOT_REACHED();
312         }
313     }
bitOp(NodeType op,GPRReg op1,GPRReg op2,GPRReg result)314     void bitOp(NodeType op, GPRReg op1, GPRReg op2, GPRReg result)
315     {
316         switch (op) {
317         case BitAnd:
318             m_jit.and32(op1, op2, result);
319             break;
320         case BitOr:
321             m_jit.or32(op1, op2, result);
322             break;
323         case BitXor:
324             m_jit.xor32(op1, op2, result);
325             break;
326         default:
327             ASSERT_NOT_REACHED();
328         }
329     }
shiftOp(NodeType op,GPRReg op1,int32_t shiftAmount,GPRReg result)330     void shiftOp(NodeType op, GPRReg op1, int32_t shiftAmount, GPRReg result)
331     {
332         switch (op) {
333         case BitRShift:
334             m_jit.rshift32(op1, Imm32(shiftAmount), result);
335             break;
336         case BitLShift:
337             m_jit.lshift32(op1, Imm32(shiftAmount), result);
338             break;
339         case BitURShift:
340             m_jit.urshift32(op1, Imm32(shiftAmount), result);
341             break;
342         default:
343             ASSERT_NOT_REACHED();
344         }
345     }
shiftOp(NodeType op,GPRReg op1,GPRReg shiftAmount,GPRReg result)346     void shiftOp(NodeType op, GPRReg op1, GPRReg shiftAmount, GPRReg result)
347     {
348         switch (op) {
349         case BitRShift:
350             m_jit.rshift32(op1, shiftAmount, result);
351             break;
352         case BitLShift:
353             m_jit.lshift32(op1, shiftAmount, result);
354             break;
355         case BitURShift:
356             m_jit.urshift32(op1, shiftAmount, result);
357             break;
358         default:
359             ASSERT_NOT_REACHED();
360         }
361     }
362 
363     // Called once a node has completed code generation but prior to setting
364     // its result, to free up its children. (This must happen prior to setting
365     // the nodes result, since the node may have the same VirtualRegister as
366     // a child, and as such will use the same GeneratioInfo).
367     void useChildren(Node&);
368 
369     // These method called to initialize the the GenerationInfo
370     // to describe the result of an operation.
371     void integerResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatInteger)
372     {
373         Node& node = m_jit.graph()[nodeIndex];
374         useChildren(node);
375 
376         VirtualRegister virtualRegister = node.virtualRegister();
377         GenerationInfo& info = m_generationInfo[virtualRegister];
378 
379         if (format == DataFormatInteger) {
380             m_jit.jitAssertIsInt32(reg);
381             m_gprs.retain(reg, virtualRegister, SpillOrderInteger);
382             info.initInteger(nodeIndex, node.refCount(), reg);
383         } else {
384             ASSERT(format == DataFormatJSInteger);
385             m_jit.jitAssertIsJSInt32(reg);
386             m_gprs.retain(reg, virtualRegister, SpillOrderJS);
387             info.initJSValue(nodeIndex, node.refCount(), reg, format);
388         }
389     }
noResult(NodeIndex nodeIndex)390     void noResult(NodeIndex nodeIndex)
391     {
392         Node& node = m_jit.graph()[nodeIndex];
393         useChildren(node);
394     }
cellResult(GPRReg reg,NodeIndex nodeIndex)395     void cellResult(GPRReg reg, NodeIndex nodeIndex)
396     {
397         Node& node = m_jit.graph()[nodeIndex];
398         useChildren(node);
399 
400         VirtualRegister virtualRegister = node.virtualRegister();
401         m_gprs.retain(reg, virtualRegister, SpillOrderCell);
402         GenerationInfo& info = m_generationInfo[virtualRegister];
403         info.initCell(nodeIndex, node.refCount(), reg);
404     }
405     void jsValueResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatJS)
406     {
407         if (format == DataFormatJSInteger)
408             m_jit.jitAssertIsJSInt32(reg);
409 
410         Node& node = m_jit.graph()[nodeIndex];
411         useChildren(node);
412 
413         VirtualRegister virtualRegister = node.virtualRegister();
414         m_gprs.retain(reg, virtualRegister, SpillOrderJS);
415         GenerationInfo& info = m_generationInfo[virtualRegister];
416         info.initJSValue(nodeIndex, node.refCount(), reg, format);
417     }
doubleResult(FPRReg reg,NodeIndex nodeIndex)418     void doubleResult(FPRReg reg, NodeIndex nodeIndex)
419     {
420         Node& node = m_jit.graph()[nodeIndex];
421         useChildren(node);
422 
423         VirtualRegister virtualRegister = node.virtualRegister();
424         m_fprs.retain(reg, virtualRegister, SpillOrderDouble);
425         GenerationInfo& info = m_generationInfo[virtualRegister];
426         info.initDouble(nodeIndex, node.refCount(), reg);
427     }
initConstantInfo(NodeIndex nodeIndex)428     void initConstantInfo(NodeIndex nodeIndex)
429     {
430         ASSERT(isInt32Constant(nodeIndex) || isDoubleConstant(nodeIndex) || isJSConstant(nodeIndex));
431         Node& node = m_jit.graph()[nodeIndex];
432         m_generationInfo[node.virtualRegister()].initConstant(nodeIndex, node.refCount());
433     }
434 
435     // These methods used to sort arguments into the correct registers.
436     template<GPRReg destA, GPRReg destB>
setupTwoStubArgs(GPRReg srcA,GPRReg srcB)437     void setupTwoStubArgs(GPRReg srcA, GPRReg srcB)
438     {
439         // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
440         // (1) both are already in arg regs, the right way around.
441         // (2) both are already in arg regs, the wrong way around.
442         // (3) neither are currently in arg registers.
443         // (4) srcA in in its correct reg.
444         // (5) srcA in in the incorrect reg.
445         // (6) srcB in in its correct reg.
446         // (7) srcB in in the incorrect reg.
447         //
448         // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
449         // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
450         // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
451         // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
452 
453         if (srcB != destA) {
454             // Handle the easy cases - two simple moves.
455             m_jit.move(srcA, destA);
456             m_jit.move(srcB, destB);
457         } else if (srcA != destB) {
458             // Handle the non-swap case - just put srcB in place first.
459             m_jit.move(srcB, destB);
460             m_jit.move(srcA, destA);
461         } else
462             m_jit.swap(destB, destB);
463     }
464     template<FPRReg destA, FPRReg destB>
setupTwoStubArgs(FPRReg srcA,FPRReg srcB)465     void setupTwoStubArgs(FPRReg srcA, FPRReg srcB)
466     {
467         // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
468         // (1) both are already in arg regs, the right way around.
469         // (2) both are already in arg regs, the wrong way around.
470         // (3) neither are currently in arg registers.
471         // (4) srcA in in its correct reg.
472         // (5) srcA in in the incorrect reg.
473         // (6) srcB in in its correct reg.
474         // (7) srcB in in the incorrect reg.
475         //
476         // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
477         // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
478         // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
479         // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
480 
481         if (srcB != destA) {
482             // Handle the easy cases - two simple moves.
483             m_jit.moveDouble(srcA, destA);
484             m_jit.moveDouble(srcB, destB);
485             return;
486         }
487 
488         if (srcA != destB) {
489             // Handle the non-swap case - just put srcB in place first.
490             m_jit.moveDouble(srcB, destB);
491             m_jit.moveDouble(srcA, destA);
492             return;
493         }
494 
495         ASSERT(srcB == destA && srcA == destB);
496         // Need to swap; pick a temporary register.
497         FPRReg temp;
498         if (destA != FPRInfo::argumentFPR3 && destA != FPRInfo::argumentFPR3)
499             temp = FPRInfo::argumentFPR3;
500         else if (destA != FPRInfo::argumentFPR2 && destA != FPRInfo::argumentFPR2)
501             temp = FPRInfo::argumentFPR2;
502         else {
503             ASSERT(destA != FPRInfo::argumentFPR1 && destA != FPRInfo::argumentFPR1);
504             temp = FPRInfo::argumentFPR1;
505         }
506         m_jit.moveDouble(destA, temp);
507         m_jit.moveDouble(destB, destA);
508         m_jit.moveDouble(temp, destB);
509     }
setupStubArguments(GPRReg arg1,GPRReg arg2)510     void setupStubArguments(GPRReg arg1, GPRReg arg2)
511     {
512         setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2);
513     }
setupStubArguments(GPRReg arg1,GPRReg arg2,GPRReg arg3)514     void setupStubArguments(GPRReg arg1, GPRReg arg2, GPRReg arg3)
515     {
516         // If neither of arg2/arg3 are in our way, then we can move arg1 into place.
517         // Then we can use setupTwoStubArgs to fix arg2/arg3.
518         if (arg2 != GPRInfo::argumentGPR1 && arg3 != GPRInfo::argumentGPR1) {
519             m_jit.move(arg1, GPRInfo::argumentGPR1);
520             setupTwoStubArgs<GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg2, arg3);
521             return;
522         }
523 
524         // If neither of arg1/arg3 are in our way, then we can move arg2 into place.
525         // Then we can use setupTwoStubArgs to fix arg1/arg3.
526         if (arg1 != GPRInfo::argumentGPR2 && arg3 != GPRInfo::argumentGPR2) {
527             m_jit.move(arg2, GPRInfo::argumentGPR2);
528             setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3>(arg1, arg3);
529             return;
530         }
531 
532         // If neither of arg1/arg2 are in our way, then we can move arg3 into place.
533         // Then we can use setupTwoStubArgs to fix arg1/arg2.
534         if (arg1 != GPRInfo::argumentGPR3 && arg2 != GPRInfo::argumentGPR3) {
535             m_jit.move(arg3, GPRInfo::argumentGPR3);
536             setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2);
537             return;
538         }
539 
540         // If we get here, we haven't been able to move any of arg1/arg2/arg3.
541         // Since all three are blocked, then all three must already be in the argument register.
542         // But are they in the right ones?
543 
544         // First, ensure arg1 is in place.
545         if (arg1 != GPRInfo::argumentGPR1) {
546             m_jit.swap(arg1, GPRInfo::argumentGPR1);
547 
548             // If arg1 wasn't in argumentGPR1, one of arg2/arg3 must be.
549             ASSERT(arg2 == GPRInfo::argumentGPR1 || arg3 == GPRInfo::argumentGPR1);
550             // If arg2 was in argumentGPR1 it no longer is (due to the swap).
551             // Otherwise arg3 must have been. Mark him as moved.
552             if (arg2 == GPRInfo::argumentGPR1)
553                 arg2 = arg1;
554             else
555                 arg3 = arg1;
556         }
557 
558         // Either arg2 & arg3 need swapping, or we're all done.
559         ASSERT((arg2 == GPRInfo::argumentGPR2 || arg3 == GPRInfo::argumentGPR3)
560             || (arg2 == GPRInfo::argumentGPR3 || arg3 == GPRInfo::argumentGPR2));
561 
562         if (arg2 != GPRInfo::argumentGPR2)
563             m_jit.swap(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3);
564     }
565 
566     // These methods add calls to C++ helper functions.
callOperation(J_DFGOperation_EJP operation,GPRReg result,GPRReg arg1,void * pointer)567     void callOperation(J_DFGOperation_EJP operation, GPRReg result, GPRReg arg1, void* pointer)
568     {
569         ASSERT(isFlushed());
570 
571         m_jit.move(arg1, GPRInfo::argumentGPR1);
572         m_jit.move(JITCompiler::TrustedImmPtr(pointer), GPRInfo::argumentGPR2);
573         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
574 
575         appendCallWithExceptionCheck(operation);
576         m_jit.move(GPRInfo::returnValueGPR, result);
577     }
callOperation(J_DFGOperation_EJI operation,GPRReg result,GPRReg arg1,Identifier * identifier)578     void callOperation(J_DFGOperation_EJI operation, GPRReg result, GPRReg arg1, Identifier* identifier)
579     {
580         callOperation((J_DFGOperation_EJP)operation, result, arg1, identifier);
581     }
callOperation(J_DFGOperation_EJ operation,GPRReg result,GPRReg arg1)582     void callOperation(J_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
583     {
584         ASSERT(isFlushed());
585 
586         m_jit.move(arg1, GPRInfo::argumentGPR1);
587         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
588 
589         appendCallWithExceptionCheck(operation);
590         m_jit.move(GPRInfo::returnValueGPR, result);
591     }
callOperation(Z_DFGOperation_EJ operation,GPRReg result,GPRReg arg1)592     void callOperation(Z_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
593     {
594         ASSERT(isFlushed());
595 
596         m_jit.move(arg1, GPRInfo::argumentGPR1);
597         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
598 
599         appendCallWithExceptionCheck(operation);
600         m_jit.move(GPRInfo::returnValueGPR, result);
601     }
callOperation(Z_DFGOperation_EJJ operation,GPRReg result,GPRReg arg1,GPRReg arg2)602     void callOperation(Z_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
603     {
604         ASSERT(isFlushed());
605 
606         setupStubArguments(arg1, arg2);
607         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
608 
609         appendCallWithExceptionCheck(operation);
610         m_jit.move(GPRInfo::returnValueGPR, result);
611     }
callOperation(J_DFGOperation_EJJ operation,GPRReg result,GPRReg arg1,GPRReg arg2)612     void callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
613     {
614         ASSERT(isFlushed());
615 
616         setupStubArguments(arg1, arg2);
617         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
618 
619         appendCallWithExceptionCheck(operation);
620         m_jit.move(GPRInfo::returnValueGPR, result);
621     }
callOperation(V_DFGOperation_EJJP operation,GPRReg arg1,GPRReg arg2,void * pointer)622     void callOperation(V_DFGOperation_EJJP operation, GPRReg arg1, GPRReg arg2, void* pointer)
623     {
624         ASSERT(isFlushed());
625 
626         setupStubArguments(arg1, arg2);
627         m_jit.move(JITCompiler::TrustedImmPtr(pointer), GPRInfo::argumentGPR3);
628         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
629 
630         appendCallWithExceptionCheck(operation);
631     }
callOperation(V_DFGOperation_EJJI operation,GPRReg arg1,GPRReg arg2,Identifier * identifier)632     void callOperation(V_DFGOperation_EJJI operation, GPRReg arg1, GPRReg arg2, Identifier* identifier)
633     {
634         callOperation((V_DFGOperation_EJJP)operation, arg1, arg2, identifier);
635     }
callOperation(V_DFGOperation_EJJJ operation,GPRReg arg1,GPRReg arg2,GPRReg arg3)636     void callOperation(V_DFGOperation_EJJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
637     {
638         ASSERT(isFlushed());
639 
640         setupStubArguments(arg1, arg2, arg3);
641         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
642 
643         appendCallWithExceptionCheck(operation);
644     }
callOperation(D_DFGOperation_DD operation,FPRReg result,FPRReg arg1,FPRReg arg2)645     void callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
646     {
647         ASSERT(isFlushed());
648 
649         setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
650 
651         m_jit.appendCall(operation);
652         m_jit.moveDouble(FPRInfo::returnValueFPR, result);
653     }
654 
appendCallWithExceptionCheck(const FunctionPtr & function)655     void appendCallWithExceptionCheck(const FunctionPtr& function)
656     {
657         m_jit.appendCallWithExceptionCheck(function, m_jit.graph()[m_compileIndex].exceptionInfo);
658     }
659 
addBranch(const MacroAssembler::Jump & jump,BlockIndex destination)660     void addBranch(const MacroAssembler::Jump& jump, BlockIndex destination)
661     {
662         m_branches.append(BranchRecord(jump, destination));
663     }
664 
linkBranches()665     void linkBranches()
666     {
667         for (size_t i = 0; i < m_branches.size(); ++i) {
668             BranchRecord& branch = m_branches[i];
669             branch.jump.linkTo(m_blockHeads[branch.destination], &m_jit);
670         }
671     }
672 
673 #ifndef NDEBUG
674     void dump(const char* label = 0);
675 #endif
676 
677 #if DFG_CONSISTENCY_CHECK
678     void checkConsistency();
679 #else
checkConsistency()680     void checkConsistency() {}
681 #endif
682 
683     // The JIT, while also provides MacroAssembler functionality.
684     JITCompiler& m_jit;
685     // This flag is used to distinguish speculative and non-speculative
686     // code generation. This is significant when filling spilled values
687     // from the RegisterFile. When spilling we attempt to store information
688     // as to the type of boxed value being stored (int32, double, cell), and
689     // when filling on the speculative path we will retrieve this type info
690     // where available. On the non-speculative path, however, we cannot rely
691     // on the spill format info, since the a value being loaded might have
692     // been spilled by either the speculative or non-speculative paths (where
693     // we entered the non-speculative path on an intervening bail-out), and
694     // the value may have been boxed differently on the two paths.
695     bool m_isSpeculative;
696     // The current node being generated.
697     BlockIndex m_block;
698     NodeIndex m_compileIndex;
699     // Virtual and physical register maps.
700     Vector<GenerationInfo, 32> m_generationInfo;
701     RegisterBank<GPRInfo> m_gprs;
702     RegisterBank<FPRInfo> m_fprs;
703 
704     Vector<MacroAssembler::Label> m_blockHeads;
705     struct BranchRecord {
BranchRecordBranchRecord706         BranchRecord(MacroAssembler::Jump jump, BlockIndex destination)
707             : jump(jump)
708             , destination(destination)
709         {
710         }
711 
712         MacroAssembler::Jump jump;
713         BlockIndex destination;
714     };
715     Vector<BranchRecord, 8> m_branches;
716 };
717 
718 // === Operand types ===
719 //
720 // IntegerOperand, DoubleOperand and JSValueOperand.
721 //
722 // These classes are used to lock the operands to a node into machine
723 // registers. These classes implement of pattern of locking a value
724 // into register at the point of construction only if it is already in
725 // registers, and otherwise loading it lazily at the point it is first
726 // used. We do so in order to attempt to avoid spilling one operand
727 // in order to make space available for another.
728 
729 class IntegerOperand {
730 public:
IntegerOperand(JITCodeGenerator * jit,NodeIndex index)731     explicit IntegerOperand(JITCodeGenerator* jit, NodeIndex index)
732         : m_jit(jit)
733         , m_index(index)
734         , m_gprOrInvalid(InvalidGPRReg)
735 #ifndef NDEBUG
736         , m_format(DataFormatNone)
737 #endif
738     {
739         ASSERT(m_jit);
740         if (jit->isFilled(index))
741             gpr();
742     }
743 
~IntegerOperand()744     ~IntegerOperand()
745     {
746         ASSERT(m_gprOrInvalid != InvalidGPRReg);
747         m_jit->unlock(m_gprOrInvalid);
748     }
749 
index()750     NodeIndex index() const
751     {
752         return m_index;
753     }
754 
format()755     DataFormat format()
756     {
757         gpr(); // m_format is set when m_gpr is locked.
758         ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
759         return m_format;
760     }
761 
gpr()762     GPRReg gpr()
763     {
764         if (m_gprOrInvalid == InvalidGPRReg)
765             m_gprOrInvalid = m_jit->fillInteger(index(), m_format);
766         return m_gprOrInvalid;
767     }
768 
769 private:
770     JITCodeGenerator* m_jit;
771     NodeIndex m_index;
772     GPRReg m_gprOrInvalid;
773     DataFormat m_format;
774 };
775 
776 class DoubleOperand {
777 public:
DoubleOperand(JITCodeGenerator * jit,NodeIndex index)778     explicit DoubleOperand(JITCodeGenerator* jit, NodeIndex index)
779         : m_jit(jit)
780         , m_index(index)
781         , m_fprOrInvalid(InvalidFPRReg)
782     {
783         ASSERT(m_jit);
784         if (jit->isFilledDouble(index))
785             fpr();
786     }
787 
~DoubleOperand()788     ~DoubleOperand()
789     {
790         ASSERT(m_fprOrInvalid != InvalidFPRReg);
791         m_jit->unlock(m_fprOrInvalid);
792     }
793 
index()794     NodeIndex index() const
795     {
796         return m_index;
797     }
798 
fpr()799     FPRReg fpr()
800     {
801         if (m_fprOrInvalid == InvalidFPRReg)
802             m_fprOrInvalid = m_jit->fillDouble(index());
803         return m_fprOrInvalid;
804     }
805 
806 private:
807     JITCodeGenerator* m_jit;
808     NodeIndex m_index;
809     FPRReg m_fprOrInvalid;
810 };
811 
812 class JSValueOperand {
813 public:
JSValueOperand(JITCodeGenerator * jit,NodeIndex index)814     explicit JSValueOperand(JITCodeGenerator* jit, NodeIndex index)
815         : m_jit(jit)
816         , m_index(index)
817         , m_gprOrInvalid(InvalidGPRReg)
818     {
819         ASSERT(m_jit);
820         if (jit->isFilled(index))
821             gpr();
822     }
823 
~JSValueOperand()824     ~JSValueOperand()
825     {
826         ASSERT(m_gprOrInvalid != InvalidGPRReg);
827         m_jit->unlock(m_gprOrInvalid);
828     }
829 
index()830     NodeIndex index() const
831     {
832         return m_index;
833     }
834 
gpr()835     GPRReg gpr()
836     {
837         if (m_gprOrInvalid == InvalidGPRReg)
838             m_gprOrInvalid = m_jit->fillJSValue(index());
839         return m_gprOrInvalid;
840     }
841 
842 private:
843     JITCodeGenerator* m_jit;
844     NodeIndex m_index;
845     GPRReg m_gprOrInvalid;
846 };
847 
848 
849 // === Temporaries ===
850 //
851 // These classes are used to allocate temporary registers.
852 // A mechanism is provided to attempt to reuse the registers
853 // currently allocated to child nodes whose value is consumed
854 // by, and not live after, this operation.
855 
856 class GPRTemporary {
857 public:
858     GPRTemporary(JITCodeGenerator*);
859     GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&);
860     GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&, SpeculateIntegerOperand&);
861     GPRTemporary(JITCodeGenerator*, IntegerOperand&);
862     GPRTemporary(JITCodeGenerator*, IntegerOperand&, IntegerOperand&);
863     GPRTemporary(JITCodeGenerator*, SpeculateCellOperand&);
864     GPRTemporary(JITCodeGenerator*, JSValueOperand&);
865 
~GPRTemporary()866     ~GPRTemporary()
867     {
868         m_jit->unlock(gpr());
869     }
870 
gpr()871     GPRReg gpr()
872     {
873         ASSERT(m_gpr != InvalidGPRReg);
874         return m_gpr;
875     }
876 
877 protected:
GPRTemporary(JITCodeGenerator * jit,GPRReg lockedGPR)878     GPRTemporary(JITCodeGenerator* jit, GPRReg lockedGPR)
879         : m_jit(jit)
880         , m_gpr(lockedGPR)
881     {
882     }
883 
884 private:
885     JITCodeGenerator* m_jit;
886     GPRReg m_gpr;
887 };
888 
889 class FPRTemporary {
890 public:
891     FPRTemporary(JITCodeGenerator*);
892     FPRTemporary(JITCodeGenerator*, DoubleOperand&);
893     FPRTemporary(JITCodeGenerator*, DoubleOperand&, DoubleOperand&);
894 
~FPRTemporary()895     ~FPRTemporary()
896     {
897         m_jit->unlock(fpr());
898     }
899 
fpr()900     FPRReg fpr() const
901     {
902         ASSERT(m_fpr != InvalidFPRReg);
903         return m_fpr;
904     }
905 
906 protected:
FPRTemporary(JITCodeGenerator * jit,FPRReg lockedFPR)907     FPRTemporary(JITCodeGenerator* jit, FPRReg lockedFPR)
908         : m_jit(jit)
909         , m_fpr(lockedFPR)
910     {
911     }
912 
913 private:
914     JITCodeGenerator* m_jit;
915     FPRReg m_fpr;
916 };
917 
918 
919 // === Results ===
920 //
921 // These classes lock the result of a call to a C++ helper function.
922 
923 class GPRResult : public GPRTemporary {
924 public:
GPRResult(JITCodeGenerator * jit)925     GPRResult(JITCodeGenerator* jit)
926         : GPRTemporary(jit, lockedResult(jit))
927     {
928     }
929 
930 private:
lockedResult(JITCodeGenerator * jit)931     static GPRReg lockedResult(JITCodeGenerator* jit)
932     {
933         jit->lock(GPRInfo::returnValueGPR);
934         return GPRInfo::returnValueGPR;
935     }
936 };
937 
938 class FPRResult : public FPRTemporary {
939 public:
FPRResult(JITCodeGenerator * jit)940     FPRResult(JITCodeGenerator* jit)
941         : FPRTemporary(jit, lockedResult(jit))
942     {
943     }
944 
945 private:
lockedResult(JITCodeGenerator * jit)946     static FPRReg lockedResult(JITCodeGenerator* jit)
947     {
948         jit->lock(FPRInfo::returnValueFPR);
949         return FPRInfo::returnValueFPR;
950     }
951 };
952 
953 } } // namespace JSC::DFG
954 
955 #endif
956 #endif
957 
958