DFG Speculative JIT does not always insert speculation checks when speculating
[WebKit-https.git] / Source / JavaScriptCore / dfg / DFGSpeculativeJIT.cpp
index 733e1b2..47def27 100644 (file)
@@ -49,7 +49,9 @@ GPRReg SpeculativeJIT::fillSpeculateIntInternal(NodeIndex nodeIndex, DataFormat&
                 returnFormat = DataFormatInteger;
                 return gpr;
             }
-            m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex), gpr);
+            terminateSpeculativeExecution();
+            returnFormat = DataFormatInteger;
+            return allocate();
         } else {
             DataFormat spillFormat = info.spillFormat();
             ASSERT(spillFormat & DataFormatJS);
@@ -174,6 +176,121 @@ GPRReg SpeculativeJIT::fillSpeculateIntStrict(NodeIndex nodeIndex)
     return result;
 }
 
+FPRReg SpeculativeJIT::fillSpeculateDouble(NodeIndex nodeIndex)
+{
+    Node& node = m_jit.graph()[nodeIndex];
+    VirtualRegister virtualRegister = node.virtualRegister();
+    GenerationInfo& info = m_generationInfo[virtualRegister];
+
+    if (info.registerFormat() == DataFormatNone) {
+        GPRReg gpr = allocate();
+
+        if (node.isConstant()) {
+            if (isInt32Constant(nodeIndex)) {
+                FPRReg fpr = fprAllocate();
+                m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(static_cast<double>(valueOfInt32Constant(nodeIndex))))), gpr);
+                m_jit.movePtrToDouble(gpr, fpr);
+                unlock(gpr);
+
+                m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
+                info.fillDouble(fpr);
+                return fpr;
+            }
+            if (isDoubleConstant(nodeIndex)) {
+                FPRReg fpr = fprAllocate();
+                m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfDoubleConstant(nodeIndex)))), gpr);
+                m_jit.movePtrToDouble(gpr, fpr);
+                unlock(gpr);
+
+                m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
+                info.fillDouble(fpr);
+                return fpr;
+            }
+            ASSERT(isJSConstant(nodeIndex));
+            JSValue jsValue = valueOfJSConstant(nodeIndex);
+            m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
+            m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
+            info.fillJSValue(gpr, DataFormatJS);
+            unlock(gpr);
+        } else {
+            DataFormat spillFormat = info.spillFormat();
+            ASSERT(spillFormat & DataFormatJS);
+            m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
+            m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
+            info.fillJSValue(gpr, spillFormat);
+            unlock(gpr);
+        }
+    }
+
+    switch (info.registerFormat()) {
+    case DataFormatNone:
+        // Should have filled, above.
+        ASSERT_NOT_REACHED();
+        
+    case DataFormatCell:
+    case DataFormatJSCell:
+    case DataFormatJS: {
+        GPRReg jsValueGpr = info.gpr();
+        m_gprs.lock(jsValueGpr);
+        FPRReg fpr = fprAllocate();
+        GPRReg tempGpr = allocate();
+
+        JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
+
+        speculationCheck(m_jit.branchTestPtr(MacroAssembler::Zero, jsValueGpr, GPRInfo::tagTypeNumberRegister));
+
+        // First, if we get here we have a double encoded as a JSValue
+        m_jit.move(jsValueGpr, tempGpr);
+        m_jit.addPtr(GPRInfo::tagTypeNumberRegister, tempGpr);
+        m_jit.movePtrToDouble(tempGpr, fpr);
+        JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
+
+        // Finally, handle integers.
+        isInteger.link(&m_jit);
+        m_jit.convertInt32ToDouble(jsValueGpr, fpr);
+        hasUnboxedDouble.link(&m_jit);
+
+        m_gprs.release(jsValueGpr);
+        m_gprs.unlock(jsValueGpr);
+        m_gprs.unlock(tempGpr);
+        m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
+        info.fillDouble(fpr);
+        return fpr;
+    }
+
+    case DataFormatJSInteger:
+    case DataFormatInteger: {
+        FPRReg fpr = fprAllocate();
+        GPRReg gpr = info.gpr();
+        m_gprs.lock(gpr);
+        m_jit.convertInt32ToDouble(gpr, fpr);
+        m_gprs.unlock(gpr);
+        return fpr;
+    }
+
+    // Unbox the double
+    case DataFormatJSDouble: {
+        GPRReg gpr = info.gpr();
+        FPRReg fpr = unboxDouble(gpr);
+
+        m_gprs.release(gpr);
+        m_fprs.retain(fpr, virtualRegister, SpillOrderDouble);
+
+        info.fillDouble(fpr);
+        return fpr;
+    }
+
+    case DataFormatDouble: {
+        FPRReg fpr = info.fpr();
+        m_fprs.lock(fpr);
+        return fpr;
+    }
+    }
+
+    ASSERT_NOT_REACHED();
+    return InvalidFPRReg;
+}
+
 GPRReg SpeculativeJIT::fillSpeculateCell(NodeIndex nodeIndex)
 {
     Node& node = m_jit.graph()[nodeIndex];
@@ -248,17 +365,17 @@ void SpeculativeJIT::compilePeepHoleIntegerBranch(Node& node, NodeIndex branchNo
         notTaken = tmp;
     }
 
-    if (isInt32Constant(node.child1)) {
-        int32_t imm = valueOfInt32Constant(node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
+    if (isInt32Constant(node.child1())) {
+        int32_t imm = valueOfInt32Constant(node.child1());
+        SpeculateIntegerOperand op2(this, node.child2());
         addBranch(m_jit.branch32(condition, JITCompiler::Imm32(imm), op2.gpr()), taken);
-    } else if (isInt32Constant(node.child2)) {
-        SpeculateIntegerOperand op1(this, node.child1);
-        int32_t imm = valueOfInt32Constant(node.child2);
+    } else if (isInt32Constant(node.child2())) {
+        SpeculateIntegerOperand op1(this, node.child1());
+        int32_t imm = valueOfInt32Constant(node.child2());
         addBranch(m_jit.branch32(condition, op1.gpr(), JITCompiler::Imm32(imm)), taken);
     } else {
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
+        SpeculateIntegerOperand op1(this, node.child1());
+        SpeculateIntegerOperand op2(this, node.child2());
         addBranch(m_jit.branch32(condition, op1.gpr(), op2.gpr()), taken);
     }
 
@@ -267,7 +384,7 @@ void SpeculativeJIT::compilePeepHoleIntegerBranch(Node& node, NodeIndex branchNo
         addBranch(m_jit.jump(), notTaken);
 }
 
-void SpeculativeJIT::compilePeepHoleEq(Node& node, NodeIndex branchNodeIndex)
+void SpeculativeJIT::compilePeepHoleCall(Node& node, NodeIndex branchNodeIndex, Z_DFGOperation_EJJ operation)
 {
     Node& branchNode = m_jit.graph()[branchNodeIndex];
     BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(branchNode.takenBytecodeOffset());
@@ -283,14 +400,14 @@ void SpeculativeJIT::compilePeepHoleEq(Node& node, NodeIndex branchNodeIndex)
         notTaken = tmp;
     }
 
-    JSValueOperand op1(this, node.child1);
-    JSValueOperand op2(this, node.child2);
+    JSValueOperand op1(this, node.child1());
+    JSValueOperand op2(this, node.child2());
     GPRReg op1GPR = op1.gpr();
     GPRReg op2GPR = op2.gpr();
     flushRegisters();
 
     GPRResult result(this);
-    callOperation(operationCompareEq, result.gpr(), op1GPR, op2GPR);
+    callOperation(operation, result.gpr(), op1GPR, op2GPR);
     addBranch(m_jit.branchTest8(condition, result.gpr()), taken);
 
     // Check for fall through, otherwise we need to jump.
@@ -298,6 +415,40 @@ void SpeculativeJIT::compilePeepHoleEq(Node& node, NodeIndex branchNodeIndex)
         addBranch(m_jit.jump(), notTaken);
 }
 
+// Returns true if the compare is fused with a subsequent branch.
+bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition condition, Z_DFGOperation_EJJ operation)
+{
+    // Fused compare & branch.
+    NodeIndex branchNodeIndex = detectPeepHoleBranch();
+    if (branchNodeIndex != NoNode) {
+        // detectPeepHoleBranch currently only permits the branch to be the very next node,
+        // so can be no intervening nodes to also reference the compare. 
+        ASSERT(node.adjustedRefCount() == 1);
+
+        if (shouldSpeculateInteger(node.child1(), node.child2()))
+            compilePeepHoleIntegerBranch(node, branchNodeIndex, condition);
+        else
+            compilePeepHoleCall(node, branchNodeIndex, operation);
+
+        use(node.child1());
+        use(node.child2());
+        m_compileIndex = branchNodeIndex;
+        return true;
+    }
+
+    // Normal case, not fused to branch.
+    SpeculateIntegerOperand op1(this, node.child1());
+    SpeculateIntegerOperand op2(this, node.child2());
+    GPRTemporary result(this, op1, op2);
+
+    m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
+
+    // If we add a DataFormatBool, we should use it here.
+    m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+    jsValueResult(result.gpr(), m_compileIndex);
+    return false;
+}
+
 void SpeculativeJIT::compile(Node& node)
 {
     NodeType op = node.op;
@@ -333,20 +484,22 @@ void SpeculativeJIT::compile(Node& node)
     case SetLocal: {
         switch (m_jit.graph().getPrediction(node.local())) {
         case PredictInt32: {
-            SpeculateIntegerOperand value(this, node.child1);
+            SpeculateIntegerOperand value(this, node.child1());
             m_jit.store32(value.gpr(), JITCompiler::payloadFor(node.local()));
             noResult(m_compileIndex);
             break;
         }
         case PredictArray: {
-            SpeculateCellOperand cell(this, node.child1);
-            m_jit.storePtr(cell.gpr(), JITCompiler::addressFor(node.local()));
+            SpeculateCellOperand cell(this, node.child1());
+            GPRReg cellGPR = cell.gpr();
+            speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(cellGPR), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
+            m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
             noResult(m_compileIndex);
             break;
         }
 
         default: {
-            JSValueOperand value(this, node.child1);
+            JSValueOperand value(this, node.child1());
             m_jit.storePtr(value.gpr(), JITCompiler::addressFor(node.local()));
             noResult(m_compileIndex);
             break;
@@ -358,23 +511,23 @@ void SpeculativeJIT::compile(Node& node)
     case BitAnd:
     case BitOr:
     case BitXor:
-        if (isInt32Constant(node.child1)) {
-            SpeculateIntegerOperand op2(this, node.child2);
+        if (isInt32Constant(node.child1())) {
+            SpeculateIntegerOperand op2(this, node.child2());
             GPRTemporary result(this, op2);
 
-            bitOp(op, valueOfInt32Constant(node.child1), op2.gpr(), result.gpr());
+            bitOp(op, valueOfInt32Constant(node.child1()), op2.gpr(), result.gpr());
 
             integerResult(result.gpr(), m_compileIndex);
-        } else if (isInt32Constant(node.child2)) {
-            SpeculateIntegerOperand op1(this, node.child1);
+        } else if (isInt32Constant(node.child2())) {
+            SpeculateIntegerOperand op1(this, node.child1());
             GPRTemporary result(this, op1);
 
-            bitOp(op, valueOfInt32Constant(node.child2), op1.gpr(), result.gpr());
+            bitOp(op, valueOfInt32Constant(node.child2()), op1.gpr(), result.gpr());
 
             integerResult(result.gpr(), m_compileIndex);
         } else {
-            SpeculateIntegerOperand op1(this, node.child1);
-            SpeculateIntegerOperand op2(this, node.child2);
+            SpeculateIntegerOperand op1(this, node.child1());
+            SpeculateIntegerOperand op2(this, node.child2());
             GPRTemporary result(this, op1, op2);
 
             GPRReg reg1 = op1.gpr();
@@ -388,17 +541,17 @@ void SpeculativeJIT::compile(Node& node)
     case BitRShift:
     case BitLShift:
     case BitURShift:
-        if (isInt32Constant(node.child2)) {
-            SpeculateIntegerOperand op1(this, node.child1);
+        if (isInt32Constant(node.child2())) {
+            SpeculateIntegerOperand op1(this, node.child1());
             GPRTemporary result(this, op1);
 
-            shiftOp(op, op1.gpr(), valueOfInt32Constant(node.child2) & 0x1f, result.gpr());
+            shiftOp(op, op1.gpr(), valueOfInt32Constant(node.child2()) & 0x1f, result.gpr());
 
             integerResult(result.gpr(), m_compileIndex);
         } else {
             // Do not allow shift amount to be used as the result, MacroAssembler does not permit this.
-            SpeculateIntegerOperand op1(this, node.child1);
-            SpeculateIntegerOperand op2(this, node.child2);
+            SpeculateIntegerOperand op1(this, node.child1());
+            SpeculateIntegerOperand op2(this, node.child2());
             GPRTemporary result(this, op1);
 
             GPRReg reg1 = op1.gpr();
@@ -410,7 +563,7 @@ void SpeculativeJIT::compile(Node& node)
         break;
 
     case UInt32ToNumber: {
-        IntegerOperand op1(this, node.child1);
+        IntegerOperand op1(this, node.child1());
         GPRTemporary result(this, op1);
 
         // Test the operand is positive.
@@ -422,7 +575,7 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case ValueToInt32: {
-        SpeculateIntegerOperand op1(this, node.child1);
+        SpeculateIntegerOperand op1(this, node.child1());
         GPRTemporary result(this, op1);
         m_jit.move(op1.gpr(), result.gpr());
         integerResult(result.gpr(), m_compileIndex, op1.format());
@@ -430,125 +583,187 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case ValueToNumber: {
-        SpeculateIntegerOperand op1(this, node.child1);
-        GPRTemporary result(this, op1);
-        m_jit.move(op1.gpr(), result.gpr());
-        integerResult(result.gpr(), m_compileIndex, op1.format());
+        if (isInteger(node.child1())) {
+            SpeculateIntegerOperand op1(this, node.child1());
+            GPRTemporary result(this, op1);
+            m_jit.move(op1.gpr(), result.gpr());
+            integerResult(result.gpr(), m_compileIndex, op1.format());
+            break;
+        }
+        SpeculateDoubleOperand op1(this, node.child1());
+        FPRTemporary result(this, op1);
+        m_jit.moveDouble(op1.fpr(), result.fpr());
+        doubleResult(result.fpr(), m_compileIndex);
         break;
     }
 
     case ValueAdd:
     case ArithAdd: {
-        if (isInt32Constant(node.child1)) {
-            int32_t imm1 = valueOfInt32Constant(node.child1);
-            SpeculateIntegerOperand op2(this, node.child2);
-            GPRTemporary result(this);
+        if (shouldSpeculateInteger(node.child1(), node.child2())) {
+            if (isInt32Constant(node.child1())) {
+                int32_t imm1 = valueOfInt32Constant(node.child1());
+                SpeculateIntegerOperand op2(this, node.child2());
+                GPRTemporary result(this);
 
-            speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr()));
+                speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, op2.gpr(), Imm32(imm1), result.gpr()));
 
-            integerResult(result.gpr(), m_compileIndex);
-            break;
-        }
-            
-        if (isInt32Constant(node.child2)) {
-            SpeculateIntegerOperand op1(this, node.child1);
-            int32_t imm2 = valueOfInt32Constant(node.child2);
-            GPRTemporary result(this);
+                integerResult(result.gpr(), m_compileIndex);
+                break;
+            }
+                
+            if (isInt32Constant(node.child2())) {
+                SpeculateIntegerOperand op1(this, node.child1());
+                int32_t imm2 = valueOfInt32Constant(node.child2());
+                GPRTemporary result(this);
 
-            speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+                speculationCheck(m_jit.branchAdd32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
 
-            integerResult(result.gpr(), m_compileIndex);
+                integerResult(result.gpr(), m_compileIndex);
+                break;
+            }
+                
+            SpeculateIntegerOperand op1(this, node.child1());
+            SpeculateIntegerOperand op2(this, node.child2());
+            GPRTemporary result(this, op1, op2);
+
+            GPRReg gpr1 = op1.gpr();
+            GPRReg gpr2 = op2.gpr();
+            GPRReg gprResult = result.gpr();
+            MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
+
+            if (gpr1 == gprResult)
+                speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
+            else if (gpr2 == gprResult)
+                speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
+            else
+                speculationCheck(check);
+
+            integerResult(gprResult, m_compileIndex);
             break;
         }
-            
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
-        GPRTemporary result(this, op1, op2);
 
-        GPRReg gpr1 = op1.gpr();
-        GPRReg gpr2 = op2.gpr();
-        GPRReg gprResult = result.gpr();
-        MacroAssembler::Jump check = m_jit.branchAdd32(MacroAssembler::Overflow, gpr1, gpr2, gprResult);
+        SpeculateDoubleOperand op1(this, node.child1());
+        SpeculateDoubleOperand op2(this, node.child2());
+        FPRTemporary result(this, op1, op2);
 
-        if (gpr1 == gprResult)
-            speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr2));
-        else if (gpr2 == gprResult)
-            speculationCheck(check, SpeculationRecovery(SpeculativeAdd, gprResult, gpr1));
-        else
-            speculationCheck(check);
+        FPRReg reg1 = op1.fpr();
+        FPRReg reg2 = op2.fpr();
+        m_jit.addDouble(reg1, reg2, result.fpr());
 
-        integerResult(gprResult, m_compileIndex);
+        doubleResult(result.fpr(), m_compileIndex);
         break;
     }
 
     case ArithSub: {
-        if (isInt32Constant(node.child2)) {
-            SpeculateIntegerOperand op1(this, node.child1);
-            int32_t imm2 = valueOfInt32Constant(node.child2);
+        if (shouldSpeculateInteger(node.child1(), node.child2())) {
+            if (isInt32Constant(node.child2())) {
+                SpeculateIntegerOperand op1(this, node.child1());
+                int32_t imm2 = valueOfInt32Constant(node.child2());
+                GPRTemporary result(this);
+
+                speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+
+                integerResult(result.gpr(), m_compileIndex);
+                break;
+            }
+                
+            SpeculateIntegerOperand op1(this, node.child1());
+            SpeculateIntegerOperand op2(this, node.child2());
             GPRTemporary result(this);
 
-            speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), Imm32(imm2), result.gpr()));
+            speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
 
             integerResult(result.gpr(), m_compileIndex);
             break;
         }
-            
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
-        GPRTemporary result(this);
 
-        speculationCheck(m_jit.branchSub32(MacroAssembler::Overflow, op1.gpr(), op2.gpr(), result.gpr()));
+        SpeculateDoubleOperand op1(this, node.child1());
+        SpeculateDoubleOperand op2(this, node.child2());
+        FPRTemporary result(this, op1);
+
+        FPRReg reg1 = op1.fpr();
+        FPRReg reg2 = op2.fpr();
+        m_jit.subDouble(reg1, reg2, result.fpr());
 
-        integerResult(result.gpr(), m_compileIndex);
+        doubleResult(result.fpr(), m_compileIndex);
         break;
     }
 
     case ArithMul: {
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
-        GPRTemporary result(this);
+        if (shouldSpeculateInteger(node.child1(), node.child2())) {
+            SpeculateIntegerOperand op1(this, node.child1());
+            SpeculateIntegerOperand op2(this, node.child2());
+            GPRTemporary result(this);
+
+            GPRReg reg1 = op1.gpr();
+            GPRReg reg2 = op2.gpr();
+            speculationCheck(m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr()));
+
+            MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.gpr());
+            speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg1, TrustedImm32(0)));
+            speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg2, TrustedImm32(0)));
+            resultNonZero.link(&m_jit);
 
-        GPRReg reg1 = op1.gpr();
-        GPRReg reg2 = op2.gpr();
-        speculationCheck(m_jit.branchMul32(MacroAssembler::Overflow, reg1, reg2, result.gpr()));
+            integerResult(result.gpr(), m_compileIndex);
+            break;
+        }
 
-        MacroAssembler::Jump resultNonZero = m_jit.branchTest32(MacroAssembler::NonZero, result.gpr());
-        speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg1, TrustedImm32(0)));
-        speculationCheck(m_jit.branch32(MacroAssembler::LessThan, reg2, TrustedImm32(0)));
-        resultNonZero.link(&m_jit);
+        SpeculateDoubleOperand op1(this, node.child1());
+        SpeculateDoubleOperand op2(this, node.child2());
+        FPRTemporary result(this, op1, op2);
 
-        integerResult(result.gpr(), m_compileIndex);
+        FPRReg reg1 = op1.fpr();
+        FPRReg reg2 = op2.fpr();
+        
+        m_jit.mulDouble(reg1, reg2, result.fpr());
+        
+        doubleResult(result.fpr(), m_compileIndex);
         break;
     }
 
     case ArithDiv: {
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
-        GPRTemporary result(this, op1, op2);
+        SpeculateDoubleOperand op1(this, node.child1());
+        SpeculateDoubleOperand op2(this, node.child2());
+        FPRTemporary result(this, op1);
 
-        op1.gpr();
-        op2.gpr();
-        terminateSpeculativeExecution();
+        FPRReg reg1 = op1.fpr();
+        FPRReg reg2 = op2.fpr();
+        m_jit.divDouble(reg1, reg2, result.fpr());
 
-        integerResult(result.gpr(), m_compileIndex);
+        doubleResult(result.fpr(), m_compileIndex);
         break;
     }
 
     case ArithMod: {
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
-        GPRTemporary result(this, op1, op2);
+        SpeculateIntegerOperand op1(this, node.child1());
+        SpeculateIntegerOperand op2(this, node.child2());
+        GPRTemporary eax(this, X86Registers::eax);
+        GPRTemporary edx(this, X86Registers::edx);
+        GPRReg op1Gpr = op1.gpr();
+        GPRReg op2Gpr = op2.gpr();
+
+        speculationCheck(m_jit.branchTestPtr(JITCompiler::Zero, op2Gpr));
+
+        GPRReg temp2 = InvalidGPRReg;
+        if (op2Gpr == X86Registers::eax || op2Gpr == X86Registers::edx) {
+            temp2 = allocate();
+            m_jit.move(op2Gpr, temp2);
+            op2Gpr = temp2;
+        }
 
-        op1.gpr();
-        op2.gpr();
-        terminateSpeculativeExecution();
+        m_jit.move(op1Gpr, eax.gpr());
+        m_jit.assembler().cdq();
+        m_jit.assembler().idivl_r(op2Gpr);
+
+        if (temp2 != InvalidGPRReg)
+            unlock(temp2);
 
-        integerResult(result.gpr(), m_compileIndex);
+        integerResult(edx.gpr(), m_compileIndex);
         break;
     }
 
     case LogicalNot: {
-        JSValueOperand value(this, node.child1);
+        JSValueOperand value(this, node.child1());
         GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
 
         m_jit.move(value.gpr(), result.gpr());
@@ -561,98 +776,34 @@ void SpeculativeJIT::compile(Node& node)
         break;
     }
 
-    case CompareLess: {
-        // Fused compare & branch.
-        NodeIndex branchNodeIndex = detectPeepHoleBranch();
-        if (branchNodeIndex != NoNode) {
-            // detectPeepHoleBranch currently only permits the branch to be the very next node,
-            // so can be no intervening nodes to also reference the compare. 
-            ASSERT(node.adjustedRefCount() == 1);
-
-            compilePeepHoleIntegerBranch(node, branchNodeIndex, JITCompiler::LessThan);
-
-            use(node.child1);
-            use(node.child2);
-            m_compileIndex = branchNodeIndex;
+    case CompareLess:
+        if (compare(node, JITCompiler::LessThan, operationCompareLess))
             return;
-        }
-
-        // Normal case, not fused to branch.
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
-        GPRTemporary result(this, op1, op2);
-
-        m_jit.compare32(JITCompiler::LessThan, op1.gpr(), op2.gpr(), result.gpr());
-
-        // If we add a DataFormatBool, we should use it here.
-        m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
-        jsValueResult(result.gpr(), m_compileIndex);
         break;
-    }
-
-    case CompareLessEq: {
-        // Fused compare & branch.
-        NodeIndex branchNodeIndex = detectPeepHoleBranch();
-        if (branchNodeIndex != NoNode) {
-            // detectPeepHoleBranch currently only permits the branch to be the very next node,
-            // so can be no intervening nodes to also reference the compare. 
-            ASSERT(node.adjustedRefCount() == 1);
-
-            compilePeepHoleIntegerBranch(node, branchNodeIndex, JITCompiler::LessThanOrEqual);
 
-            use(node.child1);
-            use(node.child2);
-            m_compileIndex = branchNodeIndex;
+    case CompareLessEq:
+        if (compare(node, JITCompiler::LessThanOrEqual, operationCompareLessEq))
             return;
-        }
-
-        // Normal case, not fused to branch.
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
-        GPRTemporary result(this, op1, op2);
-
-        m_jit.compare32(JITCompiler::LessThanOrEqual, op1.gpr(), op2.gpr(), result.gpr());
-
-        // If we add a DataFormatBool, we should use it here.
-        m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
-        jsValueResult(result.gpr(), m_compileIndex);
         break;
-    }
-
-    case CompareEq: {
-        // Fused compare & branch.
-        NodeIndex branchNodeIndex = detectPeepHoleBranch();
-        if (branchNodeIndex != NoNode) {
-            // detectPeepHoleBranch currently only permits the branch to be the very next node,
-            // so can be no intervening nodes to also reference the compare. 
-            ASSERT(node.adjustedRefCount() == 1);
-
-            if (isInteger(node.child1) || isInteger(node.child2))
-                compilePeepHoleIntegerBranch(node, branchNodeIndex, JITCompiler::Equal);
-            else
-                compilePeepHoleEq(node, branchNodeIndex);
 
-            use(node.child1);
-            use(node.child2);
-            m_compileIndex = branchNodeIndex;
+    case CompareGreater:
+        if (compare(node, JITCompiler::GreaterThan, operationCompareGreater))
             return;
-        }
-
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
-        GPRTemporary result(this, op1, op2);
+        break;
 
-        m_jit.compare32(JITCompiler::Equal, op1.gpr(), op2.gpr(), result.gpr());
+    case CompareGreaterEq:
+        if (compare(node, JITCompiler::GreaterThanOrEqual, operationCompareGreaterEq))
+            return;
+        break;
 
-        // If we add a DataFormatBool, we should use it here.
-        m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
-        jsValueResult(result.gpr(), m_compileIndex);
+    case CompareEq:
+        if (compare(node, JITCompiler::Equal, operationCompareEq))
+            return;
         break;
-    }
 
     case CompareStrictEq: {
-        SpeculateIntegerOperand op1(this, node.child1);
-        SpeculateIntegerOperand op2(this, node.child2);
+        SpeculateIntegerOperand op1(this, node.child1());
+        SpeculateIntegerOperand op2(this, node.child2());
         GPRTemporary result(this, op1, op2);
 
         m_jit.compare32(JITCompiler::Equal, op1.gpr(), op2.gpr(), result.gpr());
@@ -664,18 +815,18 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case GetByVal: {
-        NodeIndex alias = node.child3;
+        NodeIndex alias = node.child3();
         if (alias != NoNode) {
             // FIXME: result should be able to reuse child1, child2. Should have an 'UnusedOperand' type.
-            JSValueOperand aliasedValue(this, node.child3);
+            JSValueOperand aliasedValue(this, node.child3());
             GPRTemporary result(this, aliasedValue);
             m_jit.move(aliasedValue.gpr(), result.gpr());
             jsValueResult(result.gpr(), m_compileIndex);
             break;
         }
 
-        SpeculateCellOperand base(this, node.child1);
-        SpeculateStrictInt32Operand property(this, node.child2);
+        SpeculateCellOperand base(this, node.child1());
+        SpeculateStrictInt32Operand property(this, node.child2());
         GPRTemporary storage(this);
 
         GPRReg baseReg = base.gpr();
@@ -688,7 +839,7 @@ void SpeculativeJIT::compile(Node& node)
 
         // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
         // If we have predicted the base to be type array, we can skip the check.
-        Node& baseNode = m_jit.graph()[node.child1];
+        Node& baseNode = m_jit.graph()[node.child1()];
         if (baseNode.op != GetLocal || m_jit.graph().getPrediction(baseNode.local()) != PredictArray)
             speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
         speculationCheck(m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())));
@@ -705,35 +856,41 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case PutByVal: {
-        SpeculateCellOperand base(this, node.child1);
-        SpeculateStrictInt32Operand property(this, node.child2);
-        JSValueOperand value(this, node.child3);
-        GPRTemporary storage(this);
+        SpeculateCellOperand base(this, node.child1());
+        SpeculateStrictInt32Operand property(this, node.child2());
+        JSValueOperand value(this, node.child3());
+        GPRTemporary scratch(this);
 
-        // Map base, property & value into registers, allocate a register for storage.
+        // Map base, property & value into registers, allocate a scratch register.
         GPRReg baseReg = base.gpr();
         GPRReg propertyReg = property.gpr();
         GPRReg valueReg = value.gpr();
-        GPRReg storageReg = storage.gpr();
+        GPRReg scratchReg = scratch.gpr();
+        
+        if (!m_compileOkay)
+            return;
+
+        writeBarrier(m_jit, baseReg, scratchReg);
 
         // Check that base is an array, and that property is contained within m_vector (< m_vectorLength).
         // If we have predicted the base to be type array, we can skip the check.
-        Node& baseNode = m_jit.graph()[node.child1];
+        Node& baseNode = m_jit.graph()[node.child1()];
         if (baseNode.op != GetLocal || m_jit.graph().getPrediction(baseNode.local()) != PredictArray)
             speculationCheck(m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(m_jit.globalData()->jsArrayVPtr)));
         MacroAssembler::Jump withinArrayBounds = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()));
 
         // Code to handle put beyond array bounds.
-        silentSpillAllRegisters(storageReg, baseReg, propertyReg, valueReg);
+        silentSpillAllRegisters(scratchReg, baseReg, propertyReg, valueReg);
         setupStubArguments(baseReg, propertyReg, valueReg);
         m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
         JITCompiler::Call functionCall = appendCallWithExceptionCheck(operationPutByValBeyondArrayBounds);
-        silentFillAllRegisters(storageReg);
+        silentFillAllRegisters(scratchReg);
         JITCompiler::Jump wasBeyondArrayBounds = m_jit.jump();
 
         withinArrayBounds.link(&m_jit);
 
         // Get the array storage.
+        GPRReg storageReg = scratchReg;
         m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
 
         // Check if we're writing to a hole; if so increment m_numValuesInVector.
@@ -759,20 +916,23 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case PutByValAlias: {
-        SpeculateCellOperand base(this, node.child1);
-        SpeculateStrictInt32Operand property(this, node.child2);
-        JSValueOperand value(this, node.child3);
-        GPRTemporary storage(this, base); // storage may overwrite base.
+        SpeculateCellOperand base(this, node.child1());
+        SpeculateStrictInt32Operand property(this, node.child2());
+        JSValueOperand value(this, node.child3());
+        GPRTemporary scratch(this);
+        
+        GPRReg baseReg = base.gpr();
+        GPRReg scratchReg = scratch.gpr();
+
+        writeBarrier(m_jit, baseReg, scratchReg);
 
         // Get the array storage.
-        GPRReg storageReg = storage.gpr();
-        m_jit.loadPtr(MacroAssembler::Address(base.gpr(), JSArray::storageOffset()), storageReg);
+        GPRReg storageReg = scratchReg;
+        m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg);
 
-        // Map property & value into registers.
+        // Store the value to the array.
         GPRReg propertyReg = property.gpr();
         GPRReg valueReg = value.gpr();
-
-        // Store the value to the array.
         m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])));
 
         noResult(m_compileIndex);
@@ -788,7 +948,7 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case Branch: {
-        JSValueOperand value(this, node.child1);
+        JSValueOperand value(this, node.child1());
         GPRReg valueReg = value.gpr();
 
         BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
@@ -824,7 +984,7 @@ void SpeculativeJIT::compile(Node& node)
 #endif
 
         // Return the result in returnValueGPR.
-        JSValueOperand op1(this, node.child1);
+        JSValueOperand op1(this, node.child1());
         m_jit.move(op1.gpr(), GPRInfo::returnValueGPR);
 
         // Grab the return address.
@@ -840,7 +1000,7 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case ConvertThis: {
-        SpeculateCellOperand thisValue(this, node.child1);
+        SpeculateCellOperand thisValue(this, node.child1());
         GPRTemporary temp(this);
 
         m_jit.loadPtr(JITCompiler::Address(thisValue.gpr(), JSCell::structureOffset()), temp.gpr());
@@ -851,7 +1011,7 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case GetById: {
-        SpeculateCellOperand base(this, node.child1);
+        SpeculateCellOperand base(this, node.child1());
         GPRTemporary result(this, base);
 
         GPRReg resultGPR = result.gpr();
@@ -861,11 +1021,23 @@ void SpeculativeJIT::compile(Node& node)
         jsValueResult(resultGPR, m_compileIndex);
         break;
     }
+        
+    case GetMethod: {
+        SpeculateCellOperand base(this, node.child1());
+        GPRTemporary result(this, base);
+
+        GPRReg resultGPR = result.gpr();
+
+        cachedGetMethod(base.gpr(), resultGPR, node.identifierNumber());
+
+        jsValueResult(resultGPR, m_compileIndex);
+        break;
+    }
 
     case PutById: {
-        SpeculateCellOperand base(this, node.child1);
-        JSValueOperand value(this, node.child2);
-        GPRTemporary scratch(this, base);
+        SpeculateCellOperand base(this, node.child1());
+        JSValueOperand value(this, node.child2());
+        GPRTemporary scratch(this);
 
         cachedPutById(base.gpr(), value.gpr(), scratch.gpr(), node.identifierNumber(), NotDirect);
         
@@ -874,9 +1046,9 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case PutByIdDirect: {
-        SpeculateCellOperand base(this, node.child1);
-        JSValueOperand value(this, node.child2);
-        GPRTemporary scratch(this, base);
+        SpeculateCellOperand base(this, node.child1());
+        JSValueOperand value(this, node.child2());
+        GPRTemporary scratch(this);
 
         cachedPutById(base.gpr(), value.gpr(), scratch.gpr(), node.identifierNumber(), Direct);
 
@@ -896,19 +1068,87 @@ void SpeculativeJIT::compile(Node& node)
     }
 
     case PutGlobalVar: {
-        JSValueOperand value(this, node.child1);
-        GPRTemporary temp(this);
+        JSValueOperand value(this, node.child1());
+        GPRTemporary globalObject(this);
+        GPRTemporary scratch(this);
+        
+        GPRReg globalObjectReg = globalObject.gpr();
+        GPRReg scratchReg = scratch.gpr();
 
-        JSVariableObject* globalObject = m_jit.codeBlock()->globalObject();
-        m_jit.loadPtr(globalObject->addressOfRegisters(), temp.gpr());
-        m_jit.storePtr(value.gpr(), JITCompiler::addressForGlobalVar(temp.gpr(), node.varNumber()));
+        m_jit.move(MacroAssembler::TrustedImmPtr(m_jit.codeBlock()->globalObject()), globalObjectReg);
+
+        writeBarrier(m_jit, globalObjectReg, scratchReg);
+
+        m_jit.loadPtr(MacroAssembler::Address(globalObjectReg, JSVariableObject::offsetOfRegisters()), scratchReg);
+        m_jit.storePtr(value.gpr(), JITCompiler::addressForGlobalVar(scratchReg, node.varNumber()));
 
         noResult(m_compileIndex);
         break;
     }
 
+    case CheckHasInstance: {
+        SpeculateCellOperand base(this, node.child1());
+        GPRTemporary structure(this);
+
+        // Speculate that base 'ImplementsDefaultHasInstance'.
+        m_jit.loadPtr(MacroAssembler::Address(base.gpr(), JSCell::structureOffset()), structure.gpr());
+        speculationCheck(m_jit.branchTest8(MacroAssembler::Zero, MacroAssembler::Address(structure.gpr(), Structure::typeInfoFlagsOffset()), MacroAssembler::TrustedImm32(ImplementsDefaultHasInstance)));
+
+        noResult(m_compileIndex);
+        break;
+    }
+
+    case InstanceOf: {
+        SpeculateCellOperand value(this, node.child1());
+        // Base unused since we speculate default InstanceOf behaviour in CheckHasInstance.
+        SpeculateCellOperand prototype(this, node.child3());
+
+        GPRTemporary scratch(this);
+
+        GPRReg valueReg = value.gpr();
+        GPRReg prototypeReg = prototype.gpr();
+        GPRReg scratchReg = scratch.gpr();
+
+        // Check that prototype is an object.
+        m_jit.loadPtr(MacroAssembler::Address(prototypeReg, JSCell::structureOffset()), scratchReg);
+        speculationCheck(m_jit.branch8(MacroAssembler::NotEqual, MacroAssembler::Address(scratchReg, Structure::typeInfoTypeOffset()), MacroAssembler::TrustedImm32(ObjectType)));
+
+        // Initialize scratchReg with the value being checked.
+        m_jit.move(valueReg, scratchReg);
+
+        // Walk up the prototype chain of the value (in scratchReg), comparing to prototypeReg.
+        MacroAssembler::Label loop(&m_jit);
+        m_jit.loadPtr(MacroAssembler::Address(scratchReg, JSCell::structureOffset()), scratchReg);
+        m_jit.loadPtr(MacroAssembler::Address(scratchReg, Structure::prototypeOffset()), scratchReg);
+        MacroAssembler::Jump isInstance = m_jit.branchPtr(MacroAssembler::Equal, scratchReg, prototypeReg);
+        m_jit.branchTestPtr(MacroAssembler::Zero, scratchReg, GPRInfo::tagMaskRegister).linkTo(loop, &m_jit);
+
+        // No match - result is false.
+        m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(false))), scratchReg);
+        MacroAssembler::Jump putResult = m_jit.jump();
+
+        isInstance.link(&m_jit);
+        m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsBoolean(true))), scratchReg);
+
+        putResult.link(&m_jit);
+        jsValueResult(scratchReg, m_compileIndex);
+        break;
+    }
+
     case Phi:
         ASSERT_NOT_REACHED();
+
+    case Breakpoint:
+#if ENABLE(DEBUG_WITH_BREAKPOINT)
+        m_jit.breakpoint();
+#else
+        ASSERT_NOT_REACHED();
+#endif
+        break;
+        
+    case Call:
+        emitCall(node);
+        break;
     }
 
     if (node.hasResult() && node.mustGenerate())