DFG byte array support sometimes clamps values incorrectly
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGSpeculativeJIT.cpp
1 /*
2  * Copyright (C) 2011 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #include "DFGSpeculativeJIT.h"
29 #include "JSByteArray.h"
30
31 #if ENABLE(DFG_JIT)
32
33 #if USE(JSVALUE32_64)
34 #include "DFGJITCompilerInlineMethods.h"
35 #endif
36
37 namespace JSC { namespace DFG {
38
39 #ifndef NDEBUG
40 void ValueSource::dump(FILE* out) const
41 {
42     switch (kind()) {
43     case SourceNotSet:
44         fprintf(out, "NotSet");
45         break;
46     case ValueInRegisterFile:
47         fprintf(out, "InRegFile");
48         break;
49     case Int32InRegisterFile:
50         fprintf(out, "Int32");
51         break;
52     case CellInRegisterFile:
53         fprintf(out, "Cell");
54         break;
55     case BooleanInRegisterFile:
56         fprintf(out, "Bool");
57         break;
58     case HaveNode:
59         fprintf(out, "Node(%d)", m_nodeIndex);
60         break;
61     }
62 }
63 #endif
64
65 void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition)
66 {
67     Node& branchNode = at(branchNodeIndex);
68     BlockIndex taken = branchNode.takenBlockIndex();
69     BlockIndex notTaken = branchNode.notTakenBlockIndex();
70     
71     SpeculateDoubleOperand op1(this, node.child1());
72     SpeculateDoubleOperand op2(this, node.child2());
73     
74     addBranch(m_jit.branchDouble(condition, op1.fpr(), op2.fpr()), taken);
75     
76     if (notTaken != (m_block + 1))
77         addBranch(m_jit.jump(), notTaken);
78 }
79
80 void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, void* vptr, PredictionChecker predictionCheck)
81 {
82     Node& branchNode = at(branchNodeIndex);
83     BlockIndex taken = branchNode.takenBlockIndex();
84     BlockIndex notTaken = branchNode.notTakenBlockIndex();
85
86     MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;
87     
88     if (taken == (m_block + 1)) {
89         condition = MacroAssembler::NotEqual;
90         BlockIndex tmp = taken;
91         taken = notTaken;
92         notTaken = tmp;
93     }
94
95     SpeculateCellOperand op1(this, node.child1());
96     SpeculateCellOperand op2(this, node.child2());
97     
98     GPRReg op1GPR = op1.gpr();
99     GPRReg op2GPR = op2.gpr();
100     
101     if (!predictionCheck(m_state.forNode(node.child1()).m_type))
102         speculationCheck(JSValueSource::unboxedCell(op1GPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR), MacroAssembler::TrustedImmPtr(vptr)));
103     if (!predictionCheck(m_state.forNode(node.child2()).m_type))
104         speculationCheck(JSValueSource::unboxedCell(op2GPR), node.child2(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR), MacroAssembler::TrustedImmPtr(vptr)));
105     
106     addBranch(m_jit.branchPtr(condition, op1GPR, op2GPR), taken);
107     if (notTaken != (m_block + 1))
108         addBranch(m_jit.jump(), notTaken);
109 }
110
111 void SpeculativeJIT::compilePeepHoleIntegerBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition condition)
112 {
113     Node& branchNode = at(branchNodeIndex);
114     BlockIndex taken = branchNode.takenBlockIndex();
115     BlockIndex notTaken = branchNode.notTakenBlockIndex();
116
117     // The branch instruction will branch to the taken block.
118     // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
119     if (taken == (m_block + 1)) {
120         condition = JITCompiler::invert(condition);
121         BlockIndex tmp = taken;
122         taken = notTaken;
123         notTaken = tmp;
124     }
125
126     if (isInt32Constant(node.child1())) {
127         int32_t imm = valueOfInt32Constant(node.child1());
128         SpeculateIntegerOperand op2(this, node.child2());
129         addBranch(m_jit.branch32(condition, JITCompiler::Imm32(imm), op2.gpr()), taken);
130     } else if (isInt32Constant(node.child2())) {
131         SpeculateIntegerOperand op1(this, node.child1());
132         int32_t imm = valueOfInt32Constant(node.child2());
133         addBranch(m_jit.branch32(condition, op1.gpr(), JITCompiler::Imm32(imm)), taken);
134     } else {
135         SpeculateIntegerOperand op1(this, node.child1());
136         SpeculateIntegerOperand op2(this, node.child2());
137         addBranch(m_jit.branch32(condition, op1.gpr(), op2.gpr()), taken);
138     }
139
140     // Check for fall through, otherwise we need to jump.
141     if (notTaken != (m_block + 1))
142         addBranch(m_jit.jump(), notTaken);
143 }
144
145 // Returns true if the compare is fused with a subsequent branch.
146 bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_DFGOperation_EJJ operation)
147 {
148     // Fused compare & branch.
149     NodeIndex branchNodeIndex = detectPeepHoleBranch();
150     if (branchNodeIndex != NoNode) {
151         // detectPeepHoleBranch currently only permits the branch to be the very next node,
152         // so can be no intervening nodes to also reference the compare. 
153         ASSERT(node.adjustedRefCount() == 1);
154
155         if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))) {
156             compilePeepHoleIntegerBranch(node, branchNodeIndex, condition);
157             use(node.child1());
158             use(node.child2());
159         } else if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
160             compilePeepHoleDoubleBranch(node, branchNodeIndex, doubleCondition);
161             use(node.child1());
162             use(node.child2());
163         } else if (node.op == CompareEq && Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) {
164             compilePeepHoleObjectEquality(node, branchNodeIndex, m_jit.globalData()->jsFinalObjectVPtr, isFinalObjectPrediction);
165             use(node.child1());
166             use(node.child2());
167         } else if (node.op == CompareEq && Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) {
168             compilePeepHoleObjectEquality(node, branchNodeIndex, m_jit.globalData()->jsArrayVPtr, isArrayPrediction);
169             use(node.child1());
170             use(node.child2());
171         } else
172             nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation);
173
174         m_compileIndex = branchNodeIndex;
175         return true;
176     }
177     return false;
178 }
179
180 void SpeculativeJIT::compileMovHint(Node& node)
181 {
182     ASSERT(node.op == SetLocal);
183     
184     setNodeIndexForOperand(node.child1(), node.local());
185     m_lastSetOperand = node.local();
186 }
187
188 void SpeculativeJIT::compile(BasicBlock& block)
189 {
190     ASSERT(m_compileOkay);
191     ASSERT(m_compileIndex == block.begin);
192     
193     if (!block.isReachable) {
194         m_compileIndex = block.end;
195         return;
196     }
197
198     m_blockHeads[m_block] = m_jit.label();
199 #if DFG_ENABLE(JIT_BREAK_ON_EVERY_BLOCK)
200     m_jit.breakpoint();
201 #endif
202
203     ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments());
204     for (size_t i = 0; i < m_arguments.size(); ++i) {
205         NodeIndex nodeIndex = block.variablesAtHead.argument(i);
206         if (nodeIndex == NoNode)
207             m_arguments[i] = ValueSource(ValueInRegisterFile);
208         else
209             m_arguments[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
210     }
211     
212     m_state.reset();
213     m_state.beginBasicBlock(&block);
214     
215     ASSERT(m_variables.size() == block.variablesAtHead.numberOfLocals());
216     for (size_t i = 0; i < m_variables.size(); ++i) {
217         NodeIndex nodeIndex = block.variablesAtHead.local(i);
218         if (nodeIndex == NoNode)
219             m_variables[i] = ValueSource(ValueInRegisterFile);
220         else
221             m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
222     }
223     
224     m_lastSetOperand = std::numeric_limits<int>::max();
225     m_codeOriginForOSR = CodeOrigin();
226
227     for (; m_compileIndex < block.end; ++m_compileIndex) {
228         Node& node = at(m_compileIndex);
229         m_codeOriginForOSR = node.codeOrigin;
230         if (!node.shouldGenerate()) {
231 #if DFG_ENABLE(DEBUG_VERBOSE)
232             fprintf(stderr, "SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x     ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
233 #endif
234             switch (node.op) {
235             case SetLocal:
236                 compileMovHint(node);
237                 break;
238
239             case InlineStart: {
240                 InlineCallFrame* inlineCallFrame = node.codeOrigin.inlineCallFrame;
241                 unsigned argumentsStart = inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize - inlineCallFrame->arguments.size();
242                 for (unsigned i = 0; i < inlineCallFrame->arguments.size(); ++i) {
243                     ValueRecovery recovery = computeValueRecoveryFor(m_variables[argumentsStart + i]);
244                     // The recovery cannot point to registers, since the call frame reification isn't
245                     // as smart as OSR, so it can't handle that. The exception is the this argument,
246                     // which we don't really need to be able to recover.
247                     ASSERT(!i || !recovery.isInRegisters());
248                     inlineCallFrame->arguments[i] = recovery;
249                 }
250                 break;
251             }
252                 
253             default:
254                 break;
255             }
256         } else {
257             
258 #if DFG_ENABLE(DEBUG_VERBOSE)
259             fprintf(stderr, "SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x   ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
260 #endif
261 #if DFG_ENABLE(JIT_BREAK_ON_EVERY_NODE)
262             m_jit.breakpoint();
263 #endif
264             checkConsistency();
265             compile(node);
266             if (!m_compileOkay) {
267                 m_compileOkay = true;
268                 m_compileIndex = block.end;
269                 clearGenerationInfo();
270                 return;
271             }
272             
273 #if DFG_ENABLE(DEBUG_VERBOSE)
274             if (node.hasResult()) {
275                 GenerationInfo& info = m_generationInfo[node.virtualRegister()];
276                 fprintf(stderr, "-> %s, vr#%d", dataFormatToString(info.registerFormat()), (int)node.virtualRegister());
277                 if (info.registerFormat() != DataFormatNone) {
278                     if (info.registerFormat() == DataFormatDouble)
279                         fprintf(stderr, ", %s", FPRInfo::debugName(info.fpr()));
280 #if USE(JSVALUE32_64)
281                     else if (info.registerFormat() & DataFormatJS)
282                         fprintf(stderr, ", %s %s", GPRInfo::debugName(info.tagGPR()), GPRInfo::debugName(info.payloadGPR()));
283 #endif
284                     else
285                         fprintf(stderr, ", %s", GPRInfo::debugName(info.gpr()));
286                 }
287                 fprintf(stderr, "    ");
288             } else
289                 fprintf(stderr, "    ");
290 #endif
291         }
292         
293 #if DFG_ENABLE(VERBOSE_VALUE_RECOVERIES)
294         for (int operand = -m_arguments.size() - RegisterFile::CallFrameHeaderSize; operand < -RegisterFile::CallFrameHeaderSize; ++operand)
295             computeValueRecoveryFor(operand).dump(stderr);
296         
297         fprintf(stderr, " : ");
298         
299         for (int operand = 0; operand < (int)m_variables.size(); ++operand)
300             computeValueRecoveryFor(operand).dump(stderr);
301 #endif
302
303 #if DFG_ENABLE(DEBUG_VERBOSE)
304         fprintf(stderr, "\n");
305 #endif
306         
307         // Make sure that the abstract state is rematerialized for the next node.
308         m_state.execute(m_compileIndex);
309         
310         if (node.shouldGenerate())
311             checkConsistency();
312     }
313 }
314
315 // If we are making type predictions about our arguments then
316 // we need to check that they are correct on function entry.
317 void SpeculativeJIT::checkArgumentTypes()
318 {
319     ASSERT(!m_compileIndex);
320     m_codeOriginForOSR = CodeOrigin(0);
321
322     for (size_t i = 0; i < m_arguments.size(); ++i)
323         m_arguments[i] = ValueSource(ValueInRegisterFile);
324     for (size_t i = 0; i < m_variables.size(); ++i)
325         m_variables[i] = ValueSource(ValueInRegisterFile);
326     
327     for (int i = 0; i < m_jit.codeBlock()->m_numParameters; ++i) {
328         VirtualRegister virtualRegister = (VirtualRegister)(m_jit.codeBlock()->thisRegister() + i);
329         PredictedType predictedType = at(m_jit.graph().m_arguments[i]).variableAccessData()->prediction();
330 #if USE(JSVALUE64)
331         if (isInt32Prediction(predictedType))
332             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister));
333         else if (isArrayPrediction(predictedType)) {
334             GPRTemporary temp(this);
335             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
336             speculationCheck(JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
337             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
338         } else if (isByteArrayPrediction(predictedType)) {
339             GPRTemporary temp(this);
340             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
341             speculationCheck(JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
342             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
343         } else if (isBooleanPrediction(predictedType)) {
344             GPRTemporary temp(this);
345             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
346             m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr());
347             speculationCheck(JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
348         }
349 #else
350         if (isInt32Prediction(predictedType))
351             speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
352         else if (isArrayPrediction(predictedType)) {
353             GPRTemporary temp(this);
354             m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
355             speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
356             m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
357             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
358         } else if (isByteArrayPrediction(predictedType)) {
359             GPRTemporary temp(this);
360             m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
361             speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
362             m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
363             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
364         } else if (isBooleanPrediction(predictedType))
365             speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
366 #endif
367     }
368 }
369
370 bool SpeculativeJIT::compile()
371 {
372     checkArgumentTypes();
373
374     ASSERT(!m_compileIndex);
375     for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block)
376         compile(*m_jit.graph().m_blocks[m_block]);
377     linkBranches();
378     return true;
379 }
380
381 void SpeculativeJIT::linkOSREntries(LinkBuffer& linkBuffer)
382 {
383     for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().m_blocks.size(); ++blockIndex) {
384         BasicBlock& block = *m_jit.graph().m_blocks[blockIndex];
385         if (block.isOSRTarget)
386             m_jit.noticeOSREntry(block, m_blockHeads[blockIndex], linkBuffer);
387     }
388 }
389
390 ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSource)
391 {
392     switch (valueSource.kind()) {
393     case ValueInRegisterFile:
394         return ValueRecovery::alreadyInRegisterFile();
395         
396     case Int32InRegisterFile:
397         return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32();
398
399     case CellInRegisterFile:
400         return ValueRecovery::alreadyInRegisterFileAsUnboxedCell();
401
402     case BooleanInRegisterFile:
403         return ValueRecovery::alreadyInRegisterFileAsUnboxedBoolean();
404
405     case HaveNode: {
406         if (m_jit.isConstant(valueSource.nodeIndex()))
407             return ValueRecovery::constant(m_jit.valueOfJSConstant(valueSource.nodeIndex()));
408     
409         Node* nodePtr = &at(valueSource.nodeIndex());
410         if (!nodePtr->shouldGenerate()) {
411             // It's legitimately dead. As in, nobody will ever use this node, or operand,
412             // ever. Set it to Undefined to make the GC happy after the OSR.
413             return ValueRecovery::constant(jsUndefined());
414         }
415     
416         GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
417         if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) {
418             // Try to see if there is an alternate node that would contain the value we want.
419             // There are four possibilities:
420             //
421             // ValueToNumber: If the only live version of the value is a ValueToNumber node
422             //    then it means that all remaining uses of the value would have performed a
423             //    ValueToNumber conversion anyway. Thus, we can substitute ValueToNumber.
424             //
425             // ValueToInt32: Likewise, if the only remaining live version of the value is
426             //    ValueToInt32, then we can use it. But if there is both a ValueToInt32
427             //    and a ValueToNumber, then we better go with ValueToNumber because it
428             //    means that some remaining uses would have converted to number while
429             //    others would have converted to Int32.
430             //
431             // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber
432             //    then the only remaining uses are ones that want a properly formed number
433             //    rather than a UInt32 intermediate.
434             //
435             // The reverse of the above: This node could be a UInt32ToNumber, but its
436             //    alternative is still alive. This means that the only remaining uses of
437             //    the number would be fine with a UInt32 intermediate.
438         
439             bool found = false;
440         
441             if (nodePtr->op == UInt32ToNumber) {
442                 NodeIndex nodeIndex = nodePtr->child1();
443                 nodePtr = &at(nodeIndex);
444                 infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
445                 if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex)
446                     found = true;
447             }
448         
449             if (!found) {
450                 NodeIndex valueToNumberIndex = NoNode;
451                 NodeIndex valueToInt32Index = NoNode;
452                 NodeIndex uint32ToNumberIndex = NoNode;
453             
454                 for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) {
455                     GenerationInfo& info = m_generationInfo[virtualRegister];
456                     if (!info.alive())
457                         continue;
458                     if (info.nodeIndex() == NoNode)
459                         continue;
460                     Node& node = at(info.nodeIndex());
461                     if (node.child1Unchecked() != valueSource.nodeIndex())
462                         continue;
463                     switch (node.op) {
464                     case ValueToNumber:
465                     case ValueToDouble:
466                         valueToNumberIndex = info.nodeIndex();
467                         break;
468                     case ValueToInt32:
469                         valueToInt32Index = info.nodeIndex();
470                         break;
471                     case UInt32ToNumber:
472                         uint32ToNumberIndex = info.nodeIndex();
473                         break;
474                     default:
475                         break;
476                     }
477                 }
478             
479                 NodeIndex nodeIndexToUse;
480                 if (valueToNumberIndex != NoNode)
481                     nodeIndexToUse = valueToNumberIndex;
482                 else if (valueToInt32Index != NoNode)
483                     nodeIndexToUse = valueToInt32Index;
484                 else if (uint32ToNumberIndex != NoNode)
485                     nodeIndexToUse = uint32ToNumberIndex;
486                 else
487                     nodeIndexToUse = NoNode;
488             
489                 if (nodeIndexToUse != NoNode) {
490                     nodePtr = &at(nodeIndexToUse);
491                     infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
492                     ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse);
493                     found = true;
494                 }
495             }
496         
497             if (!found)
498                 return ValueRecovery::constant(jsUndefined());
499         }
500     
501         ASSERT(infoPtr->alive());
502
503         if (infoPtr->registerFormat() != DataFormatNone) {
504             if (infoPtr->registerFormat() == DataFormatDouble)
505                 return ValueRecovery::inFPR(infoPtr->fpr());
506 #if USE(JSVALUE32_64)
507             if (infoPtr->registerFormat() & DataFormatJS)
508                 return ValueRecovery::inPair(infoPtr->tagGPR(), infoPtr->payloadGPR());
509 #endif
510             return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat());
511         }
512         if (infoPtr->spillFormat() != DataFormatNone)
513             return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister()), infoPtr->spillFormat());
514     
515         ASSERT_NOT_REACHED();
516         return ValueRecovery();
517     }
518         
519     default:
520         ASSERT_NOT_REACHED();
521         return ValueRecovery();
522     }
523 }
524
525 void SpeculativeJIT::compileGetCharCodeAt(Node& node)
526 {
527     ASSERT(node.child3() == NoNode);
528     SpeculateCellOperand string(this, node.child1());
529     SpeculateStrictInt32Operand index(this, node.child2());
530
531     GPRReg stringReg = string.gpr();
532     GPRReg indexReg = index.gpr();
533
534     if (!isStringPrediction(m_state.forNode(node.child1()).m_type))
535         speculationCheck(JSValueSource::unboxedCell(stringReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(stringReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));
536
537     // unsigned comparison so we can filter out negative indices and indices that are too large
538     speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, MacroAssembler::Address(stringReg, JSString::offsetOfLength())));
539
540     GPRTemporary scratch(this);
541     GPRReg scratchReg = scratch.gpr();
542
543     m_jit.loadPtr(MacroAssembler::Address(stringReg, JSString::offsetOfValue()), scratchReg);
544
545     // Speculate that we're not accessing a rope
546     speculationCheck(JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, scratchReg));
547
548     // Load the character into scratchReg
549     JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
550
551     m_jit.loadPtr(MacroAssembler::Address(scratchReg, StringImpl::dataOffset()), scratchReg);
552     m_jit.load8(MacroAssembler::BaseIndex(scratchReg, indexReg, MacroAssembler::TimesOne, 0), scratchReg);
553     JITCompiler::Jump cont8Bit = m_jit.jump();
554
555     is16Bit.link(&m_jit);
556
557     m_jit.loadPtr(MacroAssembler::Address(scratchReg, StringImpl::dataOffset()), scratchReg);
558     m_jit.load16(MacroAssembler::BaseIndex(scratchReg, indexReg, MacroAssembler::TimesTwo, 0), scratchReg);
559
560     cont8Bit.link(&m_jit);
561
562     integerResult(scratchReg, m_compileIndex);
563 }
564
565 void SpeculativeJIT::compileGetByValOnString(Node& node)
566 {
567     ASSERT(node.child3() == NoNode);
568     SpeculateCellOperand base(this, node.child1());
569     SpeculateStrictInt32Operand property(this, node.child2());
570
571     GPRReg baseReg = base.gpr();
572     GPRReg propertyReg = property.gpr();
573
574     if (!isStringPrediction(m_state.forNode(node.child1()).m_type))
575         speculationCheck(JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));
576
577     // unsigned comparison so we can filter out negative indices and indices that are too large
578     speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSString::offsetOfLength())));
579
580     GPRTemporary scratch(this);
581     GPRReg scratchReg = scratch.gpr();
582
583     m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg);
584
585     // Speculate that we're not accessing a rope
586     speculationCheck(JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, scratchReg));
587
588     // Load the character into scratchReg
589     JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
590
591     m_jit.loadPtr(MacroAssembler::Address(scratchReg, StringImpl::dataOffset()), scratchReg);
592     m_jit.load8(MacroAssembler::BaseIndex(scratchReg, propertyReg, MacroAssembler::TimesOne, 0), scratchReg);
593     JITCompiler::Jump cont8Bit = m_jit.jump();
594
595     is16Bit.link(&m_jit);
596
597     m_jit.loadPtr(MacroAssembler::Address(scratchReg, StringImpl::dataOffset()), scratchReg);
598     m_jit.load16(MacroAssembler::BaseIndex(scratchReg, propertyReg, MacroAssembler::TimesTwo, 0), scratchReg);
599
600     // We only support ascii characters
601     speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, scratchReg, TrustedImm32(0x100)));
602
603     // 8 bit string values don't need the isASCII check.
604     cont8Bit.link(&m_jit);
605
606     GPRTemporary smallStrings(this);
607     GPRReg smallStringsReg = smallStrings.gpr();
608     m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalData()->smallStrings.singleCharacterStrings()), smallStringsReg);
609     m_jit.loadPtr(MacroAssembler::BaseIndex(smallStringsReg, scratchReg, MacroAssembler::ScalePtr, 0), scratchReg);
610     speculationCheck(JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, scratchReg));
611     cellResult(scratchReg, m_compileIndex);
612 }
613
614 void SpeculativeJIT::compileValueToInt32(Node& node)
615 {
616     if (at(node.child1()).shouldNotSpeculateInteger()) {
617         if (at(node.child1()).shouldSpeculateDouble()) {
618             SpeculateDoubleOperand op1(this, node.child1());
619             GPRTemporary result(this);
620             FPRReg fpr = op1.fpr();
621             GPRReg gpr = result.gpr();
622             JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateSuccessful);
623             
624             silentSpillAllRegisters(gpr);
625             callOperation(toInt32, gpr, fpr);
626             silentFillAllRegisters(gpr);
627             
628             truncatedToInteger.link(&m_jit);
629             integerResult(gpr, m_compileIndex);
630             return;
631         }
632         // Do it the safe way.
633         nonSpeculativeValueToInt32(node);
634         return;
635     }
636     
637     SpeculateIntegerOperand op1(this, node.child1());
638     GPRTemporary result(this, op1);
639     m_jit.move(op1.gpr(), result.gpr());
640     integerResult(result.gpr(), m_compileIndex, op1.format());
641 }
642
643 static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg source, FPRReg scratch)
644 {
645     // Unordered compare so we pick up NaN
646     static const double zero = 0;
647     static const double byteMax = 255;
648     static const double half = 0.5;
649     jit.loadDouble(&zero, scratch);
650     MacroAssembler::Jump tooSmall = jit.branchDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered, source, scratch);
651     jit.loadDouble(&byteMax, scratch);
652     MacroAssembler::Jump tooBig = jit.branchDouble(MacroAssembler::DoubleGreaterThan, source, scratch);
653     
654     jit.loadDouble(&half, scratch);
655     // FIXME: This should probably just use a floating point round!
656     // https://bugs.webkit.org/show_bug.cgi?id=72054
657     jit.addDouble(source, scratch);
658     jit.truncateDoubleToInt32(scratch, result);   
659     MacroAssembler::Jump truncatedInt = jit.jump();
660     
661     tooSmall.link(&jit);
662     jit.xorPtr(result, result);
663     MacroAssembler::Jump zeroed = jit.jump();
664     
665     tooBig.link(&jit);
666     jit.move(JITCompiler::TrustedImm32(255), result);
667     
668     truncatedInt.link(&jit);
669     zeroed.link(&jit);
670
671 }
672
673 void SpeculativeJIT::compilePutByValForByteArray(GPRReg base, GPRReg property, Node& node)
674 {
675     NodeIndex baseIndex = node.child1();
676     NodeIndex valueIndex = node.child3();
677     
678     if (!isByteArrayPrediction(m_state.forNode(baseIndex).m_type))
679         speculationCheck(JSValueSource::unboxedCell(base), baseIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
680     GPRTemporary value;
681     GPRReg valueGPR;
682
683     if (at(valueIndex).isConstant()) {
684         JSValue jsValue = valueOfJSConstant(valueIndex);
685         if (!jsValue.isNumber()) {
686             terminateSpeculativeExecution(JSValueRegs(), NoNode);
687             noResult(m_compileIndex);
688             return;
689         }
690         double d = jsValue.asNumber();
691         d += 0.5;
692         if (!(d > 0))
693             d = 0;
694         else if (d > 255)
695             d = 255;
696         GPRTemporary scratch(this);
697         GPRReg scratchReg = scratch.gpr();
698         m_jit.move(Imm32((int)d), scratchReg);
699         value.adopt(scratch);
700         valueGPR = scratchReg;
701     } else if (!at(valueIndex).shouldNotSpeculateInteger()) {
702         SpeculateIntegerOperand valueOp(this, valueIndex);
703         GPRTemporary scratch(this);
704         GPRReg scratchReg = scratch.gpr();
705         m_jit.move(valueOp.gpr(), scratchReg);
706         MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::BelowOrEqual, scratchReg, TrustedImm32(0xff));
707         MacroAssembler::Jump tooBig = m_jit.branch32(MacroAssembler::GreaterThan, scratchReg, TrustedImm32(0xff));
708         m_jit.xorPtr(scratchReg, scratchReg);
709         MacroAssembler::Jump clamped = m_jit.jump();
710         tooBig.link(&m_jit);
711         m_jit.move(TrustedImm32(255), scratchReg);
712         clamped.link(&m_jit);
713         inBounds.link(&m_jit);
714         value.adopt(scratch);
715         valueGPR = scratchReg;
716     } else {
717         SpeculateDoubleOperand valueOp(this, valueIndex);
718         GPRTemporary result(this);
719         FPRTemporary floatScratch(this);
720         FPRReg fpr = valueOp.fpr();
721         GPRReg gpr = result.gpr();
722         compileClampDoubleToByte(m_jit, gpr, fpr, floatScratch.fpr());
723         value.adopt(result);
724         valueGPR = gpr;
725     }
726     ASSERT_UNUSED(valueGPR, valueGPR != property);
727     ASSERT(valueGPR != base);
728     GPRTemporary storage(this);
729     GPRReg storageReg = storage.gpr();
730     ASSERT(valueGPR != storageReg);
731     m_jit.loadPtr(MacroAssembler::Address(base, JSByteArray::offsetOfStorage()), storageReg);
732     MacroAssembler::Jump outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(storageReg, ByteArray::offsetOfSize()));
733     m_jit.store8(value.gpr(), MacroAssembler::BaseIndex(storageReg, property, MacroAssembler::TimesOne, ByteArray::offsetOfData()));
734     outOfBounds.link(&m_jit);
735     noResult(m_compileIndex);
736 }
737
738 void SpeculativeJIT::compileGetByValOnByteArray(Node& node)
739 {
740     ASSERT(node.child3() == NoNode);
741     SpeculateCellOperand base(this, node.child1());
742     SpeculateStrictInt32Operand property(this, node.child2());
743     
744     GPRReg baseReg = base.gpr();
745     GPRReg propertyReg = property.gpr();
746     
747     if (!isByteArrayPrediction(m_state.forNode(node.child1()).m_type))
748         speculationCheck(JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
749
750     // Load the character into scratchReg
751     GPRTemporary storage(this);
752     GPRReg storageReg = storage.gpr();
753     m_jit.loadPtr(MacroAssembler::Address(baseReg, JSByteArray::offsetOfStorage()), storageReg);
754     
755     // unsigned comparison so we can filter out negative indices and indices that are too large
756     speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(storageReg, ByteArray::offsetOfSize())));
757
758     m_jit.load8(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesOne, ByteArray::offsetOfData()), storageReg);
759     integerResult(storageReg, m_compileIndex);
760 }
761
762 } } // namespace JSC::DFG
763
764 #endif