Changeset 94629 in webkit for trunk/Source/JavaScriptCore/dfg


Ignore:
Timestamp:
Sep 6, 2011, 7:47:51 PM (14 years ago)
Author:
[email protected]
Message:

DFG JIT does not optimize booleans
https://bugs.webkit.org/show_bug.cgi?id=67670

Reviewed by Gavin Barraclough.

This adds boolean value profiling, boolean prediction in the DFG,
boolean forward flow propagation in the DFGPropagator, boolean
data format in DFG generation info, and comprehensive optimizations
based on both boolean prediction and boolean generation info.
This is brings the speed-up on v8-richards to 12%, and gives slight
speed-ups elsewhere as well.

Making this work right required navigating some subtleties in
value profiling. Some functions get compiled with insufficient
information because some important path of the function never
executed. In these cases, we wish to fall back on static
speculation. But to do so, we need to ensure that predictions that
are inherent in the code (like that GetById almost certainly takes
a cell operand) are reflected in predictions that we make in
DFGPropagator. Thus, DFGPropagator now does both backward and
forward flow, using a both forward and backward fixpoint.

The backward flow in DFGPropagator is a separate static analysis,
and needs to keep a set of backward flow abstract values for
variables, arguments, and globals. To make this easy, this patch
factors out DFGGraph's prediction tracking capability into
DFGPredictionTracker, which now gets used by both DFGGraph (for
forward flow predictions) and DFGPropagator (for backward flow
predictions). Backward flow predictions eventually get merged
into forward flow ones, but the two are not equivalent: a forward
flow prediction is a superset of the backward flow prediction.

Debugging these prediction issues required a better understanding
of where we fail speculation, and what our value predictions look
like. This patch also adds optional verbose speculation failure
(so an informative printf fires whenever speculation failure occurs)
and slight improvements to the verbosity in other places.

  • bytecode/ValueProfile.h:

(JSC::ValueProfile::numberOfBooleans):
(JSC::ValueProfile::probabilityOfBoolean):
(JSC::ValueProfile::dump):
(JSC::ValueProfile::computeStatistics):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::stronglyPredict):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGGenerationInfo.h:

(JSC::DFG::dataFormatToString):
(JSC::DFG::needDataFormatConversion):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::predictArgumentTypes):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::Graph):
(JSC::DFG::Graph::predictions):
(JSC::DFG::Graph::predict):
(JSC::DFG::Graph::predictGlobalVar):
(JSC::DFG::Graph::getPrediction):
(JSC::DFG::Graph::getGlobalVarPrediction):
(JSC::DFG::Graph::isBooleanConstant):
(JSC::DFG::Graph::valueOfBooleanConstant):

  • dfg/DFGJITCodeGenerator.cpp:

(JSC::DFG::JITCodeGenerator::fillInteger):
(JSC::DFG::JITCodeGenerator::fillDouble):
(JSC::DFG::JITCodeGenerator::fillJSValue):
(JSC::DFG::JITCodeGenerator::isKnownNotInteger):
(JSC::DFG::JITCodeGenerator::isKnownBoolean):
(JSC::DFG::JITCodeGenerator::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::JITCodeGenerator::nonSpeculativeNonPeepholeCompare):
(JSC::DFG::JITCodeGenerator::nonSpeculativeNonPeepholeStrictEq):
(JSC::DFG::JITCodeGenerator::emitBranch):
(JSC::DFG::JITCodeGenerator::speculationCheck):
(JSC::DFG::GPRTemporary::GPRTemporary):

  • dfg/DFGJITCodeGenerator.h:

(JSC::DFG::JITCodeGenerator::isBooleanConstant):
(JSC::DFG::JITCodeGenerator::valueOfBooleanConstant):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::jumpFromSpeculativeToNonSpeculative):
(JSC::DFG::JITCompiler::link):

  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::debugCall):
(JSC::DFG::JITCompiler::isBooleanConstant):
(JSC::DFG::JITCompiler::valueOfBooleanConstant):

  • dfg/DFGNode.h:

(JSC::DFG::isBooleanPrediction):
(JSC::DFG::predictionToString):
(JSC::DFG::mergePredictions):
(JSC::DFG::makePrediction):
(JSC::DFG::Node::isBooleanConstant):
(JSC::DFG::Node::valueOfBooleanConstant):
(JSC::DFG::Node::hasBooleanResult):
(JSC::DFG::Node::hasNumericResult):
(JSC::DFG::Node::predict):

  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionTracker.h: Added.

(JSC::DFG::operandIsArgument):
(JSC::DFG::PredictionSlot::PredictionSlot):
(JSC::DFG::PredictionTracker::PredictionTracker):
(JSC::DFG::PredictionTracker::initializeSimilarTo):
(JSC::DFG::PredictionTracker::numberOfArguments):
(JSC::DFG::PredictionTracker::numberOfVariables):
(JSC::DFG::PredictionTracker::argumentIndexForOperand):
(JSC::DFG::PredictionTracker::predictArgument):
(JSC::DFG::PredictionTracker::predict):
(JSC::DFG::PredictionTracker::predictGlobalVar):
(JSC::DFG::PredictionTracker::getArgumentPrediction):
(JSC::DFG::PredictionTracker::getPrediction):
(JSC::DFG::PredictionTracker::getGlobalVarPrediction):

  • dfg/DFGPropagator.cpp:

(JSC::DFG::Propagator::Propagator):
(JSC::DFG::Propagator::fixpoint):
(JSC::DFG::Propagator::setPrediction):
(JSC::DFG::Propagator::mergeUse):
(JSC::DFG::Propagator::mergePrediction):
(JSC::DFG::Propagator::propagateNode):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal):
(JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculateBooleanOperand::SpeculateBooleanOperand):
(JSC::DFG::SpeculateBooleanOperand::~SpeculateBooleanOperand):
(JSC::DFG::SpeculateBooleanOperand::index):
(JSC::DFG::SpeculateBooleanOperand::gpr):
(JSC::DFG::SpeculateBooleanOperand::use):

  • runtime/JSGlobalData.h:
  • runtime/JSValue.cpp:

(JSC::JSValue::description):

Location:
trunk/Source/JavaScriptCore/dfg
Files:
1 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r94559 r94629  
    476476        ASSERT(profile);
    477477#if DFG_DEBUG_VERBOSE
    478         printf("Dynamic prediction [%u, %u]: ", nodeIndex, bytecodeIndex);
     478        printf("Dynamic profile [%u, %u]: ", nodeIndex, bytecodeIndex);
    479479        profile->dump(stdout);
    480480        printf("\n");
    481481#endif
    482482        m_graph[nodeIndex].predict(makePrediction(*m_globalData, *profile), StrongPrediction);
     483#if DFG_DEBUG_VERBOSE
     484        printf("    Prediction: %s\n", predictionToString(m_graph[nodeIndex].getPrediction()));
     485#endif
    483486#else
    484487        UNUSED_PARAM(nodeIndex);
  • trunk/Source/JavaScriptCore/dfg/DFGGenerationInfo.h

    r92986 r94629  
    4343    DataFormatInteger = 1,
    4444    DataFormatDouble = 2,
    45     DataFormatCell = 3,
     45    DataFormatBoolean = 3,
     46    DataFormatCell = 4,
    4647    DataFormatJS = 8,
    4748    DataFormatJSInteger = DataFormatJS | DataFormatInteger,
    4849    DataFormatJSDouble = DataFormatJS | DataFormatDouble,
    4950    DataFormatJSCell = DataFormatJS | DataFormatCell,
     51    DataFormatJSBoolean = DataFormatJS | DataFormatBoolean
    5052};
    5153
     
    6264    case DataFormatCell:
    6365        return "Cell";
     66    case DataFormatBoolean:
     67        return "Boolean";
    6468    case DataFormatJS:
    6569        return "JS";
     
    7074    case DataFormatJSCell:
    7175        return "JSCell";
     76    case DataFormatJSBoolean:
     77        return "JSBoolean";
    7278    default:
    7379        return "Unknown";
     
    8995    case DataFormatJSDouble:
    9096    case DataFormatJSCell:
     97    case DataFormatJSBoolean:
    9198        switch (to) {
    9299        case DataFormatInteger:
     
    98105        case DataFormatJSDouble:
    99106        case DataFormatJSCell:
     107        case DataFormatJSBoolean:
    100108            return false;
    101109        default:
     110            // This captures DataFormatBoolean, which is currently unused.
    102111            ASSERT_NOT_REACHED();
    103112        }
    104113    default:
     114        // This captures DataFormatBoolean, which is currently unused.
    105115        ASSERT_NOT_REACHED();
    106116    }
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r94559 r94629  
    5353
    5454    unsigned refCount = node.refCount();
    55     if (!refCount)
     55    if (!refCount) {
     56        printf("% 4d:\tskipped %s\n", (int)nodeIndex, opName(op));
    5657        return;
     58    }
    5759    bool mustGenerate = node.mustGenerate();
    5860    if (mustGenerate)
     
    194196{
    195197    if (exec) {
    196         size_t numberOfArguments = std::min(exec->argumentCountIncludingThis(), m_argumentPredictions.size());
     198        size_t numberOfArguments = std::min(exec->argumentCountIncludingThis(), m_predictions.numberOfArguments());
    197199       
    198200        for (size_t arg = 1; arg < numberOfArguments; ++arg) {
    199201            JSValue argumentValue = exec->argument(arg - 1);
    200202            if (argumentValue.isInt32())
    201                 m_argumentPredictions[arg].m_value |= PredictInt32;
     203                m_predictions.predictArgument(arg, PredictInt32, WeakPrediction);
    202204            else if (argumentValue.isDouble())
    203                 m_argumentPredictions[arg].m_value |= PredictDouble;
     205                m_predictions.predictArgument(arg, PredictDouble, WeakPrediction);
    204206        }
    205207    }
     
    223225#endif
    224226       
    225         mergePrediction(m_argumentPredictions[arg].m_value, makePrediction(globalData, *profile));
     227        m_predictions.predictArgument(arg, makePrediction(globalData, *profile) & ~PredictionTagMask, StrongPrediction);
    226228       
    227229#if DFG_DEBUG_VERBOSE
    228         printf("    Prediction: %s\n", predictionToString(m_argumentPredictions[arg].m_value));
     230        printf("    Prediction: %s\n", predictionToString(m_predictions.getArgumentPrediction(arg)));
    229231#endif
    230232    }
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r94559 r94629  
    3131#include "CodeBlock.h"
    3232#include "DFGNode.h"
     33#include "DFGPredictionTracker.h"
    3334#include "RegisterFile.h"
    3435#include <wtf/HashMap.h>
     
    4243
    4344namespace DFG {
    44 
    45 // helper function to distinguish vars & temporaries from arguments.
    46 inline bool operandIsArgument(int operand) { return operand < 0; }
    47 
    48 struct PredictionSlot {
    49 public:
    50     PredictionSlot()
    51         : m_value(PredictNone)
    52     {
    53     }
    54     PredictedType m_value;
    55 };
    5645
    5746typedef uint32_t BlockIndex;
     
    10493public:
    10594    Graph(unsigned numArguments, unsigned numVariables)
    106         : m_argumentPredictions(numArguments)
    107         , m_variablePredictions(numVariables)
     95        : m_predictions(numArguments, numVariables)
    10896    {
    10997    }
     
    136124        return *m_blocks[blockIndexForBytecodeOffset(bytecodeBegin)];
    137125    }
    138 
     126   
     127    PredictionTracker& predictions()
     128    {
     129        return m_predictions;
     130    }
     131   
    139132    bool predict(int operand, PredictedType prediction, PredictionSource source)
    140133    {
    141         if (operandIsArgument(operand)) {
    142             unsigned argument = operand + m_argumentPredictions.size() + RegisterFile::CallFrameHeaderSize;
    143             return mergePrediction(m_argumentPredictions[argument].m_value, makePrediction(prediction, source));
    144         }
    145        
    146         if ((unsigned)operand >= m_variablePredictions.size()) {
    147             ASSERT(operand >= 0);
    148             m_variablePredictions.resize(operand + 1);
    149         }
    150        
    151         return mergePrediction(m_variablePredictions[operand].m_value, makePrediction(prediction, source));
     134        return m_predictions.predict(operand, prediction, source);
    152135    }
    153136   
    154137    bool predictGlobalVar(unsigned varNumber, PredictedType prediction, PredictionSource source)
    155138    {
    156         HashMap<unsigned, PredictionSlot>::iterator iter = m_globalVarPredictions.find(varNumber + 1);
    157         if (iter == m_globalVarPredictions.end()) {
    158             PredictionSlot predictionSlot;
    159             bool result = mergePrediction(predictionSlot.m_value, makePrediction(prediction, source));
    160             m_globalVarPredictions.add(varNumber + 1, predictionSlot);
    161             return result;
    162         } else
    163             return mergePrediction(iter->second.m_value, makePrediction(prediction, source));
     139        return m_predictions.predictGlobalVar(varNumber, prediction, source);
    164140    }
    165141   
    166142    bool predict(Node& node, PredictedType prediction, PredictionSource source)
    167143    {
    168         switch (node.op) {
    169         case GetLocal:
    170             return predict(node.local(), prediction, source);
    171             break;
    172         case GetGlobalVar:
    173             return predictGlobalVar(node.varNumber(), prediction, source);
    174         case GetById:
    175         case GetMethod:
    176         case GetByVal:
    177         case Call:
    178         case Construct:
    179             return node.predict(prediction, source);
    180         default:
    181             return false;
    182         }
     144        return m_predictions.predict(node, prediction, source);
    183145    }
    184146
    185147    PredictedType getPrediction(int operand)
    186148    {
    187         if (operandIsArgument(operand)) {
    188             unsigned argument = operand + m_argumentPredictions.size() + RegisterFile::CallFrameHeaderSize;
    189             return m_argumentPredictions[argument].m_value;
    190         }
    191         if ((unsigned)operand < m_variablePredictions.size())
    192             return m_variablePredictions[operand].m_value;
    193         return PredictNone;
     149        return m_predictions.getPrediction(operand);
    194150    }
    195151   
    196152    PredictedType getGlobalVarPrediction(unsigned varNumber)
    197153    {
    198         HashMap<unsigned, PredictionSlot>::iterator iter = m_globalVarPredictions.find(varNumber + 1);
    199         if (iter == m_globalVarPredictions.end())
    200             return PredictNone;
    201         return iter->second.m_value;
     154        return m_predictions.getGlobalVarPrediction(varNumber);
    202155    }
    203156   
     
    212165            nodePtr = &(*this)[nodePtr->child1()];
    213166       
    214         switch (nodePtr->op) {
    215         case GetLocal:
    216             return getPrediction(nodePtr->local());
    217         case GetGlobalVar:
    218             return getGlobalVarPrediction(nodePtr->varNumber());
    219         case GetById:
    220         case GetMethod:
    221         case GetByVal:
    222         case Call:
    223         case Construct:
    224             return nodePtr->getPrediction();
    225         default:
    226             return PredictNone;
    227         }
     167        return m_predictions.getPrediction(*nodePtr);
    228168    }
    229169   
     
    245185        return at(nodeIndex).isDoubleConstant(codeBlock);
    246186    }
     187    bool isBooleanConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
     188    {
     189        return at(nodeIndex).isBooleanConstant(codeBlock);
     190    }
    247191    // Helper methods get constant values from nodes.
    248192    JSValue valueOfJSConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
     
    257201    {
    258202        return at(nodeIndex).valueOfDoubleConstant(codeBlock);
     203    }
     204    bool valueOfBooleanConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
     205    {
     206        return at(nodeIndex).valueOfBooleanConstant(codeBlock);
    259207    }
    260208
     
    272220    void refChildren(NodeIndex);
    273221
    274     Vector<PredictionSlot, 16> m_argumentPredictions;
    275     Vector<PredictionSlot, 16> m_variablePredictions;
    276     HashMap<unsigned, PredictionSlot> m_globalVarPredictions;
     222    PredictionTracker m_predictions;
    277223};
    278224
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp

    r93934 r94629  
    8181    case DataFormatCell:
    8282    case DataFormatJSCell:
     83    case DataFormatBoolean:
     84    case DataFormatJSBoolean:
    8385        // Should only be calling this function if we know this operand to be integer.
    8486        ASSERT_NOT_REACHED();
     
    154156    case DataFormatCell:
    155157    case DataFormatJSCell:
     158    case DataFormatBoolean:
     159    case DataFormatJSBoolean:
    156160        // Should only be calling this function if we know this operand to be numeric.
    157161        ASSERT_NOT_REACHED();
     
    296300    case DataFormatJSInteger:
    297301    case DataFormatJSDouble:
    298     case DataFormatJSCell: {
     302    case DataFormatJSCell:
     303    case DataFormatJSBoolean: {
    299304        GPRReg gpr = info.gpr();
    300305        m_gprs.lock(gpr);
    301306        return gpr;
    302307    }
     308       
     309    case DataFormatBoolean:
     310        // this type currently never occurs
     311        ASSERT_NOT_REACHED();
    303312    }
    304313
     
    407416    return (info.registerFormat() | DataFormatJS) == DataFormatJSDouble
    408417        || (info.registerFormat() | DataFormatJS) == DataFormatJSCell
     418        || (info.registerFormat() | DataFormatJS) == DataFormatJSBoolean
    409419        || (node.isConstant() && !valueOfJSConstant(nodeIndex).isInt32());
     420}
     421
     422bool JITCodeGenerator::isKnownBoolean(NodeIndex nodeIndex)
     423{
     424    Node& node = m_jit.graph()[nodeIndex];
     425    if (node.hasBooleanResult())
     426        return true;
     427   
     428    if (isBooleanConstant(nodeIndex))
     429        return true;
     430   
     431    VirtualRegister virtualRegister = node.virtualRegister();
     432    GenerationInfo& info = m_generationInfo[virtualRegister];
     433   
     434    return (info.registerFormat() | DataFormatJS) == DataFormatJSBoolean
     435        || (info.spillFormat() | DataFormatJS) == DataFormatJSBoolean;
    410436}
    411437
     
    589615   
    590616    m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
    591     jsValueResult(resultGPR, m_compileIndex);
     617    jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);
    592618}
    593619
     
    744770       
    745771        m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
    746         jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
     772        jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean, UseChildrenCalledExplicitly);
    747773    } else {
    748774        GPRTemporary result(this, arg2);
     
    778804        m_jit.or32(TrustedImm32(ValueFalse), resultGPR);
    779805       
    780         jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
     806        jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean, UseChildrenCalledExplicitly);
    781807    }
    782808}
     
    940966    }
    941967   
    942     jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
     968    jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean, UseChildrenCalledExplicitly);
    943969}
    944970
     
    969995    GPRReg valueGPR = value.gpr();
    970996   
    971     GPRTemporary result(this);
    972     GPRReg resultGPR = result.gpr();
    973    
    974     value.use();
    975    
    976997    BlockIndex taken = m_jit.graph().blockIndexForBytecodeOffset(node.takenBytecodeOffset());
    977998    BlockIndex notTaken = m_jit.graph().blockIndexForBytecodeOffset(node.notTakenBytecodeOffset());
    978 
    979     addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsNumber(0)))), notTaken);
    980     addBranch(m_jit.branchPtr(MacroAssembler::AboveOrEqual, valueGPR, GPRInfo::tagTypeNumberRegister), taken);
    981     addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false)))), notTaken);
    982     addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true)))), taken);
    983    
    984     silentSpillAllRegisters(resultGPR);
    985     m_jit.move(valueGPR, GPRInfo::argumentGPR1);
    986     m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
    987     appendCallWithExceptionCheck(dfgConvertJSValueToBoolean);
    988     m_jit.move(GPRInfo::returnValueGPR, resultGPR);
    989     silentFillAllRegisters(resultGPR);
    990    
    991     addBranch(m_jit.branchTest8(MacroAssembler::NonZero, resultGPR), taken);
    992     if (notTaken != (m_block + 1))
    993         addBranch(m_jit.jump(), notTaken);
    994    
    995     noResult(m_compileIndex, UseChildrenCalledExplicitly);
     999   
     1000    if (isKnownBoolean(node.child1())) {
     1001        MacroAssembler::ResultCondition condition = MacroAssembler::NonZero;
     1002       
     1003        if (taken == (m_block + 1)) {
     1004            condition = MacroAssembler::Zero;
     1005            BlockIndex tmp = taken;
     1006            taken = notTaken;
     1007            notTaken = tmp;
     1008        }
     1009       
     1010        addBranch(m_jit.branchTest32(condition, valueGPR, TrustedImm32(true)), taken);
     1011        if (notTaken != (m_block + 1))
     1012            addBranch(m_jit.jump(), notTaken);
     1013       
     1014        noResult(m_compileIndex);
     1015    } else {
     1016        GPRTemporary result(this);
     1017        GPRReg resultGPR = result.gpr();
     1018       
     1019        bool predictBoolean = isBooleanPrediction(m_jit.graph().getPrediction(m_jit.graph()[node.child1()]));
     1020   
     1021        if (predictBoolean) {
     1022            addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false)))), notTaken);
     1023            addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true)))), taken);
     1024        }
     1025       
     1026        if (m_isSpeculative && predictBoolean) {
     1027            speculationCheck(m_jit.jump());
     1028            value.use();
     1029        } else {
     1030            addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsNumber(0)))), notTaken);
     1031            addBranch(m_jit.branchPtr(MacroAssembler::AboveOrEqual, valueGPR, GPRInfo::tagTypeNumberRegister), taken);
     1032   
     1033            if (!predictBoolean) {
     1034                addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(false)))), notTaken);
     1035                addBranch(m_jit.branchPtr(MacroAssembler::Equal, valueGPR, MacroAssembler::ImmPtr(JSValue::encode(jsBoolean(true)))), taken);
     1036            }
     1037   
     1038            value.use();
     1039   
     1040            silentSpillAllRegisters(resultGPR);
     1041            m_jit.move(valueGPR, GPRInfo::argumentGPR1);
     1042            m_jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     1043            appendCallWithExceptionCheck(dfgConvertJSValueToBoolean);
     1044            m_jit.move(GPRInfo::returnValueGPR, resultGPR);
     1045            silentFillAllRegisters(resultGPR);
     1046   
     1047            addBranch(m_jit.branchTest8(MacroAssembler::NonZero, resultGPR), taken);
     1048            if (notTaken != (m_block + 1))
     1049                addBranch(m_jit.jump(), notTaken);
     1050        }
     1051       
     1052        noResult(m_compileIndex, UseChildrenCalledExplicitly);
     1053    }
    9961054}
    9971055
     
    10801138   
    10811139    m_jit.addJSCall(fastCall, slowCall, targetToCheck, isCall, m_jit.graph()[m_compileIndex].exceptionInfo);
     1140}
     1141
     1142void JITCodeGenerator::speculationCheck(MacroAssembler::Jump jumpToFail)
     1143{
     1144    ASSERT(m_isSpeculative);
     1145    static_cast<SpeculativeJIT*>(this)->speculationCheck(jumpToFail);
    10821146}
    10831147
     
    12881352}
    12891353
     1354GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateBooleanOperand& op1)
     1355    : m_jit(jit)
     1356    , m_gpr(InvalidGPRReg)
     1357{
     1358    if (m_jit->canReuse(op1.index()))
     1359        m_gpr = m_jit->reuse(op1.gpr());
     1360    else
     1361        m_gpr = m_jit->allocate();
     1362}
     1363
    12901364GPRTemporary::GPRTemporary(JITCodeGenerator* jit, JSValueOperand& op1)
    12911365    : m_jit(jit)
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h

    r93934 r94629  
    4242class SpeculateDoubleOperand;
    4343class SpeculateCellOperand;
     44class SpeculateBooleanOperand;
    4445
    4546
     
    411412    bool isKnownNotInteger(NodeIndex);
    412413
     414    bool isKnownBoolean(NodeIndex);
     415   
    413416    // Checks/accessors for constant values.
    414417    bool isConstant(NodeIndex nodeIndex) { return m_jit.isConstant(nodeIndex); }
     
    416419    bool isInt32Constant(NodeIndex nodeIndex) { return m_jit.isInt32Constant(nodeIndex); }
    417420    bool isDoubleConstant(NodeIndex nodeIndex) { return m_jit.isDoubleConstant(nodeIndex); }
     421    bool isBooleanConstant(NodeIndex nodeIndex) { return m_jit.isBooleanConstant(nodeIndex); }
    418422    int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return m_jit.valueOfInt32Constant(nodeIndex); }
    419423    double valueOfDoubleConstant(NodeIndex nodeIndex) { return m_jit.valueOfDoubleConstant(nodeIndex); }
    420424    JSValue valueOfJSConstant(NodeIndex nodeIndex) { return m_jit.valueOfJSConstant(nodeIndex); }
     425    bool valueOfBooleanConstant(NodeIndex nodeIndex) { return m_jit.valueOfBooleanConstant(nodeIndex); }
    421426    bool isNullConstant(NodeIndex nodeIndex)
    422427    {
     
    576581   
    577582    void emitCall(Node&);
     583   
     584    void speculationCheck(MacroAssembler::Jump jumpToFail);
    578585
    579586    // Called once a node has completed code generation but prior to setting
     
    11221129    GPRTemporary(JITCodeGenerator*, IntegerOperand&, IntegerOperand&);
    11231130    GPRTemporary(JITCodeGenerator*, SpeculateCellOperand&);
     1131    GPRTemporary(JITCodeGenerator*, SpeculateBooleanOperand&);
    11241132    GPRTemporary(JITCodeGenerator*, JSValueOperand&);
    11251133
  • trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp

    r94559 r94629  
    489489    breakpoint();
    490490#endif
     491   
     492#if DFG_VERBOSE_SPECULATION_FAILURE
     493    SpeculationFailureDebugInfo* debugInfo = new SpeculationFailureDebugInfo;
     494    debugInfo->codeBlock = m_codeBlock;
     495    debugInfo->debugOffset = debugOffset();
     496   
     497    debugCall(debugOperationPrintSpeculationFailure, debugInfo);
     498#endif
    491499
    492500    // Does this speculation check require any additional recovery to be performed,
     
    494502    // non-speculative path.
    495503    if (recovery) {
    496         // The only additional recovery we currently support is for integer add operation
    497         ASSERT(recovery->type() == SpeculativeAdd);
    498         ASSERT(check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].nodeIndex != NoNode);
    499         // Revert the add.
    500         sub32(recovery->src(), recovery->dest());
    501        
    502         // If recovery->dest() should have been boxed prior to the addition, then rebox
    503         // it.
    504         DataFormat format = check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].format;
    505         ASSERT(format == DataFormatInteger || format == DataFormatJSInteger || format == DataFormatJS);
    506         if (format != DataFormatInteger)
    507             orPtr(GPRInfo::tagTypeNumberRegister, recovery->dest());
     504        switch (recovery->type()) {
     505        case SpeculativeAdd: {
     506            ASSERT(check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].nodeIndex != NoNode);
     507            // Revert the add.
     508            sub32(recovery->src(), recovery->dest());
     509           
     510            // If recovery->dest() should have been boxed prior to the addition, then rebox
     511            // it.
     512            DataFormat format = check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].format;
     513            ASSERT(format == DataFormatInteger || format == DataFormatJSInteger || format == DataFormatJS);
     514            if (format != DataFormatInteger)
     515                orPtr(GPRInfo::tagTypeNumberRegister, recovery->dest());
     516            break;
     517        }
     518           
     519        case BooleanSpeculationCheck: {
     520            ASSERT(check.m_gprInfo[GPRInfo::toIndex(recovery->dest())].nodeIndex != NoNode);
     521            // Rebox the (non-)boolean
     522            xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), recovery->dest());
     523            break;
     524        }
     525           
     526        default:
     527            ASSERT_NOT_REACHED();
     528            break;
     529        }
    508530    }
    509531   
     
    876898    // Link the code, populate data in CodeBlock data structures.
    877899#if DFG_DEBUG_VERBOSE
    878     fprintf(stderr, "JIT code start at [%p, %p)\n", linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize());
     900    fprintf(stderr, "JIT code for %p start at [%p, %p)\n", m_codeBlock, linkBuffer.debugAddress(), static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize());
    879901#endif
    880902
  • trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.h

    r94559 r94629  
    5555struct SpeculationCheck;
    5656
     57#ifndef NDEBUG
     58typedef void (*V_DFGDebugOperation_EP)(ExecState*, void*);
     59#endif
     60
     61#if DFG_VERBOSE_SPECULATION_FAILURE
     62struct SpeculationFailureDebugInfo {
     63    CodeBlock* codeBlock;
     64    unsigned debugOffset;
     65};
     66#endif
     67
    5768// === CallRecord ===
    5869//
     
    206217        return functionCall;
    207218    }
     219   
     220#ifndef NDEBUG
     221    // Add a debug call. This call has no effect on JIT code execution state.
     222    void debugCall(V_DFGDebugOperation_EP function, void* argument)
     223    {
     224        for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i)
     225            storePtr(GPRInfo::toRegister(i), m_globalData->debugDataBuffer + i);
     226        for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
     227            move(TrustedImmPtr(m_globalData->debugDataBuffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
     228            storeDouble(FPRInfo::toRegister(i), GPRInfo::regT0);
     229        }
     230        move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
     231        move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
     232        move(TrustedImmPtr(reinterpret_cast<void*>(function)), GPRInfo::regT0);
     233        call(GPRInfo::regT0);
     234        for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
     235            move(TrustedImmPtr(m_globalData->debugDataBuffer + GPRInfo::numberOfRegisters + i), GPRInfo::regT0);
     236            loadDouble(GPRInfo::regT0, FPRInfo::toRegister(i));
     237        }
     238        for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i)
     239            loadPtr(m_globalData->debugDataBuffer + i, GPRInfo::toRegister(i));
     240    }
     241#endif
    208242
    209243    // Helper methods to check nodes for constants.
     
    212246    bool isInt32Constant(NodeIndex nodeIndex) { return graph().isInt32Constant(codeBlock(), nodeIndex); }
    213247    bool isDoubleConstant(NodeIndex nodeIndex) { return graph().isDoubleConstant(codeBlock(), nodeIndex); }
     248    bool isBooleanConstant(NodeIndex nodeIndex) { return graph().isBooleanConstant(codeBlock(), nodeIndex); }
    214249    // Helper methods get constant values from nodes.
    215250    JSValue valueOfJSConstant(NodeIndex nodeIndex) { return graph().valueOfJSConstant(codeBlock(), nodeIndex); }
    216251    int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return graph().valueOfInt32Constant(codeBlock(), nodeIndex); }
    217252    double valueOfDoubleConstant(NodeIndex nodeIndex) { return graph().valueOfDoubleConstant(codeBlock(), nodeIndex); }
     253    bool valueOfBooleanConstant(NodeIndex nodeIndex) { return graph().valueOfBooleanConstant(codeBlock(), nodeIndex); }
    218254
    219255    // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r94559 r94629  
    4545// Emit a breakpoint into the speculation failure code.
    4646#define DFG_JIT_BREAK_ON_SPECULATION_FAILURE 0
     47// Log every speculation failure.
     48#define DFG_VERBOSE_SPECULATION_FAILURE 0
    4749// Disable the DFG JIT without having to touch Platform.h!
    4850#define DFG_DEBUG_LOCAL_DISBALE 0
     
    9092#define NodeResultDouble  0x2000
    9193#define NodeResultInt32   0x3000
     94#define NodeResultBoolean 0x4000
    9295
    9396// This macro defines a set of information about all known node types, used to populate NodeId, NodeType below.
     
    141144    \
    142145    /* Nodes for comparison operations. */\
    143     macro(CompareLess, NodeResultJS | NodeMustGenerate) \
    144     macro(CompareLessEq, NodeResultJS | NodeMustGenerate) \
    145     macro(CompareGreater, NodeResultJS | NodeMustGenerate) \
    146     macro(CompareGreaterEq, NodeResultJS | NodeMustGenerate) \
    147     macro(CompareEq, NodeResultJS | NodeMustGenerate) \
    148     macro(CompareStrictEq, NodeResultJS) \
     146    macro(CompareLess, NodeResultBoolean | NodeMustGenerate) \
     147    macro(CompareLessEq, NodeResultBoolean | NodeMustGenerate) \
     148    macro(CompareGreater, NodeResultBoolean | NodeMustGenerate) \
     149    macro(CompareGreaterEq, NodeResultBoolean | NodeMustGenerate) \
     150    macro(CompareEq, NodeResultBoolean | NodeMustGenerate) \
     151    macro(CompareStrictEq, NodeResultBoolean) \
    149152    \
    150153    /* Calls. */\
     
    160163    macro(Breakpoint, NodeMustGenerate) \
    161164    macro(CheckHasInstance, NodeMustGenerate) \
    162     macro(InstanceOf, NodeResultJS) \
    163     macro(LogicalNot, NodeResultJS) \
     165    macro(InstanceOf, NodeResultBoolean) \
     166    macro(LogicalNot, NodeResultBoolean) \
    164167    \
    165168    /* Block terminals. */\
     
    199202static const PredictedType PredictDouble = 0x08;
    200203static const PredictedType PredictNumber = 0x0c;
    201 static const PredictedType PredictTop    = 0x0f;
     204static const PredictedType PredictBoolean = 0x10;
     205static const PredictedType PredictTop    = 0x1f;
    202206static const PredictedType StrongPredictionTag = 0x80;
    203207static const PredictedType PredictionTagMask    = 0x80;
     
    228232{
    229233    return !!(value & PredictNumber) && !(value & ~(PredictNumber | PredictionTagMask));
     234}
     235
     236inline bool isBooleanPrediction(PredictedType value)
     237{
     238    return (value & ~PredictionTagMask) == PredictBoolean;
    230239}
    231240
     
    249258        case PredictInt32:
    250259            return "p-strong-int32";
     260        case PredictDouble:
     261            return "p-strong-double";
    251262        case PredictNumber:
    252263            return "p-strong-number";
     264        case PredictBoolean:
     265            return "p-strong-boolean";
    253266        default:
    254267            return "p-strong-top";
     
    264277    case PredictInt32:
    265278        return "p-weak-int32";
     279    case PredictDouble:
     280        return "p-weak-double";
    266281    case PredictNumber:
    267282        return "p-weak-number";
     283    case PredictBoolean:
     284        return "p-weak-boolean";
    268285    default:
    269286        return "p-weak-top";
     
    326343    if (statistics.cells == statistics.samples)
    327344        return StrongPredictionTag | PredictCell;
     345   
     346    if (statistics.booleans == statistics.samples)
     347        return StrongPredictionTag | PredictBoolean;
    328348   
    329349    return StrongPredictionTag | PredictTop;
     
    424444    }
    425445   
     446    bool isBooleanConstant(CodeBlock* codeBlock)
     447    {
     448        return isConstant() && valueOfJSConstant(codeBlock).isBoolean();
     449    }
     450   
    426451    int32_t valueOfInt32Constant(CodeBlock* codeBlock)
    427452    {
     
    434459        ASSERT(isDoubleConstant(codeBlock));
    435460        return valueOfJSConstant(codeBlock).uncheckedGetNumber();
     461    }
     462   
     463    bool valueOfBooleanConstant(CodeBlock* codeBlock)
     464    {
     465        ASSERT(isBooleanConstant(codeBlock));
     466        return valueOfJSConstant(codeBlock).getBoolean();
    436467    }
    437468
     
    493524        return (op & NodeResultMask) == NodeResultJS;
    494525    }
     526   
     527    bool hasBooleanResult()
     528    {
     529        return (op & NodeResultMask) == NodeResultBoolean;
     530    }
    495531
    496532    // Check for integers or doubles.
    497533    bool hasNumericResult()
    498534    {
    499         // This check will need updating if more result types are added.
    500         ASSERT((hasInt32Result() || hasDoubleResult()) == !hasJSResult());
    501         return !hasJSResult();
     535        return hasInt32Result() || hasDoubleResult();
    502536    }
    503537
     
    564598        ASSERT(source == StrongPrediction);
    565599       
    566         PredictedType newPrediction = StrongPredictionTag | prediction;
     600        PredictedType newPrediction = StrongPredictionTag | prediction | m_opInfo2;
    567601        bool result = m_opInfo2 != newPrediction;
    568         m_opInfo2 |= newPrediction;
     602        m_opInfo2 = newPrediction;
    569603        return result;
    570604    }
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r93375 r94629  
    679679}
    680680
     681#if DFG_VERBOSE_SPECULATION_FAILURE
     682void debugOperationPrintSpeculationFailure(ExecState*, void* debugInfoRaw)
     683{
     684    SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw);
     685    printf("Speculation failure in %p at 0x%x!\n", debugInfo->codeBlock, debugInfo->debugOffset);
     686}
     687#endif
     688
    681689} // extern "C"
    682690} } // namespace JSC::DFG
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.h

    r93070 r94629  
    116116RegisterSizedBoolean dfgConvertJSValueToBoolean(ExecState*, EncodedJSValue);
    117117
     118#if DFG_VERBOSE_SPECULATION_FAILURE
     119void debugOperationPrintSpeculationFailure(ExecState*, void*);
     120#endif
     121
    118122} // extern "C"
    119123} } // namespace JSC::DFG
  • trunk/Source/JavaScriptCore/dfg/DFGPropagator.cpp

    r94559 r94629  
    4141        , m_profiledBlock(profiledBlock)
    4242    {
     43        // Predictions is a forward flow property that propagates the values seen at
     44        // a particular value source to their various uses, ensuring that uses perform
     45        // speculation that does not contravene the expected values.
    4346        m_predictions.resize(m_graph.size());
    44         for (NodeIndex i = 0; i < m_graph.size(); ++i)
     47       
     48        // Uses is a backward flow property that propagates the hard expectations at
     49        // certain uses to their value sources, ensuring that predictions about
     50        // values do not contravene the code itself. This comes up only in the
     51        // cases of obvious cell uses, like GetById and friends as well as Call.
     52        // We're essentially statically speculating that if the value profile indicates
     53        // that only booleans (for example) flow into a GetById, then the value
     54        // profile is simply wrong due to insufficient coverage and needs to be
     55        // adjusted accordingly. The alternatives would be to assume either
     56        // that the GetById never executes, or always executes on a boolean leading
     57        // to whatever bizarre behavior that's supposed to cause.
     58        m_uses.resize(m_graph.size());
     59        m_variableUses.initializeSimilarTo(m_graph.predictions());
     60       
     61        for (unsigned i = 0; i < m_graph.size(); ++i) {
    4562            m_predictions[i] = PredictNone;
     63            m_uses[i] = PredictNone;
     64        }
    4665    }
    4766   
     
    5271#endif
    5372        do {
     73            m_changed = false;
     74           
    5475            // Forward propagation is near-optimal for both topologically-sorted and
    5576            // DFS-sorted code.
    56             m_changed = false;
    5777            propagateForward();
    5878            if (!m_changed)
     
    6585            m_changed = false;
    6686            propagateBackward();
    67             if (!m_changed)
    68                 break;
    69            
    70             // Do another forward pass because forward passes are on average more
    71             // profitable.
    72             m_changed = false;
    73             propagateForward();
    7487        } while (m_changed);
    7588    }
    7689   
    7790private:
    78     void setPrediction(PredictedType prediction)
    79     {
     91    bool setPrediction(PredictedType prediction)
     92    {
     93        ASSERT(m_graph[m_compileIndex].hasResult());
     94       
    8095        if (m_predictions[m_compileIndex] == prediction)
    81             return;
     96            return false;
    8297       
    8398        m_predictions[m_compileIndex] = prediction;
    84         m_changed = true;
    85     }
    86    
    87     void mergePrediction(PredictedType prediction)
    88     {
    89         if (DFG::mergePrediction(m_predictions[m_compileIndex], prediction))
    90             m_changed = true;
     99        return true;
     100    }
     101   
     102    bool mergeUse(NodeIndex nodeIndex, PredictedType prediction)
     103    {
     104        ASSERT(m_graph[nodeIndex].hasResult());
     105       
     106        return DFG::mergePrediction(m_uses[nodeIndex], prediction);
     107    }
     108   
     109    bool mergePrediction(PredictedType prediction)
     110    {
     111        ASSERT(m_graph[m_compileIndex].hasResult());
     112       
     113        return DFG::mergePrediction(m_predictions[m_compileIndex], prediction);
    91114    }
    92115   
     
    97120       
    98121        NodeType op = node.op;
     122
     123#if DFG_DEBUG_VERBOSE
     124        printf("   %s[%u]: ", Graph::opName(op), m_compileIndex);
     125#endif
     126       
     127        bool changed = false;
     128       
    99129        switch (op) {
    100130        case JSConstant: {
    101131            JSValue value = node.valueOfJSConstant(m_codeBlock);
    102132            if (value.isInt32())
    103                 setPrediction(makePrediction(PredictInt32, StrongPrediction));
     133                changed |= setPrediction(makePrediction(PredictInt32, StrongPrediction));
    104134            else if (value.isDouble())
    105                 setPrediction(makePrediction(PredictDouble, StrongPrediction));
     135                changed |= setPrediction(makePrediction(PredictDouble, StrongPrediction));
    106136            else if (value.isCell()) {
    107137                JSCell* cell = value.asCell();
    108138                if (isJSArray(&m_globalData, cell))
    109                     setPrediction(makePrediction(PredictArray, StrongPrediction));
     139                    changed |= setPrediction(makePrediction(PredictArray, StrongPrediction));
    110140                else
    111                     setPrediction(makePrediction(PredictCell, StrongPrediction));
    112             } else
    113                 setPrediction(makePrediction(PredictTop, StrongPrediction));
     141                    changed |= setPrediction(makePrediction(PredictCell, StrongPrediction));
     142            } else if (value.isBoolean())
     143                changed |= setPrediction(makePrediction(PredictBoolean, StrongPrediction));
     144            else
     145                changed |= setPrediction(makePrediction(PredictTop, StrongPrediction));
    114146            break;
    115147        }
    116148           
    117149        case GetLocal: {
     150            changed |= m_graph.predict(node.local(), m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
     151            changed |= m_variableUses.predict(node.local(), m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
     152
    118153            PredictedType prediction = m_graph.getPrediction(node.local());
    119154            if (isStrongPrediction(prediction))
    120                 mergePrediction(prediction);
     155                changed |= mergePrediction(prediction);
    121156            break;
    122157        }
    123158           
    124159        case SetLocal: {
    125             m_changed |= m_graph.predict(node.local(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction);
     160            changed |= m_graph.predict(node.local(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction);
     161            changed |= mergeUse(node.child1(), m_variableUses.getPrediction(node.local()));
    126162            break;
    127163        }
     
    136172        case ValueToInt32:
    137173        case ArithMod: {
    138             setPrediction(makePrediction(PredictInt32, StrongPrediction));
     174            changed |= setPrediction(makePrediction(PredictInt32, StrongPrediction));
    139175            break;
    140176        }
     
    145181            if (isStrongPrediction(prediction)) {
    146182                if (isNumberPrediction(prediction))
    147                     mergePrediction(prediction);
     183                    changed |= mergePrediction(prediction);
    148184                else
    149                     mergePrediction(makePrediction(PredictNumber, StrongPrediction));
     185                    changed |= mergePrediction(makePrediction(PredictNumber, StrongPrediction));
    150186            }
     187           
    151188            break;
    152189        }
     
    159196                if (isNumberPrediction(left) && isNumberPrediction(right)) {
    160197                    if (isInt32Prediction(mergePredictions(left, right)))
    161                         mergePrediction(makePrediction(PredictInt32, StrongPrediction));
     198                        changed |= mergePrediction(makePrediction(PredictInt32, StrongPrediction));
    162199                    else
    163                         mergePrediction(makePrediction(PredictDouble, StrongPrediction));
     200                        changed |= mergePrediction(makePrediction(PredictDouble, StrongPrediction));
    164201                } else
    165                     mergePrediction(makePrediction(PredictTop, StrongPrediction));
     202                    changed |= mergePrediction(makePrediction(PredictTop, StrongPrediction));
    166203            }
    167204            break;
     
    176213            if (isStrongPrediction(left) && isStrongPrediction(right)) {
    177214                if (isInt32Prediction(mergePredictions(left, right)))
    178                     mergePrediction(makePrediction(PredictInt32, StrongPrediction));
     215                    changed |= mergePrediction(makePrediction(PredictInt32, StrongPrediction));
    179216                else
    180                     mergePrediction(makePrediction(PredictDouble, StrongPrediction));
     217                    changed |= mergePrediction(makePrediction(PredictDouble, StrongPrediction));
    181218            }
    182219            break;
     
    184221           
    185222        case ArithDiv: {
    186             setPrediction(makePrediction(PredictDouble, StrongPrediction));
     223            changed |= setPrediction(makePrediction(PredictDouble, StrongPrediction));
    187224            break;
    188225        }
     
    196233        case CompareStrictEq:
    197234        case InstanceOf: {
    198             // This is sad, as we don't have a boolean prediction, even though we easily
    199             // could.
    200             setPrediction(makePrediction(PredictTop, StrongPrediction));
     235            changed |= setPrediction(makePrediction(PredictBoolean, StrongPrediction));
    201236            break;
    202237        }
     
    204239        case GetById:
    205240        case GetMethod:
    206         case GetByVal:
     241        case GetByVal: {
     242            changed |= mergeUse(node.child1(), PredictCell | StrongPredictionTag);
     243            changed |= node.predict(m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
     244            if (isStrongPrediction(node.getPrediction()))
     245                changed |= setPrediction(node.getPrediction());
     246            break;
     247        }
     248           
    207249        case Call:
    208250        case Construct: {
     251            changed |= mergeUse(m_graph.m_varArgChildren[node.firstChild()], PredictCell | StrongPredictionTag);
     252            changed |= node.predict(m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
    209253            if (isStrongPrediction(node.getPrediction()))
    210                 setPrediction(node.getPrediction());
     254                changed |= setPrediction(node.getPrediction());
    211255            break;
    212256        }
    213257           
    214258        case ConvertThis: {
    215             setPrediction(makePrediction(PredictCell, StrongPrediction));
     259            changed |= setPrediction(makePrediction(PredictCell, StrongPrediction));
    216260            break;
    217261        }
    218262           
    219263        case GetGlobalVar: {
     264            changed |= m_variableUses.predictGlobalVar(node.varNumber(), m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
    220265            PredictedType prediction = m_graph.getGlobalVarPrediction(node.varNumber());
    221266            if (isStrongPrediction(prediction))
    222                 mergePrediction(prediction);
     267                changed |= mergePrediction(prediction);
    223268            break;
    224269        }
    225270           
    226271        case PutGlobalVar: {
    227             m_changed |= m_graph.predictGlobalVar(node.varNumber(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction);
    228             break;
    229         }
    230            
     272            changed |= m_graph.predictGlobalVar(node.varNumber(), m_predictions[node.child1()] & ~PredictionTagMask, StrongPrediction);
     273            changed |= mergeUse(node.child1(), m_variableUses.getGlobalVarPrediction(node.varNumber()));
     274            break;
     275        }
     276           
     277        case PutByVal:
     278        case PutByValAlias:
     279        case PutById:
     280        case PutByIdDirect:
     281            changed |= mergeUse(node.child1(), PredictCell | StrongPredictionTag);
     282            break;
     283
    231284#ifndef NDEBUG
    232285        // These get ignored because they don't return anything.
    233         case PutByVal:
    234         case PutByValAlias:
    235286        case DFG::Jump:
    236287        case Branch:
    237288        case Return:
    238         case PutById:
    239         case PutByIdDirect:
    240289        case CheckHasInstance:
    241290        case Phi:
     
    256305#endif
    257306        }
     307
     308#if DFG_DEBUG_VERBOSE
     309        printf("expect(%s) use(%s) %s\n", predictionToString(m_predictions[m_compileIndex]), predictionToString(m_uses[m_compileIndex]), changed ? "CHANGED" : "");
     310#endif
     311       
     312        m_changed |= changed;
    258313    }
    259314   
     
    284339   
    285340    Vector<PredictedType, 16> m_predictions;
     341    Vector<PredictedType, 16> m_uses;
     342   
     343    PredictionTracker m_variableUses;
    286344
    287345#if DFG_DEBUG_VERBOSE
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r93934 r94629  
    129129    case DataFormatDouble:
    130130    case DataFormatCell:
     131    case DataFormatBoolean:
    131132    case DataFormatJSDouble:
    132     case DataFormatJSCell: {
     133    case DataFormatJSCell:
     134    case DataFormatJSBoolean: {
    133135        terminateSpeculativeExecution();
    134136        returnFormat = DataFormatInteger;
     
    224226
    225227    switch (info.registerFormat()) {
    226     case DataFormatNone:
    227         // Should have filled, above.
     228    case DataFormatNone: // Should have filled, above.
     229    case DataFormatBoolean: // This type never occurs.
    228230        ASSERT_NOT_REACHED();
    229231       
    230232    case DataFormatCell:
    231233    case DataFormatJSCell:
    232     case DataFormatJS: {
     234    case DataFormatJS:
     235    case DataFormatJSBoolean: {
    233236        GPRReg jsValueGpr = info.gpr();
    234237        m_gprs.lock(jsValueGpr);
     
    350353    case DataFormatInteger:
    351354    case DataFormatJSDouble:
    352     case DataFormatDouble: {
     355    case DataFormatDouble:
     356    case DataFormatJSBoolean:
     357    case DataFormatBoolean: {
     358        terminateSpeculativeExecution();
     359        return allocate();
     360    }
     361    }
     362
     363    ASSERT_NOT_REACHED();
     364    return InvalidGPRReg;
     365}
     366
     367GPRReg SpeculativeJIT::fillSpeculateBoolean(NodeIndex nodeIndex)
     368{
     369    Node& node = m_jit.graph()[nodeIndex];
     370    VirtualRegister virtualRegister = node.virtualRegister();
     371    GenerationInfo& info = m_generationInfo[virtualRegister];
     372
     373    switch (info.registerFormat()) {
     374    case DataFormatNone: {
     375        GPRReg gpr = allocate();
     376
     377        if (node.isConstant()) {
     378            JSValue jsValue = valueOfJSConstant(nodeIndex);
     379            if (jsValue.isBoolean()) {
     380                m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
     381                m_jit.move(MacroAssembler::TrustedImmPtr(JSValue::encode(jsValue)), gpr);
     382                info.fillJSValue(gpr, DataFormatJSBoolean);
     383                return gpr;
     384            }
     385            terminateSpeculativeExecution();
     386            return gpr;
     387        }
     388        ASSERT(info.spillFormat() & DataFormatJS);
     389        m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
     390        m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
     391
     392        info.fillJSValue(gpr, DataFormatJS);
     393        if (info.spillFormat() != DataFormatJSBoolean) {
     394            m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
     395            speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg));
     396            m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
     397        }
     398        info.fillJSValue(gpr, DataFormatJSBoolean);
     399        return gpr;
     400    }
     401
     402    case DataFormatBoolean:
     403    case DataFormatJSBoolean: {
     404        GPRReg gpr = info.gpr();
     405        m_gprs.lock(gpr);
     406        return gpr;
     407    }
     408
     409    case DataFormatJS: {
     410        GPRReg gpr = info.gpr();
     411        m_gprs.lock(gpr);
     412        m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
     413        speculationCheck(m_jit.branchTestPtr(MacroAssembler::NonZero, gpr, TrustedImm32(static_cast<int32_t>(~1))), SpeculationRecovery(BooleanSpeculationCheck, gpr, InvalidGPRReg));
     414        m_jit.xorPtr(TrustedImm32(static_cast<int32_t>(ValueFalse)), gpr);
     415        info.fillJSValue(gpr, DataFormatJSBoolean);
     416        return gpr;
     417    }
     418
     419    case DataFormatJSInteger:
     420    case DataFormatInteger:
     421    case DataFormatJSDouble:
     422    case DataFormatDouble:
     423    case DataFormatJSCell:
     424    case DataFormatCell: {
    353425        terminateSpeculativeExecution();
    354426        return allocate();
     
    529601        // If we add a DataFormatBool, we should use it here.
    530602        m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
    531         jsValueResult(result.gpr(), m_compileIndex);
     603        jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
    532604    }
    533605   
     
    562634            VirtualRegister virtualRegister = node.virtualRegister();
    563635            m_gprs.retain(result.gpr(), virtualRegister, SpillOrderJS);
    564             m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), isArrayPrediction(prediction) ? DataFormatJSCell : DataFormatJS);
     636           
     637            DataFormat format;
     638            if (isArrayPrediction(prediction))
     639                format = DataFormatJSCell;
     640            else if (isBooleanPrediction(prediction))
     641                format = DataFormatJSBoolean;
     642            else
     643                format = DataFormatJS;
     644           
     645            m_generationInfo[virtualRegister].initJSValue(m_compileIndex, node.refCount(), result.gpr(), format);
    565646        }
    566647        break;
     
    579660            m_jit.storePtr(cellGPR, JITCompiler::addressFor(node.local()));
    580661            noResult(m_compileIndex);
     662        } else if (isBooleanPrediction(predictedType)) {
     663            SpeculateBooleanOperand boolean(this, node.child1());
     664            m_jit.storePtr(boolean.gpr(), JITCompiler::addressFor(node.local()));
     665            noResult(m_compileIndex);
    581666        } else {
    582667            JSValueOperand value(this, node.child1());
     
    842927
    843928    case LogicalNot: {
     929        if (isKnownBoolean(node.child1())) {
     930            SpeculateBooleanOperand value(this, node.child1());
     931            GPRTemporary result(this, value);
     932           
     933            m_jit.move(value.gpr(), result.gpr());
     934            m_jit.xorPtr(TrustedImm32(true), result.gpr());
     935           
     936            jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
     937            break;
     938        }
     939       
    844940        JSValueOperand value(this, node.child1());
    845941        GPRTemporary result(this); // FIXME: We could reuse, but on speculation fail would need recovery to restore tag (akin to add).
     
    851947
    852948        // If we add a DataFormatBool, we should use it here.
    853         jsValueResult(result.gpr(), m_compileIndex);
     949        jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
    854950        break;
    855951    }
     
    12281324
    12291325        putResult.link(&m_jit);
    1230         jsValueResult(scratchReg, m_compileIndex);
     1326        jsValueResult(scratchReg, m_compileIndex, DataFormatJSBoolean);
    12311327        break;
    12321328    }
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r92593 r94629  
    3838// may need be performed should a speculation check fail.
    3939enum SpeculationRecoveryType {
    40     SpeculativeAdd
     40    SpeculativeAdd,
     41    BooleanSpeculationCheck
    4142};
    4243
     
    133134    FPRReg fillSpeculateDouble(NodeIndex);
    134135    GPRReg fillSpeculateCell(NodeIndex);
    135 
    136 private:
     136    GPRReg fillSpeculateBoolean(NodeIndex);
     137
     138private:
     139    friend class JITCodeGenerator;
     140   
    137141    void compile(Node&);
    138142    void compile(BasicBlock&);
     
    409413};
    410414
     415class SpeculateBooleanOperand {
     416public:
     417    explicit SpeculateBooleanOperand(SpeculativeJIT* jit, NodeIndex index)
     418        : m_jit(jit)
     419        , m_index(index)
     420        , m_gprOrInvalid(InvalidGPRReg)
     421    {
     422        ASSERT(m_jit);
     423        if (jit->isFilled(index))
     424            gpr();
     425    }
     426   
     427    ~SpeculateBooleanOperand()
     428    {
     429        ASSERT(m_gprOrInvalid != InvalidGPRReg);
     430        m_jit->unlock(m_gprOrInvalid);
     431    }
     432   
     433    NodeIndex index() const
     434    {
     435        return m_index;
     436    }
     437   
     438    GPRReg gpr()
     439    {
     440        if (m_gprOrInvalid == InvalidGPRReg)
     441            m_gprOrInvalid = m_jit->fillSpeculateBoolean(index());
     442        return m_gprOrInvalid;
     443    }
     444   
     445    void use()
     446    {
     447        m_jit->use(m_index);
     448    }
     449
     450private:
     451    SpeculativeJIT* m_jit;
     452    NodeIndex m_index;
     453    GPRReg m_gprOrInvalid;
     454};
     455
    411456
    412457// === SpeculationCheckIndexIterator ===
Note: See TracChangeset for help on using the changeset viewer.