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);