Changeset 95523 in webkit


Ignore:
Timestamp:
Sep 20, 2011 2:41:16 AM (13 years ago)
Author:
fpizlo@apple.com
Message:

DFG JIT does not speculate aggressively enough on GetById
https://bugs.webkit.org/show_bug.cgi?id=68320

Reviewed by Oliver Hunt.

This adds the ability to access properties directly, by offset.
This optimization kicks in when at the time of DFG compilation,
it appears that the given get_by_id is self-cached by the old JIT.
Two new opcodes get introduced: CheckStructure and GetByOffset.
CheckStructure performs a speculation check on the object's
structure, and returns the storage pointer. GetByOffset performs
a direct read of the field from the storage pointer. Both
CheckStructure and GetByOffset can be CSE'd, so that we can
eliminate redundant structure checks, and redundant reads of the
same field.

This is a 4% speed-up on V8, a 2% slow-down on Kraken, and
neutral on SunSpider.

  • bytecode/PredictedType.cpp:

(JSC::predictionFromClassInfo):
(JSC::predictionFromStructure):
(JSC::predictionFromCell):

  • bytecode/PredictedType.h:
  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGGenerationInfo.h:

(JSC::DFG::dataFormatToString):
(JSC::DFG::needDataFormatConversion):
(JSC::DFG::GenerationInfo::initStorage):
(JSC::DFG::GenerationInfo::spill):
(JSC::DFG::GenerationInfo::fillStorage):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::predict):
(JSC::DFG::Graph::getPrediction):

  • dfg/DFGJITCodeGenerator.cpp:

(JSC::DFG::JITCodeGenerator::fillInteger):
(JSC::DFG::JITCodeGenerator::fillDouble):
(JSC::DFG::JITCodeGenerator::fillJSValue):
(JSC::DFG::JITCodeGenerator::fillStorage):
(JSC::DFG::GPRTemporary::GPRTemporary):

  • dfg/DFGJITCodeGenerator.h:

(JSC::DFG::JITCodeGenerator::silentSpillGPR):
(JSC::DFG::JITCodeGenerator::silentFillGPR):
(JSC::DFG::JITCodeGenerator::spill):
(JSC::DFG::JITCodeGenerator::storageResult):
(JSC::DFG::StorageOperand::StorageOperand):
(JSC::DFG::StorageOperand::~StorageOperand):
(JSC::DFG::StorageOperand::index):
(JSC::DFG::StorageOperand::gpr):
(JSC::DFG::StorageOperand::use):

  • dfg/DFGNode.h:

(JSC::DFG::OpInfo::OpInfo):
(JSC::DFG::Node::Node):
(JSC::DFG::Node::hasPrediction):
(JSC::DFG::Node::hasStructure):
(JSC::DFG::Node::structure):
(JSC::DFG::Node::hasStorageAccessData):
(JSC::DFG::Node::storageAccessDataIndex):

  • dfg/DFGPropagator.cpp:

(JSC::DFG::Propagator::propagateNode):
(JSC::DFG::Propagator::globalVarLoadElimination):
(JSC::DFG::Propagator::getMethodLoadElimination):
(JSC::DFG::Propagator::checkStructureLoadElimination):
(JSC::DFG::Propagator::getByOffsetLoadElimination):
(JSC::DFG::Propagator::performNodeCSE):

  • dfg/DFGSpeculativeJIT.cpp:

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

  • wtf/StdLibExtras.h:

(WTF::safeCast):

Location:
trunk/Source/JavaScriptCore
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r95516 r95523  
     12011-09-18  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG JIT does not speculate aggressively enough on GetById
     4        https://bugs.webkit.org/show_bug.cgi?id=68320
     5
     6        Reviewed by Oliver Hunt.
     7       
     8        This adds the ability to access properties directly, by offset.
     9        This optimization kicks in when at the time of DFG compilation,
     10        it appears that the given get_by_id is self-cached by the old JIT.
     11        Two new opcodes get introduced: CheckStructure and GetByOffset.
     12        CheckStructure performs a speculation check on the object's
     13        structure, and returns the storage pointer. GetByOffset performs
     14        a direct read of the field from the storage pointer. Both
     15        CheckStructure and GetByOffset can be CSE'd, so that we can
     16        eliminate redundant structure checks, and redundant reads of the
     17        same field.
     18       
     19        This is a 4% speed-up on V8, a 2% slow-down on Kraken, and
     20        neutral on SunSpider.
     21
     22        * bytecode/PredictedType.cpp:
     23        (JSC::predictionFromClassInfo):
     24        (JSC::predictionFromStructure):
     25        (JSC::predictionFromCell):
     26        * bytecode/PredictedType.h:
     27        * dfg/DFGByteCodeParser.cpp:
     28        (JSC::DFG::ByteCodeParser::parseBlock):
     29        * dfg/DFGGenerationInfo.h:
     30        (JSC::DFG::dataFormatToString):
     31        (JSC::DFG::needDataFormatConversion):
     32        (JSC::DFG::GenerationInfo::initStorage):
     33        (JSC::DFG::GenerationInfo::spill):
     34        (JSC::DFG::GenerationInfo::fillStorage):
     35        * dfg/DFGGraph.h:
     36        (JSC::DFG::Graph::predict):
     37        (JSC::DFG::Graph::getPrediction):
     38        * dfg/DFGJITCodeGenerator.cpp:
     39        (JSC::DFG::JITCodeGenerator::fillInteger):
     40        (JSC::DFG::JITCodeGenerator::fillDouble):
     41        (JSC::DFG::JITCodeGenerator::fillJSValue):
     42        (JSC::DFG::JITCodeGenerator::fillStorage):
     43        (JSC::DFG::GPRTemporary::GPRTemporary):
     44        * dfg/DFGJITCodeGenerator.h:
     45        (JSC::DFG::JITCodeGenerator::silentSpillGPR):
     46        (JSC::DFG::JITCodeGenerator::silentFillGPR):
     47        (JSC::DFG::JITCodeGenerator::spill):
     48        (JSC::DFG::JITCodeGenerator::storageResult):
     49        (JSC::DFG::StorageOperand::StorageOperand):
     50        (JSC::DFG::StorageOperand::~StorageOperand):
     51        (JSC::DFG::StorageOperand::index):
     52        (JSC::DFG::StorageOperand::gpr):
     53        (JSC::DFG::StorageOperand::use):
     54        * dfg/DFGNode.h:
     55        (JSC::DFG::OpInfo::OpInfo):
     56        (JSC::DFG::Node::Node):
     57        (JSC::DFG::Node::hasPrediction):
     58        (JSC::DFG::Node::hasStructure):
     59        (JSC::DFG::Node::structure):
     60        (JSC::DFG::Node::hasStorageAccessData):
     61        (JSC::DFG::Node::storageAccessDataIndex):
     62        * dfg/DFGPropagator.cpp:
     63        (JSC::DFG::Propagator::propagateNode):
     64        (JSC::DFG::Propagator::globalVarLoadElimination):
     65        (JSC::DFG::Propagator::getMethodLoadElimination):
     66        (JSC::DFG::Propagator::checkStructureLoadElimination):
     67        (JSC::DFG::Propagator::getByOffsetLoadElimination):
     68        (JSC::DFG::Propagator::performNodeCSE):
     69        * dfg/DFGSpeculativeJIT.cpp:
     70        (JSC::DFG::SpeculativeJIT::fillSpeculateIntInternal):
     71        (JSC::DFG::SpeculativeJIT::fillSpeculateDouble):
     72        (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
     73        (JSC::DFG::SpeculativeJIT::fillSpeculateBoolean):
     74        (JSC::DFG::SpeculativeJIT::compile):
     75        * wtf/StdLibExtras.h:
     76        (WTF::safeCast):
     77
    1782011-09-19  Mark Hahnenberg  <mhahnenberg@apple.com>
    279
  • trunk/Source/JavaScriptCore/bytecode/PredictedType.cpp

    r95273 r95523  
    8383#endif
    8484
    85 PredictedType predictionFromCell(JSCell* cell)
     85PredictedType predictionFromClassInfo(const ClassInfo* classInfo)
    8686{
    87     const ClassInfo* classInfo = cell->structure()->classInfo();
    88    
    8987    if (classInfo == &JSFinalObject::s_info)
    9088        return PredictFinalObject;
     
    10098   
    10199    return PredictCellOther;
     100}
     101
     102PredictedType predictionFromStructure(Structure* structure)
     103{
     104    return predictionFromClassInfo(structure->classInfo());
     105}
     106
     107PredictedType predictionFromCell(JSCell* cell)
     108{
     109    return predictionFromStructure(cell->structure());
    102110}
    103111
  • trunk/Source/JavaScriptCore/bytecode/PredictedType.h

    r95273 r95523  
    3333
    3434namespace JSC {
     35
     36class Structure;
    3537
    3638typedef uint16_t PredictedType;
     
    151153}
    152154
     155PredictedType predictionFromClassInfo(const ClassInfo*);
     156PredictedType predictionFromStructure(Structure*);
    153157PredictedType predictionFromCell(JSCell*);
    154158PredictedType predictionFromValue(JSValue);
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r95484 r95523  
    11371137        case op_get_by_id: {
    11381138            NodeIndex base = get(currentInstruction[2].u.operand);
    1139             unsigned identifier = currentInstruction[3].u.operand;
    1140            
    1141             NodeIndex getById = addToGraph(GetById, OpInfo(identifier), OpInfo(PredictNone), base);
     1139            unsigned identifierNumber = currentInstruction[3].u.operand;
     1140           
     1141            StructureStubInfo& stubInfo = m_profiledBlock->getStubInfo(m_currentIndex);
     1142           
     1143            NodeIndex getById = NoNode;
     1144            if (stubInfo.seen && stubInfo.accessType == access_get_by_id_self) {
     1145                Structure* structure = stubInfo.u.getByIdSelf.baseObjectStructure.get();
     1146                Identifier identifier = m_codeBlock->identifier(identifierNumber);
     1147                size_t offset = structure->get(*m_globalData, identifier);
     1148               
     1149                if (offset != notFound) {
     1150                    getById = addToGraph(GetByOffset, OpInfo(m_graph.m_storageAccessData.size()), OpInfo(PredictNone), addToGraph(CheckStructure, OpInfo(structure), base));
     1151                   
     1152                    StorageAccessData storageAccessData;
     1153                    storageAccessData.offset = offset;
     1154                    storageAccessData.identifierNumber = identifierNumber;
     1155                    m_graph.m_storageAccessData.append(storageAccessData);
     1156                }
     1157            }
     1158           
     1159            if (getById == NoNode)
     1160                getById = addToGraph(GetById, OpInfo(identifierNumber), OpInfo(PredictNone), base);
     1161           
    11421162            set(currentInstruction[1].u.operand, getById);
    11431163            stronglyPredict(getById);
  • trunk/Source/JavaScriptCore/dfg/DFGGenerationInfo.h

    r95240 r95523  
    4545    DataFormatBoolean = 3,
    4646    DataFormatCell = 4,
     47    DataFormatStorage = 5,
    4748    DataFormatJS = 8,
    4849    DataFormatJSInteger = DataFormatJS | DataFormatInteger,
     
    6667    case DataFormatBoolean:
    6768        return "Boolean";
     69    case DataFormatStorage:
     70        return "Storage";
    6871    case DataFormatJS:
    6972        return "JS";
     
    111114            ASSERT_NOT_REACHED();
    112115        }
     116    case DataFormatStorage:
     117        ASSERT(to == DataFormatStorage);
     118        return false;
    113119    default:
    114120        // This captures DataFormatBoolean, which is currently unused.
     
    210216        u.fpr = fpr;
    211217    }
     218    void initStorage(NodeIndex nodeIndex, uint32_t useCount, GPRReg gpr)
     219    {
     220        m_nodeIndex = nodeIndex;
     221        m_useCount = useCount;
     222        m_registerFormat = DataFormatStorage;
     223        m_spillFormat = DataFormatNone;
     224        m_canFill = false;
     225        u.gpr = gpr;
     226    }
    212227
    213228    // Get the index of the node that produced this value.
     
    289304        // We should only be spilling values that are currently in machine registers.
    290305        ASSERT(m_registerFormat != DataFormatNone);
    291         // We only spill values that have been boxed as a JSValue; otherwise the GC
    292         // would need a way to distinguish cell pointers from numeric primitives.
    293         ASSERT(spillFormat & DataFormatJS);
     306        // We only spill values that have been boxed as a JSValue because historically
     307        // we assumed that the GC would want to be able to precisely identify heap
     308        // pointers. This is not true anymore, but we still assume, in the fill code,
     309        // that any spill slot for a JS value is boxed. For storage pointers, there is
     310        // nothing we can do to box them, so we allow that to be an exception.
     311        ASSERT((spillFormat & DataFormatJS) || spillFormat == DataFormatStorage);
    294312
    295313        m_registerFormat = DataFormatNone;
     
    330348        m_registerFormat = DataFormatDouble;
    331349        u.fpr = fpr;
     350    }
     351    void fillStorage(GPRReg gpr)
     352    {
     353        m_registerFormat = DataFormatStorage;
     354        u.gpr = gpr;
    332355    }
    333356
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r95389 r95523  
    8585};
    8686
     87struct StorageAccessData {
     88    size_t offset;
     89    unsigned identifierNumber;
     90   
     91    // NOTE: the offset and identifierNumber do not by themselves
     92    // uniquely identify a property. The identifierNumber and a
     93    // Structure* do. If those two match, then the offset should
     94    // be the same, as well. For any Node that has a StorageAccessData,
     95    // it is possible to retrieve the Structure* by looking at the
     96    // first child. It should be a CheckStructure, which has the
     97    // Structure*.
     98};
     99
    87100typedef Vector <BlockIndex, 2> PredecessorList;
    88101
     
    183196        case Call:
    184197        case Construct:
     198        case GetByOffset:
    185199            return node.predict(prediction, source);
    186200        default:
     
    224238        case Call:
    225239        case Construct:
     240        case GetByOffset:
    226241            return nodePtr->getPrediction();
    227242        case CheckMethod:
     
    300315    Vector<NodeIndex, 16> m_varArgChildren;
    301316    Vector<MethodCheckData> m_methodCheckData;
     317    Vector<StorageAccessData> m_storageAccessData;
    302318    unsigned m_preservedVars;
    303319    unsigned m_parameterSlots;
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp

    r95484 r95523  
    9292    case DataFormatBoolean:
    9393    case DataFormatJSBoolean:
     94    case DataFormatStorage:
    9495        // Should only be calling this function if we know this operand to be integer.
    9596        ASSERT_NOT_REACHED();
     
    167168    case DataFormatBoolean:
    168169    case DataFormatJSBoolean:
     170    case DataFormatStorage:
    169171        // Should only be calling this function if we know this operand to be numeric.
    170172        ASSERT_NOT_REACHED();
     
    317319       
    318320    case DataFormatBoolean:
     321    case DataFormatStorage:
    319322        // this type currently never occurs
    320323        ASSERT_NOT_REACHED();
     
    322325
    323326    ASSERT_NOT_REACHED();
     327    return InvalidGPRReg;
     328}
     329
     330GPRReg JITCodeGenerator::fillStorage(NodeIndex nodeIndex)
     331{
     332    Node& node = m_jit.graph()[nodeIndex];
     333    VirtualRegister virtualRegister = node.virtualRegister();
     334    GenerationInfo& info = m_generationInfo[virtualRegister];
     335   
     336    switch (info.registerFormat()) {
     337    case DataFormatNone: {
     338        GPRReg gpr = allocate();
     339        ASSERT(info.spillFormat() == DataFormatStorage);
     340        m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
     341        m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
     342        info.fillStorage(gpr);
     343        return gpr;
     344    }
     345       
     346    case DataFormatStorage: {
     347        GPRReg gpr = info.gpr();
     348        m_gprs.lock(gpr);
     349        return gpr;
     350    }
     351       
     352    default:
     353        ASSERT_NOT_REACHED();
     354    }
     355   
    324356    return InvalidGPRReg;
    325357}
     
    10831115    wasNotDefaultHasInstance.link(&m_jit);
    10841116    jsValueResult(scratchReg, m_compileIndex, UseChildrenCalledExplicitly);
    1085 }
    1086 
    1087 template<typename To, typename From>
    1088 inline To safeCast(From value)
    1089 {
    1090     To result = static_cast<To>(value);
    1091     ASSERT(result == value);
    1092     return result;
    10931117}
    10941118
     
    20582082}
    20592083
     2084GPRTemporary::GPRTemporary(JITCodeGenerator* jit, StorageOperand& op1)
     2085    : m_jit(jit)
     2086    , m_gpr(InvalidGPRReg)
     2087{
     2088    if (m_jit->canReuse(op1.index()))
     2089        m_gpr = m_jit->reuse(op1.gpr());
     2090    else
     2091        m_gpr = m_jit->allocate();
     2092}
     2093
    20602094FPRTemporary::FPRTemporary(JITCodeGenerator* jit)
    20612095    : m_jit(jit)
  • trunk/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.h

    r95484 r95523  
    6161    enum SpillOrder {
    6262        SpillOrderConstant = 1, // no spill, and cheap fill
    63         SpillOrderSpilled = 2,  // no spill
    64         SpillOrderJS = 4,       // needs spill
    65         SpillOrderCell = 4,     // needs spill
    66         SpillOrderInteger = 5,  // needs spill and box
    67         SpillOrderDouble = 6,   // needs spill and convert
     63        SpillOrderSpilled  = 2, // no spill
     64        SpillOrderJS       = 4, // needs spill
     65        SpillOrderCell     = 4, // needs spill
     66        SpillOrderStorage  = 4, // needs spill
     67        SpillOrderInteger  = 5, // needs spill and box
     68        SpillOrderDouble   = 6, // needs spill and convert
    6869    };
    6970   
     
    7677    FPRReg fillDouble(NodeIndex);
    7778    GPRReg fillJSValue(NodeIndex);
     79    GPRReg fillStorage(NodeIndex);
    7880
    7981    // lock and unlock GPR & FPR registers.
     
    224226        DataFormat registerFormat = info.registerFormat();
    225227
    226         if (registerFormat == DataFormatInteger) {
     228        if (registerFormat == DataFormatInteger)
    227229            m_jit.store32(info.gpr(), JITCompiler::addressFor(spillMe));
    228         } else {
    229             ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
     230        else {
     231            ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell || registerFormat == DataFormatStorage);
    230232            m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
    231233        }
     
    275277            m_jit.move(valueOfJSConstantAsImmPtr(nodeIndex), info.gpr());
    276278        else {
    277             ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell);
     279            ASSERT(registerFormat & DataFormatJS || registerFormat == DataFormatCell || registerFormat == DataFormatStorage);
    278280            m_jit.loadPtr(JITCompiler::addressFor(spillMe), info.gpr());
    279281        }
     
    387389
    388390        DataFormat spillFormat = info.registerFormat();
    389         if (spillFormat == DataFormatDouble) {
     391        switch (spillFormat) {
     392        case DataFormatDouble: {
    390393            // All values are spilled as JSValues, so box the double via a temporary gpr.
    391394            GPRReg gpr = boxDouble(info.fpr());
     
    395398            return;
    396399        }
    397 
    398         // The following code handles JSValues, int32s, and cells.
    399         ASSERT(spillFormat == DataFormatInteger || spillFormat == DataFormatCell || spillFormat & DataFormatJS);
    400 
    401         GPRReg reg = info.gpr();
    402         // We need to box int32 and cell values ...
    403         // but on JSVALUE64 boxing a cell is a no-op!
    404         if (spillFormat == DataFormatInteger)
    405             m_jit.orPtr(GPRInfo::tagTypeNumberRegister, reg);
    406 
    407         // Spill the value, and record it as spilled in its boxed form.
    408         m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
    409         info.spill((DataFormat)(spillFormat | DataFormatJS));
     400           
     401        case DataFormatStorage: {
     402            // This is special, since it's not a JS value - as in it's not visible to JS
     403            // code.
     404            m_jit.storePtr(info.gpr(), JITCompiler::addressFor(spillMe));
     405            info.spill(DataFormatStorage);
     406            return;
     407        }
     408
     409        default:
     410            // The following code handles JSValues, int32s, and cells.
     411            ASSERT(spillFormat == DataFormatInteger || spillFormat == DataFormatCell || spillFormat & DataFormatJS);
     412           
     413            GPRReg reg = info.gpr();
     414            // We need to box int32 and cell values ...
     415            // but on JSVALUE64 boxing a cell is a no-op!
     416            if (spillFormat == DataFormatInteger)
     417                m_jit.orPtr(GPRInfo::tagTypeNumberRegister, reg);
     418           
     419            // Spill the value, and record it as spilled in its boxed form.
     420            m_jit.storePtr(reg, JITCompiler::addressFor(spillMe));
     421            info.spill((DataFormat)(spillFormat | DataFormatJS));
     422            return;
     423        }
    410424    }
    411425   
     
    700714    {
    701715        jsValueResult(reg, nodeIndex, DataFormatJS, mode);
     716    }
     717    void storageResult(GPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren)
     718    {
     719        Node& node = m_jit.graph()[nodeIndex];
     720        if (mode == CallUseChildren)
     721            useChildren(node);
     722       
     723        VirtualRegister virtualRegister = node.virtualRegister();
     724        m_gprs.retain(reg, virtualRegister, SpillOrderStorage);
     725        GenerationInfo& info = m_generationInfo[virtualRegister];
     726        info.initStorage(nodeIndex, node.refCount(), reg);
    702727    }
    703728    void doubleResult(FPRReg reg, NodeIndex nodeIndex, UseChildrenMode mode = CallUseChildren)
     
    11611186};
    11621187
     1188class StorageOperand {
     1189public:
     1190    explicit StorageOperand(JITCodeGenerator* jit, NodeIndex index)
     1191        : m_jit(jit)
     1192        , m_index(index)
     1193        , m_gprOrInvalid(InvalidGPRReg)
     1194    {
     1195        ASSERT(m_jit);
     1196        if (jit->isFilled(index))
     1197            gpr();
     1198    }
     1199   
     1200    ~StorageOperand()
     1201    {
     1202        ASSERT(m_gprOrInvalid != InvalidGPRReg);
     1203        m_jit->unlock(m_gprOrInvalid);
     1204    }
     1205   
     1206    NodeIndex index() const
     1207    {
     1208        return m_index;
     1209    }
     1210   
     1211    GPRReg gpr()
     1212    {
     1213        if (m_gprOrInvalid == InvalidGPRReg)
     1214            m_gprOrInvalid = m_jit->fillStorage(index());
     1215        return m_gprOrInvalid;
     1216    }
     1217   
     1218    void use()
     1219    {
     1220        m_jit->use(m_index);
     1221    }
     1222   
     1223private:
     1224    JITCodeGenerator* m_jit;
     1225    NodeIndex m_index;
     1226    GPRReg m_gprOrInvalid;
     1227};
     1228
    11631229
    11641230// === Temporaries ===
     
    11811247    GPRTemporary(JITCodeGenerator*, SpeculateBooleanOperand&);
    11821248    GPRTemporary(JITCodeGenerator*, JSValueOperand&);
     1249    GPRTemporary(JITCodeGenerator*, StorageOperand&);
    11831250
    11841251    ~GPRTemporary()
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r95484 r95523  
    120120
    121121// These values record the result type of the node (as checked by NodeResultMask, above), 0 for no result.
    122 #define NodeResultJS      0x1000
    123 #define NodeResultNumber  0x2000
    124 #define NodeResultInt32   0x3000
    125 #define NodeResultBoolean 0x4000
     122#define NodeResultJS        0x1000
     123#define NodeResultNumber    0x2000
     124#define NodeResultInt32     0x3000
     125#define NodeResultBoolean   0x4000
     126#define NodeResultStorage   0x5000
    126127
    127128// This macro defines a set of information about all known node types, used to populate NodeId, NodeType below.
     
    185186    macro(PutById, NodeMustGenerate | NodeClobbersWorld) \
    186187    macro(PutByIdDirect, NodeMustGenerate | NodeClobbersWorld) \
     188    macro(CheckStructure, NodeResultStorage | NodeMustGenerate) \
     189    macro(GetByOffset, NodeResultJS) \
    187190    macro(GetMethod, NodeResultJS | NodeMustGenerate) \
    188191    macro(CheckMethod, NodeResultJS | NodeMustGenerate) \
     
    239242// a constant index, argument, or identifier) from a NodeIndex.
    240243struct OpInfo {
    241     explicit OpInfo(unsigned value) : m_value(value) {}
    242     unsigned m_value;
     244    explicit OpInfo(int value) : m_value(value) { }
     245    explicit OpInfo(unsigned value) : m_value(value) { }
     246    explicit OpInfo(uintptr_t value) : m_value(value) { }
     247    explicit OpInfo(void* value) : m_value(reinterpret_cast<uintptr_t>(value)) { }
     248    uintptr_t m_value;
    243249};
    244250
     
    283289        , m_refCount(0)
    284290        , m_opInfo(imm1.m_value)
    285         , m_opInfo2(imm2.m_value)
     291        , m_opInfo2(safeCast<unsigned>(imm2.m_value))
    286292    {
    287293        ASSERT(!(op & NodeHasVarArgs));
     
    298304        , m_refCount(0)
    299305        , m_opInfo(imm1.m_value)
    300         , m_opInfo2(imm2.m_value)
     306        , m_opInfo2(safeCast<unsigned>(imm2.m_value))
    301307    {
    302308        ASSERT(op & NodeHasVarArgs);
     
    458464        case Call:
    459465        case Construct:
     466        case GetByOffset:
    460467            return true;
    461468        default:
     
    499506    }
    500507   
     508    bool hasStructure()
     509    {
     510        return op == CheckStructure;
     511    }
     512   
     513    Structure* structure()
     514    {
     515        return reinterpret_cast<Structure*>(m_opInfo);
     516    }
     517   
     518    bool hasStorageAccessData()
     519    {
     520        return op == GetByOffset;
     521    }
     522   
     523    unsigned storageAccessDataIndex()
     524    {
     525        return m_opInfo;
     526    }
     527   
    501528    bool hasVirtualRegister()
    502529    {
     
    610637    // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).
    611638    unsigned m_refCount;
    612     // Immediate values, accesses type-checked via accessors above.
    613     unsigned m_opInfo, m_opInfo2;
     639    // Immediate values, accesses type-checked via accessors above. The first one is
     640    // big enough to store a pointer.
     641    uintptr_t m_opInfo;
     642    unsigned m_opInfo2;
    614643};
    615644
  • trunk/Source/JavaScriptCore/dfg/DFGPropagator.cpp

    r95484 r95523  
    302302        }
    303303           
     304        case CheckStructure: {
     305            // We backward propagate what this CheckStructure tells us. Maybe that's the right way
     306            // to go; maybe it isn't. I'm not sure. What we'd really want is flow-sensitive
     307            // forward propagation of what we learn from having executed CheckStructure. But for
     308            // now we preserve the flow-insensitive nature of this analysis, because it's cheap to
     309            // run and seems to work well enough.
     310            changed |= mergeUse(node.child1(), predictionFromStructure(node.structure()) | StrongPredictionTag);
     311            changed |= setPrediction(PredictOther | StrongPredictionTag);
     312            break;
     313        }
     314           
     315        case GetByOffset: {
     316            changed |= node.predict(m_uses[m_compileIndex] & ~PredictionTagMask, StrongPrediction);
     317            if (isStrongPrediction(node.getPrediction()))
     318                changed |= setPrediction(node.getPrediction());
     319            break;
     320        }
     321           
    304322        case CheckMethod: {
    305323            changed |= mergeUse(node.child1(), PredictObjectUnknown | StrongPredictionTag);
     
    661679    NodeIndex globalVarLoadElimination(unsigned varNumber)
    662680    {
    663         NodeIndex start = startIndex();
     681        NodeIndex start = startIndexForChildren();
    664682        for (NodeIndex index = m_compileIndex; index-- > start;) {
    665683            Node& node = m_graph[index];
     
    707725    NodeIndex getMethodLoadElimination(const MethodCheckData& methodCheckData, unsigned identifierNumber, NodeIndex child1)
    708726    {
    709         NodeIndex start = startIndex();
     727        NodeIndex start = startIndexForChildren(child1);
    710728        for (NodeIndex index = m_compileIndex; index-- > start;) {
    711729            Node& node = m_graph[index];
     
    714732                && node.identifierNumber() == identifierNumber
    715733                && m_graph.m_methodCheckData[node.methodCheckDataIndex()] == methodCheckData)
     734                return index;
     735            if (clobbersWorld(index))
     736                break;
     737        }
     738        return NoNode;
     739    }
     740   
     741    NodeIndex checkStructureLoadElimination(Structure* structure, NodeIndex child1)
     742    {
     743        NodeIndex start = startIndexForChildren(child1);
     744        for (NodeIndex index = m_compileIndex; index-- > start;) {
     745            Node& node = m_graph[index];
     746            if (node.op == CheckStructure
     747                && node.child1() == child1
     748                && node.structure() == structure)
     749                return index;
     750            if (clobbersWorld(index))
     751                break;
     752        }
     753        return NoNode;
     754    }
     755   
     756    NodeIndex getByOffsetLoadElimination(unsigned identifierNumber, NodeIndex child1)
     757    {
     758        NodeIndex start = startIndexForChildren(child1);
     759        for (NodeIndex index = m_compileIndex; index-- > start;) {
     760            Node& node = m_graph[index];
     761            if (node.op == GetByOffset
     762                && node.child1() == child1
     763                && m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber == identifierNumber)
    716764                return index;
    717765            if (clobbersWorld(index))
     
    851899            break;
    852900           
     901        case CheckStructure:
     902            setReplacement(checkStructureLoadElimination(node.structure(), node.child1()));
     903            break;
     904           
     905        case GetByOffset:
     906            setReplacement(getByOffsetLoadElimination(m_graph.m_storageAccessData[node.storageAccessDataIndex()].identifierNumber, node.child1()));
     907            break;
     908           
    853909        default:
    854910            // do nothing.
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r95484 r95523  
    142142        return allocate();
    143143    }
     144       
     145    case DataFormatStorage:
     146        ASSERT_NOT_REACHED();
    144147    }
    145148
     
    273276    case DataFormatNone: // Should have filled, above.
    274277    case DataFormatBoolean: // This type never occurs.
     278    case DataFormatStorage:
    275279        ASSERT_NOT_REACHED();
    276280       
     
    407411        return allocate();
    408412    }
     413       
     414    case DataFormatStorage:
     415        ASSERT_NOT_REACHED();
    409416    }
    410417
     
    477484        return allocate();
    478485    }
     486       
     487    case DataFormatStorage:
     488        ASSERT_NOT_REACHED();
    479489    }
    480490
     
    14951505
    14961506        jsValueResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
     1507        break;
     1508    }
     1509
     1510    case CheckStructure: {
     1511        SpeculateCellOperand base(this, node.child1());
     1512        GPRTemporary result(this, base);
     1513       
     1514        GPRReg baseGPR = base.gpr();
     1515        GPRReg resultGPR = result.gpr();
     1516       
     1517        speculationCheck(m_jit.branchPtr(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), JITCompiler::TrustedImmPtr(node.structure())));
     1518       
     1519        m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), resultGPR);
     1520       
     1521        storageResult(resultGPR, m_compileIndex);
     1522        break;
     1523    }
     1524       
     1525    case GetByOffset: {
     1526        StorageOperand storage(this, node.child1());
     1527        GPRTemporary result(this, storage);
     1528       
     1529        GPRReg storageGPR = storage.gpr();
     1530        GPRReg resultGPR = result.gpr();
     1531       
     1532        StorageAccessData& storageAccessData = m_jit.graph().m_storageAccessData[node.storageAccessDataIndex()];
     1533       
     1534        m_jit.loadPtr(JITCompiler::Address(storageGPR, storageAccessData.offset * sizeof(EncodedJSValue)), resultGPR);
     1535       
     1536        jsValueResult(resultGPR, m_compileIndex);
    14971537        break;
    14981538    }
  • trunk/Source/JavaScriptCore/wtf/StdLibExtras.h

    r93466 r95523  
    2727#define WTF_StdLibExtras_h
    2828
    29 #include <wtf/Assertions.h>
     29#include "CheckedArithmetic.h"
     30#include "Assertions.h"
    3031
    3132// Use these to declare and define a static local variable (static T;) so that
     
    101102    u.from = from;
    102103    return u.to;
     104}
     105
     106template<typename To, typename From>
     107inline To safeCast(From value)
     108{
     109    ASSERT(isInBounds<To>(value));
     110    return static_cast<To>(value);
    103111}
    104112
     
    210218using WTF::binarySearch;
    211219using WTF::bitwise_cast;
     220using WTF::safeCast;
    212221
    213222#endif // WTF_StdLibExtras_h
Note: See TracChangeset for help on using the changeset viewer.