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