Changeset 118555 in webkit


Ignore:
Timestamp:
May 25, 2012 1:19:55 PM (12 years ago)
Author:
fpizlo@apple.com
Message:

DFG ConvertThis should just be a CheckStructure if the structure is known
https://bugs.webkit.org/show_bug.cgi?id=87057

Reviewed by Gavin Barraclough.

Merged r118021 from dfgopt.

This gives ValueProfile the ability to track singleton values - i.e. profiling
sites that always see the same value.

That is then used to profile the structure in op_convert_this.

This is then used to optimize op_convert_this into a CheckStructure if the
structure is always the same.

That then results in better CSE in inlined code that uses 'this', since
previously we couldn't CSE accesses on 'this' from different inline call frames.

Also fixed a bug where we were unnecessarily flushing 'this'.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dump):
(JSC::CodeBlock::stronglyVisitStrongReferences):

  • bytecode/LazyOperandValueProfile.cpp:

(JSC::CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions):

  • bytecode/LazyOperandValueProfile.h:

(CompressedLazyOperandValueProfileHolder):

  • bytecode/Opcode.h:

(JSC):
(JSC::padOpcodeName):

  • bytecode/ValueProfile.h:

(JSC::ValueProfileBase::ValueProfileBase):
(JSC::ValueProfileBase::dump):
(JSC::ValueProfileBase::computeUpdatedPrediction):
(ValueProfileBase):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):

  • dfg/DFGByteCodeParser.cpp:

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

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_convert_this):
(JSC::JIT::emitSlow_op_convert_this):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_convert_this):
(JSC::JIT::emitSlow_op_convert_this):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/JSValue.h:

(JSValue):

  • runtime/Structure.h:

(JSC::JSValue::structureOrUndefined):
(JSC):

Location:
trunk/Source/JavaScriptCore
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r118484 r118555  
     12012-05-21  Filip Pizlo  <fpizlo@apple.com>
     2
     3        DFG ConvertThis should just be a CheckStructure if the structure is known
     4        https://bugs.webkit.org/show_bug.cgi?id=87057
     5
     6        Reviewed by Gavin Barraclough.
     7       
     8        Merged r118021 from dfgopt.
     9       
     10        This gives ValueProfile the ability to track singleton values - i.e. profiling
     11        sites that always see the same value.
     12       
     13        That is then used to profile the structure in op_convert_this.
     14       
     15        This is then used to optimize op_convert_this into a CheckStructure if the
     16        structure is always the same.
     17       
     18        That then results in better CSE in inlined code that uses 'this', since
     19        previously we couldn't CSE accesses on 'this' from different inline call frames.
     20       
     21        Also fixed a bug where we were unnecessarily flushing 'this'.
     22
     23        * bytecode/CodeBlock.cpp:
     24        (JSC::CodeBlock::dump):
     25        (JSC::CodeBlock::stronglyVisitStrongReferences):
     26        * bytecode/LazyOperandValueProfile.cpp:
     27        (JSC::CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions):
     28        * bytecode/LazyOperandValueProfile.h:
     29        (CompressedLazyOperandValueProfileHolder):
     30        * bytecode/Opcode.h:
     31        (JSC):
     32        (JSC::padOpcodeName):
     33        * bytecode/ValueProfile.h:
     34        (JSC::ValueProfileBase::ValueProfileBase):
     35        (JSC::ValueProfileBase::dump):
     36        (JSC::ValueProfileBase::computeUpdatedPrediction):
     37        (ValueProfileBase):
     38        * bytecompiler/BytecodeGenerator.cpp:
     39        (JSC::BytecodeGenerator::BytecodeGenerator):
     40        * dfg/DFGByteCodeParser.cpp:
     41        (JSC::DFG::ByteCodeParser::setArgument):
     42        (JSC::DFG::ByteCodeParser::parseBlock):
     43        * jit/JITOpcodes.cpp:
     44        (JSC::JIT::emit_op_convert_this):
     45        (JSC::JIT::emitSlow_op_convert_this):
     46        * jit/JITOpcodes32_64.cpp:
     47        (JSC::JIT::emit_op_convert_this):
     48        (JSC::JIT::emitSlow_op_convert_this):
     49        * llint/LLIntSlowPaths.cpp:
     50        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
     51        * llint/LowLevelInterpreter32_64.asm:
     52        * llint/LowLevelInterpreter64.asm:
     53        * runtime/JSValue.h:
     54        (JSValue):
     55        * runtime/Structure.h:
     56        (JSC::JSValue::structureOrUndefined):
     57        (JSC):
     58
    1592012-05-24  Tim Horton  <timothy_horton@apple.com>
    260
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r118270 r118555  
    671671            int r0 = (++it)->u.operand;
    672672            dataLog("[%4d] convert_this\t %s\n", location, registerName(exec, r0).data());
     673            ++it; // Skip value profile.
    673674            break;
    674675        }
     
    20862087    }
    20872088   
    2088     m_lazyOperandValueProfiles.computeUpdatedPredictions();
     2089    m_lazyOperandValueProfiles.computeUpdatedPredictions(Collection);
    20892090#endif
    20902091
    20912092#if ENABLE(VALUE_PROFILER)
    20922093    for (unsigned profileIndex = 0; profileIndex < numberOfArgumentValueProfiles(); ++profileIndex)
    2093         valueProfileForArgument(profileIndex)->computeUpdatedPrediction();
     2094        valueProfileForArgument(profileIndex)->computeUpdatedPrediction(Collection);
    20942095    for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex)
    2095         valueProfile(profileIndex)->computeUpdatedPrediction();
     2096        valueProfile(profileIndex)->computeUpdatedPrediction(Collection);
    20962097#endif
    20972098}
  • trunk/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.cpp

    r108677 r118555  
    3434CompressedLazyOperandValueProfileHolder::~CompressedLazyOperandValueProfileHolder() { }
    3535
    36 void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions()
     36void CompressedLazyOperandValueProfileHolder::computeUpdatedPredictions(OperationInProgress operation)
    3737{
    3838    if (!m_data)
     
    4040   
    4141    for (unsigned i = 0; i < m_data->size(); ++i)
    42         m_data->at(i).computeUpdatedPrediction();
     42        m_data->at(i).computeUpdatedPrediction(operation);
    4343}
    4444
  • trunk/Source/JavaScriptCore/bytecode/LazyOperandValueProfile.h

    r108677 r118555  
    156156    ~CompressedLazyOperandValueProfileHolder();
    157157   
    158     void computeUpdatedPredictions();
     158    void computeUpdatedPredictions(OperationInProgress);
    159159   
    160160    LazyOperandValueProfile* add(const LazyOperandValueProfileKey& key);
  • trunk/Source/JavaScriptCore/bytecode/Opcode.h

    r116673 r118555  
    4444        macro(op_create_arguments, 2) \
    4545        macro(op_create_this, 2) \
    46         macro(op_convert_this, 2) \
     46        macro(op_convert_this, 3) \
    4747        \
    4848        macro(op_new_object, 2) \
  • trunk/Source/JavaScriptCore/bytecode/ValueProfile.h

    r108677 r118555  
    3434#if ENABLE(VALUE_PROFILER)
    3535
     36#include "Heap.h"
    3637#include "JSArray.h"
    3738#include "PredictedType.h"
     
    5253        , m_prediction(PredictNone)
    5354        , m_numberOfSamplesInPrediction(0)
     55        , m_singletonValueIsTop(false)
    5456    {
    5557        for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
     
    6163        , m_prediction(PredictNone)
    6264        , m_numberOfSamplesInPrediction(0)
     65        , m_singletonValueIsTop(false)
    6366    {
    6467        for (unsigned i = 0; i < totalNumberOfBuckets; ++i)
     
    113116                totalNumberOfSamples(),
    114117                predictionToString(m_prediction));
     118        fprintf(out, ", value = ");
     119        if (m_singletonValueIsTop)
     120            fprintf(out, "TOP");
     121        else
     122            fprintf(out, "%s", m_singletonValue.description());
    115123        bool first = true;
    116124        for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
     
    128136   
    129137    // Updates the prediction and returns the new one.
    130     PredictedType computeUpdatedPrediction()
     138    PredictedType computeUpdatedPrediction(OperationInProgress operation = NoOperation)
    131139    {
    132140        for (unsigned i = 0; i < totalNumberOfBuckets; ++i) {
     
    138146            mergePrediction(m_prediction, predictionFromValue(value));
    139147           
     148            if (!m_singletonValueIsTop && !!value) {
     149                if (!m_singletonValue)
     150                    m_singletonValue = value;
     151                else if (m_singletonValue != value)
     152                    m_singletonValueIsTop = true;
     153            }
     154           
    140155            m_buckets[i] = JSValue::encode(JSValue());
    141156        }
    142157       
     158        if (operation == Collection
     159            && !m_singletonValueIsTop
     160            && !!m_singletonValue
     161            && m_singletonValue.isCell()
     162            && !Heap::isMarked(m_singletonValue.asCell()))
     163            m_singletonValueIsTop = true;
     164           
    143165        return m_prediction;
    144166    }
     
    149171    unsigned m_numberOfSamplesInPrediction;
    150172   
     173    bool m_singletonValueIsTop;
     174    JSValue m_singletonValue;
     175
    151176    EncodedJSValue m_buckets[totalNumberOfBuckets];
    152177};
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r117198 r118555  
    446446        instructions().append(m_thisRegister.index());
    447447    } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) {
    448         emitOpcode(op_convert_this);
     448        ValueProfile* profile = emitProfiledOpcode(op_convert_this);
    449449        instructions().append(m_thisRegister.index());
     450        instructions().append(profile);
    450451    }
    451452}
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r118468 r118555  
    351351        NodeIndex nodeIndex = addToGraph(SetLocal, OpInfo(variableAccessData), value);
    352352        m_currentBlock->variablesAtTail.argument(argument) = nodeIndex;
    353         // Always flush arguments.
    354         addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
     353        // Always flush arguments, except for 'this'.
     354        if (argument)
     355            addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
    355356    }
    356357   
     
    15831584        case op_convert_this: {
    15841585            NodeIndex op1 = getThis();
    1585             if (m_graph[op1].op() == ConvertThis)
    1586                 setThis(op1);
    1587             else
    1588                 setThis(addToGraph(ConvertThis, op1));
     1586            if (m_graph[op1].op() != ConvertThis) {
     1587                ValueProfile* profile =
     1588                    m_inlineStackTop->m_profiledBlock->valueProfileForBytecodeOffset(m_currentProfilingIndex);
     1589                profile->computeUpdatedPrediction();
     1590#if DFG_ENABLE(DEBUG_VERBOSE)
     1591                dataLog("[@%lu bc#%u]: profile %p: ", m_graph.size(), m_currentProfilingIndex, profile);
     1592                profile->dump(WTF::dataFile());
     1593                dataLog("\n");
     1594#endif
     1595                if (profile->m_singletonValueIsTop
     1596                    || !profile->m_singletonValue
     1597                    || !profile->m_singletonValue.isCell()
     1598                    || profile->m_singletonValue.asCell()->classInfo() != &Structure::s_info)
     1599                    setThis(addToGraph(ConvertThis, op1));
     1600                else {
     1601                    addToGraph(
     1602                        CheckStructure,
     1603                        OpInfo(m_graph.addStructureSet(jsCast<Structure*>(profile->m_singletonValue.asCell()))),
     1604                        op1);
     1605                }
     1606            }
    15891607            NEXT_OPCODE(op_convert_this);
    15901608        }
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r118323 r118555  
    12581258void JIT::emit_op_convert_this(Instruction* currentInstruction)
    12591259{
    1260     emitGetVirtualRegister(currentInstruction[1].u.operand, regT0);
    1261 
    1262     emitJumpSlowCaseIfNotJSCell(regT0);
    1263     addSlowCase(branchPtr(Equal, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info)));
     1260    emitGetVirtualRegister(currentInstruction[1].u.operand, regT1);
     1261
     1262    emitJumpSlowCaseIfNotJSCell(regT1);
     1263    if (shouldEmitProfiling()) {
     1264        loadPtr(Address(regT1, JSCell::structureOffset()), regT0);
     1265        emitValueProfilingSite();
     1266    }
     1267    addSlowCase(branchPtr(Equal, Address(regT1, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info)));
    12641268}
    12651269
     
    13161320
    13171321    linkSlowCase(iter);
    1318     Jump isNotUndefined = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(jsUndefined())));
     1322    if (shouldEmitProfiling())
     1323        move(TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(jsUndefined()))), regT0);
     1324    Jump isNotUndefined = branchPtr(NotEqual, regT1, TrustedImmPtr(JSValue::encode(jsUndefined())));
     1325    emitValueProfilingSite();
    13191326    move(TrustedImmPtr(globalThis), regT0);
    13201327    emitPutVirtualRegister(currentInstruction[1].u.operand, regT0);
    13211328    emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_convert_this));
    13221329
     1330    linkSlowCase(iter);
     1331    if (shouldEmitProfiling())
     1332        move(TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(m_globalData->stringStructure.get()))), regT0);
    13231333    isNotUndefined.link(this);
    1324     linkSlowCase(iter);
     1334    emitValueProfilingSite();
    13251335    JITStubCall stubCall(this, cti_op_convert_this);
    1326     stubCall.addArgument(regT0);
     1336    stubCall.addArgument(regT1);
    13271337    stubCall.call(currentInstruction[1].u.operand);
    13281338}
  • trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp

    r118112 r118555  
    15491549    unsigned thisRegister = currentInstruction[1].u.operand;
    15501550
    1551     emitLoad(thisRegister, regT1, regT0);
    1552 
    1553     addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
    1554     addSlowCase(branchPtr(Equal, Address(regT0, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info)));
    1555 
    1556     map(m_bytecodeOffset + OPCODE_LENGTH(op_convert_this), thisRegister, regT1, regT0);
     1551    emitLoad(thisRegister, regT3, regT2);
     1552
     1553    addSlowCase(branch32(NotEqual, regT3, TrustedImm32(JSValue::CellTag)));
     1554    if (shouldEmitProfiling()) {
     1555        loadPtr(Address(regT2, JSCell::structureOffset()), regT0);
     1556        move(regT3, regT1);
     1557        emitValueProfilingSite();
     1558    }
     1559    addSlowCase(branchPtr(Equal, Address(regT2, JSCell::classInfoOffset()), TrustedImmPtr(&JSString::s_info)));
    15571560}
    15581561
     
    15631566
    15641567    linkSlowCase(iter);
    1565     Jump isNotUndefined = branch32(NotEqual, regT1, TrustedImm32(JSValue::UndefinedTag));
     1568    if (shouldEmitProfiling()) {
     1569        move(TrustedImm32(JSValue::UndefinedTag), regT1);
     1570        move(TrustedImm32(0), regT0);
     1571    }
     1572    Jump isNotUndefined = branch32(NotEqual, regT3, TrustedImm32(JSValue::UndefinedTag));
     1573    emitValueProfilingSite();
    15661574    move(TrustedImmPtr(globalThis), regT0);
    15671575    move(TrustedImm32(JSValue::CellTag), regT1);
     
    15691577    emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_convert_this));
    15701578
     1579    linkSlowCase(iter);
     1580    if (shouldEmitProfiling()) {
     1581        move(TrustedImm32(JSValue::CellTag), regT1);
     1582        move(TrustedImmPtr(m_globalData->stringStructure.get()), regT0);
     1583    }
    15711584    isNotUndefined.link(this);
    1572     linkSlowCase(iter);
     1585    emitValueProfilingSite();
    15731586    JITStubCall stubCall(this, cti_op_convert_this);
    1574     stubCall.addArgument(regT1, regT0);
     1587    stubCall.addArgument(regT3, regT2);
    15751588    stubCall.call(thisRegister);
    15761589}
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r117859 r118555  
    468468    JSValue v1 = LLINT_OP(1).jsValue();
    469469    ASSERT(v1.isPrimitive());
     470    pc[OPCODE_LENGTH(op_convert_this) - 1].u.profile->m_buckets[0] =
     471        JSValue::encode(v1.structureOrUndefined());
    470472    LLINT_RETURN(v1.toThisObject(exec));
    471473}
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r118112 r118555  
    365365    loadp JSCell::m_structure[t0], t0
    366366    bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow
    367     dispatch(2)
     367    loadi 8[PC], t1
     368    valueProfile(CellTag, t0, t1)
     369    dispatch(3)
    368370
    369371.opConvertThisSlow:
    370372    callSlowPath(_llint_slow_path_convert_this)
    371     dispatch(2)
     373    dispatch(3)
    372374
    373375
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r118112 r118555  
    242242    loadp JSCell::m_structure[t0], t0
    243243    bbb Structure::m_typeInfo + TypeInfo::m_type[t0], ObjectType, .opConvertThisSlow
    244     dispatch(2)
     244    loadp 16[PB, PC, 8], t1
     245    valueProfile(t0, t1)
     246    dispatch(3)
    245247
    246248.opConvertThisSlow:
    247249    callSlowPath(_llint_slow_path_convert_this)
    248     dispatch(2)
     250    dispatch(3)
    249251
    250252
  • trunk/Source/JavaScriptCore/runtime/JSValue.h

    r117646 r118555  
    240240        JSCell* asCell() const;
    241241        JS_EXPORT_PRIVATE bool isValidCallee();
     242       
     243        JSValue structureOrUndefined() const;
    242244
    243245        char* description() const;
  • trunk/Source/JavaScriptCore/runtime/Structure.h

    r117859 r118555  
    333333    }
    334334   
     335    inline JSValue JSValue::structureOrUndefined() const
     336    {
     337        if (isCell())
     338            return JSValue(asCell()->structure());
     339        return jsUndefined();
     340    }
     341
    335342    inline bool JSCell::isObject() const
    336343    {
Note: See TracChangeset for help on using the changeset viewer.