Title: [202093] trunk/Source/_javascript_Core
Revision
202093
Author
[email protected]
Date
2016-06-15 09:39:19 -0700 (Wed, 15 Jun 2016)

Log Message

DFGByteCodeParser should be able to infer a property is unset from the Baseline inline cache.
https://bugs.webkit.org/show_bug.cgi?id=158774

Reviewed by Filip Pizlo.

This patch allows the DFGByteCodeParser to speculatively convert a property access into a
constant if that access was always a miss in the Baseline inline cache. This patch does
not add support for MultiGetByOffset and unset properties. That functionality will come
a future patch.

* bytecode/ComplexGetStatus.cpp:
(JSC::ComplexGetStatus::computeFor):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
* bytecode/GetByIdVariant.h:
(JSC::GetByIdVariant::isPropertyUnset):
* bytecode/PutByIdVariant.h:
(JSC::PutByIdVariant::isPropertyUnset):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::load):
(JSC::DFG::ByteCodeParser::handleGetById):
* tests/stress/undefined-access-then-self-change.js: Added.
(foo):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (202092 => 202093)


--- trunk/Source/_javascript_Core/ChangeLog	2016-06-15 16:30:00 UTC (rev 202092)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-06-15 16:39:19 UTC (rev 202093)
@@ -1,3 +1,29 @@
+2016-06-15  Keith Miller  <[email protected]>
+
+        DFGByteCodeParser should be able to infer a property is unset from the Baseline inline cache.
+        https://bugs.webkit.org/show_bug.cgi?id=158774
+
+        Reviewed by Filip Pizlo.
+
+        This patch allows the DFGByteCodeParser to speculatively convert a property access into a
+        constant if that access was always a miss in the Baseline inline cache. This patch does
+        not add support for MultiGetByOffset and unset properties. That functionality will come
+        a future patch.
+
+        * bytecode/ComplexGetStatus.cpp:
+        (JSC::ComplexGetStatus::computeFor):
+        * bytecode/GetByIdStatus.cpp:
+        (JSC::GetByIdStatus::computeForStubInfoWithoutExitSiteFeedback):
+        * bytecode/GetByIdVariant.h:
+        (JSC::GetByIdVariant::isPropertyUnset):
+        * bytecode/PutByIdVariant.h:
+        (JSC::PutByIdVariant::isPropertyUnset):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::load):
+        (JSC::DFG::ByteCodeParser::handleGetById):
+        * tests/stress/undefined-access-then-self-change.js: Added.
+        (foo):
+
 2016-06-15  Yusuke Suzuki  <[email protected]>
 
         [JSC] Move calling convention flags to WTF

Modified: trunk/Source/_javascript_Core/bytecode/ComplexGetStatus.cpp (202092 => 202093)


--- trunk/Source/_javascript_Core/bytecode/ComplexGetStatus.cpp	2016-06-15 16:30:00 UTC (rev 202092)
+++ trunk/Source/_javascript_Core/bytecode/ComplexGetStatus.cpp	2016-06-15 16:39:19 UTC (rev 202093)
@@ -57,13 +57,12 @@
             result.m_conditionSet.numberOfConditionsWithKind(PropertyCondition::Presence);
         RELEASE_ASSERT(numberOfSlotBases <= 1);
         if (!numberOfSlotBases) {
-            // Currently we don't support misses. That's a bummer.
-            // FIXME: https://bugs.webkit.org/show_bug.cgi?id=133052
-            return takesSlowPath();
+            ASSERT(result.m_offset == invalidOffset);
+            return result;
         }
         ObjectPropertyCondition base = result.m_conditionSet.slotBaseCondition();
         ASSERT(base.kind() == PropertyCondition::Presence);
-        
+
         result.m_offset = base.offset();
     } else
         result.m_offset = headStructure->getConcurrently(uid);

Modified: trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp (202092 => 202093)


--- trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp	2016-06-15 16:30:00 UTC (rev 202092)
+++ trunk/Source/_javascript_Core/bytecode/GetByIdStatus.cpp	2016-06-15 16:39:19 UTC (rev 202093)
@@ -218,7 +218,8 @@
 
                 switch (access.type()) {
                 case AccessCase::Load:
-                case AccessCase::GetGetter: {
+                case AccessCase::GetGetter:
+                case AccessCase::Miss: {
                     break;
                 }
                 case AccessCase::IntrinsicGetter: {
@@ -238,7 +239,8 @@
                     // future. https://bugs.webkit.org/show_bug.cgi?id=133052
                     return GetByIdStatus(slowPathState, true);
                 } }
-                 
+
+                ASSERT((AccessCase::Miss == access.type()) == (access.offset() == invalidOffset));
                 GetByIdVariant variant(
                     StructureSet(structure), complexGetStatus.offset(),
                     complexGetStatus.conditionSet(), WTFMove(callLinkStatus),

Modified: trunk/Source/_javascript_Core/bytecode/GetByIdVariant.h (202092 => 202093)


--- trunk/Source/_javascript_Core/bytecode/GetByIdVariant.h	2016-06-15 16:30:00 UTC (rev 202092)
+++ trunk/Source/_javascript_Core/bytecode/GetByIdVariant.h	2016-06-15 16:39:19 UTC (rev 202093)
@@ -64,6 +64,8 @@
     JSFunction* intrinsicFunction() const { return m_intrinsicFunction; }
     Intrinsic intrinsic() const { return m_intrinsicFunction ? m_intrinsicFunction->intrinsic() : NoIntrinsic; }
 
+    bool isPropertyUnset() const { return offset() == invalidOffset; }
+
     bool attemptToMerge(const GetByIdVariant& other);
     
     void dump(PrintStream&) const;

Modified: trunk/Source/_javascript_Core/bytecode/PutByIdVariant.h (202092 => 202093)


--- trunk/Source/_javascript_Core/bytecode/PutByIdVariant.h	2016-06-15 16:30:00 UTC (rev 202092)
+++ trunk/Source/_javascript_Core/bytecode/PutByIdVariant.h	2016-06-15 16:39:19 UTC (rev 202093)
@@ -112,7 +112,10 @@
     
     // We don't support intrinsics for Setters (it would be sweet if we did) but we need this for templated helpers.
     Intrinsic intrinsic() const { return NoIntrinsic; }
-    
+
+    // This is needed for templated helpers.
+    bool isPropertyUnset() const { return false; }
+
     PropertyOffset offset() const
     {
         ASSERT(isSet());

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (202092 => 202093)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-06-15 16:30:00 UTC (rev 202092)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2016-06-15 16:39:19 UTC (rev 202093)
@@ -3008,11 +3008,11 @@
         Structure* structure = base->constant()->structure();
         if (!structure->dfgShouldWatch()) {
             if (!variant.conditionSet().isEmpty()) {
-                // This means that we're loading from a prototype. We expect the base not to have the
-                // property. We can only use ObjectPropertyCondition if all of the structures in the
-                // variant.structureSet() agree on the prototype (it would be hilariously rare if they
-                // didn't). Note that we are relying on structureSet() having at least one element. That
-                // will always be true here because of how GetByIdStatus/PutByIdStatus work.
+                // This means that we're loading from a prototype or we have a property miss. We expect
+                // the base not to have the property. We can only use ObjectPropertyCondition if all of
+                // the structures in the variant.structureSet() agree on the prototype (it would be
+                // hilariously rare if they didn't). Note that we are relying on structureSet() having
+                // at least one element. That will always be true here because of how GetByIdStatus/PutByIdStatus work.
                 JSObject* prototype = variant.structureSet()[0]->storedPrototypeObject();
                 bool allAgree = true;
                 for (unsigned i = 1; i < variant.structureSet().size(); ++i) {
@@ -3049,7 +3049,13 @@
 
     if (needStructureCheck)
         addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(variant.structureSet())), base);
-    
+
+    if (variant.isPropertyUnset()) {
+        if (m_graph.watchConditions(variant.conditionSet()))
+            return jsConstant(jsUndefined());
+        return nullptr;
+    }
+
     SpeculatedType loadPrediction;
     NodeType loadOp;
     if (variant.callLinkStatus() || variant.intrinsic() != NoIntrinsic) {
@@ -3144,7 +3150,7 @@
         //    optimal, if there is some rarely executed case in the chain that requires a lot
         //    of checks and those checks are not watchpointable.
         for (const GetByIdVariant& variant : getByIdStatus.variants()) {
-            if (variant.intrinsic() != NoIntrinsic) {
+            if (variant.intrinsic() != NoIntrinsic || variant.isPropertyUnset()) {
                 set(VirtualRegister(destinationOperand),
                     addToGraph(getById, OpInfo(identifierNumber), OpInfo(prediction), base));
                 return;

Added: trunk/Source/_javascript_Core/tests/stress/undefined-access-then-self-change.js (0 => 202093)


--- trunk/Source/_javascript_Core/tests/stress/undefined-access-then-self-change.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/undefined-access-then-self-change.js	2016-06-15 16:39:19 UTC (rev 202093)
@@ -0,0 +1,18 @@
+function foo(o) {
+    return o.f;
+}
+
+noInline(foo);
+
+var o = Object.create(null);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo(o);
+    if (result !== void 0)
+        throw "Error: bad result in loop: " + result;
+}
+
+o.f = 42
+var result = foo(o);
+if (result !== 42)
+    throw "Error: bad result at end: " + result;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to