Title: [198360] trunk/Source/_javascript_Core
Revision
198360
Author
[email protected]
Date
2016-03-17 16:55:09 -0700 (Thu, 17 Mar 2016)

Log Message

[ES6] Make GetProperty(.) inside ArrayPrototype.cpp spec compatible.
https://bugs.webkit.org/show_bug.cgi?id=155575

Reviewed by Filip Pizlo and Mark Lam.

This patch makes various Array.prototype.(shift | unshift | splice)
spec compliant. Before, they were performing Get and HasProperty as one 
operation. Instead, they need to be performed as two distinct operations
when it would be observable.

* runtime/ArrayPrototype.cpp:
(JSC::getProperty):
* runtime/PropertySlot.h:
(JSC::PropertySlot::PropertySlot):
(JSC::PropertySlot::isCacheableValue):
(JSC::PropertySlot::isCacheableGetter):
(JSC::PropertySlot::isCacheableCustom):
(JSC::PropertySlot::setIsTaintedByProxy):
(JSC::PropertySlot::isTaintedByProxy):
(JSC::PropertySlot::internalMethodType):
(JSC::PropertySlot::getValue):
* runtime/ProxyObject.cpp:
(JSC::ProxyObject::getOwnPropertySlotCommon):
* tests/es6.yaml:
* tests/stress/proxy-array-prototype-methods.js: Added.
(assert):
(test):
(shallowEq):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (198359 => 198360)


--- trunk/Source/_javascript_Core/ChangeLog	2016-03-17 23:26:17 UTC (rev 198359)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-03-17 23:55:09 UTC (rev 198360)
@@ -1,3 +1,34 @@
+2016-03-17  Saam barati  <[email protected]>
+
+        [ES6] Make GetProperty(.) inside ArrayPrototype.cpp spec compatible.
+        https://bugs.webkit.org/show_bug.cgi?id=155575
+
+        Reviewed by Filip Pizlo and Mark Lam.
+
+        This patch makes various Array.prototype.(shift | unshift | splice)
+        spec compliant. Before, they were performing Get and HasProperty as one 
+        operation. Instead, they need to be performed as two distinct operations
+        when it would be observable.
+
+        * runtime/ArrayPrototype.cpp:
+        (JSC::getProperty):
+        * runtime/PropertySlot.h:
+        (JSC::PropertySlot::PropertySlot):
+        (JSC::PropertySlot::isCacheableValue):
+        (JSC::PropertySlot::isCacheableGetter):
+        (JSC::PropertySlot::isCacheableCustom):
+        (JSC::PropertySlot::setIsTaintedByProxy):
+        (JSC::PropertySlot::isTaintedByProxy):
+        (JSC::PropertySlot::internalMethodType):
+        (JSC::PropertySlot::getValue):
+        * runtime/ProxyObject.cpp:
+        (JSC::ProxyObject::getOwnPropertySlotCommon):
+        * tests/es6.yaml:
+        * tests/stress/proxy-array-prototype-methods.js: Added.
+        (assert):
+        (test):
+        (shallowEq):
+
 2016-03-17  Mark Lam  <[email protected]>
 
         Make FunctionMode an enum class.

Modified: trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp (198359 => 198360)


--- trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2016-03-17 23:26:17 UTC (rev 198359)
+++ trunk/Source/_javascript_Core/runtime/ArrayPrototype.cpp	2016-03-17 23:55:09 UTC (rev 198360)
@@ -149,9 +149,15 @@
 {
     if (JSValue result = object->tryGetIndexQuickly(index))
         return result;
-    PropertySlot slot(object, PropertySlot::InternalMethodType::Get);
+    // We want to perform get and has in the same operation.
+    // We can only do so when this behavior is not observable. The
+    // only time it is observable is when we encounter a ProxyObject
+    // somewhere in the prototype chain.
+    PropertySlot slot(object, PropertySlot::InternalMethodType::HasProperty);
     if (!object->getPropertySlot(exec, index, slot))
         return JSValue();
+    if (UNLIKELY(slot.isTaintedByProxy()))
+        return object->get(exec, index);
     return slot.getValue(exec, index);
 }
 

Modified: trunk/Source/_javascript_Core/runtime/PropertySlot.h (198359 => 198360)


--- trunk/Source/_javascript_Core/runtime/PropertySlot.h	2016-03-17 23:26:17 UTC (rev 198359)
+++ trunk/Source/_javascript_Core/runtime/PropertySlot.h	2016-03-17 23:55:09 UTC (rev 198360)
@@ -86,6 +86,7 @@
         , m_cacheability(CachingAllowed)
         , m_propertyType(TypeUnset)
         , m_internalMethodType(internalMethodType)
+        , m_isTaintedByProxy(false)
     {
     }
 
@@ -102,6 +103,8 @@
     bool isCacheableValue() const { return isCacheable() && isValue(); }
     bool isCacheableGetter() const { return isCacheable() && isAccessor(); }
     bool isCacheableCustom() const { return isCacheable() && isCustom(); }
+    void setIsTaintedByProxy() { m_isTaintedByProxy = true; }
+    bool isTaintedByProxy() const { return m_isTaintedByProxy; }
 
     InternalMethodType internalMethodType() const { return m_internalMethodType; }
 
@@ -278,6 +281,7 @@
     CacheabilityType m_cacheability;
     PropertyType m_propertyType;
     InternalMethodType m_internalMethodType;
+    bool m_isTaintedByProxy;
 };
 
 ALWAYS_INLINE JSValue PropertySlot::getValue(ExecState* exec, PropertyName propertyName) const

Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.cpp (198359 => 198360)


--- trunk/Source/_javascript_Core/runtime/ProxyObject.cpp	2016-03-17 23:26:17 UTC (rev 198359)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.cpp	2016-03-17 23:55:09 UTC (rev 198360)
@@ -332,6 +332,8 @@
 bool ProxyObject::getOwnPropertySlotCommon(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
 {
     slot.disableCaching();
+    if (slot.internalMethodType() != PropertySlot::InternalMethodType::VMInquiry)
+        slot.setIsTaintedByProxy();
     switch (slot.internalMethodType()) {
     case PropertySlot::InternalMethodType::Get:
         slot.setCustom(this, CustomAccessor, performProxyGet);

Modified: trunk/Source/_javascript_Core/tests/es6.yaml (198359 => 198360)


--- trunk/Source/_javascript_Core/tests/es6.yaml	2016-03-17 23:26:17 UTC (rev 198359)
+++ trunk/Source/_javascript_Core/tests/es6.yaml	2016-03-17 23:55:09 UTC (rev 198360)
@@ -943,11 +943,11 @@
 - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.reverse.js
   cmd: runES6 :normal
 - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.shift.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.splice.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.unshift.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_internal_get_calls_Array.from.js
   cmd: runES6 :normal
 - path: es6/Proxy_internal_get_calls_Array.prototype.concat.js
@@ -1049,11 +1049,11 @@
 - path: es6/Proxy_internal_set_calls_Array.prototype.reverse.js
   cmd: runES6 :normal
 - path: es6/Proxy_internal_set_calls_Array.prototype.shift.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_internal_set_calls_Array.prototype.splice.js
   cmd: runES6 :normal
 - path: es6/Proxy_internal_set_calls_Array.prototype.unshift.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_internal_set_calls_Object.assign.js
   cmd: runES6 :normal
 - path: es6/Proxy_isExtensible_handler.js

Added: trunk/Source/_javascript_Core/tests/stress/proxy-array-prototype-methods.js (0 => 198360)


--- trunk/Source/_javascript_Core/tests/stress/proxy-array-prototype-methods.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/proxy-array-prototype-methods.js	2016-03-17 23:55:09 UTC (rev 198360)
@@ -0,0 +1,163 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion!");
+}
+
+function test(f) {
+    for (let i = 0; i < 1000; i++)
+        f();
+}
+
+function shallowEq(a, b) {
+    if (a.length !== b.length)
+        return false;
+    for (let i = 0; i < a.length; i++) {
+        if (a[i] !== b[i])
+            return false;
+    }
+    return true;
+}
+
+test(function() {
+    let delProps = new Set;
+    let hasProps = new Set;
+    let getProps = new Set;
+    let target = [ , , 1, , 4];
+    let handler = {
+        get(theTarget, key) {
+            getProps.add(key);
+            return Reflect.get(theTarget, key);
+        },
+        has(theTarget, key) {
+            hasProps.add(key);
+            return Reflect.has(theTarget, key);
+        },
+        deleteProperty(theTarget, key)
+        {
+            delProps.add(key);
+            return Reflect.deleteProperty(theTarget, key);
+        }
+    };
+
+    let proxy = new Proxy(target, handler);
+    proxy.unshift(20);
+
+    assert(delProps.size === 3);
+    assert(delProps.has("1"));
+    assert(delProps.has("2"));
+    assert(delProps.has("4"));
+
+    assert(hasProps.size === 5);
+    assert(hasProps.has("0"));
+    assert(hasProps.has("1"));
+    assert(hasProps.has("2"));
+    assert(hasProps.has("3"));
+    assert(hasProps.has("4"));
+
+    assert(getProps.size === 4);
+    assert(getProps.has("unshift"));
+    assert(getProps.has("length"));
+    assert(getProps.has("2"));
+    assert(getProps.has("4"));
+});
+
+test(function() {
+    let delProps = new Set;
+    let hasProps = new Set;
+    let getProps = new Set;
+    let target = [ 0, 0, , 1, , 4];
+    let handler = {
+        get(theTarget, key) {
+            getProps.add(key);
+            return Reflect.get(theTarget, key);
+        },
+        has(theTarget, key) {
+            hasProps.add(key);
+            return Reflect.has(theTarget, key);
+        },
+        deleteProperty(theTarget, key)
+        {
+            delProps.add(key);
+            return Reflect.deleteProperty(theTarget, key);
+        }
+    };
+
+    let proxy = new Proxy(target, handler);
+    proxy.shift();
+    assert(target.length === 5);
+
+    assert(delProps.size === 3);
+    assert(delProps.has("1"));
+    assert(delProps.has("3"));
+    assert(delProps.has("5"));
+
+    assert(hasProps.size === 5);
+    assert(hasProps.has("1"));
+    assert(hasProps.has("2"));
+    assert(hasProps.has("3"));
+    assert(hasProps.has("4"));
+    assert(hasProps.has("5"));
+
+    assert(getProps.size === 6);
+    assert(getProps.has("shift"));
+    assert(getProps.has("length"));
+    assert(getProps.has("0"));
+    assert(getProps.has("1"));
+    assert(getProps.has("3"));
+    assert(getProps.has("5"));
+});
+
+test(function() {
+    let delProps = new Set;
+    let hasProps = new Set;
+    let getProps = new Set;
+    let target = [ 0, , 1, , 2];
+    let handler = {
+        get(theTarget, key) {
+            getProps.add(key);
+            return Reflect.get(theTarget, key);
+        },
+        has(theTarget, key) {
+            hasProps.add(key);
+            return Reflect.has(theTarget, key);
+        },
+        deleteProperty(theTarget, key)
+        {
+            delProps.add(key);
+            return Reflect.deleteProperty(theTarget, key);
+        }
+    };
+
+    let proxy = new Proxy(target, handler);
+    proxy.splice(2, 2);
+
+    assert(delProps.size === 2);
+    assert(delProps.has("3"));
+    assert(delProps.has("4"));
+
+    assert(hasProps.size === 3);
+    assert(hasProps.has("2"));
+    assert(hasProps.has("3"));
+    assert(hasProps.has("4"));
+
+    assert(getProps.size === 4);
+    assert(getProps.has("splice"));
+    assert(getProps.has("length"));
+    assert(getProps.has("2"));
+    assert(getProps.has("4"));
+});
+
+test(function() {
+    let x = [1,2,3];
+    x.__proto__ = new Proxy([], {
+        get(theTarget, prop, receiver) {
+            assert(prop === "shift");
+            assert(receiver === x);
+            return Reflect.get(theTarget, prop);
+        }
+    });
+    x.shift();
+    assert(x.length === 2);
+    assert(x[0] === 2);
+    assert(x[1] === 3);
+});
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to