Bug 58198 - Clean up JSValue implementation for JSVALUE64
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGSpeculativeJIT.cpp
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 #include "config.h"
27 #include "DFGSpeculativeJIT.h"
28
29 #if ENABLE(DFG_JIT)
30
31 namespace JSC { namespace DFG {
32
33 template<bool strict>
34 GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat& returnFormat)
35 {
36     Node& node = m_jit.graph()[nodeIndex];
37     VirtualRegister virtualRegister = node.virtualRegister;
38     GenerationInfo& info = m_generationInfo[virtualRegister];
39
40     switch (info.registerFormat()) {
41     case DataFormatNone: {
42         GPRReg gpr = allocate();
43         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
44
45         if (node.isConstant()) {
46             m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
47             if (isInt32Constant(nodeIndex)) {
48                 m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), reg);
49                 info.fillInteger(gpr);
50                 returnFormat = DataFormatInteger;
51                 return gpr;
52             }
53             m_jit.move(constantAsJSValueAsImmPtr(nodeIndex), reg);
54         } else if (node.isArgument()) {
55             m_gprs.retain(gpr, virtualRegister, SpillOrderArgument);
56             m_jit.loadPtr(m_jit.addressForArgument(m_jit.graph()[nodeIndex].argumentNumber()), reg);
57         } else {
58             DataFormat spillFormat = info.spillFormat();
59             ASSERT(spillFormat & DataFormatJS);
60
61             m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
62
63             if (spillFormat == DataFormatJSInteger) {
64                 // If we know this was spilled as an integer we can fill without checking.
65                 if (strict) {
66                     m_jit.load32(JITCompiler::addressFor(virtualRegister), reg);
67                     info.fillInteger(gpr);
68                     returnFormat = DataFormatInteger;
69                     return gpr;
70                 }
71                 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg);
72                 info.fillJSValue(gpr, DataFormatJSInteger);
73                 returnFormat = DataFormatJSInteger;
74                 return gpr;
75             }
76             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg);
77         }
78
79         // Fill as JSValue, and fall through.
80         info.fillJSValue(gpr, DataFormatJSInteger);
81         m_gprs.unlock(gpr);
82     }
83
84     case DataFormatJS: {
85         // Check the value is an integer.
86         GPRReg gpr = info.gpr();
87         m_gprs.lock(gpr);
88         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
89         speculationCheck(m_jit.branchPtr(MacroAssembler::Below, reg, JITCompiler::tagTypeNumberRegister));
90         info.fillJSValue(gpr, DataFormatJSInteger);
91         // If !strict we're done, return.
92         if (!strict) {
93             returnFormat = DataFormatJSInteger;
94             return gpr;
95         }
96         // else fall through & handle as DataFormatJSInteger.
97         m_gprs.unlock(gpr);
98     }
99
100     case DataFormatJSInteger: {
101         // In a strict fill we need to strip off the value tag.
102         if (strict) {
103             GPRReg gpr = info.gpr();
104             GPRReg result;
105             // If the register has already been locked we need to take a copy.
106             // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInteger, not DataFormatJSInteger.
107             if (m_gprs.isLocked(gpr))
108                 result = allocate();
109             else {
110                 m_gprs.lock(gpr);
111                 info.fillInteger(gpr);
112                 result = gpr;
113             }
114             m_jit.zeroExtend32ToPtr(JITCompiler::gprToRegisterID(gpr), JITCompiler::gprToRegisterID(result));
115             returnFormat = DataFormatInteger;
116             return result;
117         }
118
119         GPRReg gpr = info.gpr();
120         m_gprs.lock(gpr);
121         returnFormat = DataFormatJSInteger;
122         return gpr;
123     }
124
125     case DataFormatInteger: {
126         GPRReg gpr = info.gpr();
127         m_gprs.lock(gpr);
128         returnFormat = DataFormatInteger;
129         return gpr;
130     }
131
132     case DataFormatDouble:
133     case DataFormatCell:
134     case DataFormatJSDouble:
135     case DataFormatJSCell: {
136         terminateSpeculativeExecution();
137         returnFormat = DataFormatInteger;
138         return allocate();
139     }
140     }
141
142     ASSERT_NOT_REACHED();
143     return InvalidGPRReg;
144 }
145
146 SpeculationCheck::SpeculationCheck(MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned recoveryIndex)
147     : m_check(check)
148     , m_nodeIndex(jit->m_compileIndex)
149     , m_recoveryIndex(recoveryIndex)
150 {
151     for (GPRReg gpr = gpr0; gpr < numberOfGPRs; next(gpr)) {
152         VirtualRegister virtualRegister = jit->m_gprs.name(gpr);
153         if (virtualRegister != InvalidVirtualRegister) {
154             GenerationInfo& info =  jit->m_generationInfo[virtualRegister];
155             m_gprInfo[gpr].nodeIndex = info.nodeIndex();
156             m_gprInfo[gpr].format = info.registerFormat();
157         } else
158             m_gprInfo[gpr].nodeIndex = NoNode;
159     }
160     for (FPRReg fpr = fpr0; fpr < numberOfFPRs; next(fpr)) {
161         VirtualRegister virtualRegister = jit->m_fprs.name(fpr);
162         if (virtualRegister != InvalidVirtualRegister) {
163             GenerationInfo& info =  jit->m_generationInfo[virtualRegister];
164             ASSERT(info.registerFormat() == DataFormatDouble);
165             m_fprInfo[fpr] = info.nodeIndex();
166         } else
167             m_fprInfo[fpr] = NoNode;
168     }
169 }
170
171 GPRReg SpeculativeJIT::fillSpeculateInt(NodeIndex nodeIndex, DataFormat& returnFormat)
172 {
173     return fillSpeculateIntInternal<false>(nodeIndex, returnFormat);
174 }
175
176 GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex)
177 {
178     DataFormat mustBeDataFormatInteger;
179     GPRReg result = fillSpeculateIntInternal<true>(nodeIndex, mustBeDataFormatInteger);
180     ASSERT(mustBeDataFormatInteger == DataFormatInteger);
181     return result;
182 }
183
184 GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
185 {
186     Node& node = m_jit.graph()[nodeIndex];
187     VirtualRegister virtualRegister = node.virtualRegister;
188     GenerationInfo& info = m_generationInfo[virtualRegister];
189
190     switch (info.registerFormat()) {
191     case DataFormatNone: {
192         GPRReg gpr = allocate();
193         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
194
195         if (node.isConstant()) {
196             m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
197             JSValue jsValue = constantAsJSValue(nodeIndex);
198             if (jsValue.isCell()) {
199                 m_jit.move(MacroAssembler::TrustedImmPtr(jsValue.asCell()), reg);
200                 info.fillJSValue(gpr, DataFormatJSCell);
201                 return gpr;
202             }
203             terminateSpeculativeExecution();
204             return gpr;
205         }
206         if (node.isArgument()) {
207             m_gprs.retain(gpr, virtualRegister, SpillOrderArgument);
208             m_jit.loadPtr(m_jit.addressForArgument(m_jit.graph()[nodeIndex].argumentNumber()), reg);
209             speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, reg, JITCompiler::tagMaskRegister));
210             info.fillJSValue(gpr, DataFormatJSCell);
211             return gpr;
212         }
213         ASSERT(info.spillFormat() & DataFormatJS);
214         m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
215         m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg);
216
217         if (info.spillFormat() != DataFormatJSCell)
218             speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, reg, JITCompiler::tagMaskRegister));
219         info.fillJSValue(gpr, DataFormatJSCell);
220         return gpr;
221     }
222
223     case DataFormatCell:
224     case DataFormatJSCell: {
225         GPRReg gpr = info.gpr();
226         m_gprs.lock(gpr);
227         return gpr;
228     }
229
230     case DataFormatJS: {
231         GPRReg gpr = info.gpr();
232         m_gprs.lock(gpr);
233         JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr);
234         speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, reg, JITCompiler::tagMaskRegister));
235         info.fillJSValue(gpr, DataFormatJSCell);
236         return gpr;
237     }
238
239     case DataFormatJSInteger:
240     case DataFormatInteger:
241     case DataFormatJSDouble:
242     case DataFormatDouble: {
243         terminateSpeculativeExecution();
244         return allocate();
245     }
246     }
247
248     ASSERT_NOT_REACHED();
249     return InvalidGPRReg;
250 }
251
252 bool SpeculativeJIT::compile(Node& node)
253 {
254     checkConsistency();
255
256     NodeType op = node.op;
257
258     switch (op) {
259     case Int32Constant:
260     case DoubleConstant:
261     case JSConstant:
262         initConstantInfo(m_compileIndex);
263         break;
264     
265     case Argument:
266         initArgumentInfo(m_compileIndex);
267         break;
268
269     case BitAnd:
270     case BitOr:
271     case BitXor:
272         if (isInt32Constant(node.child1)) {
273             SpeculateIntegerOperand op2(this, node.child2);
274             GPRTemporary result(this, op2);
275
276             bitOp(op, valueOfInt32Constant(node.child1), op2.registerID(), result.registerID());
277
278             integerResult(result.gpr(), m_compileIndex);
279         } else if (isInt32Constant(node.child2)) {
280             SpeculateIntegerOperand op1(this, node.child1);
281             GPRTemporary result(this, op1);
282
283             bitOp(op, valueOfInt32Constant(node.child2), op1.registerID(), result.registerID());
284
285             integerResult(result.gpr(), m_compileIndex);
286         } else {
287             SpeculateIntegerOperand op1(this, node.child1);
288             SpeculateIntegerOperand op2(this, node.child2);
289             GPRTemporary result(this, op1, op2);
290
291             MacroAssembler::RegisterID reg1 = op1.registerID();
292             MacroAssembler::RegisterID reg2 = op2.registerID();
293             bitOp(op, reg1, reg2, result.registerID());
294
295             integerResult(result.gpr(), m_compileIndex);
296         }
297         break;
298
299     case BitRShift:
300     case BitLShift:
301     case BitURShift:
302         if (isInt32Constant(node.child2)) {
303             SpeculateIntegerOperand op1(this, node.child1);
304             GPRTemporary result(this, op1);
305
306             shiftOp(op, op1.registerID(), valueOfInt32Constant(node.child2) & 0x1f, result.registerID());
307
308             integerResult(result.gpr(), m_compileIndex);
309         } else {
310             // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
311             SpeculateIntegerOperand op1(this, node.child1);
312             SpeculateIntegerOperand op2(this, node.child2);
313             GPRTemporary result(this, op1);
314
315             MacroAssembler::RegisterID reg1 = op1.registerID();
316             MacroAssembler::RegisterID reg2 = op2.registerID();
317             shiftOp(op, reg1, reg2, result.registerID());
318
319             integerResult(result.gpr(), m_compileIndex);
320         }
321         break;
322
323     case UInt32ToNumber: {
324         IntegerOperand op1(this, node.child1);
325         GPRTemporary result(this, op1);
326
327         // Test the operand is positive.
328         speculationCheck(m_jit.branch32(MacroAssembler::LessThan, op1.registerID(), TrustedImm32(0)));
329
330         m_jit.move(op1.registerID(), result.registerID());
331         integerResult(result.gpr(), m_compileIndex, op1.format());
332         break;
333     }
334
335     case NumberToInt32: {
336         SpeculateIntegerOperand op1(this, node.child1);
337         GPRTemporary result(this, op1);
338         m_jit.move(op1.registerID(), result.registerID());
339         integerResult(result.gpr(), m_compileIndex, op1.format());
340         break;
341     }
342
343     case Int32ToNumber: {
344         SpeculateIntegerOperand op1(this, node.child1);
345         GPRTemporary result(this, op1);
346         m_jit.move(op1.registerID(), result.registerID());
347         integerResult(result.gpr(), m_compileIndex, op1.format());
348         break;
349     }
350     case ValueToInt32: {
351         SpeculateIntegerOperand op1(this, node.child1);
352         GPRTemporary result(this, op1);
353         m_jit.move(op1.registerID(), result.registerID());
354         integerResult(result.gpr(), m_compileIndex, op1.format());
355         break;
356     }
357
358     case ValueToNumber: {
359         SpeculateIntegerOperand op1(this, node.child1);
360         GPRTemporary result(this, op1);
361         m_jit.move(op1.registerID(), result.registerID());
362         integerResult(result.gpr(), m_compileIndex, op1.format());
363         break;
364     }
365
366     case ValueAdd:
367     case ArithAdd: {
368         SpeculateIntegerOperand op1(this, node.child1);
369         SpeculateIntegerOperand op2(this, node.child2);
370         GPRTemporary result(this, op1, op2);
371
372         GPRReg gpr1 = op1.gpr();
373         GPRReg gpr2 = op2.gpr();
374         GPRReg gprResult = result.gpr();
375         MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, JITCompiler::gprToRegisterID(gpr1), JITCompiler::gprToRegisterID(gpr2), JITCompiler::gprToRegisterID(gprResult));
376
377         if (gpr1 == gprResult)
378             speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
379         else if (gpr2 == gprResult)
380             speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
381         else
382             speculationCheck(check);
383
384         integerResult(gprResult, m_compileIndex);
385         break;
386     }
387
388     case ArithSub: {
389         SpeculateIntegerOperand op1(this, node.child1);
390         SpeculateIntegerOperand op2(this, node.child2);
391         GPRTemporary result(this);
392
393         MacroAssembler::RegisterID reg1 = op1.registerID();
394         MacroAssembler::RegisterID reg2 = op2.registerID();
395         speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, reg1, reg2, result.registerID()));
396
397         integerResult(result.gpr(), m_compileIndex);
398         break;
399     }
400
401     case ArithMul: {
402         SpeculateIntegerOperand op1(this, node.child1);
403         SpeculateIntegerOperand op2(this, node.child2);
404         GPRTemporary result(this);
405
406         MacroAssembler::RegisterID reg1 = op1.registerID();
407         MacroAssembler::RegisterID reg2 = op2.registerID();
408         speculationCheck(m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.registerID()));
409         speculationCheck(m_jit.branchTest32(MacroAssembler::Zero, result.registerID()));
410
411         integerResult(result.gpr(), m_compileIndex);
412         break;
413     }
414
415     case ArithDiv: {
416         SpeculateIntegerOperand op1(this, node.child1);
417         SpeculateIntegerOperand op2(this, node.child2);
418         GPRTemporary result(this, op1, op2);
419
420         terminateSpeculativeExecution();
421
422         integerResult(result.gpr(), m_compileIndex);
423         break;
424     }
425
426     case ArithMod: {
427         SpeculateIntegerOperand op1(this, node.child1);
428         SpeculateIntegerOperand op2(this, node.child2);
429         GPRTemporary result(this, op1, op2);
430
431         terminateSpeculativeExecution();
432
433         integerResult(result.gpr(), m_compileIndex);
434         break;
435     }
436
437     case LogicalNot: {
438         JSValueOperand value(this, node.child1);
439         GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
440
441         m_jit.move(value.registerID(), result.registerID());
442         m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(FullTagTypeFalse)), result.registerID());
443         speculationCheck(m_jit.branchTestPtr(JITCompiler::NonZero, result.registerID(), TrustedImm32(static_cast<int32_t>(~1))));
444         m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(FullTagTypeTrue)), result.registerID());
445
446         // If we add a DataFormatBool, we should use it here.
447         jsValueResult(result.gpr(), m_compileIndex);
448         break;
449     }
450
451     case CompareLess: {
452         SpeculateIntegerOperand op1(this, node.child1);
453         SpeculateIntegerOperand op2(this, node.child2);
454         GPRTemporary result(this, op1, op2);
455
456         m_jit.set32Compare32(JITCompiler::LessThan, op1.registerID(), op2.registerID(), result.registerID());
457
458         // If we add a DataFormatBool, we should use it here.
459         m_jit.or32(TrustedImm32(FullTagTypeFalse), result.registerID());
460         jsValueResult(result.gpr(), m_compileIndex);
461         break;
462     }
463
464     case CompareLessEq: {
465         SpeculateIntegerOperand op1(this, node.child1);
466         SpeculateIntegerOperand op2(this, node.child2);
467         GPRTemporary result(this, op1, op2);
468
469         m_jit.set32Compare32(JITCompiler::LessThanOrEqual, op1.registerID(), op2.registerID(), result.registerID());
470
471         // If we add a DataFormatBool, we should use it here.
472         m_jit.or32(TrustedImm32(FullTagTypeFalse), result.registerID());
473         jsValueResult(result.gpr(), m_compileIndex);
474         break;
475     }
476
477     case CompareEq: {
478         SpeculateIntegerOperand op1(this, node.child1);
479         SpeculateIntegerOperand op2(this, node.child2);
480         GPRTemporary result(this, op1, op2);
481
482         m_jit.set32Compare32(JITCompiler::Equal, op1.registerID(), op2.registerID(), result.registerID());
483
484         // If we add a DataFormatBool, we should use it here.
485         m_jit.or32(TrustedImm32(FullTagTypeFalse), result.registerID());
486         jsValueResult(result.gpr(), m_compileIndex);
487         break;
488     }
489
490     case CompareStrictEq: {
491         SpeculateIntegerOperand op1(this, node.child1);
492         SpeculateIntegerOperand op2(this, node.child2);
493         GPRTemporary result(this, op1, op2);
494
495         m_jit.set32Compare32(JITCompiler::Equal, op1.registerID(), op2.registerID(), result.registerID());
496
497         // If we add a DataFormatBool, we should use it here.
498         m_jit.or32(TrustedImm32(FullTagTypeFalse), result.registerID());
499         jsValueResult(result.gpr(), m_compileIndex);
500         break;
501     }
502
503     case GetByVal: {
504         NodeIndex alias = node.child3;
505         if (alias != NoNode) {
506             // FIXME: result should be able to reuse child1, child2. Should have an 'UnusedOperand' type.
507             JSValueOperand aliasedValue(this, node.child3);
508             GPRTemporary result(this, aliasedValue);
509             m_jit.move(aliasedValue.registerID(), result.registerID());
510             jsValueResult(result.gpr(), m_compileIndex);
511             break;
512         }
513
514         SpeculateCellOperand base(this, node.child1);
515         SpeculateStrictInt32Operand property(this, node.child2);
516         GPRTemporary storage(this);
517
518         MacroAssembler::RegisterID baseReg = base.registerID();
519         MacroAssembler::RegisterID propertyReg = property.registerID();
520         MacroAssembler::RegisterID storageReg = storage.registerID();
521
522         // Get the array storage. We haven't yet checked this is a JSArray, so this is only safe if
523         // an access with offset JSArray::storageOffset() is valid for all JSCells!
524         m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
525
526         // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
527         speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
528         speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
529
530         // FIXME: In cases where there are subsequent by_val accesses to the same base it might help to cache
531         // the storage pointer - especially if there happens to be another register free right now. If we do so,
532         // then we'll need to allocate a new temporary for result.
533         GPRTemporary& result = storage;
534         m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.registerID());
535         speculationCheck(m_jit.branchTestPtr(MacroAssembler::Zero, result.registerID()));
536
537         jsValueResult(result.gpr(), m_compileIndex);
538         break;
539     }
540
541     case PutByVal:
542     case PutByValAlias: {
543         SpeculateStrictInt32Operand property(this, node.child2);
544         GPRTemporary storage(this);
545
546         MacroAssembler::RegisterID propertyReg;
547         MacroAssembler::RegisterID storageReg;
548
549         // This block also defines the scope for base, and all bails to the non-speculative path.
550         // At the end of this scope base will be release, and as such may be reused by for 'value'.
551         //
552         // If we've already read from this location on the speculative pass, then it cannot be beyond array bounds, or a hole.
553         if (op == PutByValAlias) {
554             SpeculateCellOperand base(this, node.child1);
555
556             // Map base & property into registers, allocate a register for storage.
557             propertyReg = property.registerID();
558             storageReg = storage.registerID();
559             MacroAssembler::RegisterID baseReg = base.registerID();
560
561             // Get the array storage.
562             m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
563         } else {
564             SpeculateCellOperand base(this, node.child1);
565
566             // Map base & property into registers, allocate a register for storage.
567             propertyReg = property.registerID();
568             storageReg = storage.registerID();
569             MacroAssembler::RegisterID baseReg = base.registerID();
570
571             // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
572             speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
573             speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
574
575             // Get the array storage.
576             m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
577
578             // Check if we're writing to a hole; if so increment m_numValuesInVector.
579             MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
580             m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)));
581
582             // If we're writing to a hole we might be growing the array; 
583             MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
584             m_jit.add32(TrustedImm32(1), propertyReg);
585             m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length)));
586             m_jit.sub32(TrustedImm32(1), propertyReg);
587
588             lengthDoesNotNeedUpdate.link(&m_jit);
589             notHoleValue.link(&m_jit);
590         }
591         // After this point base goes out of scope. This may free the register.
592         // As such, after this point we'd better not have any bails out to the non-speculative path!
593
594         // Store the value to the array.
595         JSValueOperand value(this, node.child3);
596         MacroAssembler::RegisterID valueReg = value.registerID();
597         m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
598
599         noResult(m_compileIndex);
600         break;
601     }
602
603     case Return: {
604         ASSERT(JITCompiler::callFrameRegister != JITCompiler::regT1);
605         ASSERT(JITCompiler::regT1 != JITCompiler::returnValueRegister);
606         ASSERT(JITCompiler::returnValueRegister != JITCompiler::callFrameRegister);
607
608         // Return the result in returnValueRegister.
609         JSValueOperand op1(this, node.child1);
610         m_jit.move(op1.registerID(), JITCompiler::returnValueRegister);
611
612         // Grab the return address.
613         m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, JITCompiler::regT1);
614         // Restore our caller's "r".
615         m_jit.emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, JITCompiler::callFrameRegister);
616         // Return.
617         m_jit.restoreReturnAddressBeforeReturn(JITCompiler::regT1);
618         m_jit.ret();
619         
620         noResult(m_compileIndex);
621         break;
622     }
623
624     case ConvertThis: {
625         SpeculateCellOperand thisValue(this, node.child1);
626         GPRTemporary temp(this);
627
628         m_jit.loadPtr(JITCompiler::Address(thisValue.registerID(), JSCell::structureOffset()), temp.registerID());
629         speculationCheck(m_jit.branchTest8(JITCompiler::NonZero, JITCompiler::Address(temp.registerID(), Structure::typeInfoFlagsOffset()), JITCompiler::TrustedImm32(NeedsThisConversion)));
630
631         cellResult(thisValue.gpr(), m_compileIndex);
632         break;
633     }
634
635     case GetById: {
636         JSValueOperand base(this, node.child1);
637         GPRReg baseGPR = base.gpr();
638         flushRegisters();
639
640         GPRResult result(this);
641         callOperation(operationGetById, result.gpr(), baseGPR, identifier(node.identifierNumber()));
642         jsValueResult(result.gpr(), m_compileIndex);
643         break;
644     }
645
646     case PutById: {
647         JSValueOperand base(this, node.child1);
648         JSValueOperand value(this, node.child2);
649         GPRReg valueGPR = value.gpr();
650         GPRReg baseGPR = base.gpr();
651         flushRegisters();
652
653         callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdStrict : operationPutByIdNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
654         noResult(m_compileIndex);
655         break;
656     }
657
658     case PutByIdDirect: {
659         JSValueOperand base(this, node.child1);
660         JSValueOperand value(this, node.child2);
661         GPRReg valueGPR = value.gpr();
662         GPRReg baseGPR = base.gpr();
663         flushRegisters();
664
665         callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByIdDirectStrict : operationPutByIdDirectNonStrict, valueGPR, baseGPR, identifier(node.identifierNumber()));
666         noResult(m_compileIndex);
667         break;
668     }
669
670     case GetGlobalVar: {
671         GPRTemporary result(this);
672
673         JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
674         m_jit.loadPtr(globalObject->addressOfRegisters(), result.registerID());
675         m_jit.loadPtr(JITCompiler::addressForGlobalVar(result.registerID(), node.varNumber()), result.registerID());
676
677         jsValueResult(result.gpr(), m_compileIndex);
678         break;
679     }
680
681     case PutGlobalVar: {
682         JSValueOperand value(this, node.child1);
683         GPRTemporary temp(this);
684
685         JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
686         m_jit.loadPtr(globalObject->addressOfRegisters(), temp.registerID());
687         m_jit.storePtr(value.registerID(), JITCompiler::addressForGlobalVar(temp.registerID(), node.varNumber()));
688
689         noResult(m_compileIndex);
690         break;
691     }
692     }
693
694     // Check if generation for the speculative path has failed catastrophically. :-)
695     // In the future, we may want to throw away the code we've generated in this case.
696     // For now, there is no point generating any further code, return immediately.
697     if (m_didTerminate)
698         return false;
699
700     if (node.mustGenerate())
701         use(m_compileIndex);
702
703     checkConsistency();
704
705     return true;
706 }
707
708 bool SpeculativeJIT::compile()
709 {
710     ASSERT(!m_compileIndex);
711     Node* nodes = m_jit.graph().begin();
712
713     for (; m_compileIndex < m_jit.graph().size(); ++m_compileIndex) {
714 #if DFG_DEBUG_VERBOSE
715         fprintf(stderr, "index(%d)\n", (int)m_compileIndex);
716 #endif
717
718         Node& node = nodes[m_compileIndex];
719         if (!node.refCount)
720             continue;
721         if (!compile(node))
722             return false;
723     }
724     return true;
725 }
726
727 } } // namespace JSC::DFG
728
729 #endif