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