⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 201584 in webkit


Ignore:
Timestamp:
Jun 1, 2016, 8:18:16 PM (10 years ago)
Author:
keith_miller@apple.com
Message:

canOptimizeStringObjectAccess should use ObjectPropertyConditions rather than structure watchpoints
https://bugs.webkit.org/show_bug.cgi?id=158291

Reviewed by Benjamin Poulain.

The old StringObject primitive access code used structure watchpoints. This meant that
if you set a watchpoint on String.prototype prior to tiering up to the DFG then added
a new property to String.prototype then we would never use StringObject optimizations.
This made property caching in the LLInt bad because it meant we would watchpoint
String.prototype very early in the program, which hurt date-format-xpab.js since that
benchmark relies on the StringObject optimizations.

This patch also extends ObjectPropertyConditionSet to be able to handle a slotBase
equivalence condition. Since that makes the code for generating the DFG watchpoints
significantly cleaner.

  • bytecode/ObjectPropertyCondition.cpp:

(JSC::ObjectPropertyCondition::structureEnsuresValidityAssumingImpurePropertyWatchpoint):

  • bytecode/ObjectPropertyConditionSet.cpp:

(JSC::ObjectPropertyConditionSet::hasOneSlotBaseCondition):
(JSC::ObjectPropertyConditionSet::slotBaseCondition):
(JSC::generateConditionsForPrototypeEquivalenceConcurrently):

  • bytecode/ObjectPropertyConditionSet.h:
  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::isStringPrototypeMethodSane):
(JSC::DFG::Graph::canOptimizeStringObjectAccess):

  • dfg/DFGGraph.h:
Location:
trunk/Source/JavaScriptCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r201573 r201584  
     12016-06-01  Keith Miller  <keith_miller@apple.com>
     2
     3        canOptimizeStringObjectAccess should use ObjectPropertyConditions rather than structure watchpoints
     4        https://bugs.webkit.org/show_bug.cgi?id=158291
     5
     6        Reviewed by Benjamin Poulain.
     7
     8        The old StringObject primitive access code used structure watchpoints. This meant that
     9        if you set a watchpoint on String.prototype prior to tiering up to the DFG then added
     10        a new property to String.prototype then we would never use StringObject optimizations.
     11        This made property caching in the LLInt bad because it meant we would watchpoint
     12        String.prototype very early in the program, which hurt date-format-xpab.js since that
     13        benchmark relies on the StringObject optimizations.
     14
     15        This patch also extends ObjectPropertyConditionSet to be able to handle a slotBase
     16        equivalence condition. Since that makes the code for generating the DFG watchpoints
     17        significantly cleaner.
     18
     19        * bytecode/ObjectPropertyCondition.cpp:
     20        (JSC::ObjectPropertyCondition::structureEnsuresValidityAssumingImpurePropertyWatchpoint):
     21        * bytecode/ObjectPropertyConditionSet.cpp:
     22        (JSC::ObjectPropertyConditionSet::hasOneSlotBaseCondition):
     23        (JSC::ObjectPropertyConditionSet::slotBaseCondition):
     24        (JSC::generateConditionsForPrototypeEquivalenceConcurrently):
     25        * bytecode/ObjectPropertyConditionSet.h:
     26        * dfg/DFGGraph.cpp:
     27        (JSC::DFG::Graph::isStringPrototypeMethodSane):
     28        (JSC::DFG::Graph::canOptimizeStringObjectAccess):
     29        * dfg/DFGGraph.h:
     30
    1312016-06-01  Geoffrey Garen  <ggaren@apple.com>
    232
  • trunk/Source/JavaScriptCore/bytecode/ObjectPropertyCondition.cpp

    r187780 r201584  
    5050    Structure* structure) const
    5151{
    52     return m_condition.isStillValidAssumingImpurePropertyWatchpoint(structure);
     52    return m_condition.isStillValidAssumingImpurePropertyWatchpoint(structure, m_object);
    5353}
    5454
  • trunk/Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.cpp

    r201573 r201584  
    6363bool ObjectPropertyConditionSet::hasOneSlotBaseCondition() const
    6464{
    65     return numberOfConditionsWithKind(PropertyCondition::Presence) == 1;
     65    return (numberOfConditionsWithKind(PropertyCondition::Presence) == 1) != (numberOfConditionsWithKind(PropertyCondition::Equivalence) == 1);
    6666}
    6767
     
    7171    unsigned numFound = 0;
    7272    for (const ObjectPropertyCondition& condition : *this) {
    73         if (condition.kind() == PropertyCondition::Presence) {
     73        if (condition.kind() == PropertyCondition::Presence
     74            || condition.kind() == PropertyCondition::Equivalence) {
    7475            result = condition;
    7576            numFound++;
     
    199200        break;
    200201    }
     202    case PropertyCondition::Equivalence: {
     203        unsigned attributes;
     204        PropertyOffset offset = structure->getConcurrently(uid, attributes);
     205        if (offset == invalidOffset)
     206            return ObjectPropertyCondition();
     207        JSValue value = object->getDirect(offset);
     208        result = ObjectPropertyCondition::equivalence(vm, owner, object, uid, value);
     209        break;
     210    }
    201211    default:
    202212        RELEASE_ASSERT_NOT_REACHED();
     
    241251            if (!prototype) {
    242252                if (verbose)
    243                     dataLog("Reached end up prototype chain as expected, done.\n");
     253                    dataLog("Reached end of prototype chain as expected, done.\n");
    244254                break;
    245255            }
     
    356366}
    357367
     368ObjectPropertyConditionSet generateConditionsForPrototypeEquivalenceConcurrently(
     369    VM& vm, JSGlobalObject* globalObject, Structure* headStructure, JSObject* prototype, UniquedStringImpl* uid)
     370{
     371    return generateConditions(vm, globalObject, headStructure, prototype,
     372        [&] (Vector<ObjectPropertyCondition>& conditions, JSObject* object) -> bool {
     373            PropertyCondition::Kind kind =
     374                object == prototype ? PropertyCondition::Equivalence : PropertyCondition::Absence;
     375            ObjectPropertyCondition result = generateCondition(vm, nullptr, object, uid, kind);
     376            if (!result)
     377                return false;
     378            conditions.append(result);
     379            return true;
     380        }, Concurrent);
     381}
     382
    358383ObjectPropertyConditionSet generateConditionsForPropertyMissConcurrently(
    359384    VM& vm, JSGlobalObject* globalObject, Structure* headStructure, UniquedStringImpl* uid)
  • trunk/Source/JavaScriptCore/bytecode/ObjectPropertyConditionSet.h

    r201532 r201584  
    167167    UniquedStringImpl* uid);
    168168
    169 
     169ObjectPropertyConditionSet generateConditionsForPrototypeEquivalenceConcurrently(
     170    VM&, JSGlobalObject*, Structure* headStructure, JSObject* prototype,
     171    UniquedStringImpl* uid);
    170172ObjectPropertyConditionSet generateConditionsForPropertyMissConcurrently(
    171173    VM&, JSGlobalObject*, Structure* headStructure, UniquedStringImpl* uid);
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r201182 r201584  
    15391539}
    15401540
    1541 bool Graph::isStringPrototypeMethodSane(JSObject* stringPrototype, Structure* stringPrototypeStructure, UniquedStringImpl* uid)
    1542 {
    1543     unsigned attributesUnused;
    1544     PropertyOffset offset = stringPrototypeStructure->getConcurrently(uid, attributesUnused);
    1545     if (!isValidOffset(offset))
    1546         return false;
    1547 
    1548     JSValue value = tryGetConstantProperty(stringPrototype, stringPrototypeStructure, offset);
    1549     if (!value)
    1550         return false;
    1551 
    1552     JSFunction* function = jsDynamicCast<JSFunction*>(value);
    1553     if (!function)
    1554         return false;
    1555 
    1556     if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
    1557         return false;
    1558    
    1559     return true;
    1560 }
    1561 
    15621541bool Graph::getRegExpPrototypeProperty(JSObject* regExpPrototype, Structure* regExpPrototypeStructure, UniquedStringImpl* uid, JSValue& returnJSValue)
    15631542{
     
    15881567}
    15891568
     1569bool Graph::isStringPrototypeMethodSane(JSGlobalObject* globalObject, UniquedStringImpl* uid)
     1570{
     1571    ObjectPropertyConditionSet conditions = generateConditionsForPrototypeEquivalenceConcurrently(m_vm, globalObject, globalObject->stringObjectStructure(), globalObject->stringPrototype(), uid);
     1572
     1573    if (!conditions.isValid())
     1574        return false;
     1575
     1576    ObjectPropertyCondition equivalenceCondition = conditions.slotBaseCondition();
     1577    RELEASE_ASSERT(equivalenceCondition.hasRequiredValue());
     1578    JSFunction* function = jsDynamicCast<JSFunction*>(equivalenceCondition.condition().requiredValue());
     1579    if (!function)
     1580        return false;
     1581
     1582    if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
     1583        return false;
     1584   
     1585    return watchConditions(conditions);
     1586}
     1587
     1588
    15901589bool Graph::canOptimizeStringObjectAccess(const CodeOrigin& codeOrigin)
    15911590{
     
    15931592        return false;
    15941593
     1594    JSGlobalObject* globalObject = globalObjectFor(codeOrigin);
    15951595    Structure* stringObjectStructure = globalObjectFor(codeOrigin)->stringObjectStructure();
    15961596    registerStructure(stringObjectStructure);
     
    15981598    ASSERT(stringObjectStructure->storedPrototype().asCell()->classInfo() == StringPrototype::info());
    15991599
    1600     FrozenValue* stringPrototypeObjectValue = freeze(stringObjectStructure->storedPrototype());
    1601     StringPrototype* stringPrototypeObject = stringPrototypeObjectValue->dynamicCast<StringPrototype*>();
    1602     Structure* stringPrototypeStructure = stringPrototypeObjectValue->structure();
    1603     if (registerStructure(stringPrototypeStructure) != StructureRegisteredAndWatched)
    1604         return false;
    1605 
    1606     if (stringPrototypeStructure->isDictionary())
    1607         return false;
    1608 
    1609     if (!watchConditions(generateConditionsForPropertyMissConcurrently(m_vm, globalObjectFor(codeOrigin), stringObjectStructure, m_vm.propertyNames->toPrimitiveSymbol.impl())))
     1600    if (!watchConditions(generateConditionsForPropertyMissConcurrently(m_vm, globalObject, stringObjectStructure, m_vm.propertyNames->toPrimitiveSymbol.impl())))
    16101601        return false;
    16111602
     
    16151606    // between the two, just because that seems like it would get confusing. So we
    16161607    // just require both methods to be sane.
    1617     if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, m_vm.propertyNames->valueOf.impl()))
     1608    if (!isStringPrototypeMethodSane(globalObject, m_vm.propertyNames->valueOf.impl()))
    16181609        return false;
    1619     if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, m_vm.propertyNames->toString.impl()))
    1620         return false;
    1621 
    1622     return true;
     1610    return isStringPrototypeMethodSane(globalObject, m_vm.propertyNames->toString.impl());
    16231611}
    16241612
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r201182 r201584  
    911911private:
    912912
    913     bool isStringPrototypeMethodSane(JSObject* stringPrototype, Structure* stringPrototypeStructure, UniquedStringImpl*);
     913    bool isStringPrototypeMethodSane(JSGlobalObject*, UniquedStringImpl*);
    914914
    915915    void handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock*, BasicBlock* successor);
Note: See TracChangeset for help on using the changeset viewer.