ValueRecovery should be moved out of the DFG JIT
[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 OSRExit::OSRExit(JSValueSource jsValueSource, ValueProfile* valueProfile, MacroAssembler::Jump check, SpeculativeJIT* jit, unsigned recoveryIndex)
66     : m_jsValueSource(jsValueSource)
67     , m_valueProfile(valueProfile)
68     , m_check(check)
69     , m_nodeIndex(jit->m_compileIndex)
70     , m_codeOrigin(jit->m_codeOriginForOSR)
71     , m_recoveryIndex(recoveryIndex)
72     , m_arguments(jit->m_arguments.size())
73     , m_variables(jit->m_variables.size())
74     , m_lastSetOperand(jit->m_lastSetOperand)
75 {
76     ASSERT(m_codeOrigin.isSet());
77     for (unsigned argument = 0; argument < m_arguments.size(); ++argument)
78         m_arguments[argument] = jit->computeValueRecoveryFor(jit->m_arguments[argument]);
79     for (unsigned variable = 0; variable < m_variables.size(); ++variable)
80         m_variables[variable] = jit->computeValueRecoveryFor(jit->m_variables[variable]);
81 }
82
83 #ifndef NDEBUG
84 void OSRExit::dump(FILE* out) const
85 {
86     for (unsigned argument = 0; argument < m_arguments.size(); ++argument)
87         m_arguments[argument].dump(out);
88     fprintf(out, " : ");
89     for (unsigned variable = 0; variable < m_variables.size(); ++variable)
90         m_variables[variable].dump(out);
91 }
92 #endif
93
94 void SpeculativeJIT::compilePeepHoleDoubleBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::DoubleCondition condition)
95 {
96     Node& branchNode = at(branchNodeIndex);
97     BlockIndex taken = branchNode.takenBlockIndex();
98     BlockIndex notTaken = branchNode.notTakenBlockIndex();
99     
100     SpeculateDoubleOperand op1(this, node.child1());
101     SpeculateDoubleOperand op2(this, node.child2());
102     
103     addBranch(m_jit.branchDouble(condition, op1.fpr(), op2.fpr()), taken);
104     
105     if (notTaken != (m_block + 1))
106         addBranch(m_jit.jump(), notTaken);
107 }
108
109 void SpeculativeJIT::compilePeepHoleObjectEquality(Node& node, NodeIndex branchNodeIndex, void* vptr, PredictionChecker predictionCheck)
110 {
111     Node& branchNode = at(branchNodeIndex);
112     BlockIndex taken = branchNode.takenBlockIndex();
113     BlockIndex notTaken = branchNode.notTakenBlockIndex();
114
115     MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;
116     
117     if (taken == (m_block + 1)) {
118         condition = MacroAssembler::NotEqual;
119         BlockIndex tmp = taken;
120         taken = notTaken;
121         notTaken = tmp;
122     }
123
124     SpeculateCellOperand op1(this, node.child1());
125     SpeculateCellOperand op2(this, node.child2());
126     
127     GPRReg op1GPR = op1.gpr();
128     GPRReg op2GPR = op2.gpr();
129     
130     if (!predictionCheck(m_state.forNode(node.child1()).m_type))
131         speculationCheck(JSValueSource::unboxedCell(op1GPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1GPR), MacroAssembler::TrustedImmPtr(vptr)));
132     if (!predictionCheck(m_state.forNode(node.child2()).m_type))
133         speculationCheck(JSValueSource::unboxedCell(op2GPR), node.child2(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op2GPR), MacroAssembler::TrustedImmPtr(vptr)));
134     
135     addBranch(m_jit.branchPtr(condition, op1GPR, op2GPR), taken);
136     if (notTaken != (m_block + 1))
137         addBranch(m_jit.jump(), notTaken);
138 }
139
140 void SpeculativeJIT::compilePeepHoleIntegerBranch(Node& node, NodeIndex branchNodeIndex, JITCompiler::RelationalCondition condition)
141 {
142     Node& branchNode = at(branchNodeIndex);
143     BlockIndex taken = branchNode.takenBlockIndex();
144     BlockIndex notTaken = branchNode.notTakenBlockIndex();
145
146     // The branch instruction will branch to the taken block.
147     // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
148     if (taken == (m_block + 1)) {
149         condition = JITCompiler::invert(condition);
150         BlockIndex tmp = taken;
151         taken = notTaken;
152         notTaken = tmp;
153     }
154
155     if (isInt32Constant(node.child1())) {
156         int32_t imm = valueOfInt32Constant(node.child1());
157         SpeculateIntegerOperand op2(this, node.child2());
158         addBranch(m_jit.branch32(condition, JITCompiler::Imm32(imm), op2.gpr()), taken);
159     } else if (isInt32Constant(node.child2())) {
160         SpeculateIntegerOperand op1(this, node.child1());
161         int32_t imm = valueOfInt32Constant(node.child2());
162         addBranch(m_jit.branch32(condition, op1.gpr(), JITCompiler::Imm32(imm)), taken);
163     } else {
164         SpeculateIntegerOperand op1(this, node.child1());
165         SpeculateIntegerOperand op2(this, node.child2());
166         addBranch(m_jit.branch32(condition, op1.gpr(), op2.gpr()), taken);
167     }
168
169     // Check for fall through, otherwise we need to jump.
170     if (notTaken != (m_block + 1))
171         addBranch(m_jit.jump(), notTaken);
172 }
173
174 // Returns true if the compare is fused with a subsequent branch.
175 bool SpeculativeJIT::compilePeepHoleBranch(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_DFGOperation_EJJ operation)
176 {
177     // Fused compare & branch.
178     NodeIndex branchNodeIndex = detectPeepHoleBranch();
179     if (branchNodeIndex != NoNode) {
180         // detectPeepHoleBranch currently only permits the branch to be the very next node,
181         // so can be no intervening nodes to also reference the compare. 
182         ASSERT(node.adjustedRefCount() == 1);
183
184         if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))) {
185             compilePeepHoleIntegerBranch(node, branchNodeIndex, condition);
186             use(node.child1());
187             use(node.child2());
188         } else if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
189             compilePeepHoleDoubleBranch(node, branchNodeIndex, doubleCondition);
190             use(node.child1());
191             use(node.child2());
192         } else if (node.op == CompareEq && Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) {
193             compilePeepHoleObjectEquality(node, branchNodeIndex, m_jit.globalData()->jsFinalObjectVPtr, isFinalObjectPrediction);
194             use(node.child1());
195             use(node.child2());
196         } else if (node.op == CompareEq && Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) {
197             compilePeepHoleObjectEquality(node, branchNodeIndex, m_jit.globalData()->jsArrayVPtr, isArrayPrediction);
198             use(node.child1());
199             use(node.child2());
200         } else
201             nonSpeculativePeepholeBranch(node, branchNodeIndex, condition, operation);
202
203         m_compileIndex = branchNodeIndex;
204         return true;
205     }
206     return false;
207 }
208
209 void SpeculativeJIT::compileMovHint(Node& node)
210 {
211     ASSERT(node.op == SetLocal);
212     
213     setNodeIndexForOperand(node.child1(), node.local());
214     m_lastSetOperand = node.local();
215 }
216
217 void SpeculativeJIT::compile(BasicBlock& block)
218 {
219     ASSERT(m_compileOkay);
220     ASSERT(m_compileIndex == block.begin);
221     
222     if (!block.isReachable) {
223         m_compileIndex = block.end;
224         return;
225     }
226
227     if (block.isOSRTarget)
228         m_jit.noticeOSREntry(block);
229
230     m_blockHeads[m_block] = m_jit.label();
231 #if DFG_ENABLE(JIT_BREAK_ON_EVERY_BLOCK)
232     m_jit.breakpoint();
233 #endif
234
235     ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments());
236     for (size_t i = 0; i < m_arguments.size(); ++i) {
237         NodeIndex nodeIndex = block.variablesAtHead.argument(i);
238         if (nodeIndex == NoNode)
239             m_arguments[i] = ValueSource(ValueInRegisterFile);
240         else
241             m_arguments[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
242     }
243     
244     m_state.reset();
245     m_state.beginBasicBlock(&block);
246     
247     ASSERT(m_variables.size() == block.variablesAtHead.numberOfLocals());
248     for (size_t i = 0; i < m_variables.size(); ++i) {
249         NodeIndex nodeIndex = block.variablesAtHead.local(i);
250         if (nodeIndex == NoNode)
251             m_variables[i] = ValueSource(ValueInRegisterFile);
252         else
253             m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
254     }
255     
256     m_lastSetOperand = std::numeric_limits<int>::max();
257     m_codeOriginForOSR = CodeOrigin();
258
259     for (; m_compileIndex < block.end; ++m_compileIndex) {
260         Node& node = at(m_compileIndex);
261         m_codeOriginForOSR = node.codeOrigin;
262         if (!node.shouldGenerate()) {
263 #if DFG_ENABLE(DEBUG_VERBOSE)
264             fprintf(stderr, "SpeculativeJIT skipping Node @%d (bc#%u) at JIT offset 0x%x     ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
265 #endif
266             if (node.op == SetLocal)
267                 compileMovHint(node);
268         } else {
269             
270 #if DFG_ENABLE(DEBUG_VERBOSE)
271             fprintf(stderr, "SpeculativeJIT generating Node @%d (bc#%u) at JIT offset 0x%x   ", (int)m_compileIndex, node.codeOrigin.bytecodeIndex, m_jit.debugOffset());
272 #endif
273 #if DFG_ENABLE(JIT_BREAK_ON_EVERY_NODE)
274             m_jit.breakpoint();
275 #endif
276             checkConsistency();
277             compile(node);
278             if (!m_compileOkay) {
279                 m_compileOkay = true;
280                 m_compileIndex = block.end;
281                 clearGenerationInfo();
282                 return;
283             }
284             
285 #if DFG_ENABLE(DEBUG_VERBOSE)
286             if (node.hasResult()) {
287                 GenerationInfo& info = m_generationInfo[node.virtualRegister()];
288                 fprintf(stderr, "-> %s, vr#%d", dataFormatToString(info.registerFormat()), (int)node.virtualRegister());
289                 if (info.registerFormat() != DataFormatNone) {
290                     if (info.registerFormat() == DataFormatDouble)
291                         fprintf(stderr, ", %s", FPRInfo::debugName(info.fpr()));
292 #if USE(JSVALUE32_64)
293                     else if (info.registerFormat() & DataFormatJS)
294                         fprintf(stderr, ", %s %s", GPRInfo::debugName(info.tagGPR()), GPRInfo::debugName(info.payloadGPR()));
295 #endif
296                     else
297                         fprintf(stderr, ", %s", GPRInfo::debugName(info.gpr()));
298                 }
299                 fprintf(stderr, "    ");
300             } else
301                 fprintf(stderr, "    ");
302 #endif
303         }
304         
305 #if DFG_ENABLE(VERBOSE_VALUE_RECOVERIES)
306         for (int operand = -m_arguments.size() - RegisterFile::CallFrameHeaderSize; operand < -RegisterFile::CallFrameHeaderSize; ++operand)
307             computeValueRecoveryFor(operand).dump(stderr);
308         
309         fprintf(stderr, " : ");
310         
311         for (int operand = 0; operand < (int)m_variables.size(); ++operand)
312             computeValueRecoveryFor(operand).dump(stderr);
313 #endif
314
315 #if DFG_ENABLE(DEBUG_VERBOSE)
316         fprintf(stderr, "\n");
317 #endif
318         
319         // Make sure that the abstract state is rematerialized for the next node.
320         m_state.execute(m_compileIndex);
321         
322         if (node.shouldGenerate())
323             checkConsistency();
324     }
325 }
326
327 // If we are making type predictions about our arguments then
328 // we need to check that they are correct on function entry.
329 void SpeculativeJIT::checkArgumentTypes()
330 {
331     ASSERT(!m_compileIndex);
332     m_codeOriginForOSR = CodeOrigin(0);
333
334     for (size_t i = 0; i < m_arguments.size(); ++i)
335         m_arguments[i] = ValueSource(ValueInRegisterFile);
336     for (size_t i = 0; i < m_variables.size(); ++i)
337         m_variables[i] = ValueSource(ValueInRegisterFile);
338     
339     for (int i = 0; i < m_jit.codeBlock()->m_numParameters; ++i) {
340         VirtualRegister virtualRegister = (VirtualRegister)(m_jit.codeBlock()->thisRegister() + i);
341         PredictedType predictedType = at(m_jit.graph().m_arguments[i]).variableAccessData()->prediction();
342 #if USE(JSVALUE64)
343         if (isInt32Prediction(predictedType))
344             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::Below, JITCompiler::addressFor(virtualRegister), GPRInfo::tagTypeNumberRegister));
345         else if (isArrayPrediction(predictedType)) {
346             GPRTemporary temp(this);
347             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
348             speculationCheck(JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
349             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
350         } else if (isByteArrayPrediction(predictedType)) {
351             GPRTemporary temp(this);
352             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
353             speculationCheck(JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), GPRInfo::tagMaskRegister));
354             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
355         } else if (isBooleanPrediction(predictedType)) {
356             GPRTemporary temp(this);
357             m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), temp.gpr());
358             m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), temp.gpr());
359             speculationCheck(JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::NonZero, temp.gpr(), TrustedImm32(static_cast<int32_t>(~1))));
360         }
361 #else
362         if (isInt32Prediction(predictedType))
363             speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::Int32Tag)));
364         else if (isArrayPrediction(predictedType)) {
365             GPRTemporary temp(this);
366             m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
367             speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
368             m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
369             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
370         } else if (isByteArrayPrediction(predictedType)) {
371             GPRTemporary temp(this);
372             m_jit.load32(JITCompiler::tagFor(virtualRegister), temp.gpr());
373             speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, temp.gpr(), TrustedImm32(JSValue::CellTag)));
374             m_jit.load32(JITCompiler::payloadFor(virtualRegister), temp.gpr());
375             speculationCheck(JSValueRegs(), NoNode, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
376         } else if (isBooleanPrediction(predictedType))
377             speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::BooleanTag)));
378 #endif
379     }
380 }
381
382 bool SpeculativeJIT::compile()
383 {
384     checkArgumentTypes();
385
386     ASSERT(!m_compileIndex);
387     for (m_block = 0; m_block < m_jit.graph().m_blocks.size(); ++m_block)
388         compile(*m_jit.graph().m_blocks[m_block]);
389     linkBranches();
390     return true;
391 }
392
393 ValueRecovery SpeculativeJIT::computeValueRecoveryFor(const ValueSource& valueSource)
394 {
395     switch (valueSource.kind()) {
396     case ValueInRegisterFile:
397         return ValueRecovery::alreadyInRegisterFile();
398         
399     case Int32InRegisterFile:
400         return ValueRecovery::alreadyInRegisterFileAsUnboxedInt32();
401
402     case CellInRegisterFile:
403         return ValueRecovery::alreadyInRegisterFileAsUnboxedCell();
404
405     case BooleanInRegisterFile:
406         return ValueRecovery::alreadyInRegisterFileAsUnboxedBoolean();
407
408     case HaveNode: {
409         if (m_jit.isConstant(valueSource.nodeIndex()))
410             return ValueRecovery::constant(m_jit.valueOfJSConstant(valueSource.nodeIndex()));
411     
412         Node* nodePtr = &at(valueSource.nodeIndex());
413         if (!nodePtr->shouldGenerate()) {
414             // It's legitimately dead. As in, nobody will ever use this node, or operand,
415             // ever. Set it to Undefined to make the GC happy after the OSR.
416             return ValueRecovery::constant(jsUndefined());
417         }
418     
419         GenerationInfo* infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
420         if (!infoPtr->alive() || infoPtr->nodeIndex() != valueSource.nodeIndex()) {
421             // Try to see if there is an alternate node that would contain the value we want.
422             // There are four possibilities:
423             //
424             // ValueToNumber: If the only live version of the value is a ValueToNumber node
425             //    then it means that all remaining uses of the value would have performed a
426             //    ValueToNumber conversion anyway. Thus, we can substitute ValueToNumber.
427             //
428             // ValueToInt32: Likewise, if the only remaining live version of the value is
429             //    ValueToInt32, then we can use it. But if there is both a ValueToInt32
430             //    and a ValueToNumber, then we better go with ValueToNumber because it
431             //    means that some remaining uses would have converted to number while
432             //    others would have converted to Int32.
433             //
434             // UInt32ToNumber: If the only live version of the value is a UInt32ToNumber
435             //    then the only remaining uses are ones that want a properly formed number
436             //    rather than a UInt32 intermediate.
437             //
438             // The reverse of the above: This node could be a UInt32ToNumber, but its
439             //    alternative is still alive. This means that the only remaining uses of
440             //    the number would be fine with a UInt32 intermediate.
441         
442             bool found = false;
443         
444             if (nodePtr->op == UInt32ToNumber) {
445                 NodeIndex nodeIndex = nodePtr->child1();
446                 nodePtr = &at(nodeIndex);
447                 infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
448                 if (infoPtr->alive() && infoPtr->nodeIndex() == nodeIndex)
449                     found = true;
450             }
451         
452             if (!found) {
453                 NodeIndex valueToNumberIndex = NoNode;
454                 NodeIndex valueToInt32Index = NoNode;
455                 NodeIndex uint32ToNumberIndex = NoNode;
456             
457                 for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) {
458                     GenerationInfo& info = m_generationInfo[virtualRegister];
459                     if (!info.alive())
460                         continue;
461                     if (info.nodeIndex() == NoNode)
462                         continue;
463                     Node& node = at(info.nodeIndex());
464                     if (node.child1Unchecked() != valueSource.nodeIndex())
465                         continue;
466                     switch (node.op) {
467                     case ValueToNumber:
468                     case ValueToDouble:
469                         valueToNumberIndex = info.nodeIndex();
470                         break;
471                     case ValueToInt32:
472                         valueToInt32Index = info.nodeIndex();
473                         break;
474                     case UInt32ToNumber:
475                         uint32ToNumberIndex = info.nodeIndex();
476                         break;
477                     default:
478                         break;
479                     }
480                 }
481             
482                 NodeIndex nodeIndexToUse;
483                 if (valueToNumberIndex != NoNode)
484                     nodeIndexToUse = valueToNumberIndex;
485                 else if (valueToInt32Index != NoNode)
486                     nodeIndexToUse = valueToInt32Index;
487                 else if (uint32ToNumberIndex != NoNode)
488                     nodeIndexToUse = uint32ToNumberIndex;
489                 else
490                     nodeIndexToUse = NoNode;
491             
492                 if (nodeIndexToUse != NoNode) {
493                     nodePtr = &at(nodeIndexToUse);
494                     infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
495                     ASSERT(infoPtr->alive() && infoPtr->nodeIndex() == nodeIndexToUse);
496                     found = true;
497                 }
498             }
499         
500             if (!found)
501                 return ValueRecovery::constant(jsUndefined());
502         }
503     
504         ASSERT(infoPtr->alive());
505
506         if (infoPtr->registerFormat() != DataFormatNone) {
507             if (infoPtr->registerFormat() == DataFormatDouble)
508                 return ValueRecovery::inFPR(infoPtr->fpr());
509 #if USE(JSVALUE32_64)
510             if (infoPtr->registerFormat() & DataFormatJS)
511                 return ValueRecovery::inPair(infoPtr->tagGPR(), infoPtr->payloadGPR());
512 #endif
513             return ValueRecovery::inGPR(infoPtr->gpr(), infoPtr->registerFormat());
514         }
515         if (infoPtr->spillFormat() != DataFormatNone)
516             return ValueRecovery::displacedInRegisterFile(static_cast<VirtualRegister>(nodePtr->virtualRegister()), infoPtr->spillFormat());
517     
518         ASSERT_NOT_REACHED();
519         return ValueRecovery();
520     }
521         
522     default:
523         ASSERT_NOT_REACHED();
524         return ValueRecovery();
525     }
526 }
527
528 void SpeculativeJIT::compileGetCharCodeAt(Node& node)
529 {
530     ASSERT(node.child3() == NoNode);
531     SpeculateCellOperand string(this, node.child1());
532     SpeculateStrictInt32Operand index(this, node.child2());
533
534     GPRReg stringReg = string.gpr();
535     GPRReg indexReg = index.gpr();
536
537     if (!isStringPrediction(m_state.forNode(node.child1()).m_type))
538         speculationCheck(JSValueSource::unboxedCell(stringReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(stringReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));
539
540     // unsigned comparison so we can filter out negative indices and indices that are too large
541     speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, indexReg, MacroAssembler::Address(stringReg, JSString::offsetOfLength())));
542
543     GPRTemporary scratch(this);
544     GPRReg scratchReg = scratch.gpr();
545
546     m_jit.loadPtr(MacroAssembler::Address(stringReg, JSString::offsetOfValue()), scratchReg);
547
548     // Speculate that we're not accessing a rope
549     speculationCheck(JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, scratchReg));
550
551     // Load the character into scratchReg
552     JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
553
554     m_jit.loadPtr(MacroAssembler::Address(scratchReg, StringImpl::dataOffset()), scratchReg);
555     m_jit.load8(MacroAssembler::BaseIndex(scratchReg, indexReg, MacroAssembler::TimesOne, 0), scratchReg);
556     JITCompiler::Jump cont8Bit = m_jit.jump();
557
558     is16Bit.link(&m_jit);
559
560     m_jit.loadPtr(MacroAssembler::Address(scratchReg, StringImpl::dataOffset()), scratchReg);
561     m_jit.load16(MacroAssembler::BaseIndex(scratchReg, indexReg, MacroAssembler::TimesTwo, 0), scratchReg);
562
563     cont8Bit.link(&m_jit);
564
565     integerResult(scratchReg, m_compileIndex);
566 }
567
568 void SpeculativeJIT::compileGetByValOnString(Node& node)
569 {
570     ASSERT(node.child3() == NoNode);
571     SpeculateCellOperand base(this, node.child1());
572     SpeculateStrictInt32Operand property(this, node.child2());
573
574     GPRReg baseReg = base.gpr();
575     GPRReg propertyReg = property.gpr();
576
577     if (!isStringPrediction(m_state.forNode(node.child1()).m_type))
578         speculationCheck(JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsStringVPtr)));
579
580     // unsigned comparison so we can filter out negative indices and indices that are too large
581     speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSString::offsetOfLength())));
582
583     GPRTemporary scratch(this);
584     GPRReg scratchReg = scratch.gpr();
585
586     m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), scratchReg);
587
588     // Speculate that we're not accessing a rope
589     speculationCheck(JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, scratchReg));
590
591     // Load the character into scratchReg
592     JITCompiler::Jump is16Bit = m_jit.branchTest32(MacroAssembler::Zero, MacroAssembler::Address(scratchReg, StringImpl::flagsOffset()), TrustedImm32(StringImpl::flagIs8Bit()));
593
594     m_jit.loadPtr(MacroAssembler::Address(scratchReg, StringImpl::dataOffset()), scratchReg);
595     m_jit.load8(MacroAssembler::BaseIndex(scratchReg, propertyReg, MacroAssembler::TimesOne, 0), scratchReg);
596     JITCompiler::Jump cont8Bit = m_jit.jump();
597
598     is16Bit.link(&m_jit);
599
600     m_jit.loadPtr(MacroAssembler::Address(scratchReg, StringImpl::dataOffset()), scratchReg);
601     m_jit.load16(MacroAssembler::BaseIndex(scratchReg, propertyReg, MacroAssembler::TimesTwo, 0), scratchReg);
602
603     // We only support ascii characters
604     speculationCheck(JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, scratchReg, TrustedImm32(0x100)));
605
606     // 8 bit string values don't need the isASCII check.
607     cont8Bit.link(&m_jit);
608
609     GPRTemporary smallStrings(this);
610     GPRReg smallStringsReg = smallStrings.gpr();
611     m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.globalData()->smallStrings.singleCharacterStrings()), smallStringsReg);
612     m_jit.loadPtr(MacroAssembler::BaseIndex(smallStringsReg, scratchReg, MacroAssembler::ScalePtr, 0), scratchReg);
613     speculationCheck(JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, scratchReg));
614     cellResult(scratchReg, m_compileIndex);
615 }
616
617 void SpeculativeJIT::compileValueToInt32(Node& node)
618 {
619     if (at(node.child1()).shouldNotSpeculateInteger()) {
620         if (at(node.child1()).shouldSpeculateDouble()) {
621             SpeculateDoubleOperand op1(this, node.child1());
622             GPRTemporary result(this);
623             FPRReg fpr = op1.fpr();
624             GPRReg gpr = result.gpr();
625             JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateSuccessful);
626             
627             silentSpillAllRegisters(gpr);
628             callOperation(toInt32, gpr, fpr);
629             silentFillAllRegisters(gpr);
630             
631             truncatedToInteger.link(&m_jit);
632             integerResult(gpr, m_compileIndex);
633             return;
634         }
635         // Do it the safe way.
636         nonSpeculativeValueToInt32(node);
637         return;
638     }
639     
640     SpeculateIntegerOperand op1(this, node.child1());
641     GPRTemporary result(this, op1);
642     m_jit.move(op1.gpr(), result.gpr());
643     integerResult(result.gpr(), m_compileIndex, op1.format());
644 }
645
646 static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg source, FPRReg scratch)
647 {
648     // Unordered compare so we pick up NaN
649     static const double zero = 0;
650     static const double byteMax = 255;
651     static const double half = 0.5;
652     jit.loadDouble(&zero, scratch);
653     MacroAssembler::Jump tooSmall = jit.branchDouble(MacroAssembler::DoubleLessThanOrEqualOrUnordered, source, scratch);
654     jit.loadDouble(&byteMax, scratch);
655     MacroAssembler::Jump tooBig = jit.branchDouble(MacroAssembler::DoubleGreaterThan, source, scratch);
656     
657     jit.loadDouble(&half, scratch);
658     jit.addDouble(source, scratch);
659     jit.truncateDoubleToInt32(scratch, result);   
660     MacroAssembler::Jump truncatedInt = jit.jump();
661     
662     tooSmall.link(&jit);
663     jit.xorPtr(result, result);
664     MacroAssembler::Jump zeroed = jit.jump();
665     
666     tooBig.link(&jit);
667     jit.move(JITCompiler::TrustedImm32(255), result);
668     
669     truncatedInt.link(&jit);
670     zeroed.link(&jit);
671
672 }
673
674 void SpeculativeJIT::compilePutByValForByteArray(GPRReg base, GPRReg property, Node& node)
675 {
676     NodeIndex baseIndex = node.child1();
677     NodeIndex valueIndex = node.child3();
678     
679     if (!isByteArrayPrediction(m_state.forNode(baseIndex).m_type))
680         speculationCheck(JSValueSource::unboxedCell(base), baseIndex, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsByteArrayVPtr)));
681     GPRTemporary value;
682     GPRReg valueGPR;
683
684     if (at(valueIndex).isConstant()) {
685         JSValue jsValue = valueOfJSConstant(valueIndex);
686         if (!jsValue.isNumber()) {
687             terminateSpeculativeExecution(JSValueRegs(), NoNode);
688             noResult(m_compileIndex);
689             return;
690         }
691         double d = jsValue.asNumber();
692         d += 0.5;
693         if (!(d > 0))
694             d = 0;
695         else if (d > 255)
696             d = 255;
697         GPRTemporary scratch(this);
698         GPRReg scratchReg = scratch.gpr();
699         m_jit.move(Imm32((int)d), scratchReg);
700         value.adopt(scratch);
701         valueGPR = scratchReg;
702     } else if (!at(valueIndex).shouldNotSpeculateInteger()) {
703         SpeculateIntegerOperand valueOp(this, valueIndex);
704         GPRTemporary scratch(this);
705         GPRReg scratchReg = scratch.gpr();
706         m_jit.move(valueOp.gpr(), scratchReg);
707         MacroAssembler::Jump inBounds = m_jit.branch32(MacroAssembler::BelowOrEqual, scratchReg, TrustedImm32(0xff));
708         MacroAssembler::Jump tooBig = m_jit.branch32(MacroAssembler::GreaterThan, scratchReg, TrustedImm32(0xff));
709         m_jit.xorPtr(scratchReg, scratchReg);
710         MacroAssembler::Jump clamped = m_jit.jump();
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(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