Title: [222590] trunk
Revision
222590
Author
[email protected]
Date
2017-09-27 17:44:28 -0700 (Wed, 27 Sep 2017)

Log Message

Propagate hasBeenFlattenedBefore in Structure's transition constructor and fix our for-in caching to fail when the prototype chain has an object with a dictionary structure
https://bugs.webkit.org/show_bug.cgi?id=177523

Reviewed by Mark Lam.

JSTests:

* stress/prototype-chain-has-dictionary-structure-for-in-caching.js: Added.
(assert):
(Test):
(addMethods.Test.prototype.string_appeared_here.i.methodNumber):
(addMethods):
(i.Test.prototype.propName):

Source/_javascript_Core:

There was a bug in Structure's transition constructor where it didn't
propagate forward the hasBeenFlattenedBefore bit. In practice, this meant
that every time we asked a dictionary structure if it has been flattened
before, it would return false. This patch fixes this bug. It also fixes
a bug that this uncovers in our for-in implementation. Our implementation
would cache the property name enumerator even when the prototype chain
included a structure that is as dictionary. This is wrong because that
prototype object may add properties without transitioning, and the for-in
loop would vend a stale set of prototype properties.

* jit/JITOperations.cpp:
* runtime/JSPropertyNameEnumerator.h:
(JSC::propertyNameEnumerator):
* runtime/Structure.cpp:
(JSC::Structure::Structure):
(JSC::Structure::canCachePropertyNameEnumerator const):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (222589 => 222590)


--- trunk/JSTests/ChangeLog	2017-09-28 00:27:09 UTC (rev 222589)
+++ trunk/JSTests/ChangeLog	2017-09-28 00:44:28 UTC (rev 222590)
@@ -1,3 +1,17 @@
+2017-09-27  Saam Barati  <[email protected]>
+
+        Propagate hasBeenFlattenedBefore in Structure's transition constructor and fix our for-in caching to fail when the prototype chain has an object with a dictionary structure
+        https://bugs.webkit.org/show_bug.cgi?id=177523
+
+        Reviewed by Mark Lam.
+
+        * stress/prototype-chain-has-dictionary-structure-for-in-caching.js: Added.
+        (assert):
+        (Test):
+        (addMethods.Test.prototype.string_appeared_here.i.methodNumber):
+        (addMethods):
+        (i.Test.prototype.propName):
+
 2017-09-27  Mark Lam  <[email protected]>
 
         Yarr::Parser::tryConsumeGroupName() should check for the end of the pattern.

Added: trunk/JSTests/stress/prototype-chain-has-dictionary-structure-for-in-caching.js (0 => 222590)


--- trunk/JSTests/stress/prototype-chain-has-dictionary-structure-for-in-caching.js	                        (rev 0)
+++ trunk/JSTests/stress/prototype-chain-has-dictionary-structure-for-in-caching.js	2017-09-28 00:44:28 UTC (rev 222590)
@@ -0,0 +1,36 @@
+
+function assert(b) {
+    if (!b)
+        throw new Error("Bad")
+}
+
+var Test = function(){};
+
+let methodNumber = 0;
+function addMethods() {
+    const methodCount = 65;
+    for (var i = 0; i < methodCount; i++){
+        Test.prototype['myMethod' + i + methodNumber] = function(){};
+        ++methodNumber;
+    }
+}
+
+addMethods();
+
+var test1 = new Test();
+
+for (var k in test1) { }
+
+let test2 = new Test();
+
+for (let i = 0; i < 100; ++i ) {
+    let propName = 'myAdditionalMethod' + i;
+    Test.prototype[propName] = function(){};
+    let foundNewPrototypeProperty = false;
+    for (let k in test2) {
+        if (propName === k)
+            foundNewPrototypeProperty = true;
+    }
+    assert(foundNewPrototypeProperty);
+    addMethods();
+}

Modified: trunk/Source/_javascript_Core/ChangeLog (222589 => 222590)


--- trunk/Source/_javascript_Core/ChangeLog	2017-09-28 00:27:09 UTC (rev 222589)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-09-28 00:44:28 UTC (rev 222590)
@@ -1,3 +1,27 @@
+2017-09-27  Saam Barati  <[email protected]>
+
+        Propagate hasBeenFlattenedBefore in Structure's transition constructor and fix our for-in caching to fail when the prototype chain has an object with a dictionary structure
+        https://bugs.webkit.org/show_bug.cgi?id=177523
+
+        Reviewed by Mark Lam.
+
+        There was a bug in Structure's transition constructor where it didn't
+        propagate forward the hasBeenFlattenedBefore bit. In practice, this meant
+        that every time we asked a dictionary structure if it has been flattened
+        before, it would return false. This patch fixes this bug. It also fixes
+        a bug that this uncovers in our for-in implementation. Our implementation
+        would cache the property name enumerator even when the prototype chain
+        included a structure that is as dictionary. This is wrong because that
+        prototype object may add properties without transitioning, and the for-in
+        loop would vend a stale set of prototype properties.
+
+        * jit/JITOperations.cpp:
+        * runtime/JSPropertyNameEnumerator.h:
+        (JSC::propertyNameEnumerator):
+        * runtime/Structure.cpp:
+        (JSC::Structure::Structure):
+        (JSC::Structure::canCachePropertyNameEnumerator const):
+
 2017-09-27  Mark Lam  <[email protected]>
 
         Yarr::Parser::tryConsumeGroupName() should check for the end of the pattern.

Modified: trunk/Source/_javascript_Core/jit/JITOperations.cpp (222589 => 222590)


--- trunk/Source/_javascript_Core/jit/JITOperations.cpp	2017-09-28 00:27:09 UTC (rev 222589)
+++ trunk/Source/_javascript_Core/jit/JITOperations.cpp	2017-09-28 00:44:28 UTC (rev 222590)
@@ -2407,9 +2407,12 @@
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
+    auto scope = DECLARE_THROW_SCOPE(vm);
 
     JSObject* base = cell->toObject(exec, exec->lexicalGlobalObject());
+    RETURN_IF_EXCEPTION(scope, { });
 
+    scope.release();
     return propertyNameEnumerator(exec, base);
 }
 

Modified: trunk/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h (222589 => 222590)


--- trunk/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h	2017-09-28 00:27:09 UTC (rev 222589)
+++ trunk/Source/_javascript_Core/runtime/JSPropertyNameEnumerator.h	2017-09-28 00:44:28 UTC (rev 222590)
@@ -133,11 +133,11 @@
 
     ASSERT(propertyNames.size() < UINT32_MAX);
 
-    normalizePrototypeChain(exec, structure);
+    bool successfullyNormalizedChain = normalizePrototypeChain(exec, structure) != InvalidPrototypeChain;
 
     enumerator = JSPropertyNameEnumerator::create(vm, structure, indexedLength, numberStructureProperties, WTFMove(propertyNames));
     enumerator->setCachedPrototypeChain(vm, structure->prototypeChain(exec));
-    if (!indexedLength && structure->canCachePropertyNameEnumerator())
+    if (!indexedLength && successfullyNormalizedChain && structure->canCachePropertyNameEnumerator())
         structure->setCachedPropertyNameEnumerator(vm, enumerator);
     return enumerator;
 }

Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (222589 => 222590)


--- trunk/Source/_javascript_Core/runtime/Structure.cpp	2017-09-28 00:27:09 UTC (rev 222589)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp	2017-09-28 00:44:28 UTC (rev 222590)
@@ -253,7 +253,8 @@
     , m_offset(invalidOffset)
 {
     setDictionaryKind(previous->dictionaryKind());
-    setIsPinnedPropertyTable(previous->hasBeenFlattenedBefore());
+    setIsPinnedPropertyTable(false);
+    setHasBeenFlattenedBefore(previous->hasBeenFlattenedBefore());
     setHasGetterSetterProperties(previous->hasGetterSetterProperties());
     setHasCustomGetterSetterProperties(previous->hasCustomGetterSetterProperties());
     setHasReadOnlyOrGetterSetterPropertiesExcludingProto(previous->hasReadOnlyOrGetterSetterPropertiesExcludingProto());
@@ -1287,6 +1288,8 @@
     while (true) {
         if (!structure->get())
             break;
+        if (structure->get()->isDictionary())
+            return false;
         if (structure->get()->typeInfo().overridesGetPropertyNames())
             return false;
         structure++;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to