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