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