7107913c84b0f41083b732c362641c31eace7446
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGSpeculativeJIT.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 DFGSpeculativeJIT_h
27 #define DFGSpeculativeJIT_h
28
29 #if ENABLE(DFG_JIT)
30
31 #include <dfg/DFGAbstractState.h>
32 #include <dfg/DFGJITCodeGenerator.h>
33
34 namespace JSC { namespace DFG {
35
36 class SpeculativeJIT;
37
38 // This enum describes the types of additional recovery that
39 // may need be performed should a speculation check fail.
40 enum SpeculationRecoveryType {
41     SpeculativeAdd,
42     BooleanSpeculationCheck
43 };
44
45 // === SpeculationRecovery ===
46 //
47 // This class provides additional information that may be associated with a
48 // speculation check - for example 
49 class SpeculationRecovery {
50 public:
51     SpeculationRecovery(SpeculationRecoveryType type, GPRReg dest, GPRReg src)
52         : m_type(type)
53         , m_dest(dest)
54         , m_src(src)
55     {
56     }
57
58     SpeculationRecoveryType type() { return m_type; }
59     GPRReg dest() { return m_dest; }
60     GPRReg src() { return m_src; }
61
62 private:
63     // Indicates the type of additional recovery to be performed.
64     SpeculationRecoveryType m_type;
65     // different recovery types may required different additional information here.
66     GPRReg m_dest;
67     GPRReg m_src;
68 };
69
70 enum ValueSourceKind {
71     SourceNotSet,
72     ValueInRegisterFile,
73     Int32InRegisterFile,
74     CellInRegisterFile,
75     BooleanInRegisterFile,
76     HaveNode
77 };
78
79 class ValueSource {
80 public:
81     ValueSource()
82         : m_nodeIndex(nodeIndexFromKind(SourceNotSet))
83     {
84     }
85     
86     explicit ValueSource(ValueSourceKind valueSourceKind)
87         : m_nodeIndex(nodeIndexFromKind(valueSourceKind))
88     {
89         ASSERT(kind() != SourceNotSet);
90         ASSERT(kind() != HaveNode);
91     }
92     
93     explicit ValueSource(NodeIndex nodeIndex)
94         : m_nodeIndex(nodeIndex)
95     {
96         ASSERT(kind() == HaveNode);
97     }
98     
99     static ValueSource forPrediction(PredictedType prediction)
100     {
101         if (isInt32Prediction(prediction))
102             return ValueSource(Int32InRegisterFile);
103         if (isArrayPrediction(prediction) || isByteArrayPrediction(prediction))
104             return ValueSource(CellInRegisterFile);
105         if (isBooleanPrediction(prediction))
106             return ValueSource(BooleanInRegisterFile);
107         return ValueSource(ValueInRegisterFile);
108     }
109     
110     bool isSet() const
111     {
112         return kindFromNodeIndex(m_nodeIndex) != SourceNotSet;
113     }
114     
115     ValueSourceKind kind() const
116     {
117         return kindFromNodeIndex(m_nodeIndex);
118     }
119     
120     NodeIndex nodeIndex() const
121     {
122         ASSERT(kind() == HaveNode);
123         return m_nodeIndex;
124     }
125     
126 #ifndef NDEBUG
127     void dump(FILE* out) const;
128 #endif
129     
130 private:
131     static NodeIndex nodeIndexFromKind(ValueSourceKind kind)
132     {
133         ASSERT(kind >= SourceNotSet && kind < HaveNode);
134         return NoNode - kind;
135     }
136     
137     static ValueSourceKind kindFromNodeIndex(NodeIndex nodeIndex)
138     {
139         unsigned kind = static_cast<unsigned>(NoNode - nodeIndex);
140         if (kind >= static_cast<unsigned>(HaveNode))
141             return HaveNode;
142         return static_cast<ValueSourceKind>(kind);
143     }
144     
145     NodeIndex m_nodeIndex;
146 };
147     
148 // Describes how to recover a given bytecode virtual register at a given
149 // code point.
150 enum ValueRecoveryTechnique {
151     // It's already in the register file at the right location.
152     AlreadyInRegisterFile,
153     // It's already in the register file but unboxed.
154     AlreadyInRegisterFileAsUnboxedInt32,
155     AlreadyInRegisterFileAsUnboxedCell,
156     AlreadyInRegisterFileAsUnboxedBoolean,
157     // It's in a register.
158     InGPR,
159     UnboxedInt32InGPR,
160     UnboxedBooleanInGPR,
161 #if USE(JSVALUE32_64)
162     InPair,
163 #endif
164     InFPR,
165     // It's in the register file, but at a different location.
166     DisplacedInRegisterFile,
167     // It's in the register file, at a different location, and it's unboxed.
168     Int32DisplacedInRegisterFile,
169     DoubleDisplacedInRegisterFile,
170     // It's a constant.
171     Constant,
172     // Don't know how to recover it.
173     DontKnow
174 };
175
176 class ValueRecovery {
177 public:
178     ValueRecovery()
179         : m_technique(DontKnow)
180     {
181     }
182     
183     static ValueRecovery alreadyInRegisterFile()
184     {
185         ValueRecovery result;
186         result.m_technique = AlreadyInRegisterFile;
187         return result;
188     }
189     
190     static ValueRecovery alreadyInRegisterFileAsUnboxedInt32()
191     {
192         ValueRecovery result;
193         result.m_technique = AlreadyInRegisterFileAsUnboxedInt32;
194         return result;
195     }
196     
197     static ValueRecovery alreadyInRegisterFileAsUnboxedCell()
198     {
199         ValueRecovery result;
200         result.m_technique = AlreadyInRegisterFileAsUnboxedCell;
201         return result;
202     }
203     
204     static ValueRecovery alreadyInRegisterFileAsUnboxedBoolean()
205     {
206         ValueRecovery result;
207         result.m_technique = AlreadyInRegisterFileAsUnboxedBoolean;
208         return result;
209     }
210     
211     static ValueRecovery inGPR(GPRReg gpr, DataFormat dataFormat)
212     {
213         ASSERT(dataFormat != DataFormatNone);
214 #if USE(JSVALUE32_64)
215         ASSERT(dataFormat == DataFormatInteger || dataFormat == DataFormatCell || dataFormat == DataFormatBoolean);
216 #endif
217         ValueRecovery result;
218         if (dataFormat == DataFormatInteger)
219             result.m_technique = UnboxedInt32InGPR;
220         else if (dataFormat == DataFormatBoolean)
221             result.m_technique = UnboxedBooleanInGPR;
222         else
223             result.m_technique = InGPR;
224         result.m_source.gpr = gpr;
225         return result;
226     }
227     
228 #if USE(JSVALUE32_64)
229     static ValueRecovery inPair(GPRReg tagGPR, GPRReg payloadGPR)
230     {
231         ValueRecovery result;
232         result.m_technique = InPair;
233         result.m_source.pair.tagGPR = tagGPR;
234         result.m_source.pair.payloadGPR = payloadGPR;
235         return result;
236     }
237 #endif
238
239     static ValueRecovery inFPR(FPRReg fpr)
240     {
241         ValueRecovery result;
242         result.m_technique = InFPR;
243         result.m_source.fpr = fpr;
244         return result;
245     }
246     
247     static ValueRecovery displacedInRegisterFile(VirtualRegister virtualReg, DataFormat dataFormat)
248     {
249         ValueRecovery result;
250         switch (dataFormat) {
251         case DataFormatInteger:
252             result.m_technique = Int32DisplacedInRegisterFile;
253             break;
254             
255         case DataFormatDouble:
256             result.m_technique = DoubleDisplacedInRegisterFile;
257             break;
258
259         default:
260             ASSERT(dataFormat != DataFormatNone && dataFormat != DataFormatStorage);
261             result.m_technique = DisplacedInRegisterFile;
262             break;
263         }
264         result.m_source.virtualReg = virtualReg;
265         return result;
266     }
267     
268     static ValueRecovery constant(JSValue value)
269     {
270         ValueRecovery result;
271         result.m_technique = Constant;
272         result.m_source.constant = JSValue::encode(value);
273         return result;
274     }
275     
276     ValueRecoveryTechnique technique() const { return m_technique; }
277     
278     GPRReg gpr() const
279     {
280         ASSERT(m_technique == InGPR || m_technique == UnboxedInt32InGPR || m_technique == UnboxedBooleanInGPR);
281         return m_source.gpr;
282     }
283     
284 #if USE(JSVALUE32_64)
285     GPRReg tagGPR() const
286     {
287         ASSERT(m_technique == InPair);
288         return m_source.pair.tagGPR;
289     }
290     
291     GPRReg payloadGPR() const
292     {
293         ASSERT(m_technique == InPair);
294         return m_source.pair.payloadGPR;
295     }
296 #endif
297     
298     FPRReg fpr() const
299     {
300         ASSERT(m_technique == InFPR);
301         return m_source.fpr;
302     }
303     
304     VirtualRegister virtualRegister() const
305     {
306         ASSERT(m_technique == DisplacedInRegisterFile || m_technique == Int32DisplacedInRegisterFile || m_technique == DoubleDisplacedInRegisterFile);
307         return m_source.virtualReg;
308     }
309     
310     JSValue constant() const
311     {
312         ASSERT(m_technique == Constant);
313         return JSValue::decode(m_source.constant);
314     }
315     
316 #ifndef NDEBUG
317     void dump(FILE* out) const;
318 #endif
319     
320 private:
321     ValueRecoveryTechnique m_technique;
322     union {
323         GPRReg gpr;
324         FPRReg fpr;
325 #if USE(JSVALUE32_64)
326         struct {
327             GPRReg tagGPR;
328             GPRReg payloadGPR;
329         } pair;
330 #endif
331         VirtualRegister virtualReg;
332         EncodedJSValue constant;
333     } m_source;
334 };
335
336 // === OSRExit ===
337 //
338 // This structure describes how to exit the speculative path by
339 // going into baseline code.
340 struct OSRExit {
341     OSRExit(JSValueSource, ValueProfile*, MacroAssembler::Jump, SpeculativeJIT*, unsigned recoveryIndex = 0);
342     
343     JSValueSource m_jsValueSource;
344     ValueProfile* m_valueProfile;
345     
346     MacroAssembler::Jump m_check;
347     NodeIndex m_nodeIndex;
348     CodeOrigin m_codeOrigin;
349     
350     unsigned m_recoveryIndex;
351     
352     // Convenient way of iterating over ValueRecoveries while being
353     // generic over argument versus variable.
354     int numberOfRecoveries() const { return m_arguments.size() + m_variables.size(); }
355     const ValueRecovery& valueRecovery(int index) const
356     {
357         if (index < (int)m_arguments.size())
358             return m_arguments[index];
359         return m_variables[index - m_arguments.size()];
360     }
361     bool isArgument(int index) const { return index < (int)m_arguments.size(); }
362     bool isVariable(int index) const { return !isArgument(index); }
363     int argumentForIndex(int index) const
364     {
365         return index;
366     }
367     int variableForIndex(int index) const
368     {
369         return index - m_arguments.size();
370     }
371     int operandForArgument(int argument) const
372     {
373         return argument - m_arguments.size() - RegisterFile::CallFrameHeaderSize;
374     }
375     int operandForIndex(int index) const
376     {
377         if (index < (int)m_arguments.size())
378             return operandForArgument(index);
379         return index - m_arguments.size();
380     }
381     
382 #ifndef NDEBUG
383     void dump(FILE* out) const;
384 #endif
385     
386     Vector<ValueRecovery, 0> m_arguments;
387     Vector<ValueRecovery, 0> m_variables;
388     int m_lastSetOperand;
389 };
390 typedef SegmentedVector<OSRExit, 16> OSRExitVector;
391
392 // === SpeculativeJIT ===
393 //
394 // The SpeculativeJIT is used to generate a fast, but potentially
395 // incomplete code path for the dataflow. When code generating
396 // we may make assumptions about operand types, dynamically check,
397 // and bail-out to an alternate code path if these checks fail.
398 // Importantly, the speculative code path cannot be reentered once
399 // a speculative check has failed. This allows the SpeculativeJIT
400 // to propagate type information (including information that has
401 // only speculatively been asserted) through the dataflow.
402 class SpeculativeJIT : public JITCodeGenerator {
403     friend struct OSRExit;
404 public:
405     SpeculativeJIT(JITCompiler&);
406
407     bool compile();
408
409     // Retrieve the list of bail-outs from the speculative path,
410     // and additional recovery information.
411     OSRExitVector& osrExits()
412     {
413         return m_osrExits;
414     }
415     SpeculationRecovery* speculationRecovery(size_t index)
416     {
417         // OSRExit::m_recoveryIndex is offset by 1,
418         // 0 means no recovery.
419         return index ? &m_speculationRecoveryList[index - 1] : 0;
420     }
421
422     // Called by the speculative operand types, below, to fill operand to
423     // machine registers, implicitly generating speculation checks as needed.
424     GPRReg fillSpeculateInt(NodeIndex, DataFormat& returnFormat);
425     GPRReg fillSpeculateIntStrict(NodeIndex);
426     FPRReg fillSpeculateDouble(NodeIndex);
427     GPRReg fillSpeculateCell(NodeIndex);
428     GPRReg fillSpeculateBoolean(NodeIndex);
429
430 private:
431     friend class JITCodeGenerator;
432     
433     void compile(Node&);
434     void compileMovHint(Node&);
435     void compile(BasicBlock&);
436
437     void checkArgumentTypes();
438
439     bool isInteger(NodeIndex nodeIndex)
440     {
441         Node& node = at(nodeIndex);
442         if (node.hasInt32Result())
443             return true;
444
445         if (isInt32Constant(nodeIndex))
446             return true;
447
448         VirtualRegister virtualRegister = node.virtualRegister();
449         GenerationInfo& info = m_generationInfo[virtualRegister];
450         
451         return info.isJSInteger();
452     }
453     
454     bool compare(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ);
455     bool compilePeepHoleBranch(Node&, MacroAssembler::RelationalCondition, MacroAssembler::DoubleCondition, S_DFGOperation_EJJ);
456     void compilePeepHoleIntegerBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition);
457     void compilePeepHoleDoubleBranch(Node&, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition);
458     void compilePeepHoleObjectEquality(Node&, NodeIndex branchNodeIndex, void* vptr, PredictionChecker);
459     void compileObjectEquality(Node&, void* vptr, PredictionChecker);
460     void compileValueAdd(Node&);
461     void compileObjectOrOtherLogicalNot(NodeIndex value, void* vptr, bool needSpeculationCheck);
462     void compileLogicalNot(Node&);
463     void emitObjectOrOtherBranch(NodeIndex value, BlockIndex taken, BlockIndex notTaken, void *vptr, bool needSpeculationCheck);
464     void emitBranch(Node&);
465     
466     void compileGetCharCodeAt(Node&);
467     void compileGetByValOnString(Node&);
468     void compileValueToInt32(Node&);
469     void compileGetByValOnByteArray(Node&);
470     void compilePutByValForByteArray(GPRReg base, GPRReg property, Node&);
471     
472     // It is acceptable to have structure be equal to scratch, so long as you're fine
473     // with the structure GPR being clobbered.
474     template<typename T>
475     void emitAllocateJSFinalObject(T structure, GPRReg resultGPR, GPRReg scratchGPR, MacroAssembler::JumpList& slowPath)
476     {
477         MarkedSpace::SizeClass* sizeClass = &m_jit.globalData()->heap.sizeClassForObject(sizeof(JSFinalObject));
478         
479         m_jit.loadPtr(&sizeClass->firstFreeCell, resultGPR);
480         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, resultGPR));
481         
482         // The object is half-allocated: we have what we know is a fresh object, but
483         // it's still on the GC's free list.
484         
485         // Ditch the structure by placing it into the structure slot, so that we can reuse
486         // scratchGPR.
487         m_jit.storePtr(structure, MacroAssembler::Address(resultGPR, JSObject::structureOffset()));
488         
489         // Now that we have scratchGPR back, remove the object from the free list
490         m_jit.loadPtr(MacroAssembler::Address(resultGPR), scratchGPR);
491         m_jit.storePtr(scratchGPR, &sizeClass->firstFreeCell);
492         
493         // Initialize the object's vtable
494         m_jit.storePtr(MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsFinalObjectVPtr), MacroAssembler::Address(resultGPR));
495         
496         // Initialize the object's inheritorID.
497         m_jit.storePtr(MacroAssembler::TrustedImmPtr(0), MacroAssembler::Address(resultGPR, JSObject::offsetOfInheritorID()));
498         
499         // Initialize the object's property storage pointer.
500         m_jit.addPtr(MacroAssembler::TrustedImm32(sizeof(JSObject)), resultGPR, scratchGPR);
501         m_jit.storePtr(scratchGPR, MacroAssembler::Address(resultGPR, JSFinalObject::offsetOfPropertyStorage()));
502     }
503
504 #if USE(JSVALUE64) 
505     JITCompiler::Jump convertToDouble(GPRReg value, FPRReg result, GPRReg tmp);
506 #elif USE(JSVALUE32_64)
507     JITCompiler::Jump convertToDouble(JSValueOperand&, FPRReg result);
508 #endif
509
510     // Add a speculation check without additional recovery.
511     void speculationCheck(JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail)
512     {
513         if (!m_compileOkay)
514             return;
515         m_osrExits.append(OSRExit(jsValueSource, m_jit.valueProfileFor(nodeIndex), jumpToFail, this));
516     }
517     // Add a speculation check with additional recovery.
518     void speculationCheck(JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::Jump jumpToFail, const SpeculationRecovery& recovery)
519     {
520         if (!m_compileOkay)
521             return;
522         m_speculationRecoveryList.append(recovery);
523         m_osrExits.append(OSRExit(jsValueSource, m_jit.valueProfileFor(nodeIndex), jumpToFail, this, m_speculationRecoveryList.size()));
524     }
525
526     // Called when we statically determine that a speculation will fail.
527     void terminateSpeculativeExecution(JSValueRegs jsValueRegs, NodeIndex nodeIndex)
528     {
529 #if DFG_ENABLE(DEBUG_VERBOSE)
530         fprintf(stderr, "SpeculativeJIT was terminated.\n");
531 #endif
532         if (!m_compileOkay)
533             return;
534         speculationCheck(jsValueRegs, nodeIndex, m_jit.jump());
535         m_compileOkay = false;
536     }
537
538     template<bool strict>
539     GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat);
540     
541     // It is possible, during speculative generation, to reach a situation in which we
542     // can statically determine a speculation will fail (for example, when two nodes
543     // will make conflicting speculations about the same operand). In such cases this
544     // flag is cleared, indicating no further code generation should take place.
545     bool m_compileOkay;
546     // This vector tracks bail-outs from the speculative path to the old JIT.
547     OSRExitVector m_osrExits;
548     // Some bail-outs need to record additional information recording specific recovery
549     // to be performed (for example, on detected overflow from an add, we may need to
550     // reverse the addition if an operand is being overwritten).
551     Vector<SpeculationRecovery, 16> m_speculationRecoveryList;
552     
553     // Tracking for which nodes are currently holding the values of arguments and bytecode
554     // operand-indexed variables.
555     
556     ValueSource valueSourceForOperand(int operand)
557     {
558         return valueSourceReferenceForOperand(operand);
559     }
560     
561     void setNodeIndexForOperand(NodeIndex nodeIndex, int operand)
562     {
563         valueSourceReferenceForOperand(operand) = ValueSource(nodeIndex);
564     }
565     
566     // Call this with care, since it both returns a reference into an array
567     // and potentially resizes the array. So it would not be right to call this
568     // twice and then perform operands on both references, since the one from
569     // the first call may no longer be valid.
570     ValueSource& valueSourceReferenceForOperand(int operand)
571     {
572         if (operandIsArgument(operand)) {
573             int argument = operand + m_arguments.size() + RegisterFile::CallFrameHeaderSize;
574             return m_arguments[argument];
575         }
576         
577         if ((unsigned)operand >= m_variables.size())
578             m_variables.resize(operand + 1);
579         
580         return m_variables[operand];
581     }
582     
583     Vector<ValueSource, 0> m_arguments;
584     Vector<ValueSource, 0> m_variables;
585     int m_lastSetOperand;
586     CodeOrigin m_codeOriginForOSR;
587     
588     AbstractState m_state;
589     
590     ValueRecovery computeValueRecoveryFor(const ValueSource&);
591
592     ValueRecovery computeValueRecoveryFor(int operand)
593     {
594         return computeValueRecoveryFor(valueSourceForOperand(operand));
595     }
596 };
597
598
599 // === Speculative Operand types ===
600 //
601 // SpeculateIntegerOperand, SpeculateStrictInt32Operand and SpeculateCellOperand.
602 //
603 // These are used to lock the operands to a node into machine registers within the
604 // SpeculativeJIT. The classes operate like those provided by the JITCodeGenerator,
605 // however these will perform a speculative check for a more restrictive type than
606 // we can statically determine the operand to have. If the operand does not have
607 // the requested type, a bail-out to the non-speculative path will be taken.
608
609 class SpeculateIntegerOperand {
610 public:
611     explicit SpeculateIntegerOperand(SpeculativeJIT* jit, NodeIndex index)
612         : m_jit(jit)
613         , m_index(index)
614         , m_gprOrInvalid(InvalidGPRReg)
615 #ifndef NDEBUG
616         , m_format(DataFormatNone)
617 #endif
618     {
619         ASSERT(m_jit);
620         if (jit->isFilled(index))
621             gpr();
622     }
623
624     ~SpeculateIntegerOperand()
625     {
626         ASSERT(m_gprOrInvalid != InvalidGPRReg);
627         m_jit->unlock(m_gprOrInvalid);
628     }
629
630     NodeIndex index() const
631     {
632         return m_index;
633     }
634
635     DataFormat format()
636     {
637         gpr(); // m_format is set when m_gpr is locked.
638         ASSERT(m_format == DataFormatInteger || m_format == DataFormatJSInteger);
639         return m_format;
640     }
641
642     GPRReg gpr()
643     {
644         if (m_gprOrInvalid == InvalidGPRReg)
645             m_gprOrInvalid = m_jit->fillSpeculateInt(index(), m_format);
646         return m_gprOrInvalid;
647     }
648
649 private:
650     SpeculativeJIT* m_jit;
651     NodeIndex m_index;
652     GPRReg m_gprOrInvalid;
653     DataFormat m_format;
654 };
655
656 class SpeculateStrictInt32Operand {
657 public:
658     explicit SpeculateStrictInt32Operand(SpeculativeJIT* jit, NodeIndex index)
659         : m_jit(jit)
660         , m_index(index)
661         , m_gprOrInvalid(InvalidGPRReg)
662     {
663         ASSERT(m_jit);
664         if (jit->isFilled(index))
665             gpr();
666     }
667
668     ~SpeculateStrictInt32Operand()
669     {
670         ASSERT(m_gprOrInvalid != InvalidGPRReg);
671         m_jit->unlock(m_gprOrInvalid);
672     }
673
674     NodeIndex index() const
675     {
676         return m_index;
677     }
678
679     GPRReg gpr()
680     {
681         if (m_gprOrInvalid == InvalidGPRReg)
682             m_gprOrInvalid = m_jit->fillSpeculateIntStrict(index());
683         return m_gprOrInvalid;
684     }
685     
686     void use()
687     {
688         m_jit->use(m_index);
689     }
690
691 private:
692     SpeculativeJIT* m_jit;
693     NodeIndex m_index;
694     GPRReg m_gprOrInvalid;
695 };
696
697 class SpeculateDoubleOperand {
698 public:
699     explicit SpeculateDoubleOperand(SpeculativeJIT* jit, NodeIndex index)
700         : m_jit(jit)
701         , m_index(index)
702         , m_fprOrInvalid(InvalidFPRReg)
703     {
704         ASSERT(m_jit);
705         if (jit->isFilled(index))
706             fpr();
707     }
708
709     ~SpeculateDoubleOperand()
710     {
711         ASSERT(m_fprOrInvalid != InvalidFPRReg);
712         m_jit->unlock(m_fprOrInvalid);
713     }
714
715     NodeIndex index() const
716     {
717         return m_index;
718     }
719
720     FPRReg fpr()
721     {
722         if (m_fprOrInvalid == InvalidFPRReg)
723             m_fprOrInvalid = m_jit->fillSpeculateDouble(index());
724         return m_fprOrInvalid;
725     }
726
727 private:
728     SpeculativeJIT* m_jit;
729     NodeIndex m_index;
730     FPRReg m_fprOrInvalid;
731 };
732
733 class SpeculateCellOperand {
734 public:
735     explicit SpeculateCellOperand(SpeculativeJIT* jit, NodeIndex index)
736         : m_jit(jit)
737         , m_index(index)
738         , m_gprOrInvalid(InvalidGPRReg)
739     {
740         ASSERT(m_jit);
741         if (jit->isFilled(index))
742             gpr();
743     }
744
745     ~SpeculateCellOperand()
746     {
747         ASSERT(m_gprOrInvalid != InvalidGPRReg);
748         m_jit->unlock(m_gprOrInvalid);
749     }
750
751     NodeIndex index() const
752     {
753         return m_index;
754     }
755
756     GPRReg gpr()
757     {
758         if (m_gprOrInvalid == InvalidGPRReg)
759             m_gprOrInvalid = m_jit->fillSpeculateCell(index());
760         return m_gprOrInvalid;
761     }
762     
763     void use()
764     {
765         m_jit->use(m_index);
766     }
767
768 private:
769     SpeculativeJIT* m_jit;
770     NodeIndex m_index;
771     GPRReg m_gprOrInvalid;
772 };
773
774 class SpeculateBooleanOperand {
775 public:
776     explicit SpeculateBooleanOperand(SpeculativeJIT* jit, NodeIndex index)
777         : m_jit(jit)
778         , m_index(index)
779         , m_gprOrInvalid(InvalidGPRReg)
780     {
781         ASSERT(m_jit);
782         if (jit->isFilled(index))
783             gpr();
784     }
785     
786     ~SpeculateBooleanOperand()
787     {
788         ASSERT(m_gprOrInvalid != InvalidGPRReg);
789         m_jit->unlock(m_gprOrInvalid);
790     }
791     
792     NodeIndex index() const
793     {
794         return m_index;
795     }
796     
797     GPRReg gpr()
798     {
799         if (m_gprOrInvalid == InvalidGPRReg)
800             m_gprOrInvalid = m_jit->fillSpeculateBoolean(index());
801         return m_gprOrInvalid;
802     }
803     
804     void use()
805     {
806         m_jit->use(m_index);
807     }
808
809 private:
810     SpeculativeJIT* m_jit;
811     NodeIndex m_index;
812     GPRReg m_gprOrInvalid;
813 };
814
815 inline SpeculativeJIT::SpeculativeJIT(JITCompiler& jit)
816     : JITCodeGenerator(jit)
817     , m_compileOkay(true)
818     , m_arguments(jit.codeBlock()->m_numParameters)
819     , m_variables(jit.graph().m_localVars)
820     , m_lastSetOperand(std::numeric_limits<int>::max())
821     , m_state(m_jit.codeBlock(), m_jit.graph())
822 {
823 }
824
825 } } // namespace JSC::DFG
826
827 #endif
828 #endif
829