https://bugs.webkit.org/show_bug.cgi?id=63218
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGJITCodeGenerator.h
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.
74     void lock(GPRReg reg)
75     {
76         m_gprs.lock(reg);
77     }
78     void lock(FPRReg reg)
79     {
80         m_fprs.lock(reg);
81     }
82     void unlock(GPRReg reg)
83     {
84         m_gprs.unlock(reg);
85     }
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.
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     }
99     GPRReg reuse(GPRReg reg)
100     {
101         m_gprs.lock(reg);
102         return reg;
103     }
104     FPRReg reuse(FPRReg reg)
105     {
106         m_fprs.lock(reg);
107         return reg;
108     }
109
110     // Allocate a gpr/fpr.
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     }
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).
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     }
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:
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 are used when generating 'unexpected'
157     // calls out from JIT code to C++ helper routines -
158     // they spill all live values to the appropriate
159     // slots in the RegisterFile without changing any state
160     // in the GenerationInfo.
161     void silentSpillGPR(VirtualRegister spillMe, GPRReg canTrample, GPRReg exclude = InvalidGPRReg)
162     {
163         GenerationInfo& info = m_generationInfo[spillMe];
164         ASSERT(info.registerFormat() != DataFormatNone);
165         ASSERT(info.registerFormat() != DataFormatDouble);
166
167         if (!info.needsSpill() || (info.gpr() == exclude))
168             return;
169
170         DataFormat registerFormat = info.registerFormat();
171
172         if (registerFormat == DataFormatInteger) {
173             m_jit.orPtr(GPRInfo::tagTypeNumberRegister, info.gpr(), canTrample);
174             m_jit.storePtr(canTrample, JITCompiler::addressFor(spillMe));
175         } else {
176             ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
177             m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
178         }
179     }
180     void silentSpillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
181     {
182         GenerationInfo& info = m_generationInfo[spillMe];
183         ASSERT(info.registerFormat() == DataFormatDouble);
184
185         if (!info.needsSpill() || (info.fpr() == exclude))
186             return;
187
188         boxDouble(info.fpr(), canTrample);
189         m_jit.storePtr(canTrample, JITCompiler::addressFor(spillMe));
190     }
191
192     void silentFillGPR(VirtualRegister spillMe, GPRReg exclude = InvalidGPRReg)
193     {
194         GenerationInfo& info = m_generationInfo[spillMe];
195         if (info.gpr() == exclude)
196             return;
197
198         NodeIndex nodeIndex = info.nodeIndex();
199         Node& node = m_jit.graph()[nodeIndex];
200         ASSERT(info.registerFormat() != DataFormatNone);
201         ASSERT(info.registerFormat() != DataFormatDouble);
202         DataFormat registerFormat = info.registerFormat();
203
204         if (registerFormat == DataFormatInteger) {
205             if (node.isConstant()) {
206                 ASSERT(isInt32Constant(nodeIndex));
207                 m_jit.move(Imm32(valueOfInt32Constant(nodeIndex)), info.gpr());
208             } else
209                 m_jit.load32(JITCompiler::addressFor(spillMe), info.gpr());
210             return;
211         }
212
213         if (node.isConstant())
214             m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex), info.gpr());
215         else {
216             ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
217             m_jit.loadPtr(JITCompiler::addressFor(spillMe), info.gpr());
218         }
219     }
220     void silentFillFPR(VirtualRegister spillMe, GPRReg canTrample, FPRReg exclude = InvalidFPRReg)
221     {
222         GenerationInfo& info = m_generationInfo[spillMe];
223         if (info.fpr() == exclude)
224             return;
225
226         NodeIndex nodeIndex = info.nodeIndex();
227         Node& node = m_jit.graph()[nodeIndex];
228         ASSERT(info.registerFormat() == DataFormatDouble);
229
230         if (node.isConstant()) {
231             ASSERT(isDoubleConstant(nodeIndex));
232             m_jit.move(JITCompiler::ImmPtr(bitwise_cast<void*>(valueOfDoubleConstant(nodeIndex))), canTrample);
233             m_jit.movePtrToDouble(canTrample, info.fpr());
234         } else {
235             m_jit.loadPtr(JITCompiler::addressFor(spillMe), canTrample);
236             unboxDouble(canTrample, info.fpr());
237         }
238     }
239
240     void silentSpillAllRegisters(GPRReg exclude, GPRReg preserve1 = InvalidGPRReg, GPRReg preserve2 = InvalidGPRReg, GPRReg preserve3 = InvalidGPRReg)
241     {
242         GPRReg canTrample = GPRInfo::regT0;
243         if (preserve1 != GPRInfo::regT0 && preserve2 != GPRInfo::regT0 && preserve3 != GPRInfo::regT0)
244             canTrample = GPRInfo::regT0;
245         else if (preserve1 != GPRInfo::regT1 && preserve2 != GPRInfo::regT1 && preserve3 != GPRInfo::regT1)
246             canTrample = GPRInfo::regT1;
247         else if (preserve1 != GPRInfo::regT2 && preserve2 != GPRInfo::regT2 && preserve3 != GPRInfo::regT2)
248             canTrample = GPRInfo::regT2;
249         else
250             canTrample = GPRInfo::regT3;
251         
252         for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
253             if (iter.name() != InvalidVirtualRegister)
254                 silentSpillGPR(iter.name(), canTrample, exclude);
255         }
256         for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
257             if (iter.name() != InvalidVirtualRegister)
258                 silentSpillFPR(iter.name(), canTrample);
259         }
260     }
261     void silentSpillAllRegisters(FPRReg exclude, GPRReg preserve = InvalidGPRReg)
262     {
263         GPRReg canTrample = GPRInfo::regT0;
264         if (preserve == GPRInfo::regT0)
265             canTrample = GPRInfo::regT1;
266         
267         for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
268             if (iter.name() != InvalidVirtualRegister)
269                 silentSpillGPR(iter.name(), canTrample);
270         }
271         for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
272             if (iter.name() != InvalidVirtualRegister)
273                 silentSpillFPR(iter.name(), canTrample, exclude);
274         }
275     }
276     void silentFillAllRegisters(GPRReg exclude)
277     {
278         GPRReg canTrample = GPRInfo::regT0;
279         if (exclude == GPRInfo::regT0)
280             canTrample = GPRInfo::regT1;
281         
282         for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
283             if (iter.name() != InvalidVirtualRegister)
284                 silentFillFPR(iter.name(), canTrample);
285         }
286         for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
287             if (iter.name() != InvalidVirtualRegister)
288                 silentFillGPR(iter.name(), exclude);
289         }
290     }
291     void silentFillAllRegisters(FPRReg exclude)
292     {
293         GPRReg canTrample = GPRInfo::regT0;
294         
295         for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
296             if (iter.name() != InvalidVirtualRegister) {
297                 ASSERT_UNUSED(exclude, iter.regID() != exclude);
298                 silentFillFPR(iter.name(), canTrample, exclude);
299             }
300         }
301         for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
302             if (iter.name() != InvalidVirtualRegister)
303                 silentFillGPR(iter.name());
304         }
305     }
306
307     // These methods convert between doubles, and doubles boxed and JSValues.
308     GPRReg boxDouble(FPRReg fpr, GPRReg gpr)
309     {
310         m_jit.moveDoubleToPtr(fpr, gpr);
311         m_jit.subPtr(GPRInfo::tagTypeNumberRegister, gpr);
312         return gpr;
313     }
314     FPRReg unboxDouble(GPRReg gpr, FPRReg fpr)
315     {
316         m_jit.addPtr(GPRInfo::tagTypeNumberRegister, gpr);
317         m_jit.movePtrToDouble(gpr, fpr);
318         return fpr;
319     }
320     GPRReg boxDouble(FPRReg fpr)
321     {
322         return boxDouble(fpr, allocate());
323     }
324     FPRReg unboxDouble(GPRReg gpr)
325     {
326         return unboxDouble(gpr, fprAllocate());
327     }
328
329     // Called on an operand once it has been consumed by a parent node.
330     void use(NodeIndex nodeIndex)
331     {
332         VirtualRegister virtualRegister = m_jit.graph()[nodeIndex].virtualRegister();
333         GenerationInfo& info = m_generationInfo[virtualRegister];
334
335         // use() returns true when the value becomes dead, and any
336         // associated resources may be freed.
337         if (!info.use())
338             return;
339
340         // Release the associated machine registers.
341         DataFormat registerFormat = info.registerFormat();
342         if (registerFormat == DataFormatDouble)
343             m_fprs.release(info.fpr());
344         else if (registerFormat != DataFormatNone)
345             m_gprs.release(info.gpr());
346     }
347
348     // Spill a VirtualRegister to the RegisterFile.
349     void spill(VirtualRegister spillMe)
350     {
351         GenerationInfo& info = m_generationInfo[spillMe];
352
353         // Check the GenerationInfo to see if this value need writing
354         // to the RegisterFile - if not, mark it as spilled & return.
355         if (!info.needsSpill()) {
356             info.setSpilled();
357             return;
358         }
359
360         DataFormat spillFormat = info.registerFormat();
361         if (spillFormat == DataFormatDouble) {
362             // All values are spilled as JSValues, so box the double via a temporary gpr.
363             GPRReg gpr = boxDouble(info.fpr());
364             m_jit.storePtr(gpr, JITCompiler::addressFor(spillMe));
365             unlock(gpr);
366             info.spill(DataFormatJSDouble);
367             return;
368         }
369
370         // The following code handles JSValues, int32s, and cells.
371         ASSERT(spillFormat == DataFormatInteger || spillFormat == DataFormatCell || spillFormat & DataFormatJS);
372
373         GPRReg reg = info.gpr();
374         // We need to box int32 and cell values ...
375         // but on JSVALUE64 boxing a cell is a no-op!
376         if (spillFormat == DataFormatInteger)
377             m_jit.orPtr(GPRInfo::tagTypeNumberRegister, reg);
378
379         // Spill the value, and record it as spilled in its boxed form.
380         m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
381         info.spill((DataFormat)(spillFormat | DataFormatJS));
382     }
383
384     // Checks/accessors for constant values.
385     bool isConstant(NodeIndex nodeIndex) { return m_jit.isConstant(nodeIndex); }
386     bool isJSConstant(NodeIndex nodeIndex) { return m_jit.isJSConstant(nodeIndex); }
387     bool isInt32Constant(NodeIndex nodeIndex) { return m_jit.isInt32Constant(nodeIndex); }
388     bool isDoubleConstant(NodeIndex nodeIndex) { return m_jit.isDoubleConstant(nodeIndex); }
389     int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); }
390     double valueOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.valueOfDoubleConstant(nodeIndex); }
391     JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(nodeIndex); }
392
393     Identifier* identifier(unsigned index)
394     {
395         return &m_jit.codeBlock()->identifier(index);
396     }
397
398     // Spill all VirtualRegisters back to the RegisterFile.
399     void flushRegisters()
400     {
401         for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
402             if (iter.name() != InvalidVirtualRegister) {
403                 spill(iter.name());
404                 iter.release();
405             }
406         }
407         for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
408             if (iter.name() != InvalidVirtualRegister) {
409                 spill(iter.name());
410                 iter.release();
411             }
412         }
413     }
414
415 #ifndef NDEBUG
416     // Used to ASSERT flushRegisters() has been called prior to
417     // calling out from JIT code to a C helper function.
418     bool isFlushed()
419     {
420         for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
421             if (iter.name() != InvalidVirtualRegister)
422                 return false;
423         }
424         for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
425             if (iter.name() != InvalidVirtualRegister)
426                 return false;
427         }
428         return true;
429     }
430 #endif
431
432     MacroAssembler::ImmPtr valueOfJSConstantAsImmPtr(NodeIndex nodeIndex)
433     {
434         return MacroAssembler::ImmPtr(JSValue::encode(valueOfJSConstant(nodeIndex)));
435     }
436
437     // Helper functions to enable code sharing in implementations of bit/shift ops.
438     void bitOp(NodeType op, int32_t imm, GPRReg op1, GPRReg result)
439     {
440         switch (op) {
441         case BitAnd:
442             m_jit.and32(Imm32(imm), op1, result);
443             break;
444         case BitOr:
445             m_jit.or32(Imm32(imm), op1, result);
446             break;
447         case BitXor:
448             m_jit.xor32(Imm32(imm), op1, result);
449             break;
450         default:
451             ASSERT_NOT_REACHED();
452         }
453     }
454     void bitOp(NodeType op, GPRReg op1, GPRReg op2, GPRReg result)
455     {
456         switch (op) {
457         case BitAnd:
458             m_jit.and32(op1, op2, result);
459             break;
460         case BitOr:
461             m_jit.or32(op1, op2, result);
462             break;
463         case BitXor:
464             m_jit.xor32(op1, op2, result);
465             break;
466         default:
467             ASSERT_NOT_REACHED();
468         }
469     }
470     void shiftOp(NodeType op, GPRReg op1, int32_t shiftAmount, GPRReg result)
471     {
472         switch (op) {
473         case BitRShift:
474             m_jit.rshift32(op1, Imm32(shiftAmount), result);
475             break;
476         case BitLShift:
477             m_jit.lshift32(op1, Imm32(shiftAmount), result);
478             break;
479         case BitURShift:
480             m_jit.urshift32(op1, Imm32(shiftAmount), result);
481             break;
482         default:
483             ASSERT_NOT_REACHED();
484         }
485     }
486     void shiftOp(NodeType op, GPRReg op1, GPRReg shiftAmount, GPRReg result)
487     {
488         switch (op) {
489         case BitRShift:
490             m_jit.rshift32(op1, shiftAmount, result);
491             break;
492         case BitLShift:
493             m_jit.lshift32(op1, shiftAmount, result);
494             break;
495         case BitURShift:
496             m_jit.urshift32(op1, shiftAmount, result);
497             break;
498         default:
499             ASSERT_NOT_REACHED();
500         }
501     }
502
503     // Called once a node has completed code generation but prior to setting
504     // its result, to free up its children. (This must happen prior to setting
505     // the nodes result, since the node may have the same VirtualRegister as
506     // a child, and as such will use the same GeneratioInfo).
507     void useChildren(Node&);
508
509     // These method called to initialize the the GenerationInfo
510     // to describe the result of an operation.
511     void integerResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatInteger)
512     {
513         Node& node = m_jit.graph()[nodeIndex];
514         useChildren(node);
515
516         VirtualRegister virtualRegister = node.virtualRegister();
517         GenerationInfo& info = m_generationInfo[virtualRegister];
518
519         if (format == DataFormatInteger) {
520             m_jit.jitAssertIsInt32(reg);
521             m_gprs.retain(reg, virtualRegister, SpillOrderInteger);
522             info.initInteger(nodeIndex, node.refCount(), reg);
523         } else {
524             ASSERT(format == DataFormatJSInteger);
525             m_jit.jitAssertIsJSInt32(reg);
526             m_gprs.retain(reg, virtualRegister, SpillOrderJS);
527             info.initJSValue(nodeIndex, node.refCount(), reg, format);
528         }
529     }
530     void noResult(NodeIndex nodeIndex)
531     {
532         Node& node = m_jit.graph()[nodeIndex];
533         useChildren(node);
534     }
535     void cellResult(GPRReg reg, NodeIndex nodeIndex)
536     {
537         Node& node = m_jit.graph()[nodeIndex];
538         useChildren(node);
539
540         VirtualRegister virtualRegister = node.virtualRegister();
541         m_gprs.retain(reg, virtualRegister, SpillOrderCell);
542         GenerationInfo& info = m_generationInfo[virtualRegister];
543         info.initCell(nodeIndex, node.refCount(), reg);
544     }
545     void jsValueResult(GPRReg reg, NodeIndex nodeIndex, DataFormat format = DataFormatJS)
546     {
547         if (format == DataFormatJSInteger)
548             m_jit.jitAssertIsJSInt32(reg);
549         
550         Node& node = m_jit.graph()[nodeIndex];
551         useChildren(node);
552
553         VirtualRegister virtualRegister = node.virtualRegister();
554         m_gprs.retain(reg, virtualRegister, SpillOrderJS);
555         GenerationInfo& info = m_generationInfo[virtualRegister];
556         info.initJSValue(nodeIndex, node.refCount(), reg, format);
557     }
558     void doubleResult(FPRReg reg, NodeIndex nodeIndex)
559     {
560         Node& node = m_jit.graph()[nodeIndex];
561         useChildren(node);
562
563         VirtualRegister virtualRegister = node.virtualRegister();
564         m_fprs.retain(reg, virtualRegister, SpillOrderDouble);
565         GenerationInfo& info = m_generationInfo[virtualRegister];
566         info.initDouble(nodeIndex, node.refCount(), reg);
567     }
568     void initConstantInfo(NodeIndex nodeIndex)
569     {
570         ASSERT(isInt32Constant(nodeIndex) || isDoubleConstant(nodeIndex) || isJSConstant(nodeIndex));
571         Node& node = m_jit.graph()[nodeIndex];
572         m_generationInfo[node.virtualRegister()].initConstant(nodeIndex, node.refCount());
573     }
574
575     // These methods used to sort arguments into the correct registers.
576     template<GPRReg destA, GPRReg destB>
577     void setupTwoStubArgs(GPRReg srcA, GPRReg srcB)
578     {
579         // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
580         // (1) both are already in arg regs, the right way around.
581         // (2) both are already in arg regs, the wrong way around.
582         // (3) neither are currently in arg registers.
583         // (4) srcA in in its correct reg.
584         // (5) srcA in in the incorrect reg.
585         // (6) srcB in in its correct reg.
586         // (7) srcB in in the incorrect reg.
587         //
588         // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
589         // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
590         // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
591         // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
592
593         if (srcB != destA) {
594             // Handle the easy cases - two simple moves.
595             m_jit.move(srcA, destA);
596             m_jit.move(srcB, destB);
597         } else if (srcA != destB) {
598             // Handle the non-swap case - just put srcB in place first.
599             m_jit.move(srcB, destB);
600             m_jit.move(srcA, destA);
601         } else
602             m_jit.swap(destA, destB);
603     }
604     template<FPRReg destA, FPRReg destB>
605     void setupTwoStubArgs(FPRReg srcA, FPRReg srcB)
606     {
607         // Assuming that srcA != srcB, there are 7 interesting states the registers may be in:
608         // (1) both are already in arg regs, the right way around.
609         // (2) both are already in arg regs, the wrong way around.
610         // (3) neither are currently in arg registers.
611         // (4) srcA in in its correct reg.
612         // (5) srcA in in the incorrect reg.
613         // (6) srcB in in its correct reg.
614         // (7) srcB in in the incorrect reg.
615         //
616         // The trivial approach is to simply emit two moves, to put srcA in place then srcB in
617         // place (the MacroAssembler will omit redundant moves). This apporach will be safe in
618         // cases 1, 3, 4, 5, 6, and in cases where srcA==srcB. The two problem cases are 2
619         // (requires a swap) and 7 (must move srcB first, to avoid trampling.)
620
621         if (srcB != destA) {
622             // Handle the easy cases - two simple moves.
623             m_jit.moveDouble(srcA, destA);
624             m_jit.moveDouble(srcB, destB);
625             return;
626         }
627         
628         if (srcA != destB) {
629             // Handle the non-swap case - just put srcB in place first.
630             m_jit.moveDouble(srcB, destB);
631             m_jit.moveDouble(srcA, destA);
632             return;
633         }
634
635         ASSERT(srcB == destA && srcA == destB);
636         // Need to swap; pick a temporary register.
637         FPRReg temp;
638         if (destA != FPRInfo::argumentFPR3 && destA != FPRInfo::argumentFPR3)
639             temp = FPRInfo::argumentFPR3;
640         else if (destA != FPRInfo::argumentFPR2 && destA != FPRInfo::argumentFPR2)
641             temp = FPRInfo::argumentFPR2;
642         else {
643             ASSERT(destA != FPRInfo::argumentFPR1 && destA != FPRInfo::argumentFPR1);
644             temp = FPRInfo::argumentFPR1;
645         }
646         m_jit.moveDouble(destA, temp);
647         m_jit.moveDouble(destB, destA);
648         m_jit.moveDouble(temp, destB);
649     }
650     void setupStubArguments(GPRReg arg1, GPRReg arg2)
651     {
652         setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2);
653     }
654     void setupStubArguments(GPRReg arg1, GPRReg arg2, GPRReg arg3)
655     {
656         // If neither of arg2/arg3 are in our way, then we can move arg1 into place.
657         // Then we can use setupTwoStubArgs to fix arg2/arg3.
658         if (arg2 != GPRInfo::argumentGPR1 && arg3 != GPRInfo::argumentGPR1) {
659             m_jit.move(arg1, GPRInfo::argumentGPR1);
660             setupTwoStubArgs<GPRInfo::argumentGPR2, GPRInfo::argumentGPR3>(arg2, arg3);
661             return;
662         }
663
664         // If neither of arg1/arg3 are in our way, then we can move arg2 into place.
665         // Then we can use setupTwoStubArgs to fix arg1/arg3.
666         if (arg1 != GPRInfo::argumentGPR2 && arg3 != GPRInfo::argumentGPR2) {
667             m_jit.move(arg2, GPRInfo::argumentGPR2);
668             setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR3>(arg1, arg3);
669             return;
670         }
671
672         // If neither of arg1/arg2 are in our way, then we can move arg3 into place.
673         // Then we can use setupTwoStubArgs to fix arg1/arg2.
674         if (arg1 != GPRInfo::argumentGPR3 && arg2 != GPRInfo::argumentGPR3) {
675             m_jit.move(arg3, GPRInfo::argumentGPR3);
676             setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(arg1, arg2);
677             return;
678         }
679
680         // If we get here, we haven't been able to move any of arg1/arg2/arg3.
681         // Since all three are blocked, then all three must already be in the argument register.
682         // But are they in the right ones?
683
684         // First, ensure arg1 is in place.
685         if (arg1 != GPRInfo::argumentGPR1) {
686             m_jit.swap(arg1, GPRInfo::argumentGPR1);
687
688             // If arg1 wasn't in argumentGPR1, one of arg2/arg3 must be.
689             ASSERT(arg2 == GPRInfo::argumentGPR1 || arg3 == GPRInfo::argumentGPR1);
690             // If arg2 was in argumentGPR1 it no longer is (due to the swap).
691             // Otherwise arg3 must have been. Mark him as moved.
692             if (arg2 == GPRInfo::argumentGPR1)
693                 arg2 = arg1;
694             else
695                 arg3 = arg1;
696         }
697
698         // Either arg2 & arg3 need swapping, or we're all done.
699         ASSERT((arg2 == GPRInfo::argumentGPR2 || arg3 == GPRInfo::argumentGPR3)
700             || (arg2 == GPRInfo::argumentGPR3 || arg3 == GPRInfo::argumentGPR2));
701
702         if (arg2 != GPRInfo::argumentGPR2)
703             m_jit.swap(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3);
704     }
705
706     // These methods add calls to C++ helper functions.
707     void callOperation(J_DFGOperation_EJP operation, GPRReg result, GPRReg arg1, void* pointer)
708     {
709         ASSERT(isFlushed());
710
711         m_jit.move(arg1, GPRInfo::argumentGPR1);
712         m_jit.move(JITCompiler::TrustedImmPtr(pointer), GPRInfo::argumentGPR2);
713         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
714
715         appendCallWithExceptionCheck(operation);
716         m_jit.move(GPRInfo::returnValueGPR, result);
717     }
718     void callOperation(J_DFGOperation_EJI operation, GPRReg result, GPRReg arg1, Identifier* identifier)
719     {
720         callOperation((J_DFGOperation_EJP)operation, result, arg1, identifier);
721     }
722     void callOperation(J_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
723     {
724         ASSERT(isFlushed());
725
726         m_jit.move(arg1, GPRInfo::argumentGPR1);
727         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
728
729         appendCallWithExceptionCheck(operation);
730         m_jit.move(GPRInfo::returnValueGPR, result);
731     }
732     void callOperation(Z_DFGOperation_EJ operation, GPRReg result, GPRReg arg1)
733     {
734         ASSERT(isFlushed());
735
736         m_jit.move(arg1, GPRInfo::argumentGPR1);
737         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
738
739         appendCallWithExceptionCheck(operation);
740         m_jit.move(GPRInfo::returnValueGPR, result);
741     }
742     void callOperation(Z_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
743     {
744         ASSERT(isFlushed());
745
746         setupStubArguments(arg1, arg2);
747         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
748
749         appendCallWithExceptionCheck(operation);
750         m_jit.move(GPRInfo::returnValueGPR, result);
751     }
752     void callOperation(J_DFGOperation_EJJ operation, GPRReg result, GPRReg arg1, GPRReg arg2)
753     {
754         ASSERT(isFlushed());
755
756         setupStubArguments(arg1, arg2);
757         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
758
759         appendCallWithExceptionCheck(operation);
760         m_jit.move(GPRInfo::returnValueGPR, result);
761     }
762     void callOperation(V_DFGOperation_EJJP operation, GPRReg arg1, GPRReg arg2, void* pointer)
763     {
764         ASSERT(isFlushed());
765
766         setupStubArguments(arg1, arg2);
767         m_jit.move(JITCompiler::TrustedImmPtr(pointer), GPRInfo::argumentGPR3);
768         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
769
770         appendCallWithExceptionCheck(operation);
771     }
772     void callOperation(V_DFGOperation_EJJI operation, GPRReg arg1, GPRReg arg2, Identifier* identifier)
773     {
774         callOperation((V_DFGOperation_EJJP)operation, arg1, arg2, identifier);
775     }
776     void callOperation(V_DFGOperation_EJJJ operation, GPRReg arg1, GPRReg arg2, GPRReg arg3)
777     {
778         ASSERT(isFlushed());
779
780         setupStubArguments(arg1, arg2, arg3);
781         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
782
783         appendCallWithExceptionCheck(operation);
784     }
785     void callOperation(D_DFGOperation_DD operation, FPRReg result, FPRReg arg1, FPRReg arg2)
786     {
787         ASSERT(isFlushed());
788
789         setupTwoStubArgs<FPRInfo::argumentFPR0, FPRInfo::argumentFPR1>(arg1, arg2);
790
791         m_jit.appendCall(operation);
792         m_jit.moveDouble(FPRInfo::returnValueFPR, result);
793     }
794
795     JITCompiler::Call appendCallWithExceptionCheck(const FunctionPtr& function)
796     {
797         return m_jit.appendCallWithExceptionCheck(function, m_jit.graph()[m_compileIndex].exceptionInfo);
798     }
799
800     void addBranch(const MacroAssembler::Jump& jump, BlockIndex destination)
801     {
802         m_branches.append(BranchRecord(jump, destination));
803     }
804
805     void linkBranches()
806     {
807         for (size_t i = 0; i < m_branches.size(); ++i) {
808             BranchRecord& branch = m_branches[i];
809             branch.jump.linkTo(m_blockHeads[branch.destination], &m_jit);
810         }
811     }
812
813 #ifndef NDEBUG
814     void dump(const char* label = 0);
815 #endif
816
817 #if DFG_CONSISTENCY_CHECK
818     void checkConsistency();
819 #else
820     void checkConsistency() {}
821 #endif
822
823     // The JIT, while also provides MacroAssembler functionality.
824     JITCompiler& m_jit;
825     // This flag is used to distinguish speculative and non-speculative
826     // code generation. This is significant when filling spilled values
827     // from the RegisterFile. When spilling we attempt to store information
828     // as to the type of boxed value being stored (int32, double, cell), and
829     // when filling on the speculative path we will retrieve this type info
830     // where available. On the non-speculative path, however, we cannot rely
831     // on the spill format info, since the a value being loaded might have
832     // been spilled by either the speculative or non-speculative paths (where
833     // we entered the non-speculative path on an intervening bail-out), and
834     // the value may have been boxed differently on the two paths.
835     bool m_isSpeculative;
836     // The current node being generated.
837     BlockIndex m_block;
838     NodeIndex m_compileIndex;
839     // Virtual and physical register maps.
840     Vector<GenerationInfo, 32> m_generationInfo;
841     RegisterBank<GPRInfo> m_gprs;
842     RegisterBank<FPRInfo> m_fprs;
843
844     Vector<MacroAssembler::Label> m_blockHeads;
845     struct BranchRecord {
846         BranchRecord(MacroAssembler::Jump jump, BlockIndex destination)
847             : jump(jump)
848             , destination(destination)
849         {
850         }
851
852         MacroAssembler::Jump jump;
853         BlockIndex destination;
854     };
855     Vector<BranchRecord, 8> m_branches;
856 };
857
858 // === Operand types ===
859 //
860 // IntegerOperand, DoubleOperand and JSValueOperand.
861 //
862 // These classes are used to lock the operands to a node into machine
863 // registers. These classes implement of pattern of locking a value
864 // into register at the point of construction only if it is already in
865 // registers, and otherwise loading it lazily at the point it is first
866 // used. We do so in order to attempt to avoid spilling one operand
867 // in order to make space available for another.
868
869 class IntegerOperand {
870 public:
871     explicit IntegerOperand(JITCodeGenerator* jit, NodeIndex index)
872         : m_jit(jit)
873         , m_index(index)
874         , m_gprOrInvalid(InvalidGPRReg)
875 #ifndef NDEBUG
876         , m_format(DataFormatNone)
877 #endif
878     {
879         ASSERT(m_jit);
880         if (jit->isFilled(index))
881             gpr();
882     }
883
884     ~IntegerOperand()
885     {
886         ASSERT(m_gprOrInvalid != InvalidGPRReg);
887         m_jit->unlock(m_gprOrInvalid);
888     }
889
890     NodeIndex index() const
891     {
892         return m_index;
893     }
894
895     DataFormat format()
896     {
897         gpr(); // m_format is set when m_gpr is locked.
898         ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
899         return m_format;
900     }
901
902     GPRReg gpr()
903     {
904         if (m_gprOrInvalid == InvalidGPRReg)
905             m_gprOrInvalid = m_jit->fillInteger(index(), m_format);
906         return m_gprOrInvalid;
907     }
908
909 private:
910     JITCodeGenerator* m_jit;
911     NodeIndex m_index;
912     GPRReg m_gprOrInvalid;
913     DataFormat m_format;
914 };
915
916 class DoubleOperand {
917 public:
918     explicit DoubleOperand(JITCodeGenerator* jit, NodeIndex index)
919         : m_jit(jit)
920         , m_index(index)
921         , m_fprOrInvalid(InvalidFPRReg)
922     {
923         ASSERT(m_jit);
924         if (jit->isFilledDouble(index))
925             fpr();
926     }
927
928     ~DoubleOperand()
929     {
930         ASSERT(m_fprOrInvalid != InvalidFPRReg);
931         m_jit->unlock(m_fprOrInvalid);
932     }
933
934     NodeIndex index() const
935     {
936         return m_index;
937     }
938
939     FPRReg fpr()
940     {
941         if (m_fprOrInvalid == InvalidFPRReg)
942             m_fprOrInvalid = m_jit->fillDouble(index());
943         return m_fprOrInvalid;
944     }
945
946 private:
947     JITCodeGenerator* m_jit;
948     NodeIndex m_index;
949     FPRReg m_fprOrInvalid;
950 };
951
952 class JSValueOperand {
953 public:
954     explicit JSValueOperand(JITCodeGenerator* jit, NodeIndex index)
955         : m_jit(jit)
956         , m_index(index)
957         , m_gprOrInvalid(InvalidGPRReg)
958     {
959         ASSERT(m_jit);
960         if (jit->isFilled(index))
961             gpr();
962     }
963
964     ~JSValueOperand()
965     {
966         ASSERT(m_gprOrInvalid != InvalidGPRReg);
967         m_jit->unlock(m_gprOrInvalid);
968     }
969
970     NodeIndex index() const
971     {
972         return m_index;
973     }
974
975     GPRReg gpr()
976     {
977         if (m_gprOrInvalid == InvalidGPRReg)
978             m_gprOrInvalid = m_jit->fillJSValue(index());
979         return m_gprOrInvalid;
980     }
981
982 private:
983     JITCodeGenerator* m_jit;
984     NodeIndex m_index;
985     GPRReg m_gprOrInvalid;
986 };
987
988
989 // === Temporaries ===
990 //
991 // These classes are used to allocate temporary registers.
992 // A mechanism is provided to attempt to reuse the registers
993 // currently allocated to child nodes whose value is consumed
994 // by, and not live after, this operation.
995
996 class GPRTemporary {
997 public:
998     GPRTemporary(JITCodeGenerator*);
999     GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&);
1000     GPRTemporary(JITCodeGenerator*, SpeculateIntegerOperand&, SpeculateIntegerOperand&);
1001     GPRTemporary(JITCodeGenerator*, IntegerOperand&);
1002     GPRTemporary(JITCodeGenerator*, IntegerOperand&, IntegerOperand&);
1003     GPRTemporary(JITCodeGenerator*, SpeculateCellOperand&);
1004     GPRTemporary(JITCodeGenerator*, JSValueOperand&);
1005
1006     ~GPRTemporary()
1007     {
1008         m_jit->unlock(gpr());
1009     }
1010
1011     GPRReg gpr()
1012     {
1013         ASSERT(m_gpr != InvalidGPRReg);
1014         return m_gpr;
1015     }
1016
1017 protected:
1018     GPRTemporary(JITCodeGenerator* jit, GPRReg lockedGPR)
1019         : m_jit(jit)
1020         , m_gpr(lockedGPR)
1021     {
1022     }
1023
1024 private:
1025     JITCodeGenerator* m_jit;
1026     GPRReg m_gpr;
1027 };
1028
1029 class FPRTemporary {
1030 public:
1031     FPRTemporary(JITCodeGenerator*);
1032     FPRTemporary(JITCodeGenerator*, DoubleOperand&);
1033     FPRTemporary(JITCodeGenerator*, DoubleOperand&, DoubleOperand&);
1034
1035     ~FPRTemporary()
1036     {
1037         m_jit->unlock(fpr());
1038     }
1039
1040     FPRReg fpr() const
1041     {
1042         ASSERT(m_fpr != InvalidFPRReg);
1043         return m_fpr;
1044     }
1045
1046 protected:
1047     FPRTemporary(JITCodeGenerator* jit, FPRReg lockedFPR)
1048         : m_jit(jit)
1049         , m_fpr(lockedFPR)
1050     {
1051     }
1052
1053 private:
1054     JITCodeGenerator* m_jit;
1055     FPRReg m_fpr;
1056 };
1057
1058
1059 // === Results ===
1060 //
1061 // These classes lock the result of a call to a C++ helper function.
1062
1063 class GPRResult : public GPRTemporary {
1064 public:
1065     GPRResult(JITCodeGenerator* jit)
1066         : GPRTemporary(jit, lockedResult(jit))
1067     {
1068     }
1069
1070 private:
1071     static GPRReg lockedResult(JITCodeGenerator* jit)
1072     {
1073         jit->lock(GPRInfo::returnValueGPR);
1074         return GPRInfo::returnValueGPR;
1075     }
1076 };
1077
1078 class FPRResult : public FPRTemporary {
1079 public:
1080     FPRResult(JITCodeGenerator* jit)
1081         : FPRTemporary(jit, lockedResult(jit))
1082     {
1083     }
1084
1085 private:
1086     static FPRReg lockedResult(JITCodeGenerator* jit)
1087     {
1088         jit->lock(FPRInfo::returnValueFPR);
1089         return FPRInfo::returnValueFPR;
1090     }
1091 };
1092
1093 } } // namespace JSC::DFG
1094
1095 #endif
1096 #endif
1097