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