Title: [201584] trunk/Source/_javascript_Core
Revision
201584
Author
[email protected]
Date
2016-06-01 20:18:16 -0700 (Wed, 01 Jun 2016)

Log 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:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (201583 => 201584)


--- trunk/Source/_javascript_Core/ChangeLog	2016-06-02 01:09:55 UTC (rev 201583)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-06-02 03:18:16 UTC (rev 201584)
@@ -1,3 +1,33 @@
+2016-06-01  Keith Miller  <[email protected]>
+
+        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:
+
 2016-06-01  Geoffrey Garen  <[email protected]>
 
         Unreviewed, rolling in r201436.

Modified: trunk/Source/_javascript_Core/bytecode/ObjectPropertyCondition.cpp (201583 => 201584)


--- trunk/Source/_javascript_Core/bytecode/ObjectPropertyCondition.cpp	2016-06-02 01:09:55 UTC (rev 201583)
+++ trunk/Source/_javascript_Core/bytecode/ObjectPropertyCondition.cpp	2016-06-02 03:18:16 UTC (rev 201584)
@@ -49,7 +49,7 @@
 bool ObjectPropertyCondition::structureEnsuresValidityAssumingImpurePropertyWatchpoint(
     Structure* structure) const
 {
-    return m_condition.isStillValidAssumingImpurePropertyWatchpoint(structure);
+    return m_condition.isStillValidAssumingImpurePropertyWatchpoint(structure, m_object);
 }
 
 bool ObjectPropertyCondition::structureEnsuresValidityAssumingImpurePropertyWatchpoint() const

Modified: trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.cpp (201583 => 201584)


--- trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.cpp	2016-06-02 01:09:55 UTC (rev 201583)
+++ trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.cpp	2016-06-02 03:18:16 UTC (rev 201584)
@@ -62,7 +62,7 @@
 
 bool ObjectPropertyConditionSet::hasOneSlotBaseCondition() const
 {
-    return numberOfConditionsWithKind(PropertyCondition::Presence) == 1;
+    return (numberOfConditionsWithKind(PropertyCondition::Presence) == 1) != (numberOfConditionsWithKind(PropertyCondition::Equivalence) == 1);
 }
 
 ObjectPropertyCondition ObjectPropertyConditionSet::slotBaseCondition() const
@@ -70,7 +70,8 @@
     ObjectPropertyCondition result;
     unsigned numFound = 0;
     for (const ObjectPropertyCondition& condition : *this) {
-        if (condition.kind() == PropertyCondition::Presence) {
+        if (condition.kind() == PropertyCondition::Presence
+            || condition.kind() == PropertyCondition::Equivalence) {
             result = condition;
             numFound++;
         }
@@ -198,6 +199,15 @@
             vm, owner, object, uid, object->structure()->storedPrototypeObject());
         break;
     }
+    case PropertyCondition::Equivalence: {
+        unsigned attributes;
+        PropertyOffset offset = structure->getConcurrently(uid, attributes);
+        if (offset == invalidOffset)
+            return ObjectPropertyCondition();
+        JSValue value = object->getDirect(offset);
+        result = ObjectPropertyCondition::equivalence(vm, owner, object, uid, value);
+        break;
+    }
     default:
         RELEASE_ASSERT_NOT_REACHED();
         return ObjectPropertyCondition();
@@ -240,7 +250,7 @@
         if (value.isNull()) {
             if (!prototype) {
                 if (verbose)
-                    dataLog("Reached end up prototype chain as expected, done.\n");
+                    dataLog("Reached end of prototype chain as expected, done.\n");
                 break;
             }
             if (verbose)
@@ -355,6 +365,21 @@
         });
 }
 
+ObjectPropertyConditionSet generateConditionsForPrototypeEquivalenceConcurrently(
+    VM& vm, JSGlobalObject* globalObject, Structure* headStructure, JSObject* prototype, UniquedStringImpl* uid)
+{
+    return generateConditions(vm, globalObject, headStructure, prototype,
+        [&] (Vector<ObjectPropertyCondition>& conditions, JSObject* object) -> bool {
+            PropertyCondition::Kind kind =
+                object == prototype ? PropertyCondition::Equivalence : PropertyCondition::Absence;
+            ObjectPropertyCondition result = generateCondition(vm, nullptr, object, uid, kind);
+            if (!result)
+                return false;
+            conditions.append(result);
+            return true;
+        }, Concurrent);
+}
+
 ObjectPropertyConditionSet generateConditionsForPropertyMissConcurrently(
     VM& vm, JSGlobalObject* globalObject, Structure* headStructure, UniquedStringImpl* uid)
 {

Modified: trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.h (201583 => 201584)


--- trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.h	2016-06-02 01:09:55 UTC (rev 201583)
+++ trunk/Source/_javascript_Core/bytecode/ObjectPropertyConditionSet.h	2016-06-02 03:18:16 UTC (rev 201584)
@@ -166,7 +166,9 @@
     VM&, JSCell* owner, ExecState*, Structure* headStructure, JSObject* prototype,
     UniquedStringImpl* uid);
 
-
+ObjectPropertyConditionSet generateConditionsForPrototypeEquivalenceConcurrently(
+    VM&, JSGlobalObject*, Structure* headStructure, JSObject* prototype,
+    UniquedStringImpl* uid);
 ObjectPropertyConditionSet generateConditionsForPropertyMissConcurrently(
     VM&, JSGlobalObject*, Structure* headStructure, UniquedStringImpl* uid);
 ObjectPropertyConditionSet generateConditionsForPropertySetterMissConcurrently(

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (201583 => 201584)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2016-06-02 01:09:55 UTC (rev 201583)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2016-06-02 03:18:16 UTC (rev 201584)
@@ -1538,27 +1538,6 @@
     return MethodOfGettingAValueProfile();
 }
 
-bool Graph::isStringPrototypeMethodSane(JSObject* stringPrototype, Structure* stringPrototypeStructure, UniquedStringImpl* uid)
-{
-    unsigned attributesUnused;
-    PropertyOffset offset = stringPrototypeStructure->getConcurrently(uid, attributesUnused);
-    if (!isValidOffset(offset))
-        return false;
-
-    JSValue value = tryGetConstantProperty(stringPrototype, stringPrototypeStructure, offset);
-    if (!value)
-        return false;
-
-    JSFunction* function = jsDynamicCast<JSFunction*>(value);
-    if (!function)
-        return false;
-
-    if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
-        return false;
-    
-    return true;
-}
-
 bool Graph::getRegExpPrototypeProperty(JSObject* regExpPrototype, Structure* regExpPrototypeStructure, UniquedStringImpl* uid, JSValue& returnJSValue)
 {
     unsigned attributesUnused;
@@ -1587,39 +1566,48 @@
     return true;
 }
 
+bool Graph::isStringPrototypeMethodSane(JSGlobalObject* globalObject, UniquedStringImpl* uid)
+{
+    ObjectPropertyConditionSet conditions = generateConditionsForPrototypeEquivalenceConcurrently(m_vm, globalObject, globalObject->stringObjectStructure(), globalObject->stringPrototype(), uid);
+
+    if (!conditions.isValid())
+        return false;
+
+    ObjectPropertyCondition equivalenceCondition = conditions.slotBaseCondition();
+    RELEASE_ASSERT(equivalenceCondition.hasRequiredValue());
+    JSFunction* function = jsDynamicCast<JSFunction*>(equivalenceCondition.condition().requiredValue());
+    if (!function)
+        return false;
+
+    if (function->executable()->intrinsicFor(CodeForCall) != StringPrototypeValueOfIntrinsic)
+        return false;
+    
+    return watchConditions(conditions);
+}
+
+
 bool Graph::canOptimizeStringObjectAccess(const CodeOrigin& codeOrigin)
 {
     if (hasExitSite(codeOrigin, NotStringObject))
         return false;
 
+    JSGlobalObject* globalObject = globalObjectFor(codeOrigin);
     Structure* stringObjectStructure = globalObjectFor(codeOrigin)->stringObjectStructure();
     registerStructure(stringObjectStructure);
     ASSERT(stringObjectStructure->storedPrototype().isObject());
     ASSERT(stringObjectStructure->storedPrototype().asCell()->classInfo() == StringPrototype::info());
 
-    FrozenValue* stringPrototypeObjectValue = freeze(stringObjectStructure->storedPrototype());
-    StringPrototype* stringPrototypeObject = stringPrototypeObjectValue->dynamicCast<StringPrototype*>();
-    Structure* stringPrototypeStructure = stringPrototypeObjectValue->structure();
-    if (registerStructure(stringPrototypeStructure) != StructureRegisteredAndWatched)
+    if (!watchConditions(generateConditionsForPropertyMissConcurrently(m_vm, globalObject, stringObjectStructure, m_vm.propertyNames->toPrimitiveSymbol.impl())))
         return false;
 
-    if (stringPrototypeStructure->isDictionary())
-        return false;
-
-    if (!watchConditions(generateConditionsForPropertyMissConcurrently(m_vm, globalObjectFor(codeOrigin), stringObjectStructure, m_vm.propertyNames->toPrimitiveSymbol.impl())))
-        return false;
-
     // We're being conservative here. We want DFG's ToString on StringObject to be
     // used in both numeric contexts (that would call valueOf()) and string contexts
     // (that would call toString()). We don't want the DFG to have to distinguish
     // between the two, just because that seems like it would get confusing. So we
     // just require both methods to be sane.
-    if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, m_vm.propertyNames->valueOf.impl()))
+    if (!isStringPrototypeMethodSane(globalObject, m_vm.propertyNames->valueOf.impl()))
         return false;
-    if (!isStringPrototypeMethodSane(stringPrototypeObject, stringPrototypeStructure, m_vm.propertyNames->toString.impl()))
-        return false;
-
-    return true;
+    return isStringPrototypeMethodSane(globalObject, m_vm.propertyNames->toString.impl());
 }
 
 bool Graph::willCatchExceptionInMachineFrame(CodeOrigin codeOrigin, CodeOrigin& opCatchOriginOut, HandlerInfo*& catchHandlerOut)

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (201583 => 201584)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.h	2016-06-02 01:09:55 UTC (rev 201583)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h	2016-06-02 03:18:16 UTC (rev 201584)
@@ -910,7 +910,7 @@
     bool m_hasExceptionHandlers { false };
 private:
 
-    bool isStringPrototypeMethodSane(JSObject* stringPrototype, Structure* stringPrototypeStructure, UniquedStringImpl*);
+    bool isStringPrototypeMethodSane(JSGlobalObject*, UniquedStringImpl*);
 
     void handleSuccessor(Vector<BasicBlock*, 16>& worklist, BasicBlock*, BasicBlock* successor);
     
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to