Title: [197042] trunk/Source/_javascript_Core
Revision
197042
Author
sbar...@apple.com
Date
2016-02-24 12:43:21 -0800 (Wed, 24 Feb 2016)

Log Message

[ES6] Implement Proxy.[[Delete]]
https://bugs.webkit.org/show_bug.cgi?id=154607

Reviewed by Mark Lam.

This patch implements Proxy.[[Delete]] with respect to section 9.5.10 of the ECMAScript spec.
https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-delete-p

* runtime/ProxyObject.cpp:
(JSC::ProxyObject::getConstructData):
(JSC::ProxyObject::performDelete):
(JSC::ProxyObject::deleteProperty):
(JSC::ProxyObject::deletePropertyByIndex):
* runtime/ProxyObject.h:
* tests/es6.yaml:
* tests/stress/proxy-delete.js: Added.
(assert):
(throw.new.Error.let.handler.get deleteProperty):
(throw.new.Error):
(assert.let.handler.deleteProperty):
(let.handler.deleteProperty):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (197041 => 197042)


--- trunk/Source/_javascript_Core/ChangeLog	2016-02-24 20:31:40 UTC (rev 197041)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-02-24 20:43:21 UTC (rev 197042)
@@ -1,3 +1,27 @@
+2016-02-24  Saam Barati  <sbar...@apple.com>
+
+        [ES6] Implement Proxy.[[Delete]]
+        https://bugs.webkit.org/show_bug.cgi?id=154607
+
+        Reviewed by Mark Lam.
+
+        This patch implements Proxy.[[Delete]] with respect to section 9.5.10 of the ECMAScript spec.
+        https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-delete-p
+
+        * runtime/ProxyObject.cpp:
+        (JSC::ProxyObject::getConstructData):
+        (JSC::ProxyObject::performDelete):
+        (JSC::ProxyObject::deleteProperty):
+        (JSC::ProxyObject::deletePropertyByIndex):
+        * runtime/ProxyObject.h:
+        * tests/es6.yaml:
+        * tests/stress/proxy-delete.js: Added.
+        (assert):
+        (throw.new.Error.let.handler.get deleteProperty):
+        (throw.new.Error):
+        (assert.let.handler.deleteProperty):
+        (let.handler.deleteProperty):
+
 2016-02-24  Filip Pizlo  <fpi...@apple.com>
 
         Stackmaps have problems with double register constraints

Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.cpp (197041 => 197042)


--- trunk/Source/_javascript_Core/runtime/ProxyObject.cpp	2016-02-24 20:31:40 UTC (rev 197041)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.cpp	2016-02-24 20:43:21 UTC (rev 197042)
@@ -405,4 +405,75 @@
     return ConstructTypeHost;
 }
 
+template <typename DefaultDeleteFunction>
+bool ProxyObject::performDelete(ExecState* exec, PropertyName propertyName, DefaultDeleteFunction defaultDeleteFunction)
+{
+    VM& vm = exec->vm();
+    JSValue handlerValue = this->handler();
+    if (handlerValue.isNull()) {
+        throwVMTypeError(exec, ASCIILiteral("Proxy 'handler' is null. It should be an Object."));
+        return false;
+    }
+
+    JSObject* handler = jsCast<JSObject*>(handlerValue);
+    CallData callData;
+    CallType callType;
+    JSValue deletePropertyMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "deleteProperty"), ASCIILiteral("'deleteProperty' property of a Proxy's handler should be callable."));
+    if (exec->hadException())
+        return false;
+    JSObject* target = this->target();
+    if (deletePropertyMethod.isUndefined())
+        return defaultDeleteFunction();
+
+    MarkedArgumentBuffer arguments;
+    arguments.append(target);
+    arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
+    JSValue trapResult = call(exec, deletePropertyMethod, callType, callData, handler, arguments);
+    if (exec->hadException())
+        return false;
+
+    bool trapResultAsBool = trapResult.toBoolean(exec);
+    if (exec->hadException())
+        return false;
+
+    if (!trapResultAsBool)
+        return false;
+
+    PropertyDescriptor descriptor;
+    if (target->getOwnPropertyDescriptor(exec, propertyName, descriptor)) {
+        if (!descriptor.configurable()) {
+            throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'deleteProperty' method should return false when the target's property is not configurable."));
+            return false;
+        }
+    }
+
+    if (exec->hadException())
+        return false;
+
+    return true;
+}
+
+bool ProxyObject::deleteProperty(JSCell* cell, ExecState* exec, PropertyName propertyName)
+{
+    ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
+    auto defaultDelete = [&] () -> bool {
+        JSObject* target = jsCast<JSObject*>(thisObject->target());
+        return target->methodTable(exec->vm())->deleteProperty(target, exec, propertyName);
+    };
+    return thisObject->performDelete(exec, propertyName, defaultDelete);
+}
+
+bool ProxyObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
+{
+    ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
+    Identifier ident = Identifier::from(exec, propertyName); 
+    if (exec->hadException())
+        return false;
+    auto defaultDelete = [&] () -> bool {
+        JSObject* target = jsCast<JSObject*>(thisObject->target());
+        return target->methodTable(exec->vm())->deletePropertyByIndex(target, exec, propertyName);
+    };
+    return thisObject->performDelete(exec, ident.impl(), defaultDelete);
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.h (197041 => 197042)


--- trunk/Source/_javascript_Core/runtime/ProxyObject.h	2016-02-24 20:31:40 UTC (rev 197041)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.h	2016-02-24 20:43:21 UTC (rev 197042)
@@ -63,11 +63,15 @@
     static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
     static CallType getCallData(JSCell*, CallData&);
     static ConstructType getConstructData(JSCell*, ConstructData&);
+    static bool deleteProperty(JSCell*, ExecState*, PropertyName);
+    static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
     static void visitChildren(JSCell*, SlotVisitor&);
 
     bool getOwnPropertySlotCommon(ExecState*, PropertyName, PropertySlot&);
     bool performInternalMethodGetOwnProperty(ExecState*, PropertyName, PropertySlot&);
     bool performHasProperty(ExecState*, PropertyName, PropertySlot&);
+    template <typename DefaultDeleteFunction>
+    bool performDelete(ExecState*, PropertyName, DefaultDeleteFunction);
 
     WriteBarrier<JSObject> m_target;
     WriteBarrier<Unknown> m_handler;

Modified: trunk/Source/_javascript_Core/tests/es6.yaml (197041 => 197042)


--- trunk/Source/_javascript_Core/tests/es6.yaml	2016-02-24 20:31:40 UTC (rev 197041)
+++ trunk/Source/_javascript_Core/tests/es6.yaml	2016-02-24 20:43:21 UTC (rev 197042)
@@ -917,7 +917,7 @@
 - path: es6/Proxy_defineProperty_handler.js
   cmd: runES6 :fail
 - path: es6/Proxy_deleteProperty_handler.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_enumerate_handler.js
   cmd: runES6 :fail
 - path: es6/Proxy_get_handler.js
@@ -937,9 +937,9 @@
 - path: es6/Proxy_internal_defineProperty_calls_SetIntegrityLevel.js
   cmd: runES6 :fail
 - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.copyWithin.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.pop.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.reverse.js
   cmd: runES6 :fail
 - path: es6/Proxy_internal_deleteProperty_calls_Array.prototype.shift.js

Added: trunk/Source/_javascript_Core/tests/stress/proxy-delete.js (0 => 197042)


--- trunk/Source/_javascript_Core/tests/stress/proxy-delete.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/proxy-delete.js	2016-02-24 20:43:21 UTC (rev 197042)
@@ -0,0 +1,277 @@
+function assert(b) {
+    if (!b)
+        throw new Error("bad assertion.");
+}
+
+{
+    let target = {x: 20};
+    let error = null;
+    let handler = {
+        get deleteProperty() {
+            error = new Error;
+            throw error;
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        try {
+            delete proxy.x;
+        } catch(e) {
+            assert(e === error);
+            threw = true;
+        }
+        assert(threw);
+    }
+}
+
+{
+    let target = {x: 20};
+    let error = null;
+    let handler = {
+        deleteProperty: function() {
+            error = new Error;
+            throw error;
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        try {
+            delete proxy.x;
+        } catch(e) {
+            assert(e === error);
+            threw = true;
+        }
+        assert(threw);
+    }
+}
+
+{
+    let target = {x: 20};
+    let error = null;
+    let handler = {
+        deleteProperty: 45
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        try {
+            delete proxy.x;
+        } catch(e) {
+            assert(e.toString() === "TypeError: 'deleteProperty' property of a Proxy's handler should be callable.");
+            threw = true;
+        }
+        assert(threw);
+    }
+}
+
+{
+    let target = {};
+    Object.defineProperty(target, "x", {
+        configurable: false,
+        value: 25
+    });
+    let error = null;
+    let handler = {
+        deleteProperty: function(theTarget, propName) {
+            delete theTarget[propName];
+            return true;
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        try {
+            delete proxy.x;
+        } catch(e) {
+            assert(e.toString() === "TypeError: Proxy handler's 'deleteProperty' method should return false when the target's property is not configurable.");
+            threw = true;
+        }
+        assert(threw);
+    }
+}
+
+{
+    let target = {};
+    let error = null;
+    let handler = {
+        deleteProperty: null
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        target.x = i;
+        assert(proxy.x === i);
+        let result = delete proxy.x;
+        assert(result);
+        assert(proxy.x === undefined);
+    }
+}
+
+{
+    let target = {};
+    let error = null;
+    let handler = {
+        deleteProperty: undefined
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        target[i] = i;
+        assert(proxy[i] === i);
+        let result = delete proxy[i];
+        assert(result);
+        assert(proxy[i] === undefined);
+    }
+}
+
+{
+    let target = {};
+    let called = false;
+    let handler = {
+        deleteProperty: function(theTarget, propName) {
+            called = true;
+            assert(theTarget === target);
+            assert(propName === "x");
+            return delete theTarget[propName];
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        target.x = i;
+        assert(proxy.x === i);
+        let result = delete proxy.x;
+        assert(result);
+        assert(proxy.x === undefined);
+        assert(target.x === undefined);
+        assert(called);
+        called = false;
+    }
+}
+
+{
+    let target = {};
+    let called = false;
+    let handler = {
+        deleteProperty: function(theTarget, propName) {
+            called = true;
+            assert(theTarget === target);
+            assert(propName === "x");
+            return delete theTarget[propName];
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        target.x = i;
+        assert(proxy.x === i);
+        let result = delete proxy["x"];
+        assert(result);
+        assert(proxy.x === undefined);
+        assert(target.x === undefined);
+        assert(called);
+        called = false;
+    }
+}
+
+{
+    let target = {};
+    let called = false;
+    let handler = {
+        deleteProperty: function(theTarget, propName) {
+            called = true;
+            assert(theTarget === target);
+            return delete theTarget[propName];
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        target[i] = i;
+        assert(proxy[i] === i);
+        let result = delete proxy[i];
+        assert(result);
+        assert(proxy[i] === undefined);
+        assert(target[i] === undefined);
+        assert(called);
+        called = false;
+    }
+}
+
+{
+    let target = {};
+    let called = false;
+    let handler = {
+        deleteProperty: function(theTarget, propName) {
+            called = true;
+            assert(theTarget === target);
+            delete theTarget[propName];
+            return false; // We're liars.
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        target[i] = i;
+        assert(proxy[i] === i);
+        let result = delete proxy[i];
+        assert(!result);
+        assert(proxy[i] === undefined);
+        assert(target[i] === undefined);
+        assert(called);
+        called = false;
+    }
+}
+
+{
+    let target = {};
+    let error = null;
+    let called = false;
+    let handler = {
+        deleteProperty: function(theTarget, propName) {
+            called = true;
+            return delete theTarget[propName];
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        Object.defineProperty(target, "x", {
+            configurable: true,
+            writable: false,
+            value: 25
+        });
+        target.x = 30;
+        assert(target.x === 25);
+        assert(proxy.x === 25);
+        delete proxy.x;
+        assert(target.x === undefined);
+        assert(proxy.x === undefined);
+        assert(!("x" in proxy));
+        assert(!("x" in target));
+        assert(called);
+        called = false;
+    }
+}
+
+{
+    let target = {};
+    let error = null;
+    Object.defineProperty(target, "x", {
+        configurable: false,
+        writable: false,
+        value: 25
+    });
+    let called = false;
+    let handler = {
+        deleteProperty: function(theTarget, propName) {
+            called = true;
+            return delete theTarget[propName];
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        target.x = 30;
+        assert(target.x === 25);
+        assert(proxy.x === 25);
+        let result = delete proxy.x;
+        assert(!result);
+        assert(called);
+        called = false;
+    }
+}
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to