]> git.saurik.com Git - apple/javascriptcore.git/blame - dfg/DFGSpeculativeJIT.cpp
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGSpeculativeJIT.cpp
CommitLineData
14957cd0
A
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
6fe7ccc8
A
31#include "LinkBuffer.h"
32
14957cd0
A
33namespace JSC { namespace DFG {
34
6fe7ccc8
A
35// On Windows we need to wrap fmod; on other platforms we can call it directly.
36// On ARMv7 we assert that all function pointers have to low bit set (point to thumb code).
37#if CALLING_CONVENTION_IS_STDCALL || CPU(ARM_THUMB2)
38static double DFG_OPERATION fmodAsDFGOperation(double x, double y)
39{
40 return fmod(x, y);
41}
42#else
43#define fmodAsDFGOperation fmod
44#endif
45
46void SpeculativeJIT::clearGenerationInfo()
47{
48 for (unsigned i = 0; i < m_generationInfo.size(); ++i)
49 m_generationInfo[i] = GenerationInfo();
50 m_gprs = RegisterBank<GPRInfo>();
51 m_fprs = RegisterBank<FPRInfo>();
52}
53
54GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex)
14957cd0
A
55{
56 Node& node = m_jit.graph()[nodeIndex];
57 VirtualRegister virtualRegister = node.virtualRegister();
58 GenerationInfo& info = m_generationInfo[virtualRegister];
6fe7ccc8 59
14957cd0
A
60 switch (info.registerFormat()) {
61 case DataFormatNone: {
6fe7ccc8
A
62 if (info.spillFormat() == DataFormatStorage) {
63 GPRReg gpr = allocate();
14957cd0 64 m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
14957cd0 65 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
6fe7ccc8 66 info.fillStorage(gpr);
14957cd0
A
67 return gpr;
68 }
6fe7ccc8
A
69
70 // Must be a cell; fill it as a cell and then return the pointer.
71 return fillSpeculateCell(nodeIndex);
14957cd0 72 }
6fe7ccc8
A
73
74 case DataFormatStorage: {
14957cd0
A
75 GPRReg gpr = info.gpr();
76 m_gprs.lock(gpr);
14957cd0
A
77 return gpr;
78 }
6fe7ccc8
A
79
80 default:
81 return fillSpeculateCell(nodeIndex);
14957cd0 82 }
6fe7ccc8 83}
14957cd0 84
6fe7ccc8
A
85void SpeculativeJIT::useChildren(Node& node)
86{
87 if (node.flags() & NodeHasVarArgs) {
88 for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
89 use(m_jit.graph().m_varArgChildren[childIdx]);
90 } else {
91 Edge child1 = node.child1();
92 if (!child1) {
93 ASSERT(!node.child2() && !node.child3());
94 return;
95 }
96 use(child1);
97
98 Edge child2 = node.child2();
99 if (!child2) {
100 ASSERT(!node.child3());
101 return;
102 }
103 use(child2);
104
105 Edge child3 = node.child3();
106 if (!child3)
107 return;
108 use(child3);
14957cd0 109 }
6fe7ccc8 110}
14957cd0 111
6fe7ccc8
A
112bool SpeculativeJIT::isStrictInt32(NodeIndex nodeIndex)
113{
114 if (isInt32Constant(nodeIndex))
115 return true;
116
117 Node& node = m_jit.graph()[nodeIndex];
118 GenerationInfo& info = m_generationInfo[node.virtualRegister()];
119
120 return info.registerFormat() == DataFormatInteger;
14957cd0
A
121}
122
6fe7ccc8 123bool SpeculativeJIT::isKnownInteger(NodeIndex nodeIndex)
14957cd0 124{
6fe7ccc8
A
125 if (isInt32Constant(nodeIndex))
126 return true;
127
128 Node& node = m_jit.graph()[nodeIndex];
129
130 if (node.hasInt32Result())
131 return true;
132
133 GenerationInfo& info = m_generationInfo[node.virtualRegister()];
134
135 return info.isJSInteger();
14957cd0
A
136}
137
6fe7ccc8 138bool SpeculativeJIT::isKnownNumeric(NodeIndex nodeIndex)
14957cd0 139{
6fe7ccc8
A
140 if (isInt32Constant(nodeIndex) || isNumberConstant(nodeIndex))
141 return true;
142
143 Node& node = m_jit.graph()[nodeIndex];
144
145 if (node.hasNumberResult())
146 return true;
147
148 GenerationInfo& info = m_generationInfo[node.virtualRegister()];
149
150 return info.isJSInteger() || info.isJSDouble();
14957cd0
A
151}
152
6fe7ccc8 153bool SpeculativeJIT::isKnownCell(NodeIndex nodeIndex)
14957cd0 154{
6fe7ccc8 155 return m_generationInfo[m_jit.graph()[nodeIndex].virtualRegister()].isJSCell();
14957cd0
A
156}
157
6fe7ccc8 158bool SpeculativeJIT::isKnownNotCell(NodeIndex nodeIndex)
14957cd0
A
159{
160 Node& node = m_jit.graph()[nodeIndex];
161 VirtualRegister virtualRegister = node.virtualRegister();
162 GenerationInfo& info = m_generationInfo[virtualRegister];
6fe7ccc8
A
163 if (node.hasConstant() && !valueOfJSConstant(nodeIndex).isCell())
164 return true;
165 return !(info.isJSCell() || info.isUnknownJS());
166}
14957cd0 167
6fe7ccc8
A
168bool SpeculativeJIT::isKnownNotInteger(NodeIndex nodeIndex)
169{
170 Node& node = m_jit.graph()[nodeIndex];
171 VirtualRegister virtualRegister = node.virtualRegister();
172 GenerationInfo& info = m_generationInfo[virtualRegister];
173
174 return info.isJSDouble() || info.isJSCell() || info.isJSBoolean()
175 || (node.hasConstant() && !valueOfJSConstant(nodeIndex).isInt32());
176}
14957cd0 177
6fe7ccc8
A
178bool SpeculativeJIT::isKnownNotNumber(NodeIndex nodeIndex)
179{
180 Node& node = m_jit.graph()[nodeIndex];
181 VirtualRegister virtualRegister = node.virtualRegister();
182 GenerationInfo& info = m_generationInfo[virtualRegister];
183
184 return (!info.isJSDouble() && !info.isJSInteger() && !info.isUnknownJS())
185 || (node.hasConstant() && !isNumberConstant(nodeIndex));
186}
14957cd0 187
6fe7ccc8
A
188void SpeculativeJIT::writeBarrier(MacroAssembler& jit, GPRReg owner, GPRReg scratch1, GPRReg scratch2, WriteBarrierUseKind useKind)
189{
190 UNUSED_PARAM(jit);
191 UNUSED_PARAM(owner);
192 UNUSED_PARAM(scratch1);
193 UNUSED_PARAM(scratch2);
194 UNUSED_PARAM(useKind);
195 ASSERT(owner != scratch1);
196 ASSERT(owner != scratch2);
197 ASSERT(scratch1 != scratch2);
198
199#if ENABLE(WRITE_BARRIER_PROFILING)
200 JITCompiler::emitCount(jit, WriteBarrierCounters::jitCounterFor(useKind));
201#endif
202 markCellCard(jit, owner, scratch1, scratch2);
203}
204
205void SpeculativeJIT::markCellCard(MacroAssembler& jit, GPRReg owner, GPRReg scratch1, GPRReg scratch2)
206{
207 UNUSED_PARAM(jit);
208 UNUSED_PARAM(owner);
209 UNUSED_PARAM(scratch1);
210 UNUSED_PARAM(scratch2);
211
212#if ENABLE(GGC)
213 jit.move(owner, scratch1);
214 jit.andPtr(TrustedImm32(static_cast<int32_t>(MarkedBlock::blockMask)), scratch1);
215 jit.move(owner, scratch2);
216 // consume additional 8 bits as we're using an approximate filter
217 jit.rshift32(TrustedImm32(MarkedBlock::atomShift + 8), scratch2);
218 jit.andPtr(TrustedImm32(MarkedBlock::atomMask >> 8), scratch2);
219 MacroAssembler::Jump filter = jit.branchTest8(MacroAssembler::Zero, MacroAssembler::BaseIndex(scratch1, scratch2, MacroAssembler::TimesOne, MarkedBlock::offsetOfMarks()));
220 jit.move(owner, scratch2);
221 jit.rshift32(TrustedImm32(MarkedBlock::cardShift), scratch2);
222 jit.andPtr(TrustedImm32(MarkedBlock::cardMask), scratch2);
223 jit.store8(TrustedImm32(1), MacroAssembler::BaseIndex(scratch1, scratch2, MacroAssembler::TimesOne, MarkedBlock::offsetOfCards()));
224 filter.link(&jit);
225#endif
226}
227
228void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, GPRReg valueGPR, Edge valueUse, WriteBarrierUseKind useKind, GPRReg scratch1, GPRReg scratch2)
229{
230 UNUSED_PARAM(ownerGPR);
231 UNUSED_PARAM(valueGPR);
232 UNUSED_PARAM(scratch1);
233 UNUSED_PARAM(scratch2);
234 UNUSED_PARAM(useKind);
235
236 if (isKnownNotCell(valueUse.index()))
237 return;
238
239#if ENABLE(WRITE_BARRIER_PROFILING)
240 JITCompiler::emitCount(m_jit, WriteBarrierCounters::jitCounterFor(useKind));
241#endif
242
243#if ENABLE(GGC)
244 GPRTemporary temp1;
245 GPRTemporary temp2;
246 if (scratch1 == InvalidGPRReg) {
247 GPRTemporary scratchGPR(this);
248 temp1.adopt(scratchGPR);
249 scratch1 = temp1.gpr();
250 }
251 if (scratch2 == InvalidGPRReg) {
252 GPRTemporary scratchGPR(this);
253 temp2.adopt(scratchGPR);
254 scratch2 = temp2.gpr();
255 }
256
257 JITCompiler::Jump rhsNotCell;
258 bool hadCellCheck = false;
259 if (!isKnownCell(valueUse.index()) && !isCellPrediction(m_jit.getPrediction(valueUse.index()))) {
260 hadCellCheck = true;
261 rhsNotCell = m_jit.branchIfNotCell(valueGPR);
14957cd0
A
262 }
263
6fe7ccc8
A
264 markCellCard(m_jit, ownerGPR, scratch1, scratch2);
265
266 if (hadCellCheck)
267 rhsNotCell.link(&m_jit);
268#endif
269}
270
271void SpeculativeJIT::writeBarrier(GPRReg ownerGPR, JSCell* value, WriteBarrierUseKind useKind, GPRReg scratch1, GPRReg scratch2)
272{
273 UNUSED_PARAM(ownerGPR);
274 UNUSED_PARAM(value);
275 UNUSED_PARAM(scratch1);
276 UNUSED_PARAM(scratch2);
277 UNUSED_PARAM(useKind);
278
279 if (Heap::isMarked(value))
280 return;
281
282#if ENABLE(WRITE_BARRIER_PROFILING)
283 JITCompiler::emitCount(m_jit, WriteBarrierCounters::jitCounterFor(useKind));
284#endif
285
286#if ENABLE(GGC)
287 GPRTemporary temp1;
288 GPRTemporary temp2;
289 if (scratch1 == InvalidGPRReg) {
290 GPRTemporary scratchGPR(this);
291 temp1.adopt(scratchGPR);
292 scratch1 = temp1.gpr();
293 }
294 if (scratch2 == InvalidGPRReg) {
295 GPRTemporary scratchGPR(this);
296 temp2.adopt(scratchGPR);
297 scratch2 = temp2.gpr();
14957cd0
A
298 }
299
6fe7ccc8
A
300 markCellCard(m_jit, ownerGPR, scratch1, scratch2);
301#endif
302}
303
304void SpeculativeJIT::writeBarrier(JSCell* owner, GPRReg valueGPR, Edge valueUse, WriteBarrierUseKind useKind, GPRReg scratch)
305{
306 UNUSED_PARAM(owner);
307 UNUSED_PARAM(valueGPR);
308 UNUSED_PARAM(scratch);
309 UNUSED_PARAM(useKind);
310
311 if (isKnownNotCell(valueUse.index()))
312 return;
313
314#if ENABLE(WRITE_BARRIER_PROFILING)
315 JITCompiler::emitCount(m_jit, WriteBarrierCounters::jitCounterFor(useKind));
316#endif
317
318#if ENABLE(GGC)
319 JITCompiler::Jump rhsNotCell;
320 bool hadCellCheck = false;
321 if (!isKnownCell(valueUse.index()) && !isCellPrediction(m_jit.getPrediction(valueUse.index()))) {
322 hadCellCheck = true;
323 rhsNotCell = m_jit.branchIfNotCell(valueGPR);
14957cd0 324 }
6fe7ccc8
A
325
326 GPRTemporary temp;
327 if (scratch == InvalidGPRReg) {
328 GPRTemporary scratchGPR(this);
329 temp.adopt(scratchGPR);
330 scratch = temp.gpr();
14957cd0
A
331 }
332
6fe7ccc8
A
333 uint8_t* cardAddress = Heap::addressOfCardFor(owner);
334 m_jit.move(JITCompiler::TrustedImmPtr(cardAddress), scratch);
335 m_jit.store8(JITCompiler::TrustedImm32(1), JITCompiler::Address(scratch));
336
337 if (hadCellCheck)
338 rhsNotCell.link(&m_jit);
339#endif
14957cd0
A
340}
341
6fe7ccc8 342bool SpeculativeJIT::nonSpeculativeCompare(Node& node, MacroAssembler::RelationalCondition cond, S_DFGOperation_EJJ helperFunction)
14957cd0 343{
6fe7ccc8
A
344 unsigned branchIndexInBlock = detectPeepHoleBranch();
345 if (branchIndexInBlock != UINT_MAX) {
346 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
14957cd0 347
6fe7ccc8
A
348 ASSERT(node.adjustedRefCount() == 1);
349
350 nonSpeculativePeepholeBranch(node, branchNodeIndex, cond, helperFunction);
351
352 m_indexInBlock = branchIndexInBlock;
353 m_compileIndex = branchNodeIndex;
354
355 return true;
14957cd0 356 }
6fe7ccc8
A
357
358 nonSpeculativeNonPeepholeCompare(node, cond, helperFunction);
359
360 return false;
361}
14957cd0 362
6fe7ccc8
A
363bool SpeculativeJIT::nonSpeculativeStrictEq(Node& node, bool invert)
364{
365 unsigned branchIndexInBlock = detectPeepHoleBranch();
366 if (branchIndexInBlock != UINT_MAX) {
367 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
368
369 ASSERT(node.adjustedRefCount() == 1);
370
371 nonSpeculativePeepholeStrictEq(node, branchNodeIndex, invert);
372
373 m_indexInBlock = branchIndexInBlock;
374 m_compileIndex = branchNodeIndex;
375
376 return true;
14957cd0 377 }
6fe7ccc8
A
378
379 nonSpeculativeNonPeepholeStrictEq(node, invert);
380
381 return false;
382}
14957cd0 383
6fe7ccc8
A
384#ifndef NDEBUG
385static const char* dataFormatString(DataFormat format)
386{
387 // These values correspond to the DataFormat enum.
388 const char* strings[] = {
389 "[ ]",
390 "[ i]",
391 "[ d]",
392 "[ c]",
393 "Err!",
394 "Err!",
395 "Err!",
396 "Err!",
397 "[J ]",
398 "[Ji]",
399 "[Jd]",
400 "[Jc]",
401 "Err!",
402 "Err!",
403 "Err!",
404 "Err!",
405 };
406 return strings[format];
14957cd0
A
407}
408
6fe7ccc8 409void SpeculativeJIT::dump(const char* label)
14957cd0 410{
6fe7ccc8
A
411 if (label)
412 dataLog("<%s>\n", label);
413
414 dataLog(" gprs:\n");
415 m_gprs.dump();
416 dataLog(" fprs:\n");
417 m_fprs.dump();
418 dataLog(" VirtualRegisters:\n");
419 for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
420 GenerationInfo& info = m_generationInfo[i];
421 if (info.alive())
422 dataLog(" % 3d:%s%s", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
423 else
424 dataLog(" % 3d:[__][__]", i);
425 if (info.registerFormat() == DataFormatDouble)
426 dataLog(":fpr%d\n", info.fpr());
427 else if (info.registerFormat() != DataFormatNone
428#if USE(JSVALUE32_64)
429 && !(info.registerFormat() & DataFormatJS)
430#endif
431 ) {
432 ASSERT(info.gpr() != InvalidGPRReg);
433 dataLog(":%s\n", GPRInfo::debugName(info.gpr()));
434 } else
435 dataLog("\n");
436 }
437 if (label)
438 dataLog("</%s>\n", label);
439}
440#endif
14957cd0 441
14957cd0 442
6fe7ccc8
A
443#if DFG_ENABLE(CONSISTENCY_CHECK)
444void SpeculativeJIT::checkConsistency()
445{
446 bool failed = false;
14957cd0 447
6fe7ccc8
A
448 for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
449 if (iter.isLocked()) {
450 dataLog("DFG_CONSISTENCY_CHECK failed: gpr %s is locked.\n", iter.debugName());
451 failed = true;
452 }
453 }
454 for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
455 if (iter.isLocked()) {
456 dataLog("DFG_CONSISTENCY_CHECK failed: fpr %s is locked.\n", iter.debugName());
457 failed = true;
14957cd0 458 }
14957cd0
A
459 }
460
6fe7ccc8
A
461 for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
462 VirtualRegister virtualRegister = (VirtualRegister)i;
463 GenerationInfo& info = m_generationInfo[virtualRegister];
464 if (!info.alive())
465 continue;
466 switch (info.registerFormat()) {
467 case DataFormatNone:
14957cd0 468 break;
6fe7ccc8
A
469 case DataFormatJS:
470 case DataFormatJSInteger:
471 case DataFormatJSDouble:
472 case DataFormatJSCell:
473 case DataFormatJSBoolean:
474#if USE(JSVALUE32_64)
475 break;
476#endif
477 case DataFormatInteger:
478 case DataFormatCell:
479 case DataFormatBoolean:
480 case DataFormatStorage: {
481 GPRReg gpr = info.gpr();
482 ASSERT(gpr != InvalidGPRReg);
483 if (m_gprs.name(gpr) != virtualRegister) {
484 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (gpr %s).\n", virtualRegister, GPRInfo::debugName(gpr));
485 failed = true;
486 }
14957cd0
A
487 break;
488 }
6fe7ccc8
A
489 case DataFormatDouble: {
490 FPRReg fpr = info.fpr();
491 ASSERT(fpr != InvalidFPRReg);
492 if (m_fprs.name(fpr) != virtualRegister) {
493 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (fpr %s).\n", virtualRegister, FPRInfo::debugName(fpr));
494 failed = true;
495 }
14957cd0
A
496 break;
497 }
498 }
14957cd0
A
499 }
500
6fe7ccc8
A
501 for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
502 VirtualRegister virtualRegister = iter.name();
503 if (virtualRegister == InvalidVirtualRegister)
504 continue;
14957cd0 505
6fe7ccc8
A
506 GenerationInfo& info = m_generationInfo[virtualRegister];
507#if USE(JSVALUE64)
508 if (iter.regID() != info.gpr()) {
509 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
510 failed = true;
511 }
512#else
513 if (!(info.registerFormat() & DataFormatJS)) {
514 if (iter.regID() != info.gpr()) {
515 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
516 failed = true;
517 }
14957cd0 518 } else {
6fe7ccc8
A
519 if (iter.regID() != info.tagGPR() && iter.regID() != info.payloadGPR()) {
520 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
521 failed = true;
522 }
523 }
524#endif
525 }
14957cd0 526
6fe7ccc8
A
527 for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
528 VirtualRegister virtualRegister = iter.name();
529 if (virtualRegister == InvalidVirtualRegister)
530 continue;
14957cd0 531
6fe7ccc8
A
532 GenerationInfo& info = m_generationInfo[virtualRegister];
533 if (iter.regID() != info.fpr()) {
534 dataLog("DFG_CONSISTENCY_CHECK failed: name mismatch for fpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
535 failed = true;
14957cd0 536 }
6fe7ccc8 537 }
14957cd0 538
6fe7ccc8
A
539 if (failed) {
540 dump();
541 CRASH();
542 }
543}
544#endif
14957cd0 545
6fe7ccc8
A
546GPRTemporary::GPRTemporary()
547 : m_jit(0)
548 , m_gpr(InvalidGPRReg)
549{
550}
14957cd0 551
6fe7ccc8
A
552GPRTemporary::GPRTemporary(SpeculativeJIT* jit)
553 : m_jit(jit)
554 , m_gpr(InvalidGPRReg)
555{
556 m_gpr = m_jit->allocate();
557}
14957cd0 558
6fe7ccc8
A
559GPRTemporary::GPRTemporary(SpeculativeJIT* jit, GPRReg specific)
560 : m_jit(jit)
561 , m_gpr(InvalidGPRReg)
562{
563 m_gpr = m_jit->allocate(specific);
564}
14957cd0 565
6fe7ccc8
A
566GPRTemporary::GPRTemporary(SpeculativeJIT* jit, SpeculateIntegerOperand& op1)
567 : m_jit(jit)
568 , m_gpr(InvalidGPRReg)
569{
570 if (m_jit->canReuse(op1.index()))
571 m_gpr = m_jit->reuse(op1.gpr());
572 else
573 m_gpr = m_jit->allocate();
574}
14957cd0 575
6fe7ccc8
A
576GPRTemporary::GPRTemporary(SpeculativeJIT* jit, SpeculateIntegerOperand& op1, SpeculateIntegerOperand& op2)
577 : m_jit(jit)
578 , m_gpr(InvalidGPRReg)
579{
580 if (m_jit->canReuse(op1.index()))
581 m_gpr = m_jit->reuse(op1.gpr());
582 else if (m_jit->canReuse(op2.index()))
583 m_gpr = m_jit->reuse(op2.gpr());
584 else
585 m_gpr = m_jit->allocate();
586}
14957cd0 587
6fe7ccc8
A
588GPRTemporary::GPRTemporary(SpeculativeJIT* jit, SpeculateStrictInt32Operand& op1)
589 : m_jit(jit)
590 , m_gpr(InvalidGPRReg)
591{
592 if (m_jit->canReuse(op1.index()))
593 m_gpr = m_jit->reuse(op1.gpr());
594 else
595 m_gpr = m_jit->allocate();
596}
14957cd0 597
6fe7ccc8
A
598GPRTemporary::GPRTemporary(SpeculativeJIT* jit, IntegerOperand& op1)
599 : m_jit(jit)
600 , m_gpr(InvalidGPRReg)
601{
602 if (m_jit->canReuse(op1.index()))
603 m_gpr = m_jit->reuse(op1.gpr());
604 else
605 m_gpr = m_jit->allocate();
606}
14957cd0 607
6fe7ccc8
A
608GPRTemporary::GPRTemporary(SpeculativeJIT* jit, IntegerOperand& op1, IntegerOperand& op2)
609 : m_jit(jit)
610 , m_gpr(InvalidGPRReg)
611{
612 if (m_jit->canReuse(op1.index()))
613 m_gpr = m_jit->reuse(op1.gpr());
614 else if (m_jit->canReuse(op2.index()))
615 m_gpr = m_jit->reuse(op2.gpr());
616 else
617 m_gpr = m_jit->allocate();
618}
14957cd0 619
6fe7ccc8
A
620GPRTemporary::GPRTemporary(SpeculativeJIT* jit, SpeculateCellOperand& op1)
621 : m_jit(jit)
622 , m_gpr(InvalidGPRReg)
623{
624 if (m_jit->canReuse(op1.index()))
625 m_gpr = m_jit->reuse(op1.gpr());
626 else
627 m_gpr = m_jit->allocate();
628}
14957cd0 629
6fe7ccc8
A
630GPRTemporary::GPRTemporary(SpeculativeJIT* jit, SpeculateBooleanOperand& op1)
631 : m_jit(jit)
632 , m_gpr(InvalidGPRReg)
633{
634 if (m_jit->canReuse(op1.index()))
635 m_gpr = m_jit->reuse(op1.gpr());
636 else
637 m_gpr = m_jit->allocate();
638}
14957cd0 639
6fe7ccc8
A
640#if USE(JSVALUE64)
641GPRTemporary::GPRTemporary(SpeculativeJIT* jit, JSValueOperand& op1)
642 : m_jit(jit)
643 , m_gpr(InvalidGPRReg)
644{
645 if (m_jit->canReuse(op1.index()))
646 m_gpr = m_jit->reuse(op1.gpr());
647 else
648 m_gpr = m_jit->allocate();
649}
650#else
651GPRTemporary::GPRTemporary(SpeculativeJIT* jit, JSValueOperand& op1, bool tag)
652 : m_jit(jit)
653 , m_gpr(InvalidGPRReg)
654{
655 if (!op1.isDouble() && m_jit->canReuse(op1.index()))
656 m_gpr = m_jit->reuse(tag ? op1.tagGPR() : op1.payloadGPR());
657 else
658 m_gpr = m_jit->allocate();
659}
660#endif
14957cd0 661
6fe7ccc8
A
662GPRTemporary::GPRTemporary(SpeculativeJIT* jit, StorageOperand& op1)
663 : m_jit(jit)
664 , m_gpr(InvalidGPRReg)
665{
666 if (m_jit->canReuse(op1.index()))
667 m_gpr = m_jit->reuse(op1.gpr());
668 else
669 m_gpr = m_jit->allocate();
670}
14957cd0 671
6fe7ccc8
A
672void GPRTemporary::adopt(GPRTemporary& other)
673{
674 ASSERT(!m_jit);
675 ASSERT(m_gpr == InvalidGPRReg);
676 ASSERT(other.m_jit);
677 ASSERT(other.m_gpr != InvalidGPRReg);
678 m_jit = other.m_jit;
679 m_gpr = other.m_gpr;
680 other.m_jit = 0;
681 other.m_gpr = InvalidGPRReg;
682}
14957cd0 683
6fe7ccc8
A
684FPRTemporary::FPRTemporary(SpeculativeJIT* jit)
685 : m_jit(jit)
686 , m_fpr(InvalidFPRReg)
687{
688 m_fpr = m_jit->fprAllocate();
689}
14957cd0 690
6fe7ccc8
A
691FPRTemporary::FPRTemporary(SpeculativeJIT* jit, DoubleOperand& op1)
692 : m_jit(jit)
693 , m_fpr(InvalidFPRReg)
694{
695 if (m_jit->canReuse(op1.index()))
696 m_fpr = m_jit->reuse(op1.fpr());
697 else
698 m_fpr = m_jit->fprAllocate();
699}
700
701FPRTemporary::FPRTemporary(SpeculativeJIT* jit, DoubleOperand& op1, DoubleOperand& op2)
702 : m_jit(jit)
703 , m_fpr(InvalidFPRReg)
704{
705 if (m_jit->canReuse(op1.index()))
706 m_fpr = m_jit->reuse(op1.fpr());
707 else if (m_jit->canReuse(op2.index()))
708 m_fpr = m_jit->reuse(op2.fpr());
709 else
710 m_fpr = m_jit->fprAllocate();
711}
712
713FPRTemporary::FPRTemporary(SpeculativeJIT* jit, SpeculateDoubleOperand& op1)
714 : m_jit(jit)
715 , m_fpr(InvalidFPRReg)
716{
717 if (m_jit->canReuse(op1.index()))
718 m_fpr = m_jit->reuse(op1.fpr());
719 else
720 m_fpr = m_jit->fprAllocate();
721}
722
723FPRTemporary::FPRTemporary(SpeculativeJIT* jit, SpeculateDoubleOperand& op1, SpeculateDoubleOperand& op2)
724 : m_jit(jit)
725 , m_fpr(InvalidFPRReg)
726{
727 if (m_jit->canReuse(op1.index()))
728 m_fpr = m_jit->reuse(op1.fpr());
729 else if (m_jit->canReuse(op2.index()))
730 m_fpr = m_jit->reuse(op2.fpr());
731 else
732 m_fpr = m_jit->fprAllocate();
733}
734
735#if USE(JSVALUE32_64)
736FPRTemporary::FPRTemporary(SpeculativeJIT* jit, JSValueOperand& op1)
737 : m_jit(jit)
738 , m_fpr(InvalidFPRReg)
739{
740 if (op1.isDouble() && m_jit->canReuse(op1.index()))
741 m_fpr = m_jit->reuse(op1.fpr());
742 else
743 m_fpr = m_jit->fprAllocate();
744}
745#endif
746
747void ValueSource::dump(FILE* out) const
748{
749 switch (kind()) {
750 case SourceNotSet:
751 fprintf(out, "NotSet");
752 break;
753 case SourceIsDead:
754 fprintf(out, "IsDead");
755 break;
756 case ValueInRegisterFile:
757 fprintf(out, "InRegFile");
758 break;
759 case Int32InRegisterFile:
760 fprintf(out, "Int32");
761 break;
762 case CellInRegisterFile:
763 fprintf(out, "Cell");
764 break;
765 case BooleanInRegisterFile:
766 fprintf(out, "Bool");
767 break;
768 case DoubleInRegisterFile:
769 fprintf(out, "Double");
770 break;
771 case HaveNode:
772 fprintf(out, "Node(%d)", m_nodeIndex);
773 break;
774 }
775}
776
777void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition)
778{
779 Node& branchNode = at(branchNodeIndex);
780 BlockIndex taken = branchNode.takenBlockIndex();
781 BlockIndex notTaken = branchNode.notTakenBlockIndex();
782
783 SpeculateDoubleOperand op1(this, node.child1());
784 SpeculateDoubleOperand op2(this, node.child2());
785
786 branchDouble(condition, op1.fpr(), op2.fpr(), taken);
787 jump(notTaken);
788}
789
790void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, const ClassInfo* classInfo, PredictionChecker predictionCheck)
791{
792 Node& branchNode = at(branchNodeIndex);
793 BlockIndex taken = branchNode.takenBlockIndex();
794 BlockIndex notTaken = branchNode.notTakenBlockIndex();
795
796 MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;
797
798 if (taken == (m_block + 1)) {
799 condition = MacroAssembler::NotEqual;
800 BlockIndex tmp = taken;
801 taken = notTaken;
802 notTaken = tmp;
803 }
804
805 SpeculateCellOperand op1(this, node.child1());
806 SpeculateCellOperand op2(this, node.child2());
807
808 GPRReg op1GPR = op1.gpr();
809 GPRReg op2GPR = op2.gpr();
810
811 if (!predictionCheck(m_state.forNode(node.child1()).m_type))
812 speculationCheck(BadType, JSValueSource::unboxedCell(op1GPR), node.child1().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
813 if (!predictionCheck(m_state.forNode(node.child2()).m_type))
814 speculationCheck(BadType, JSValueSource::unboxedCell(op2GPR), node.child2().index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(classInfo)));
815
816 branchPtr(condition, op1GPR, op2GPR, taken);
817 jump(notTaken);
818}
819
820void SpeculativeJIT::compilePeepHoleIntegerBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition condition)
821{
822 Node& branchNode = at(branchNodeIndex);
823 BlockIndex taken = branchNode.takenBlockIndex();
824 BlockIndex notTaken = branchNode.notTakenBlockIndex();
825
826 // The branch instruction will branch to the taken block.
827 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
828 if (taken == (m_block + 1)) {
829 condition = JITCompiler::invert(condition);
830 BlockIndex tmp = taken;
831 taken = notTaken;
832 notTaken = tmp;
833 }
834
835 if (isInt32Constant(node.child1().index())) {
836 int32_t imm = valueOfInt32Constant(node.child1().index());
837 SpeculateIntegerOperand op2(this, node.child2());
838 branch32(condition, JITCompiler::Imm32(imm), op2.gpr(), taken);
839 } else if (isInt32Constant(node.child2().index())) {
840 SpeculateIntegerOperand op1(this, node.child1());
841 int32_t imm = valueOfInt32Constant(node.child2().index());
842 branch32(condition, op1.gpr(), JITCompiler::Imm32(imm), taken);
843 } else {
844 SpeculateIntegerOperand op1(this, node.child1());
845 SpeculateIntegerOperand op2(this, node.child2());
846 branch32(condition, op1.gpr(), op2.gpr(), taken);
847 }
848
849 jump(notTaken);
850}
851
852// Returns true if the compare is fused with a subsequent branch.
853bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_DFGOperation_EJJ operation)
854{
855 // Fused compare & branch.
856 unsigned branchIndexInBlock = detectPeepHoleBranch();
857 if (branchIndexInBlock != UINT_MAX) {
858 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
859
860 // detectPeepHoleBranch currently only permits the branch to be the very next node,
861 // so can be no intervening nodes to also reference the compare.
862 ASSERT(node.adjustedRefCount() == 1);
863
864 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())))
865 compilePeepHoleIntegerBranch(node, branchNodeIndex, condition);
866 else if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2())))
867 compilePeepHoleDoubleBranch(node, branchNodeIndex, doubleCondition);
868 else if (node.op() == CompareEq) {
869 if (Node::shouldSpeculateFinalObject(
870 at(node.child1()), at(node.child2()))) {
871 compilePeepHoleObjectEquality(
872 node, branchNodeIndex, &JSFinalObject::s_info,
873 isFinalObjectPrediction);
874 } else if (Node::shouldSpeculateArray(
875 at(node.child1()), at(node.child2()))) {
876 compilePeepHoleObjectEquality(
877 node, branchNodeIndex, &JSArray::s_info,
878 isArrayPrediction);
879 } else if (at(node.child1()).shouldSpeculateFinalObject()
880 && at(node.child2()).shouldSpeculateFinalObjectOrOther()) {
881 compilePeepHoleObjectToObjectOrOtherEquality(
882 node.child1(), node.child2(), branchNodeIndex,
883 &JSFinalObject::s_info, isFinalObjectPrediction);
884 } else if (at(node.child1()).shouldSpeculateFinalObjectOrOther()
885 && at(node.child2()).shouldSpeculateFinalObject()) {
886 compilePeepHoleObjectToObjectOrOtherEquality(
887 node.child2(), node.child1(), branchNodeIndex,
888 &JSFinalObject::s_info, isFinalObjectPrediction);
889 } else if (at(node.child1()).shouldSpeculateArray()
890 && at(node.child2()).shouldSpeculateArrayOrOther()) {
891 compilePeepHoleObjectToObjectOrOtherEquality(
892 node.child1(), node.child2(), branchNodeIndex,
893 &JSArray::s_info, isArrayPrediction);
894 } else if (at(node.child1()).shouldSpeculateArrayOrOther()
895 && at(node.child2()).shouldSpeculateArray()) {
896 compilePeepHoleObjectToObjectOrOtherEquality(
897 node.child2(), node.child1(), branchNodeIndex,
898 &JSArray::s_info, isArrayPrediction);
899 } else {
900 nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation);
901 return true;
902 }
903 } else {
904 nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation);
905 return true;
14957cd0 906 }
14957cd0 907
6fe7ccc8
A
908 use(node.child1());
909 use(node.child2());
910 m_indexInBlock = branchIndexInBlock;
911 m_compileIndex = branchNodeIndex;
912 return true;
913 }
914 return false;
915}
916
917void SpeculativeJIT::compileMovHint(Node& node)
918{
919 ASSERT(node.op() == SetLocal);
920
921 setNodeIndexForOperand(node.child1().index(), node.local());
922 m_lastSetOperand = node.local();
923}
14957cd0 924
6fe7ccc8
A
925void SpeculativeJIT::compile(BasicBlock& block)
926{
927 ASSERT(m_compileOkay);
928
929 if (!block.isReachable)
930 return;
931
932 m_blockHeads[m_block] = m_jit.label();
933#if DFG_ENABLE(JIT_BREAK_ON_EVERY_BLOCK)
934 m_jit.breakpoint();
935#endif
936
937 m_jit.jitAssertHasValidCallFrame();
938
939 ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments());
940 for (size_t i = 0; i < m_arguments.size(); ++i) {
941 NodeIndex nodeIndex = block.variablesAtHead.argument(i);
942 if (nodeIndex == NoNode || m_jit.graph().argumentIsCaptured(i))
943 m_arguments[i] = ValueSource(ValueInRegisterFile);
944 else
945 m_arguments[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
946 }
947
948 m_state.reset();
949 m_state.beginBasicBlock(&block);
950
951 ASSERT(m_variables.size() == block.variablesAtHead.numberOfLocals());
952 for (size_t i = 0; i < m_variables.size(); ++i) {
953 NodeIndex nodeIndex = block.variablesAtHead.local(i);
954 if ((nodeIndex == NoNode || !at(nodeIndex).refCount()) && !m_jit.graph().localIsCaptured(i))
955 m_variables[i] = ValueSource(SourceIsDead);
956 else if (m_jit.graph().localIsCaptured(i))
957 m_variables[i] = ValueSource(ValueInRegisterFile);
958 else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat())
959 m_variables[i] = ValueSource(DoubleInRegisterFile);
14957cd0 960 else
6fe7ccc8
A
961 m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
962 }
963
964 m_lastSetOperand = std::numeric_limits<int>::max();
965 m_codeOriginForOSR = CodeOrigin();
966
967 if (DFG_ENABLE_EDGE_CODE_VERIFICATION) {
968 JITCompiler::Jump verificationSucceeded =
969 m_jit.branch32(JITCompiler::Equal, GPRInfo::regT0, TrustedImm32(m_block));
970 m_jit.breakpoint();
971 verificationSucceeded.link(&m_jit);
972 }
14957cd0 973
6fe7ccc8
A
974 for (m_indexInBlock = 0; m_indexInBlock < block.size(); ++m_indexInBlock) {
975 m_compileIndex = block[m_indexInBlock];
976 Node& node = at(m_compileIndex);
977 m_codeOriginForOSR = node.codeOrigin;
978 if (!node.shouldGenerate()) {
979#if DFG_ENABLE(DEBUG_VERBOSE)
980 dataLog("SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
981#endif
982 switch (node.op()) {
983 case SetLocal:
984 compileMovHint(node);
985 break;
986
987 case InlineStart: {
988 InlineCallFrame* inlineCallFrame = node.codeOrigin.inlineCallFrame;
989 int argumentCountIncludingThis = inlineCallFrame->arguments.size();
990 for (int i = 0; i < argumentCountIncludingThis; ++i) {
991 ValueRecovery recovery = computeValueRecoveryFor(m_variables[inlineCallFrame->stackOffset + CallFrame::argumentOffsetIncludingThis(i)]);
992 // The recovery should refer either to something that has already been
993 // stored into the register file at the right place, or to a constant,
994 // since the Arguments code isn't smart enough to handle anything else.
995 // The exception is the this argument, which we don't really need to be
996 // able to recover.
997#if DFG_ENABLE(DEBUG_VERBOSE)
998 dataLog("\nRecovery for argument %d: ", i);
999 recovery.dump(WTF::dataFile());
1000#endif
1001 ASSERT(!i || (recovery.isAlreadyInRegisterFile() || recovery.isConstant()));
1002 inlineCallFrame->arguments[i] = recovery;
1003 }
1004 break;
1005 }
1006
1007 default:
1008 break;
1009 }
1010 } else {
1011
1012#if DFG_ENABLE(DEBUG_VERBOSE)
1013 dataLog("SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
1014#endif
1015#if DFG_ENABLE(JIT_BREAK_ON_EVERY_NODE)
1016 m_jit.breakpoint();
1017#endif
1018#if DFG_ENABLE(XOR_DEBUG_AID)
1019 m_jit.xorPtr(JITCompiler::TrustedImm32(m_compileIndex), GPRInfo::regT0);
1020 m_jit.xorPtr(JITCompiler::TrustedImm32(m_compileIndex), GPRInfo::regT0);
1021#endif
1022 checkConsistency();
1023 compile(node);
1024 if (!m_compileOkay) {
1025 m_compileOkay = true;
1026 clearGenerationInfo();
1027 return;
1028 }
1029
1030#if DFG_ENABLE(DEBUG_VERBOSE)
1031 if (node.hasResult()) {
1032 GenerationInfo& info = m_generationInfo[node.virtualRegister()];
1033 dataLog("-> %s, vr#%d", dataFormatToString(info.registerFormat()), (int)node.virtualRegister());
1034 if (info.registerFormat() != DataFormatNone) {
1035 if (info.registerFormat() == DataFormatDouble)
1036 dataLog(", %s", FPRInfo::debugName(info.fpr()));
1037#if USE(JSVALUE32_64)
1038 else if (info.registerFormat() & DataFormatJS)
1039 dataLog(", %s %s", GPRInfo::debugName(info.tagGPR()), GPRInfo::debugName(info.payloadGPR()));
1040#endif
1041 else
1042 dataLog(", %s", GPRInfo::debugName(info.gpr()));
1043 }
1044 dataLog(" ");
1045 } else
1046 dataLog(" ");
1047#endif
1048 }
1049
1050#if DFG_ENABLE(VERBOSE_VALUE_RECOVERIES)
1051 for (size_t i = 0; i < m_arguments.size(); ++i)
1052 computeValueRecoveryFor(argumentToOperand(i)).dump(stderr);
1053
1054 dataLog(" : ");
1055
1056 for (int operand = 0; operand < (int)m_variables.size(); ++operand)
1057 computeValueRecoveryFor(operand).dump(stderr);
1058#endif
1059
1060#if DFG_ENABLE(DEBUG_VERBOSE)
1061 dataLog("\n");
1062#endif
1063
1064 // Make sure that the abstract state is rematerialized for the next node.
1065 m_state.execute(m_indexInBlock);
1066
1067 if (node.shouldGenerate())
1068 checkConsistency();
1069 }
1070
1071 // Perform the most basic verification that children have been used correctly.
1072#if !ASSERT_DISABLED
1073 for (unsigned index = 0; index < m_generationInfo.size(); ++index) {
1074 GenerationInfo& info = m_generationInfo[index];
1075 ASSERT(!info.alive());
1076 }
1077#endif
1078}
1079
1080// If we are making type predictions about our arguments then
1081// we need to check that they are correct on function entry.
1082void SpeculativeJIT::checkArgumentTypes()
1083{
1084 ASSERT(!m_compileIndex);
1085 m_codeOriginForOSR = CodeOrigin(0);
1086
1087 for (size_t i = 0; i < m_arguments.size(); ++i)
1088 m_arguments[i] = ValueSource(ValueInRegisterFile);
1089 for (size_t i = 0; i < m_variables.size(); ++i)
1090 m_variables[i] = ValueSource(ValueInRegisterFile);
1091
1092 for (int i = 0; i < m_jit.codeBlock()->numParameters(); ++i) {
1093 NodeIndex nodeIndex = m_jit.graph().m_arguments[i];
1094 Node& node = at(nodeIndex);
1095 ASSERT(node.op() == SetArgument);
1096 if (!node.shouldGenerate()) {
1097 // The argument is dead. We don't do any checks for such arguments.
1098 continue;
1099 }
1100
1101 VariableAccessData* variableAccessData = node.variableAccessData();
1102 VirtualRegister virtualRegister = variableAccessData->local();
1103 PredictedType predictedType = variableAccessData->prediction();
1104
1105 JSValueSource valueSource = JSValueSource(JITCompiler::addressFor(virtualRegister));
1106
1107#if USE(JSVALUE64)
1108 if (isInt32Prediction(predictedType))
1109 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister));
1110 else if (isArrayPrediction(predictedType)) {
1111 GPRTemporary temp(this);
1112 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1113 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1114 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
1115 } else if (isBooleanPrediction(predictedType)) {
1116 GPRTemporary temp(this);
1117 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1118 m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr());
1119 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
1120 } else if (isInt8ArrayPrediction(predictedType)) {
1121 GPRTemporary temp(this);
1122 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1123 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1124 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int8ArrayDescriptor().m_classInfo)));
1125 } else if (isInt16ArrayPrediction(predictedType)) {
1126 GPRTemporary temp(this);
1127 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1128 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1129 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int16ArrayDescriptor().m_classInfo)));
1130 } else if (isInt32ArrayPrediction(predictedType)) {
1131 GPRTemporary temp(this);
1132 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1133 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1134 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int32ArrayDescriptor().m_classInfo)));
1135 } else if (isUint8ArrayPrediction(predictedType)) {
1136 GPRTemporary temp(this);
1137 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1138 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1139 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo)));
1140 } else if (isUint8ClampedArrayPrediction(predictedType)) {
1141 GPRTemporary temp(this);
1142 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1143 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1144 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo)));
1145 } else if (isUint16ArrayPrediction(predictedType)) {
1146 GPRTemporary temp(this);
1147 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1148 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1149 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint16ArrayDescriptor().m_classInfo)));
1150 } else if (isUint32ArrayPrediction(predictedType)) {
1151 GPRTemporary temp(this);
1152 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1153 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1154 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint32ArrayDescriptor().m_classInfo)));
1155 } else if (isFloat32ArrayPrediction(predictedType)) {
1156 GPRTemporary temp(this);
1157 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1158 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1159 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float32ArrayDescriptor().m_classInfo)));
1160 } else if (isFloat64ArrayPrediction(predictedType)) {
1161 GPRTemporary temp(this);
1162 m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
1163 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
1164 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float64ArrayDescriptor().m_classInfo)));
1165 }
1166#else
1167 if (isInt32Prediction(predictedType))
1168 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
1169 else if (isArrayPrediction(predictedType)) {
1170 GPRTemporary temp(this);
1171 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1172 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1173 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1174 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
1175 } else if (isBooleanPrediction(predictedType))
1176 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
1177 else if (isInt8ArrayPrediction(predictedType)) {
1178 GPRTemporary temp(this);
1179 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1180 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1181 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1182 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int8ArrayDescriptor().m_classInfo)));
1183 } else if (isInt16ArrayPrediction(predictedType)) {
1184 GPRTemporary temp(this);
1185 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1186 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1187 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1188 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int16ArrayDescriptor().m_classInfo)));
1189 } else if (isInt32ArrayPrediction(predictedType)) {
1190 GPRTemporary temp(this);
1191 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1192 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1193 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1194 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->int32ArrayDescriptor().m_classInfo)));
1195 } else if (isUint8ArrayPrediction(predictedType)) {
1196 GPRTemporary temp(this);
1197 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1198 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1199 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1200 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ArrayDescriptor().m_classInfo)));
1201 } else if (isUint8ClampedArrayPrediction(predictedType)) {
1202 GPRTemporary temp(this);
1203 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1204 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1205 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1206 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint8ClampedArrayDescriptor().m_classInfo)));
1207 } else if (isUint16ArrayPrediction(predictedType)) {
1208 GPRTemporary temp(this);
1209 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1210 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1211 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1212 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint16ArrayDescriptor().m_classInfo)));
1213 } else if (isUint32ArrayPrediction(predictedType)) {
1214 GPRTemporary temp(this);
1215 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1216 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1217 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1218 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->uint32ArrayDescriptor().m_classInfo)));
1219 } else if (isFloat32ArrayPrediction(predictedType)) {
1220 GPRTemporary temp(this);
1221 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1222 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1223 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1224 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float32ArrayDescriptor().m_classInfo)));
1225 } else if (isFloat64ArrayPrediction(predictedType)) {
1226 GPRTemporary temp(this);
1227 m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
1228 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
1229 m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
1230 speculationCheck(BadType, valueSource, nodeIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->float64ArrayDescriptor().m_classInfo)));
1231 }
1232#endif
1233 }
1234}
1235
1236bool SpeculativeJIT::compile()
1237{
1238 checkArgumentTypes();
1239
1240 if (DFG_ENABLE_EDGE_CODE_VERIFICATION)
1241 m_jit.move(TrustedImm32(0), GPRInfo::regT0);
1242
1243 ASSERT(!m_compileIndex);
1244 for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block)
1245 compile(*m_jit.graph().m_blocks[m_block]);
1246 linkBranches();
1247 return true;
1248}
1249
1250void SpeculativeJIT::createOSREntries()
1251{
1252 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().m_blocks.size(); ++blockIndex) {
1253 BasicBlock& block = *m_jit.graph().m_blocks[blockIndex];
1254 if (!block.isOSRTarget)
1255 continue;
1256
1257 // Currently we only need to create OSR entry trampolines when using edge code
1258 // verification. But in the future, we'll need this for other things as well (like
1259 // when we have global reg alloc).
1260 // If we don't need OSR entry trampolin
1261 if (!DFG_ENABLE_EDGE_CODE_VERIFICATION) {
1262 m_osrEntryHeads.append(m_blockHeads[blockIndex]);
1263 continue;
1264 }
1265
1266 m_osrEntryHeads.append(m_jit.label());
1267 m_jit.move(TrustedImm32(blockIndex), GPRInfo::regT0);
1268 m_jit.jump().linkTo(m_blockHeads[blockIndex], &m_jit);
1269 }
1270}
1271
1272void SpeculativeJIT::linkOSREntries(LinkBuffer& linkBuffer)
1273{
1274 unsigned osrEntryIndex = 0;
1275 for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().m_blocks.size(); ++blockIndex) {
1276 BasicBlock& block = *m_jit.graph().m_blocks[blockIndex];
1277 if (block.isOSRTarget)
1278 m_jit.noticeOSREntry(block, m_osrEntryHeads[osrEntryIndex++], linkBuffer);
1279 }
1280 ASSERT(osrEntryIndex == m_osrEntryHeads.size());
1281}
1282
1283ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSource)
1284{
1285 switch (valueSource.kind()) {
1286 case SourceIsDead:
1287 return ValueRecovery::constant(jsUndefined());
1288
1289 case ValueInRegisterFile:
1290 return ValueRecovery::alreadyInRegisterFile();
1291
1292 case Int32InRegisterFile:
1293 return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32();
1294
1295 case CellInRegisterFile:
1296 return ValueRecovery::alreadyInRegisterFileAsUnboxedCell();
1297
1298 case BooleanInRegisterFile:
1299 return ValueRecovery::alreadyInRegisterFileAsUnboxedBoolean();
1300
1301 case DoubleInRegisterFile:
1302 return ValueRecovery::alreadyInRegisterFileAsUnboxedDouble();
1303
1304 case HaveNode: {
1305 if (isConstant(valueSource.nodeIndex()))
1306 return ValueRecovery::constant(valueOfJSConstant(valueSource.nodeIndex()));
1307
1308 Node* nodePtr = &at(valueSource.nodeIndex());
1309 if (!nodePtr->shouldGenerate()) {
1310 // It's legitimately dead. As in, nobody will ever use this node, or operand,
1311 // ever. Set it to Undefined to make the GC happy after the OSR.
1312 return ValueRecovery::constant(jsUndefined());
1313 }
1314
1315 GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
1316 if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) {
1317 // Try to see if there is an alternate node that would contain the value we want.
1318 // There are four possibilities:
1319 //
1320 // Int32ToDouble: We can use this in place of the original node, but
1321 // we'd rather not; so we use it only if it is the only remaining
1322 // live version.
1323 //
1324 // ValueToInt32: If the only remaining live version of the value is
1325 // ValueToInt32, then we can use it.
1326 //
1327 // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber
1328 // then the only remaining uses are ones that want a properly formed number
1329 // rather than a UInt32 intermediate.
1330 //
1331 // The reverse of the above: This node could be a UInt32ToNumber, but its
1332 // alternative is still alive. This means that the only remaining uses of
1333 // the number would be fine with a UInt32 intermediate.
1334 //
1335 // DoubleAsInt32: Same as UInt32ToNumber.
1336 //
1337
1338 bool found = false;
1339
1340 if (nodePtr->op() == UInt32ToNumber || nodePtr->op() == DoubleAsInt32) {
1341 NodeIndex nodeIndex = nodePtr->child1().index();
1342 nodePtr = &at(nodeIndex);
1343 infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
1344 if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex)
1345 found = true;
1346 }
1347
1348 if (!found) {
1349 NodeIndex int32ToDoubleIndex = NoNode;
1350 NodeIndex valueToInt32Index = NoNode;
1351 NodeIndex uint32ToNumberIndex = NoNode;
1352 NodeIndex doubleAsInt32Index = NoNode;
1353
1354 for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) {
1355 GenerationInfo& info = m_generationInfo[virtualRegister];
1356 if (!info.alive())
1357 continue;
1358 if (info.nodeIndex() == NoNode)
1359 continue;
1360 Node& node = at(info.nodeIndex());
1361 if (node.child1Unchecked() != valueSource.nodeIndex())
1362 continue;
1363 switch (node.op()) {
1364 case Int32ToDouble:
1365 int32ToDoubleIndex = info.nodeIndex();
1366 break;
1367 case ValueToInt32:
1368 valueToInt32Index = info.nodeIndex();
1369 break;
1370 case UInt32ToNumber:
1371 uint32ToNumberIndex = info.nodeIndex();
1372 break;
1373 case DoubleAsInt32:
1374 doubleAsInt32Index = info.nodeIndex();
1375 default:
1376 break;
1377 }
1378 }
1379
1380 NodeIndex nodeIndexToUse;
1381 if (doubleAsInt32Index != NoNode)
1382 nodeIndexToUse = doubleAsInt32Index;
1383 else if (int32ToDoubleIndex != NoNode)
1384 nodeIndexToUse = int32ToDoubleIndex;
1385 else if (valueToInt32Index != NoNode)
1386 nodeIndexToUse = valueToInt32Index;
1387 else if (uint32ToNumberIndex != NoNode)
1388 nodeIndexToUse = uint32ToNumberIndex;
1389 else
1390 nodeIndexToUse = NoNode;
1391
1392 if (nodeIndexToUse != NoNode) {
1393 nodePtr = &at(nodeIndexToUse);
1394 infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
1395 ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse);
1396 found = true;
1397 }
1398 }
1399
1400 if (!found)
1401 return ValueRecovery::constant(jsUndefined());
1402 }
1403
1404 ASSERT(infoPtr->alive());
1405
1406 if (infoPtr->registerFormat() != DataFormatNone) {
1407 if (infoPtr->registerFormat() == DataFormatDouble)
1408 return ValueRecovery::inFPR(infoPtr->fpr());
1409#if USE(JSVALUE32_64)
1410 if (infoPtr->registerFormat() & DataFormatJS)
1411 return ValueRecovery::inPair(infoPtr->tagGPR(), infoPtr->payloadGPR());
1412#endif
1413 return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat());
1414 }
1415 if (infoPtr->spillFormat() != DataFormatNone)
1416 return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister()), infoPtr->spillFormat());
1417
1418 ASSERT_NOT_REACHED();
1419 return ValueRecovery();
1420 }
1421
1422 default:
1423 ASSERT_NOT_REACHED();
1424 return ValueRecovery();
1425 }
1426}
1427
1428void SpeculativeJIT::compileGetCharCodeAt(Node& node)
1429{
1430 ASSERT(node.child3() == NoNode);
1431 SpeculateCellOperand string(this, node.child1());
1432 SpeculateStrictInt32Operand index(this, node.child2());
1433 StorageOperand storage(this, node.child3());
1434
1435 GPRReg stringReg = string.gpr();
1436 GPRReg indexReg = index.gpr();
1437 GPRReg storageReg = storage.gpr();
1438
1439 if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) {
1440 ASSERT(!(at(node.child1()).prediction() & PredictString));
1441 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
1442 noResult(m_compileIndex);
1443 return;
1444 }
1445
1446 // unsigned comparison so we can filter out negative indices and indices that are too large
1447 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, MacroAssembler::Address(stringReg, JSString::offsetOfLength())));
1448
1449 GPRTemporary scratch(this);
1450 GPRReg scratchReg = scratch.gpr();
1451
1452 m_jit.loadPtr(MacroAssembler::Address(stringReg, JSString::offsetOfValue()), scratchReg);
1453
1454 // Load the character into scratchReg
1455 JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
1456
1457 m_jit.load8(MacroAssembler::BaseIndex(storageReg, indexReg, MacroAssembler::TimesOne, 0), scratchReg);
1458 JITCompiler::Jump cont8Bit = m_jit.jump();
1459
1460 is16Bit.link(&m_jit);
1461
1462 m_jit.load16(MacroAssembler::BaseIndex(storageReg, indexReg, MacroAssembler::TimesTwo, 0), scratchReg);
1463
1464 cont8Bit.link(&m_jit);
1465
1466 integerResult(scratchReg, m_compileIndex);
1467}
1468
1469void SpeculativeJIT::compileGetByValOnString(Node& node)
1470{
1471 SpeculateCellOperand base(this, node.child1());
1472 SpeculateStrictInt32Operand property(this, node.child2());
1473 StorageOperand storage(this, node.child3());
1474 GPRReg baseReg = base.gpr();
1475 GPRReg propertyReg = property.gpr();
1476 GPRReg storageReg = storage.gpr();
1477
1478 if (!isStringPrediction(m_state.forNode(node.child1()).m_type)) {
1479 ASSERT(!(at(node.child1()).prediction() & PredictString));
1480 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
1481 noResult(m_compileIndex);
1482 return;
1483 }
1484
1485 // unsigned comparison so we can filter out negative indices and indices that are too large
1486 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSString::offsetOfLength())));
1487
1488 GPRTemporary scratch(this);
1489 GPRReg scratchReg = scratch.gpr();
1490
1491 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg);
1492
1493 // Load the character into scratchReg
1494 JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
1495
1496 m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne, 0), scratchReg);
1497 JITCompiler::Jump cont8Bit = m_jit.jump();
1498
1499 is16Bit.link(&m_jit);
1500
1501 m_jit.load16(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo, 0), scratchReg);
1502
1503 // We only support ascii characters
1504 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, scratchReg, TrustedImm32(0x100)));
1505
1506 // 8 bit string values don't need the isASCII check.
1507 cont8Bit.link(&m_jit);
1508
1509 GPRTemporary smallStrings(this);
1510 GPRReg smallStringsReg = smallStrings.gpr();
1511 m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalData()->smallStrings.singleCharacterStrings()), smallStringsReg);
1512 m_jit.loadPtr(MacroAssembler::BaseIndex(smallStringsReg, scratchReg, MacroAssembler::ScalePtr, 0), scratchReg);
1513 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, scratchReg));
1514 cellResult(scratchReg, m_compileIndex);
1515}
1516
1517GeneratedOperandType SpeculativeJIT::checkGeneratedTypeForToInt32(NodeIndex nodeIndex)
1518{
1519#if DFG_ENABLE(DEBUG_VERBOSE)
1520 dataLog("checkGeneratedTypeForToInt32@%d ", nodeIndex);
1521#endif
1522 Node& node = at(nodeIndex);
1523 VirtualRegister virtualRegister = node.virtualRegister();
1524 GenerationInfo& info = m_generationInfo[virtualRegister];
1525
1526 if (info.registerFormat() == DataFormatNone) {
1527 if (node.hasConstant()) {
1528 if (isInt32Constant(nodeIndex))
1529 return GeneratedOperandInteger;
1530
1531 if (isNumberConstant(nodeIndex))
1532 return GeneratedOperandDouble;
1533
1534 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
1535 return GeneratedOperandTypeUnknown;
1536 }
1537
1538 if (info.spillFormat() == DataFormatDouble)
1539 return GeneratedOperandDouble;
14957cd0
A
1540 }
1541
6fe7ccc8
A
1542 switch (info.registerFormat()) {
1543 case DataFormatBoolean: // This type never occurs.
1544 case DataFormatStorage:
1545 ASSERT_NOT_REACHED();
1546
1547 case DataFormatCell:
1548 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
1549 return GeneratedOperandTypeUnknown;
1550
1551 case DataFormatNone:
1552 case DataFormatJSCell:
1553 case DataFormatJS:
1554 case DataFormatJSBoolean:
1555 return GeneratedOperandJSValue;
1556
1557 case DataFormatJSInteger:
1558 case DataFormatInteger:
1559 return GeneratedOperandInteger;
1560
1561 case DataFormatJSDouble:
1562 case DataFormatDouble:
1563 return GeneratedOperandDouble;
1564 }
1565
1566 ASSERT_NOT_REACHED();
1567 return GeneratedOperandTypeUnknown;
1568}
1569
1570void SpeculativeJIT::compileValueToInt32(Node& node)
1571{
1572 if (at(node.child1()).shouldSpeculateInteger()) {
1573 SpeculateIntegerOperand op1(this, node.child1());
1574 GPRTemporary result(this, op1);
1575 m_jit.move(op1.gpr(), result.gpr());
1576 integerResult(result.gpr(), m_compileIndex, op1.format());
1577 return;
1578 }
1579
1580 if (at(node.child1()).shouldSpeculateNumber()) {
1581 switch (checkGeneratedTypeForToInt32(node.child1().index())) {
1582 case GeneratedOperandInteger: {
1583 SpeculateIntegerOperand op1(this, node.child1());
1584 GPRTemporary result(this, op1);
1585 m_jit.move(op1.gpr(), result.gpr());
1586 integerResult(result.gpr(), m_compileIndex, op1.format());
1587 return;
1588 }
1589 case GeneratedOperandDouble: {
14957cd0 1590 GPRTemporary result(this);
6fe7ccc8
A
1591 DoubleOperand op1(this, node.child1());
1592 FPRReg fpr = op1.fpr();
1593 GPRReg gpr = result.gpr();
1594 JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateSuccessful);
14957cd0 1595
6fe7ccc8
A
1596 silentSpillAllRegisters(gpr);
1597 callOperation(toInt32, gpr, fpr);
1598 silentFillAllRegisters(gpr);
14957cd0 1599
6fe7ccc8
A
1600 truncatedToInteger.link(&m_jit);
1601 integerResult(gpr, m_compileIndex);
1602 return;
1603 }
1604 case GeneratedOperandJSValue: {
1605 GPRTemporary result(this);
1606#if USE(JSVALUE64)
1607 JSValueOperand op1(this, node.child1());
1608
1609 GPRReg gpr = op1.gpr();
1610 GPRReg resultGpr = result.gpr();
1611 FPRTemporary tempFpr(this);
1612 FPRReg fpr = tempFpr.fpr();
1613
1614 JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, gpr, GPRInfo::tagTypeNumberRegister);
1615
1616 speculationCheck(BadType, JSValueRegs(gpr), node.child1().index(), m_jit.branchTestPtr(MacroAssembler::Zero, gpr, GPRInfo::tagTypeNumberRegister));
1617
1618 // First, if we get here we have a double encoded as a JSValue
1619 m_jit.move(gpr, resultGpr);
1620 unboxDouble(resultGpr, fpr);
1621
1622 silentSpillAllRegisters(resultGpr);
1623 callOperation(toInt32, resultGpr, fpr);
1624 silentFillAllRegisters(resultGpr);
1625
1626 JITCompiler::Jump converted = m_jit.jump();
1627
1628 isInteger.link(&m_jit);
1629 m_jit.zeroExtend32ToPtr(gpr, resultGpr);
1630
1631 converted.link(&m_jit);
1632#else
1633 Node& childNode = at(node.child1().index());
1634 VirtualRegister virtualRegister = childNode.virtualRegister();
1635 GenerationInfo& info = m_generationInfo[virtualRegister];
1636
1637 JSValueOperand op1(this, node.child1());
1638
1639 GPRReg payloadGPR = op1.payloadGPR();
1640 GPRReg resultGpr = result.gpr();
1641
1642 if (info.registerFormat() == DataFormatJSInteger)
1643 m_jit.move(payloadGPR, resultGpr);
1644 else {
1645 GPRReg tagGPR = op1.tagGPR();
1646 FPRTemporary tempFpr(this);
1647 FPRReg fpr = tempFpr.fpr();
1648 FPRTemporary scratch(this);
1649
1650 JITCompiler::Jump isInteger = m_jit.branch32(MacroAssembler::Equal, tagGPR, TrustedImm32(JSValue::Int32Tag));
1651
1652 speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), node.child1().index(), m_jit.branch32(MacroAssembler::AboveOrEqual, tagGPR, TrustedImm32(JSValue::LowestTag)));
1653
1654 unboxDouble(tagGPR, payloadGPR, fpr, scratch.fpr());
1655
1656 silentSpillAllRegisters(resultGpr);
1657 callOperation(toInt32, resultGpr, fpr);
1658 silentFillAllRegisters(resultGpr);
1659
1660 JITCompiler::Jump converted = m_jit.jump();
1661
1662 isInteger.link(&m_jit);
1663 m_jit.move(payloadGPR, resultGpr);
1664
1665 converted.link(&m_jit);
1666 }
1667#endif
1668 integerResult(resultGpr, m_compileIndex);
1669 return;
1670 }
1671 case GeneratedOperandTypeUnknown:
1672 ASSERT_NOT_REACHED();
14957cd0
A
1673 break;
1674 }
6fe7ccc8
A
1675 }
1676
1677 if (at(node.child1()).shouldSpeculateBoolean()) {
1678 SpeculateBooleanOperand op1(this, node.child1());
1679 GPRTemporary result(this, op1);
1680
1681 m_jit.and32(JITCompiler::TrustedImm32(1), op1.gpr());
1682
1683 integerResult(op1.gpr(), m_compileIndex);
1684 return;
1685 }
1686
1687 // Do it the safe way.
1688 nonSpeculativeValueToInt32(node);
1689 return;
1690}
1691
1692void SpeculativeJIT::compileUInt32ToNumber(Node& node)
1693{
1694 if (!nodeCanSpeculateInteger(node.arithNodeFlags())) {
1695 // We know that this sometimes produces doubles. So produce a double every
1696 // time. This at least allows subsequent code to not have weird conditionals.
14957cd0 1697
6fe7ccc8
A
1698 IntegerOperand op1(this, node.child1());
1699 FPRTemporary result(this);
1700
1701 GPRReg inputGPR = op1.gpr();
1702 FPRReg outputFPR = result.fpr();
1703
1704 m_jit.convertInt32ToDouble(inputGPR, outputFPR);
1705
1706 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, inputGPR, TrustedImm32(0));
1707 m_jit.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32), outputFPR);
1708 positive.link(&m_jit);
1709
1710 doubleResult(outputFPR, m_compileIndex);
1711 return;
1712 }
14957cd0 1713
6fe7ccc8
A
1714 IntegerOperand op1(this, node.child1());
1715 GPRTemporary result(this, op1);
14957cd0 1716
6fe7ccc8
A
1717 // Test the operand is positive. This is a very special speculation check - we actually
1718 // use roll-forward speculation here, where if this fails, we jump to the baseline
1719 // instruction that follows us, rather than the one we're executing right now. We have
1720 // to do this because by this point, the original values necessary to compile whatever
1721 // operation the UInt32ToNumber originated from might be dead.
1722 forwardSpeculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, op1.gpr(), TrustedImm32(0)), ValueRecovery::uint32InGPR(op1.gpr()));
1723
1724 m_jit.move(op1.gpr(), result.gpr());
1725 integerResult(result.gpr(), m_compileIndex, op1.format());
1726}
1727
1728void SpeculativeJIT::compileDoubleAsInt32(Node& node)
1729{
1730 SpeculateDoubleOperand op1(this, node.child1());
1731 FPRTemporary scratch(this);
1732 GPRTemporary result(this);
1733
1734 FPRReg valueFPR = op1.fpr();
1735 FPRReg scratchFPR = scratch.fpr();
1736 GPRReg resultGPR = result.gpr();
1737
1738 JITCompiler::JumpList failureCases;
1739 m_jit.branchConvertDoubleToInt32(valueFPR, resultGPR, failureCases, scratchFPR);
1740 forwardSpeculationCheck(Overflow, JSValueRegs(), NoNode, failureCases, ValueRecovery::inFPR(valueFPR));
1741
1742 integerResult(resultGPR, m_compileIndex);
1743}
1744
1745void SpeculativeJIT::compileInt32ToDouble(Node& node)
1746{
1747#if USE(JSVALUE64)
1748 // On JSVALUE64 we have a way of loading double constants in a more direct manner
1749 // than a int->double conversion. On 32_64, unfortunately, we currently don't have
1750 // any such mechanism - though we could have it, if we just provisioned some memory
1751 // in CodeBlock for the double form of integer constants.
1752 if (at(node.child1()).hasConstant()) {
1753 ASSERT(isInt32Constant(node.child1().index()));
1754 FPRTemporary result(this);
1755 GPRTemporary temp(this);
1756 m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfNumberConstant(node.child1().index())))), temp.gpr());
1757 m_jit.movePtrToDouble(temp.gpr(), result.fpr());
1758 doubleResult(result.fpr(), m_compileIndex);
1759 return;
1760 }
1761#endif
1762
1763 if (isInt32Prediction(m_state.forNode(node.child1()).m_type)) {
1764 SpeculateIntegerOperand op1(this, node.child1());
1765 FPRTemporary result(this);
1766 m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
1767 doubleResult(result.fpr(), m_compileIndex);
1768 return;
14957cd0 1769 }
6fe7ccc8
A
1770
1771 JSValueOperand op1(this, node.child1());
1772 FPRTemporary result(this);
1773
1774#if USE(JSVALUE64)
1775 GPRTemporary temp(this);
1776
1777 GPRReg op1GPR = op1.gpr();
1778 GPRReg tempGPR = temp.gpr();
1779 FPRReg resultFPR = result.fpr();
1780
1781 JITCompiler::Jump isInteger = m_jit.branchPtr(
1782 MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister);
1783
1784 speculationCheck(
1785 BadType, JSValueRegs(op1GPR), node.child1(),
1786 m_jit.branchTestPtr(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister));
1787
1788 m_jit.move(op1GPR, tempGPR);
1789 unboxDouble(tempGPR, resultFPR);
1790 JITCompiler::Jump done = m_jit.jump();
1791
1792 isInteger.link(&m_jit);
1793 m_jit.convertInt32ToDouble(op1GPR, resultFPR);
1794 done.link(&m_jit);
1795#else
1796 FPRTemporary temp(this);
1797
1798 GPRReg op1TagGPR = op1.tagGPR();
1799 GPRReg op1PayloadGPR = op1.payloadGPR();
1800 FPRReg tempFPR = temp.fpr();
1801 FPRReg resultFPR = result.fpr();
1802
1803 JITCompiler::Jump isInteger = m_jit.branch32(
1804 MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag));
1805
1806 speculationCheck(
1807 BadType, JSValueRegs(op1TagGPR, op1PayloadGPR), node.child1(),
1808 m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
1809
1810 unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR);
1811 JITCompiler::Jump done = m_jit.jump();
1812
1813 isInteger.link(&m_jit);
1814 m_jit.convertInt32ToDouble(op1PayloadGPR, resultFPR);
1815 done.link(&m_jit);
1816#endif
1817
1818 doubleResult(resultFPR, m_compileIndex);
1819}
14957cd0 1820
6fe7ccc8
A
1821static double clampDoubleToByte(double d)
1822{
1823 d += 0.5;
1824 if (!(d > 0))
1825 d = 0;
1826 else if (d > 255)
1827 d = 255;
1828 return d;
1829}
14957cd0 1830
6fe7ccc8
A
1831static void compileClampIntegerToByte(JITCompiler& jit, GPRReg result)
1832{
1833 MacroAssembler::Jump inBounds = jit.branch32(MacroAssembler::BelowOrEqual, result, JITCompiler::TrustedImm32(0xff));
1834 MacroAssembler::Jump tooBig = jit.branch32(MacroAssembler::GreaterThan, result, JITCompiler::TrustedImm32(0xff));
1835 jit.xorPtr(result, result);
1836 MacroAssembler::Jump clamped = jit.jump();
1837 tooBig.link(&jit);
1838 jit.move(JITCompiler::TrustedImm32(255), result);
1839 clamped.link(&jit);
1840 inBounds.link(&jit);
1841}
14957cd0 1842
6fe7ccc8
A
1843static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg source, FPRReg scratch)
1844{
1845 // Unordered compare so we pick up NaN
1846 static const double zero = 0;
1847 static const double byteMax = 255;
1848 static const double half = 0.5;
1849 jit.loadDouble(&zero, scratch);
1850 MacroAssembler::Jump tooSmall = jit.branchDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered, source, scratch);
1851 jit.loadDouble(&byteMax, scratch);
1852 MacroAssembler::Jump tooBig = jit.branchDouble(MacroAssembler::DoubleGreaterThan, source, scratch);
1853
1854 jit.loadDouble(&half, scratch);
1855 // FIXME: This should probably just use a floating point round!
1856 // https://bugs.webkit.org/show_bug.cgi?id=72054
1857 jit.addDouble(source, scratch);
1858 jit.truncateDoubleToInt32(scratch, result);
1859 MacroAssembler::Jump truncatedInt = jit.jump();
1860
1861 tooSmall.link(&jit);
1862 jit.xorPtr(result, result);
1863 MacroAssembler::Jump zeroed = jit.jump();
1864
1865 tooBig.link(&jit);
1866 jit.move(JITCompiler::TrustedImm32(255), result);
1867
1868 truncatedInt.link(&jit);
1869 zeroed.link(&jit);
14957cd0 1870
6fe7ccc8
A
1871}
1872
1873void SpeculativeJIT::compileGetTypedArrayLength(const TypedArrayDescriptor& descriptor, Node& node, bool needsSpeculationCheck)
1874{
1875 SpeculateCellOperand base(this, node.child1());
1876 GPRTemporary result(this);
1877
1878 GPRReg baseGPR = base.gpr();
1879 GPRReg resultGPR = result.gpr();
1880
1881 if (needsSpeculationCheck)
1882 speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
1883
1884 m_jit.load32(MacroAssembler::Address(baseGPR, descriptor.m_lengthOffset), resultGPR);
1885
1886 integerResult(resultGPR, m_compileIndex);
1887}
1888
1889void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness)
1890{
1891 SpeculateCellOperand base(this, node.child1());
1892 SpeculateStrictInt32Operand property(this, node.child2());
1893 StorageOperand storage(this, node.child3());
1894
1895 GPRReg baseReg = base.gpr();
1896 GPRReg propertyReg = property.gpr();
1897 GPRReg storageReg = storage.gpr();
1898
1899 GPRTemporary result(this);
1900 GPRReg resultReg = result.gpr();
1901
1902 if (speculationRequirements != NoTypedArrayTypeSpecCheck) {
1903 ASSERT_NOT_REACHED();
1904 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
1905 noResult(m_compileIndex);
1906 return;
1907 }
1908
1909 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset));
1910 m_jit.xorPtr(resultReg, resultReg);
1911 MacroAssembler::Jump outOfBounds = m_jit.jump();
1912 inBounds.link(&m_jit);
1913 switch (elementSize) {
1914 case 1:
1915 if (signedness == SignedTypedArray)
1916 m_jit.load8Signed(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg);
1917 else
1918 m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne), resultReg);
1919 break;
1920 case 2:
1921 if (signedness == SignedTypedArray)
1922 m_jit.load16Signed(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg);
1923 else
1924 m_jit.load16(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesTwo), resultReg);
1925 break;
1926 case 4:
1927 m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg);
14957cd0 1928 break;
6fe7ccc8
A
1929 default:
1930 ASSERT_NOT_REACHED();
14957cd0 1931 }
6fe7ccc8
A
1932 outOfBounds.link(&m_jit);
1933 if (elementSize < 4 || signedness == SignedTypedArray) {
1934 integerResult(resultReg, m_compileIndex);
1935 return;
1936 }
1937
1938 ASSERT(elementSize == 4 && signedness == UnsignedTypedArray);
1939 if (node.shouldSpeculateInteger()) {
1940 forwardSpeculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultReg, TrustedImm32(0)), ValueRecovery::uint32InGPR(resultReg));
1941 integerResult(resultReg, m_compileIndex);
1942 return;
1943 }
1944
1945 FPRTemporary fresult(this);
1946 m_jit.convertInt32ToDouble(resultReg, fresult.fpr());
1947 JITCompiler::Jump positive = m_jit.branch32(MacroAssembler::GreaterThanOrEqual, resultReg, TrustedImm32(0));
1948 m_jit.addDouble(JITCompiler::AbsoluteAddress(&AssemblyHelpers::twoToThe32), fresult.fpr());
1949 positive.link(&m_jit);
1950 doubleResult(fresult.fpr(), m_compileIndex);
1951}
14957cd0 1952
6fe7ccc8
A
1953void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness, TypedArrayRounding rounding)
1954{
1955 Edge baseUse = node.child1();
1956 Edge valueUse = node.child3();
1957
1958 if (speculationRequirements != NoTypedArrayTypeSpecCheck)
1959 speculationCheck(BadType, JSValueSource::unboxedCell(base), baseUse, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
1960 GPRTemporary value;
1961 GPRReg valueGPR;
1962
1963 if (at(valueUse).isConstant()) {
1964 JSValue jsValue = valueOfJSConstant(valueUse.index());
1965 if (!jsValue.isNumber()) {
1966 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
1967 noResult(m_compileIndex);
1968 return;
1969 }
1970 double d = jsValue.asNumber();
1971 if (rounding == ClampRounding) {
1972 ASSERT(elementSize == 1);
1973 d = clampDoubleToByte(d);
1974 }
1975 GPRTemporary scratch(this);
1976 GPRReg scratchReg = scratch.gpr();
1977 m_jit.move(Imm32(toInt32(d)), scratchReg);
1978 value.adopt(scratch);
1979 valueGPR = scratchReg;
1980 } else if (at(valueUse).shouldSpeculateInteger()) {
1981 SpeculateIntegerOperand valueOp(this, valueUse);
1982 GPRTemporary scratch(this);
1983 GPRReg scratchReg = scratch.gpr();
1984 m_jit.move(valueOp.gpr(), scratchReg);
1985 if (rounding == ClampRounding) {
1986 ASSERT(elementSize == 1);
1987 compileClampIntegerToByte(m_jit, scratchReg);
1988 }
1989 value.adopt(scratch);
1990 valueGPR = scratchReg;
1991 } else if (rounding == ClampRounding) {
1992 ASSERT(elementSize == 1);
1993 SpeculateDoubleOperand valueOp(this, valueUse);
1994 GPRTemporary result(this);
1995 FPRTemporary floatScratch(this);
1996 FPRReg fpr = valueOp.fpr();
1997 GPRReg gpr = result.gpr();
1998 compileClampDoubleToByte(m_jit, gpr, fpr, floatScratch.fpr());
1999 value.adopt(result);
2000 valueGPR = gpr;
2001 } else {
2002 SpeculateDoubleOperand valueOp(this, valueUse);
2003 GPRTemporary result(this);
2004 FPRReg fpr = valueOp.fpr();
2005 GPRReg gpr = result.gpr();
2006 MacroAssembler::Jump notNaN = m_jit.branchDouble(MacroAssembler::DoubleEqual, fpr, fpr);
2007 m_jit.xorPtr(gpr, gpr);
2008 MacroAssembler::Jump fixed = m_jit.jump();
2009 notNaN.link(&m_jit);
2010
2011 MacroAssembler::Jump done;
2012 if (signedness == SignedTypedArray)
2013 done = m_jit.branchTruncateDoubleToInt32(fpr, gpr, MacroAssembler::BranchIfTruncateSuccessful);
2014 else
2015 done = m_jit.branchTruncateDoubleToUint32(fpr, gpr, MacroAssembler::BranchIfTruncateSuccessful);
14957cd0 2016
6fe7ccc8
A
2017 silentSpillAllRegisters(gpr);
2018 callOperation(toInt32, gpr, fpr);
2019 silentFillAllRegisters(gpr);
14957cd0 2020
6fe7ccc8
A
2021 done.link(&m_jit);
2022 fixed.link(&m_jit);
2023 value.adopt(result);
2024 valueGPR = gpr;
2025 }
2026 ASSERT_UNUSED(valueGPR, valueGPR != property);
2027 ASSERT(valueGPR != base);
2028 GPRTemporary storage(this);
2029 GPRReg storageReg = storage.gpr();
2030 ASSERT(valueGPR != storageReg);
2031 m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg);
2032 MacroAssembler::Jump outOfBounds;
2033 if (speculationRequirements != NoTypedArraySpecCheck)
2034 outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset));
2035
2036 switch (elementSize) {
2037 case 1:
2038 m_jit.store8(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesOne));
2039 break;
2040 case 2:
2041 m_jit.store16(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesTwo));
2042 break;
2043 case 4:
2044 m_jit.store32(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesFour));
14957cd0 2045 break;
6fe7ccc8
A
2046 default:
2047 ASSERT_NOT_REACHED();
14957cd0 2048 }
6fe7ccc8
A
2049 if (speculationRequirements != NoTypedArraySpecCheck)
2050 outOfBounds.link(&m_jit);
2051 noResult(m_compileIndex);
2052}
14957cd0 2053
6fe7ccc8
A
2054void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements)
2055{
2056 SpeculateCellOperand base(this, node.child1());
2057 SpeculateStrictInt32Operand property(this, node.child2());
2058 StorageOperand storage(this, node.child3());
2059
2060 GPRReg baseReg = base.gpr();
2061 GPRReg propertyReg = property.gpr();
2062 GPRReg storageReg = storage.gpr();
2063
2064 if (speculationRequirements != NoTypedArrayTypeSpecCheck) {
2065 ASSERT_NOT_REACHED();
2066 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
2067 noResult(m_compileIndex);
2068 return;
2069 }
14957cd0 2070
6fe7ccc8
A
2071 FPRTemporary result(this);
2072 FPRReg resultReg = result.fpr();
2073 ASSERT(speculationRequirements != NoTypedArraySpecCheck);
2074 MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, descriptor.m_lengthOffset));
2075 static const double zero = 0;
2076 m_jit.loadDouble(&zero, resultReg);
2077 MacroAssembler::Jump outOfBounds = m_jit.jump();
2078 inBounds.link(&m_jit);
2079 switch (elementSize) {
2080 case 4:
2081 m_jit.loadFloat(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg);
2082 m_jit.convertFloatToDouble(resultReg, resultReg);
2083 break;
2084 case 8: {
2085 m_jit.loadDouble(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight), resultReg);
2086 MacroAssembler::Jump notNaN = m_jit.branchDouble(MacroAssembler::DoubleEqual, resultReg, resultReg);
2087 static const double NaN = std::numeric_limits<double>::quiet_NaN();
2088 m_jit.loadDouble(&NaN, resultReg);
2089 notNaN.link(&m_jit);
2090 break;
2091 }
2092 default:
2093 ASSERT_NOT_REACHED();
2094 }
2095 outOfBounds.link(&m_jit);
2096 doubleResult(resultReg, m_compileIndex);
2097}
14957cd0 2098
6fe7ccc8
A
2099void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements)
2100{
2101 Edge baseUse = node.child1();
2102 Edge valueUse = node.child3();
2103
2104 SpeculateDoubleOperand valueOp(this, valueUse);
2105
2106 if (speculationRequirements != NoTypedArrayTypeSpecCheck)
2107 speculationCheck(BadType, JSValueSource::unboxedCell(base), baseUse.index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2108
2109 GPRTemporary result(this);
2110
2111 GPRTemporary storage(this);
2112 GPRReg storageReg = storage.gpr();
2113
2114 m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg);
2115 MacroAssembler::Jump outOfBounds;
2116 if (speculationRequirements != NoTypedArraySpecCheck)
2117 outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset));
2118
2119 switch (elementSize) {
2120 case 4: {
2121 FPRTemporary scratch(this);
2122 m_jit.moveDouble(valueOp.fpr(), scratch.fpr());
2123 m_jit.convertDoubleToFloat(valueOp.fpr(), scratch.fpr());
2124 m_jit.storeFloat(scratch.fpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesFour));
14957cd0
A
2125 break;
2126 }
6fe7ccc8
A
2127 case 8:
2128 m_jit.storeDouble(valueOp.fpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesEight));
14957cd0 2129 break;
6fe7ccc8
A
2130 default:
2131 ASSERT_NOT_REACHED();
14957cd0 2132 }
6fe7ccc8
A
2133 if (speculationRequirements != NoTypedArraySpecCheck)
2134 outOfBounds.link(&m_jit);
2135 noResult(m_compileIndex);
2136}
14957cd0 2137
6fe7ccc8
A
2138void SpeculativeJIT::compileInstanceOfForObject(Node&, GPRReg valueReg, GPRReg prototypeReg, GPRReg scratchReg)
2139{
2140 // Check that prototype is an object.
2141 m_jit.loadPtr(MacroAssembler::Address(prototypeReg, JSCell::structureOffset()), scratchReg);
2142 speculationCheck(BadType, JSValueRegs(), NoNode, m_jit.branchIfNotObject(scratchReg));
2143
2144 // Initialize scratchReg with the value being checked.
2145 m_jit.move(valueReg, scratchReg);
2146
2147 // Walk up the prototype chain of the value (in scratchReg), comparing to prototypeReg.
2148 MacroAssembler::Label loop(&m_jit);
2149 m_jit.loadPtr(MacroAssembler::Address(scratchReg, JSCell::structureOffset()), scratchReg);
2150#if USE(JSVALUE64)
2151 m_jit.loadPtr(MacroAssembler::Address(scratchReg, Structure::prototypeOffset()), scratchReg);
2152#else
2153 m_jit.load32(MacroAssembler::Address(scratchReg, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), scratchReg);
2154#endif
2155 MacroAssembler::Jump isInstance = m_jit.branchPtr(MacroAssembler::Equal, scratchReg, prototypeReg);
2156#if USE(JSVALUE64)
2157 m_jit.branchTestPtr(MacroAssembler::Zero, scratchReg, GPRInfo::tagMaskRegister).linkTo(loop, &m_jit);
2158#else
2159 m_jit.branchTest32(MacroAssembler::NonZero, scratchReg).linkTo(loop, &m_jit);
2160#endif
2161
2162 // No match - result is false.
2163#if USE(JSVALUE64)
2164 m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), scratchReg);
2165#else
2166 m_jit.move(MacroAssembler::TrustedImm32(0), scratchReg);
2167#endif
2168 MacroAssembler::Jump putResult = m_jit.jump();
2169
2170 isInstance.link(&m_jit);
2171#if USE(JSVALUE64)
2172 m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(true))), scratchReg);
2173#else
2174 m_jit.move(MacroAssembler::TrustedImm32(1), scratchReg);
2175#endif
2176
2177 putResult.link(&m_jit);
2178}
14957cd0 2179
6fe7ccc8
A
2180void SpeculativeJIT::compileInstanceOf(Node& node)
2181{
2182 if ((!!(at(node.child1()).prediction() & ~PredictCell)
2183 && !!(m_state.forNode(node.child1()).m_type & ~PredictCell))
2184 || at(node.child1()).adjustedRefCount() == 1) {
2185 // It might not be a cell. Speculate less aggressively.
2186 // Or: it might only be used once (i.e. by us), so we get zero benefit
2187 // from speculating any more aggressively than we absolutely need to.
2188
2189 JSValueOperand value(this, node.child1());
2190 SpeculateCellOperand prototype(this, node.child3());
2191 GPRTemporary scratch(this);
2192
2193 GPRReg prototypeReg = prototype.gpr();
2194 GPRReg scratchReg = scratch.gpr();
2195
2196#if USE(JSVALUE64)
2197 GPRReg valueReg = value.gpr();
2198 MacroAssembler::Jump isCell = m_jit.branchTestPtr(MacroAssembler::Zero, valueReg, GPRInfo::tagMaskRegister);
2199 m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), scratchReg);
2200#else
2201 GPRReg valueTagReg = value.tagGPR();
2202 GPRReg valueReg = value.payloadGPR();
2203 MacroAssembler::Jump isCell = m_jit.branch32(MacroAssembler::Equal, valueTagReg, TrustedImm32(JSValue::CellTag));
2204 m_jit.move(MacroAssembler::TrustedImm32(0), scratchReg);
2205#endif
14957cd0 2206
6fe7ccc8
A
2207 MacroAssembler::Jump done = m_jit.jump();
2208
2209 isCell.link(&m_jit);
2210
2211 compileInstanceOfForObject(node, valueReg, prototypeReg, scratchReg);
2212
2213 done.link(&m_jit);
14957cd0 2214
6fe7ccc8
A
2215#if USE(JSVALUE64)
2216 jsValueResult(scratchReg, m_compileIndex, DataFormatJSBoolean);
2217#else
2218 booleanResult(scratchReg, m_compileIndex);
2219#endif
2220 return;
14957cd0 2221 }
6fe7ccc8
A
2222
2223 SpeculateCellOperand value(this, node.child1());
2224 // Base unused since we speculate default InstanceOf behaviour in CheckHasInstance.
2225 SpeculateCellOperand prototype(this, node.child3());
2226
2227 GPRTemporary scratch(this);
2228
2229 GPRReg valueReg = value.gpr();
2230 GPRReg prototypeReg = prototype.gpr();
2231 GPRReg scratchReg = scratch.gpr();
2232
2233 compileInstanceOfForObject(node, valueReg, prototypeReg, scratchReg);
2234
2235#if USE(JSVALUE64)
2236 jsValueResult(scratchReg, m_compileIndex, DataFormatJSBoolean);
2237#else
2238 booleanResult(scratchReg, m_compileIndex);
2239#endif
2240}
14957cd0 2241
6fe7ccc8
A
2242void SpeculativeJIT::compileSoftModulo(Node& node)
2243{
2244 // In the fast path, the dividend value could be the final result
2245 // (in case of |dividend| < |divisor|), so we speculate it as strict int32.
2246 SpeculateStrictInt32Operand op1(this, node.child1());
2247#if CPU(X86) || CPU(X86_64)
2248 if (isInt32Constant(node.child2().index())) {
2249 int32_t divisor = valueOfInt32Constant(node.child2().index());
2250 if (divisor) {
2251 GPRReg op1Gpr = op1.gpr();
2252
2253 GPRTemporary eax(this, X86Registers::eax);
2254 GPRTemporary edx(this, X86Registers::edx);
2255 GPRTemporary scratch(this);
2256 GPRReg scratchGPR = scratch.gpr();
2257
2258 GPRReg op1SaveGPR;
2259 if (op1Gpr == X86Registers::eax || op1Gpr == X86Registers::edx) {
2260 op1SaveGPR = allocate();
2261 ASSERT(op1Gpr != op1SaveGPR);
2262 m_jit.move(op1Gpr, op1SaveGPR);
2263 } else
2264 op1SaveGPR = op1Gpr;
2265 ASSERT(op1SaveGPR != X86Registers::eax);
2266 ASSERT(op1SaveGPR != X86Registers::edx);
2267
2268 m_jit.move(op1Gpr, eax.gpr());
2269 m_jit.move(TrustedImm32(divisor), scratchGPR);
2270 if (divisor == -1)
2271 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branch32(JITCompiler::Equal, eax.gpr(), TrustedImm32(-2147483647-1)));
2272 m_jit.assembler().cdq();
2273 m_jit.assembler().idivl_r(scratchGPR);
2274 // Check that we're not about to create negative zero.
2275 // FIXME: if the node use doesn't care about neg zero, we can do this more easily.
2276 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, op1SaveGPR, TrustedImm32(0));
2277 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchTest32(JITCompiler::Zero, edx.gpr()));
2278 numeratorPositive.link(&m_jit);
2279
2280 if (op1SaveGPR != op1Gpr)
2281 unlock(op1SaveGPR);
14957cd0 2282
6fe7ccc8 2283 integerResult(edx.gpr(), m_compileIndex);
14957cd0
A
2284 return;
2285 }
14957cd0 2286 }
6fe7ccc8 2287#endif
14957cd0 2288
6fe7ccc8
A
2289 SpeculateIntegerOperand op2(this, node.child2());
2290#if CPU(X86) || CPU(X86_64)
2291 GPRTemporary eax(this, X86Registers::eax);
2292 GPRTemporary edx(this, X86Registers::edx);
2293 GPRReg op1GPR = op1.gpr();
2294 GPRReg op2GPR = op2.gpr();
2295
2296 GPRReg op2TempGPR;
2297 GPRReg temp;
2298 GPRReg op1SaveGPR;
2299
2300 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {
2301 op2TempGPR = allocate();
2302 temp = op2TempGPR;
2303 } else {
2304 op2TempGPR = InvalidGPRReg;
2305 if (op1GPR == X86Registers::eax)
2306 temp = X86Registers::edx;
2307 else
2308 temp = X86Registers::eax;
14957cd0 2309 }
6fe7ccc8
A
2310
2311 if (op1GPR == X86Registers::eax || op1GPR == X86Registers::edx) {
2312 op1SaveGPR = allocate();
2313 ASSERT(op1GPR != op1SaveGPR);
2314 m_jit.move(op1GPR, op1SaveGPR);
2315 } else
2316 op1SaveGPR = op1GPR;
2317
2318 ASSERT(temp != op1GPR);
2319 ASSERT(temp != op2GPR);
2320 ASSERT(op1SaveGPR != X86Registers::eax);
2321 ASSERT(op1SaveGPR != X86Registers::edx);
2322
2323 m_jit.add32(JITCompiler::TrustedImm32(1), op2GPR, temp);
2324
2325 JITCompiler::Jump safeDenominator = m_jit.branch32(JITCompiler::Above, temp, JITCompiler::TrustedImm32(1));
2326
2327 JITCompiler::Jump done;
2328 // FIXME: if the node is not used as number then we can do this more easily.
2329 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchTest32(JITCompiler::Zero, op2GPR));
2330 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branch32(JITCompiler::Equal, op1GPR, TrustedImm32(-2147483647-1)));
2331
2332 safeDenominator.link(&m_jit);
2333
2334 if (op2TempGPR != InvalidGPRReg) {
2335 m_jit.move(op2GPR, op2TempGPR);
2336 op2GPR = op2TempGPR;
2337 }
2338
2339 m_jit.move(op1GPR, eax.gpr());
2340 m_jit.assembler().cdq();
2341 m_jit.assembler().idivl_r(op2GPR);
2342
2343 if (op2TempGPR != InvalidGPRReg)
2344 unlock(op2TempGPR);
2345
2346 // Check that we're not about to create negative zero.
2347 // FIXME: if the node use doesn't care about neg zero, we can do this more easily.
2348 JITCompiler::Jump numeratorPositive = m_jit.branch32(JITCompiler::GreaterThanOrEqual, op1SaveGPR, TrustedImm32(0));
2349 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchTest32(JITCompiler::Zero, edx.gpr()));
2350 numeratorPositive.link(&m_jit);
2351
2352 if (op1SaveGPR != op1GPR)
2353 unlock(op1SaveGPR);
2354
2355 integerResult(edx.gpr(), m_compileIndex);
2356#else // CPU(X86) || CPU(X86_64) --> so not X86
2357 // Do this the *safest* way possible: call out to a C function that will do the modulo,
2358 // and then attempt to convert back.
2359 GPRReg op1GPR = op1.gpr();
2360 GPRReg op2GPR = op2.gpr();
2361
2362 FPRResult result(this);
2363
2364 flushRegisters();
2365 callOperation(operationFModOnInts, result.fpr(), op1GPR, op2GPR);
2366
2367 FPRTemporary scratch(this);
2368 GPRTemporary intResult(this);
2369 JITCompiler::JumpList failureCases;
2370 m_jit.branchConvertDoubleToInt32(result.fpr(), intResult.gpr(), failureCases, scratch.fpr());
2371 speculationCheck(Overflow, JSValueRegs(), NoNode, failureCases);
2372
2373 integerResult(intResult.gpr(), m_compileIndex);
2374#endif // CPU(X86) || CPU(X86_64)
2375}
14957cd0 2376
6fe7ccc8
A
2377void SpeculativeJIT::compileAdd(Node& node)
2378{
2379 if (m_jit.graph().addShouldSpeculateInteger(node)) {
2380 if (isNumberConstant(node.child1().index())) {
2381 int32_t imm1 = valueOfNumberConstantAsInt32(node.child1().index());
2382 SpeculateIntegerOperand op2(this, node.child2());
2383 GPRTemporary result(this);
14957cd0 2384
6fe7ccc8
A
2385 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2386 m_jit.move(op2.gpr(), result.gpr());
2387 m_jit.add32(Imm32(imm1), result.gpr());
2388 } else
2389 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr()));
14957cd0 2390
6fe7ccc8
A
2391 integerResult(result.gpr(), m_compileIndex);
2392 return;
14957cd0 2393 }
6fe7ccc8
A
2394
2395 if (isNumberConstant(node.child2().index())) {
2396 SpeculateIntegerOperand op1(this, node.child1());
2397 int32_t imm2 = valueOfNumberConstantAsInt32(node.child2().index());
2398 GPRTemporary result(this);
2399
2400 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2401 m_jit.move(op1.gpr(), result.gpr());
2402 m_jit.add32(Imm32(imm2), result.gpr());
2403 } else
2404 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
14957cd0 2405
6fe7ccc8
A
2406 integerResult(result.gpr(), m_compileIndex);
2407 return;
2408 }
2409
2410 SpeculateIntegerOperand op1(this, node.child1());
2411 SpeculateIntegerOperand op2(this, node.child2());
2412 GPRTemporary result(this, op1, op2);
14957cd0 2413
6fe7ccc8
A
2414 GPRReg gpr1 = op1.gpr();
2415 GPRReg gpr2 = op2.gpr();
2416 GPRReg gprResult = result.gpr();
14957cd0 2417
6fe7ccc8
A
2418 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2419 if (gpr1 == gprResult)
2420 m_jit.add32(gpr2, gprResult);
2421 else {
2422 m_jit.move(gpr2, gprResult);
2423 m_jit.add32(gpr1, gprResult);
2424 }
2425 } else {
2426 MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
2427
2428 if (gpr1 == gprResult)
2429 speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
2430 else if (gpr2 == gprResult)
2431 speculationCheck(Overflow, JSValueRegs(), NoNode, check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
2432 else
2433 speculationCheck(Overflow, JSValueRegs(), NoNode, check);
2434 }
14957cd0 2435
6fe7ccc8
A
2436 integerResult(gprResult, m_compileIndex);
2437 return;
14957cd0 2438 }
6fe7ccc8
A
2439
2440 if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
2441 SpeculateDoubleOperand op1(this, node.child1());
2442 SpeculateDoubleOperand op2(this, node.child2());
2443 FPRTemporary result(this, op1, op2);
14957cd0 2444
6fe7ccc8
A
2445 FPRReg reg1 = op1.fpr();
2446 FPRReg reg2 = op2.fpr();
2447 m_jit.addDouble(reg1, reg2, result.fpr());
14957cd0 2448
6fe7ccc8
A
2449 doubleResult(result.fpr(), m_compileIndex);
2450 return;
2451 }
14957cd0 2452
6fe7ccc8
A
2453 if (node.op() == ValueAdd) {
2454 compileValueAdd(node);
2455 return;
2456 }
2457
2458 // We don't handle this yet. :-(
2459 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
2460}
14957cd0 2461
6fe7ccc8
A
2462void SpeculativeJIT::compileArithSub(Node& node)
2463{
2464 if (m_jit.graph().addShouldSpeculateInteger(node)) {
2465 if (isNumberConstant(node.child2().index())) {
2466 SpeculateIntegerOperand op1(this, node.child1());
2467 int32_t imm2 = valueOfNumberConstantAsInt32(node.child2().index());
2468 GPRTemporary result(this);
14957cd0 2469
6fe7ccc8
A
2470 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2471 m_jit.move(op1.gpr(), result.gpr());
2472 m_jit.sub32(Imm32(imm2), result.gpr());
2473 } else {
2474#if ENABLE(JIT_CONSTANT_BLINDING)
2475 GPRTemporary scratch(this);
2476 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr(), scratch.gpr()));
2477#else
2478 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
2479#endif
2480 }
14957cd0 2481
6fe7ccc8
A
2482 integerResult(result.gpr(), m_compileIndex);
2483 return;
2484 }
2485
2486 if (isNumberConstant(node.child1().index())) {
2487 int32_t imm1 = valueOfNumberConstantAsInt32(node.child1().index());
2488 SpeculateIntegerOperand op2(this, node.child2());
2489 GPRTemporary result(this);
2490
2491 m_jit.move(Imm32(imm1), result.gpr());
2492 if (nodeCanTruncateInteger(node.arithNodeFlags()))
2493 m_jit.sub32(op2.gpr(), result.gpr());
2494 else
2495 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op2.gpr(), result.gpr()));
2496
2497 integerResult(result.gpr(), m_compileIndex);
2498 return;
2499 }
2500
2501 SpeculateIntegerOperand op1(this, node.child1());
2502 SpeculateIntegerOperand op2(this, node.child2());
2503 GPRTemporary result(this);
14957cd0 2504
6fe7ccc8
A
2505 if (nodeCanTruncateInteger(node.arithNodeFlags())) {
2506 m_jit.move(op1.gpr(), result.gpr());
2507 m_jit.sub32(op2.gpr(), result.gpr());
2508 } else
2509 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
14957cd0 2510
6fe7ccc8
A
2511 integerResult(result.gpr(), m_compileIndex);
2512 return;
14957cd0 2513 }
6fe7ccc8
A
2514
2515 SpeculateDoubleOperand op1(this, node.child1());
2516 SpeculateDoubleOperand op2(this, node.child2());
2517 FPRTemporary result(this, op1);
14957cd0 2518
6fe7ccc8
A
2519 FPRReg reg1 = op1.fpr();
2520 FPRReg reg2 = op2.fpr();
2521 m_jit.subDouble(reg1, reg2, result.fpr());
14957cd0 2522
6fe7ccc8
A
2523 doubleResult(result.fpr(), m_compileIndex);
2524}
14957cd0 2525
6fe7ccc8
A
2526void SpeculativeJIT::compileArithNegate(Node& node)
2527{
2528 if (m_jit.graph().negateShouldSpeculateInteger(node)) {
2529 SpeculateIntegerOperand op1(this, node.child1());
2530 GPRTemporary result(this);
14957cd0 2531
6fe7ccc8 2532 m_jit.move(op1.gpr(), result.gpr());
14957cd0 2533
6fe7ccc8
A
2534 if (nodeCanTruncateInteger(node.arithNodeFlags()))
2535 m_jit.neg32(result.gpr());
2536 else {
2537 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchNeg32(MacroAssembler::Overflow, result.gpr()));
2538 if (!nodeCanIgnoreNegativeZero(node.arithNodeFlags()))
2539 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, result.gpr()));
2540 }
14957cd0 2541
6fe7ccc8
A
2542 integerResult(result.gpr(), m_compileIndex);
2543 return;
14957cd0 2544 }
6fe7ccc8
A
2545
2546 SpeculateDoubleOperand op1(this, node.child1());
2547 FPRTemporary result(this);
14957cd0 2548
6fe7ccc8 2549 m_jit.negateDouble(op1.fpr(), result.fpr());
14957cd0 2550
6fe7ccc8
A
2551 doubleResult(result.fpr(), m_compileIndex);
2552}
14957cd0 2553
6fe7ccc8
A
2554void SpeculativeJIT::compileArithMul(Node& node)
2555{
2556 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())) && node.canSpeculateInteger()) {
2557 SpeculateIntegerOperand op1(this, node.child1());
2558 SpeculateIntegerOperand op2(this, node.child2());
2559 GPRTemporary result(this);
14957cd0 2560
6fe7ccc8
A
2561 GPRReg reg1 = op1.gpr();
2562 GPRReg reg2 = op2.gpr();
14957cd0 2563
6fe7ccc8
A
2564 // What is unfortunate is that we cannot take advantage of nodeCanTruncateInteger()
2565 // here. A multiply on integers performed in the double domain and then truncated to
2566 // an integer will give a different result than a multiply performed in the integer
2567 // domain and then truncated, if the integer domain result would have resulted in
2568 // something bigger than what a 32-bit integer can hold. JavaScript mandates that
2569 // the semantics are always as if the multiply had been performed in the double
2570 // domain.
2571
2572 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr()));
2573
2574 // Check for negative zero, if the users of this node care about such things.
2575 if (!nodeCanIgnoreNegativeZero(node.arithNodeFlags())) {
2576 MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.gpr());
2577 speculationCheck(NegativeZero, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, reg1, TrustedImm32(0)));
2578 speculationCheck(NegativeZero, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, reg2, TrustedImm32(0)));
2579 resultNonZero.link(&m_jit);
14957cd0
A
2580 }
2581
6fe7ccc8
A
2582 integerResult(result.gpr(), m_compileIndex);
2583 return;
14957cd0
A
2584 }
2585
6fe7ccc8
A
2586 SpeculateDoubleOperand op1(this, node.child1());
2587 SpeculateDoubleOperand op2(this, node.child2());
2588 FPRTemporary result(this, op1, op2);
14957cd0 2589
6fe7ccc8
A
2590 FPRReg reg1 = op1.fpr();
2591 FPRReg reg2 = op2.fpr();
14957cd0 2592
6fe7ccc8
A
2593 m_jit.mulDouble(reg1, reg2, result.fpr());
2594
2595 doubleResult(result.fpr(), m_compileIndex);
2596}
14957cd0 2597
6fe7ccc8
A
2598#if CPU(X86) || CPU(X86_64)
2599void SpeculativeJIT::compileIntegerArithDivForX86(Node& node)
2600{
2601 SpeculateIntegerOperand op1(this, node.child1());
2602 SpeculateIntegerOperand op2(this, node.child2());
2603 GPRTemporary eax(this, X86Registers::eax);
2604 GPRTemporary edx(this, X86Registers::edx);
2605 GPRReg op1GPR = op1.gpr();
2606 GPRReg op2GPR = op2.gpr();
2607
2608 GPRReg op2TempGPR;
2609 GPRReg temp;
2610 if (op2GPR == X86Registers::eax || op2GPR == X86Registers::edx) {
2611 op2TempGPR = allocate();
2612 temp = op2TempGPR;
2613 } else {
2614 op2TempGPR = InvalidGPRReg;
2615 if (op1GPR == X86Registers::eax)
2616 temp = X86Registers::edx;
2617 else
2618 temp = X86Registers::eax;
14957cd0 2619 }
6fe7ccc8
A
2620
2621 ASSERT(temp != op1GPR);
2622 ASSERT(temp != op2GPR);
2623
2624 m_jit.add32(JITCompiler::TrustedImm32(1), op2GPR, temp);
2625
2626 JITCompiler::Jump safeDenominator = m_jit.branch32(JITCompiler::Above, temp, JITCompiler::TrustedImm32(1));
2627
2628 JITCompiler::Jump done;
2629 if (nodeUsedAsNumber(node.arithNodeFlags())) {
2630 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchTest32(JITCompiler::Zero, op2GPR));
2631 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branch32(JITCompiler::Equal, op1GPR, TrustedImm32(-2147483647-1)));
2632 } else {
2633 JITCompiler::Jump zero = m_jit.branchTest32(JITCompiler::Zero, op2GPR);
2634 JITCompiler::Jump notNeg2ToThe31 = m_jit.branch32(JITCompiler::Equal, op1GPR, TrustedImm32(-2147483647-1));
2635 zero.link(&m_jit);
2636 m_jit.move(TrustedImm32(0), eax.gpr());
2637 done = m_jit.jump();
2638 notNeg2ToThe31.link(&m_jit);
14957cd0 2639 }
6fe7ccc8
A
2640
2641 safeDenominator.link(&m_jit);
2642
2643 // If the user cares about negative zero, then speculate that we're not about
2644 // to produce negative zero.
2645 if (!nodeCanIgnoreNegativeZero(node.arithNodeFlags())) {
2646 MacroAssembler::Jump numeratorNonZero = m_jit.branchTest32(MacroAssembler::NonZero, op1GPR);
2647 speculationCheck(NegativeZero, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, op2GPR, TrustedImm32(0)));
2648 numeratorNonZero.link(&m_jit);
14957cd0 2649 }
6fe7ccc8
A
2650
2651 if (op2TempGPR != InvalidGPRReg) {
2652 m_jit.move(op2GPR, op2TempGPR);
2653 op2GPR = op2TempGPR;
14957cd0 2654 }
6fe7ccc8
A
2655
2656 m_jit.move(op1GPR, eax.gpr());
2657 m_jit.assembler().cdq();
2658 m_jit.assembler().idivl_r(op2GPR);
2659
2660 if (op2TempGPR != InvalidGPRReg)
2661 unlock(op2TempGPR);
2662
2663 // Check that there was no remainder. If there had been, then we'd be obligated to
2664 // produce a double result instead.
2665 if (nodeUsedAsNumber(node.arithNodeFlags()))
2666 speculationCheck(Overflow, JSValueRegs(), NoNode, m_jit.branchTest32(JITCompiler::NonZero, edx.gpr()));
2667 else
2668 done.link(&m_jit);
2669
2670 integerResult(eax.gpr(), m_compileIndex);
2671}
2672#endif // CPU(X86) || CPU(X86_64)
14957cd0 2673
6fe7ccc8
A
2674void SpeculativeJIT::compileArithMod(Node& node)
2675{
2676 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))
2677 && node.canSpeculateInteger()) {
2678 compileSoftModulo(node);
2679 return;
14957cd0 2680 }
6fe7ccc8
A
2681
2682 SpeculateDoubleOperand op1(this, node.child1());
2683 SpeculateDoubleOperand op2(this, node.child2());
2684
2685 FPRReg op1FPR = op1.fpr();
2686 FPRReg op2FPR = op2.fpr();
2687
2688 flushRegisters();
2689
2690 FPRResult result(this);
14957cd0 2691
6fe7ccc8
A
2692 callOperation(fmodAsDFGOperation, result.fpr(), op1FPR, op2FPR);
2693
2694 doubleResult(result.fpr(), m_compileIndex);
2695}
14957cd0 2696
6fe7ccc8
A
2697// Returns true if the compare is fused with a subsequent branch.
2698bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_DFGOperation_EJJ operation)
2699{
2700 if (compilePeepHoleBranch(node, condition, doubleCondition, operation))
2701 return true;
14957cd0 2702
6fe7ccc8
A
2703 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))) {
2704 compileIntegerCompare(node, condition);
2705 return false;
14957cd0 2706 }
6fe7ccc8
A
2707
2708 if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
2709 compileDoubleCompare(node, doubleCondition);
2710 return false;
14957cd0 2711 }
6fe7ccc8
A
2712
2713 if (node.op() == CompareEq) {
2714 if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) {
2715 compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectPrediction);
2716 return false;
2717 }
2718
2719 if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) {
2720 compileObjectEquality(node, &JSArray::s_info, isArrayPrediction);
2721 return false;
2722 }
2723
2724 if (at(node.child1()).shouldSpeculateFinalObject()
2725 && at(node.child2()).shouldSpeculateFinalObjectOrOther()) {
2726 compileObjectToObjectOrOtherEquality(
2727 node.child1(), node.child2(), &JSFinalObject::s_info,
2728 isFinalObjectPrediction);
2729 return false;
2730 }
2731
2732 if (at(node.child1()).shouldSpeculateFinalObjectOrOther()
2733 && at(node.child2()).shouldSpeculateFinalObject()) {
2734 compileObjectToObjectOrOtherEquality(
2735 node.child2(), node.child1(), &JSFinalObject::s_info,
2736 isFinalObjectPrediction);
2737 return false;
2738 }
2739
2740 if (at(node.child1()).shouldSpeculateArray()
2741 && at(node.child2()).shouldSpeculateArrayOrOther()) {
2742 compileObjectToObjectOrOtherEquality(
2743 node.child1(), node.child2(), &JSArray::s_info,
2744 isArrayPrediction);
2745 return false;
2746 }
2747
2748 if (at(node.child1()).shouldSpeculateArrayOrOther()
2749 && at(node.child2()).shouldSpeculateArray()) {
2750 compileObjectToObjectOrOtherEquality(
2751 node.child2(), node.child1(), &JSArray::s_info,
2752 isArrayPrediction);
2753 return false;
2754 }
2755 }
2756
2757 nonSpeculativeNonPeepholeCompare(node, condition, operation);
2758 return false;
14957cd0
A
2759}
2760
6fe7ccc8 2761bool SpeculativeJIT::compileStrictEqForConstant(Node& node, Edge value, JSValue constant)
14957cd0 2762{
6fe7ccc8
A
2763 JSValueOperand op1(this, value);
2764
2765 unsigned branchIndexInBlock = detectPeepHoleBranch();
2766 if (branchIndexInBlock != UINT_MAX) {
2767 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
2768 Node& branchNode = at(branchNodeIndex);
2769 BlockIndex taken = branchNode.takenBlockIndex();
2770 BlockIndex notTaken = branchNode.notTakenBlockIndex();
2771 MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;
2772
2773 // The branch instruction will branch to the taken block.
2774 // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
2775 if (taken == (m_block + 1)) {
2776 condition = MacroAssembler::NotEqual;
2777 BlockIndex tmp = taken;
2778 taken = notTaken;
2779 notTaken = tmp;
2780 }
14957cd0 2781
6fe7ccc8
A
2782#if USE(JSVALUE64)
2783 branchPtr(condition, op1.gpr(), MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(constant))), taken);
2784#else
2785 GPRReg payloadGPR = op1.payloadGPR();
2786 GPRReg tagGPR = op1.tagGPR();
2787 if (condition == MacroAssembler::Equal) {
2788 // Drop down if not equal, go elsewhere if equal.
2789 MacroAssembler::Jump notEqual = m_jit.branch32(MacroAssembler::NotEqual, tagGPR, MacroAssembler::Imm32(constant.tag()));
2790 branch32(MacroAssembler::Equal, payloadGPR, MacroAssembler::Imm32(constant.payload()), taken);
2791 notEqual.link(&m_jit);
2792 } else {
2793 // Drop down if equal, go elsehwere if not equal.
2794 branch32(MacroAssembler::NotEqual, tagGPR, MacroAssembler::Imm32(constant.tag()), taken);
2795 branch32(MacroAssembler::NotEqual, payloadGPR, MacroAssembler::Imm32(constant.payload()), taken);
2796 }
14957cd0 2797#endif
6fe7ccc8
A
2798
2799 jump(notTaken);
2800
2801 use(node.child1());
2802 use(node.child2());
2803 m_indexInBlock = branchIndexInBlock;
2804 m_compileIndex = branchNodeIndex;
2805 return true;
14957cd0 2806 }
6fe7ccc8
A
2807
2808 GPRTemporary result(this);
2809
2810#if USE(JSVALUE64)
2811 GPRReg op1GPR = op1.gpr();
2812 GPRReg resultGPR = result.gpr();
2813 m_jit.move(MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(ValueFalse)), resultGPR);
2814 MacroAssembler::Jump notEqual = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(constant))));
2815 m_jit.or32(MacroAssembler::TrustedImm32(1), resultGPR);
2816 notEqual.link(&m_jit);
2817 jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);
2818#else
2819 GPRReg op1PayloadGPR = op1.payloadGPR();
2820 GPRReg op1TagGPR = op1.tagGPR();
2821 GPRReg resultGPR = result.gpr();
2822 m_jit.move(TrustedImm32(0), resultGPR);
2823 MacroAssembler::JumpList notEqual;
2824 notEqual.append(m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, MacroAssembler::Imm32(constant.tag())));
2825 notEqual.append(m_jit.branch32(MacroAssembler::NotEqual, op1PayloadGPR, MacroAssembler::Imm32(constant.payload())));
2826 m_jit.move(TrustedImm32(1), resultGPR);
2827 notEqual.link(&m_jit);
2828 booleanResult(resultGPR, m_compileIndex);
2829#endif
2830
2831 return false;
14957cd0
A
2832}
2833
6fe7ccc8 2834bool SpeculativeJIT::compileStrictEq(Node& node)
14957cd0 2835{
6fe7ccc8
A
2836 // 1) If either operand is a constant and that constant is not a double, integer,
2837 // or string, then do a JSValue comparison.
2838
2839 if (isJSConstant(node.child1().index())) {
2840 JSValue value = valueOfJSConstant(node.child1().index());
2841 if (!value.isNumber() && !value.isString())
2842 return compileStrictEqForConstant(node, node.child2(), value);
2843 }
2844
2845 if (isJSConstant(node.child2().index())) {
2846 JSValue value = valueOfJSConstant(node.child2().index());
2847 if (!value.isNumber() && !value.isString())
2848 return compileStrictEqForConstant(node, node.child1(), value);
2849 }
2850
2851 // 2) If the operands are predicted integer, do an integer comparison.
2852
2853 if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))) {
2854 unsigned branchIndexInBlock = detectPeepHoleBranch();
2855 if (branchIndexInBlock != UINT_MAX) {
2856 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
2857 compilePeepHoleIntegerBranch(node, branchNodeIndex, MacroAssembler::Equal);
2858 use(node.child1());
2859 use(node.child2());
2860 m_indexInBlock = branchIndexInBlock;
2861 m_compileIndex = branchNodeIndex;
2862 return true;
14957cd0 2863 }
6fe7ccc8
A
2864 compileIntegerCompare(node, MacroAssembler::Equal);
2865 return false;
2866 }
2867
2868 // 3) If the operands are predicted double, do a double comparison.
2869
2870 if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
2871 unsigned branchIndexInBlock = detectPeepHoleBranch();
2872 if (branchIndexInBlock != UINT_MAX) {
2873 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
2874 compilePeepHoleDoubleBranch(node, branchNodeIndex, MacroAssembler::DoubleEqual);
2875 use(node.child1());
2876 use(node.child2());
2877 m_indexInBlock = branchIndexInBlock;
2878 m_compileIndex = branchNodeIndex;
2879 return true;
14957cd0 2880 }
6fe7ccc8
A
2881 compileDoubleCompare(node, MacroAssembler::DoubleEqual);
2882 return false;
14957cd0 2883 }
6fe7ccc8
A
2884
2885 // 4) If the operands are predicted final object or array, then do a final object
2886 // or array comparison.
2887
2888 if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) {
2889 unsigned branchIndexInBlock = detectPeepHoleBranch();
2890 if (branchIndexInBlock != UINT_MAX) {
2891 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
2892 compilePeepHoleObjectEquality(node, branchNodeIndex, &JSFinalObject::s_info, isFinalObjectPrediction);
2893 use(node.child1());
2894 use(node.child2());
2895 m_indexInBlock = branchIndexInBlock;
2896 m_compileIndex = branchNodeIndex;
2897 return true;
2898 }
2899 compileObjectEquality(node, &JSFinalObject::s_info, isFinalObjectPrediction);
2900 return false;
2901 }
2902
2903 if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) {
2904 unsigned branchIndexInBlock = detectPeepHoleBranch();
2905 if (branchIndexInBlock != UINT_MAX) {
2906 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
2907 compilePeepHoleObjectEquality(node, branchNodeIndex, &JSArray::s_info, isArrayPrediction);
2908 use(node.child1());
2909 use(node.child2());
2910 m_indexInBlock = branchIndexInBlock;
2911 m_compileIndex = branchNodeIndex;
2912 return true;
2913 }
2914 compileObjectEquality(node, &JSArray::s_info, isArrayPrediction);
2915 return false;
2916 }
2917
2918 // 5) Fall back to non-speculative strict equality.
2919
2920 return nonSpeculativeStrictEq(node);
14957cd0
A
2921}
2922
6fe7ccc8 2923void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node)
14957cd0 2924{
6fe7ccc8
A
2925 if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) {
2926 terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode);
2927 return;
2928 }
2929
2930 SpeculateCellOperand base(this, node.child1());
2931 GPRReg baseReg = base.gpr();
2932
2933 PredictedType basePrediction = at(node.child2()).prediction();
2934 if (!(basePrediction & PredictInt32) && basePrediction) {
2935 ASSERT_NOT_REACHED();
2936 terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode);
2937 noResult(m_compileIndex);
2938 return;
2939 }
2940
2941 GPRTemporary storage(this);
2942 GPRReg storageReg = storage.gpr();
2943 if (at(node.child1()).prediction() == PredictString) {
2944 if (!isStringPrediction(m_state.forNode(node.child1()).m_type))
2945 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSString::s_info)));
2946
2947 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg);
2948
2949 // Speculate that we're not accessing a rope
2950 speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, storageReg));
2951
2952 m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg);
2953 } else if (at(node.child1()).shouldSpeculateInt8Array()) {
2954 const TypedArrayDescriptor& descriptor = m_jit.globalData()->int8ArrayDescriptor();
2955 if (!isInt8ArrayPrediction(m_state.forNode(node.child1()).m_type))
2956 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2957 m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
2958 } else if (at(node.child1()).shouldSpeculateInt16Array()) {
2959 const TypedArrayDescriptor& descriptor = m_jit.globalData()->int16ArrayDescriptor();
2960 if (!isInt16ArrayPrediction(m_state.forNode(node.child1()).m_type))
2961 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2962 m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
2963 } else if (at(node.child1()).shouldSpeculateInt32Array()) {
2964 const TypedArrayDescriptor& descriptor = m_jit.globalData()->int32ArrayDescriptor();
2965 if (!isInt32ArrayPrediction(m_state.forNode(node.child1()).m_type))
2966 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2967 m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
2968 } else if (at(node.child1()).shouldSpeculateUint8Array()) {
2969 const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ArrayDescriptor();
2970 if (!isUint8ArrayPrediction(m_state.forNode(node.child1()).m_type))
2971 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2972 m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
2973 } else if (at(node.child1()).shouldSpeculateUint8ClampedArray()) {
2974 const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ClampedArrayDescriptor();
2975 if (!isUint8ClampedArrayPrediction(m_state.forNode(node.child1()).m_type))
2976 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2977 m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
2978 } else if (at(node.child1()).shouldSpeculateUint16Array()) {
2979 const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint16ArrayDescriptor();
2980 if (!isUint16ArrayPrediction(m_state.forNode(node.child1()).m_type))
2981 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2982 m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
2983 } else if (at(node.child1()).shouldSpeculateUint32Array()) {
2984 const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint32ArrayDescriptor();
2985 if (!isUint32ArrayPrediction(m_state.forNode(node.child1()).m_type))
2986 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2987 m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
2988 } else if (at(node.child1()).shouldSpeculateFloat32Array()) {
2989 const TypedArrayDescriptor& descriptor = m_jit.globalData()->float32ArrayDescriptor();
2990 if (!isFloat32ArrayPrediction(m_state.forNode(node.child1()).m_type))
2991 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2992 m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
2993 } else if (at(node.child1()).shouldSpeculateFloat64Array()) {
2994 const TypedArrayDescriptor& descriptor = m_jit.globalData()->float64ArrayDescriptor();
2995 if (!isFloat64ArrayPrediction(m_state.forNode(node.child1()).m_type))
2996 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo)));
2997 m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg);
2998 } else {
2999 if (!isArrayPrediction(m_state.forNode(node.child1()).m_type))
3000 speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSArray::s_info)));
3001 m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
14957cd0 3002 }
6fe7ccc8 3003 storageResult(storageReg, m_compileIndex);
14957cd0
A
3004}
3005
6fe7ccc8 3006void SpeculativeJIT::compileNewFunctionNoCheck(Node& node)
14957cd0 3007{
6fe7ccc8
A
3008 GPRResult result(this);
3009 GPRReg resultGPR = result.gpr();
3010 flushRegisters();
3011 callOperation(
3012 operationNewFunction, resultGPR, m_jit.codeBlock()->functionDecl(node.functionDeclIndex()));
3013 cellResult(resultGPR, m_compileIndex);
3014}
14957cd0 3015
6fe7ccc8
A
3016void SpeculativeJIT::compileNewFunctionExpression(Node& node)
3017{
3018 GPRResult result(this);
3019 GPRReg resultGPR = result.gpr();
3020 flushRegisters();
3021 callOperation(
3022 operationNewFunctionExpression,
3023 resultGPR,
3024 m_jit.codeBlock()->functionExpr(node.functionExprIndex()));
3025 cellResult(resultGPR, m_compileIndex);
3026}
3027
3028bool SpeculativeJIT::compileRegExpExec(Node& node)
3029{
3030 unsigned branchIndexInBlock = detectPeepHoleBranch();
3031 if (branchIndexInBlock == UINT_MAX)
3032 return false;
3033 NodeIndex branchNodeIndex = m_jit.graph().m_blocks[m_block]->at(branchIndexInBlock);
3034 ASSERT(node.adjustedRefCount() == 1);
3035
3036 Node& branchNode = at(branchNodeIndex);
3037 BlockIndex taken = branchNode.takenBlockIndex();
3038 BlockIndex notTaken = branchNode.notTakenBlockIndex();
3039
3040 bool invert = false;
3041 if (taken == (m_block + 1)) {
3042 invert = true;
3043 BlockIndex tmp = taken;
3044 taken = notTaken;
3045 notTaken = tmp;
14957cd0 3046 }
6fe7ccc8
A
3047
3048 SpeculateCellOperand base(this, node.child1());
3049 SpeculateCellOperand argument(this, node.child2());
3050 GPRReg baseGPR = base.gpr();
3051 GPRReg argumentGPR = argument.gpr();
3052
3053 flushRegisters();
3054 GPRResult result(this);
3055 callOperation(operationRegExpTest, result.gpr(), baseGPR, argumentGPR);
3056
3057 branchTest32(invert ? JITCompiler::Zero : JITCompiler::NonZero, result.gpr(), taken);
3058 jump(notTaken);
3059
3060 use(node.child1());
3061 use(node.child2());
3062 m_indexInBlock = branchIndexInBlock;
3063 m_compileIndex = branchNodeIndex;
3064
14957cd0
A
3065 return true;
3066}
3067
3068} } // namespace JSC::DFG
3069
3070#endif