Title: [197711] trunk/Source/_javascript_Core
Revision
197711
Author
[email protected]
Date
2016-03-07 15:27:44 -0800 (Mon, 07 Mar 2016)

Log Message

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

Reviewed by Mark Lam.

This patch is a straight forward implementation of Proxy.[[GetPrototypeOf]]
with respect to section 9.5.1 of the ECMAScript spec.
https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-getprototypeof

* runtime/ProxyObject.cpp:
(JSC::performProxyGet):
(JSC::ProxyObject::setPrototype):
(JSC::ProxyObject::performGetPrototype):
(JSC::ProxyObject::getPrototype):
(JSC::ProxyObject::visitChildren):
* runtime/ProxyObject.h:
* tests/es6.yaml:
* tests/stress/proxy-get-prototype-of.js: Added.
(assert):
(throw.new.Error.let.handler.get getPrototypeOf):
(throw.new.Error.get let):
(throw.new.Error.get catch):
(throw.new.Error):
(assert.let.handler.getPrototypeOf):
(assert.get let):
(assert.get catch):
(assert.):
(let.handler.getPrototypeOf):
(get let):
(let.handler.has):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (197710 => 197711)


--- trunk/Source/_javascript_Core/ChangeLog	2016-03-07 23:24:47 UTC (rev 197710)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-03-07 23:27:44 UTC (rev 197711)
@@ -1,3 +1,36 @@
+2016-03-07  Saam barati  <[email protected]>
+
+        [ES6] Implement Proxy.[[GetPrototypeOf]]
+        https://bugs.webkit.org/show_bug.cgi?id=155099
+
+        Reviewed by Mark Lam.
+
+        This patch is a straight forward implementation of Proxy.[[GetPrototypeOf]]
+        with respect to section 9.5.1 of the ECMAScript spec.
+        https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-getprototypeof
+
+        * runtime/ProxyObject.cpp:
+        (JSC::performProxyGet):
+        (JSC::ProxyObject::setPrototype):
+        (JSC::ProxyObject::performGetPrototype):
+        (JSC::ProxyObject::getPrototype):
+        (JSC::ProxyObject::visitChildren):
+        * runtime/ProxyObject.h:
+        * tests/es6.yaml:
+        * tests/stress/proxy-get-prototype-of.js: Added.
+        (assert):
+        (throw.new.Error.let.handler.get getPrototypeOf):
+        (throw.new.Error.get let):
+        (throw.new.Error.get catch):
+        (throw.new.Error):
+        (assert.let.handler.getPrototypeOf):
+        (assert.get let):
+        (assert.get catch):
+        (assert.):
+        (let.handler.getPrototypeOf):
+        (get let):
+        (let.handler.has):
+
 2016-03-07  Brian Burg  <[email protected]>
 
         Web Inspector: rename generated *EnumConversionHelpers.h to *TypeConversions.h

Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.cpp (197710 => 197711)


--- trunk/Source/_javascript_Core/runtime/ProxyObject.cpp	2016-03-07 23:24:47 UTC (rev 197710)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.cpp	2016-03-07 23:27:44 UTC (rev 197711)
@@ -101,6 +101,9 @@
     ProxyObject* proxyObject = jsCast<ProxyObject*>(proxyObjectAsObject);
     JSObject* target = proxyObject->target();
 
+    if (propertyName == vm.propertyNames->underscoreProto)
+        return JSValue::encode(proxyObject->performGetPrototype(exec));
+
     auto performDefaultGet = [&] {
         return JSValue::encode(target->get(exec, propertyName));
     };
@@ -1021,6 +1024,60 @@
     return jsCast<ProxyObject*>(object)->performSetPrototype(exec, prototype, shouldThrowIfCantSet);
 }
 
+JSValue ProxyObject::performGetPrototype(ExecState* exec)
+{
+    VM& vm = exec->vm();
+
+    JSValue handlerValue = this->handler();
+    if (handlerValue.isNull()) {
+        throwVMTypeError(exec, ASCIILiteral("Proxy 'handler' is null. It should be an Object."));
+        return JSValue();
+    }
+
+    JSObject* handler = jsCast<JSObject*>(handlerValue);
+    CallData callData;
+    CallType callType;
+    JSValue getPrototypeOfMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "getPrototypeOf"), ASCIILiteral("'getPrototypeOf' property of a Proxy's handler should be callable."));
+    if (vm.exception())
+        return JSValue();
+
+    JSObject* target = this->target();
+    if (getPrototypeOfMethod.isUndefined())
+        return target->getPrototype(vm, exec);
+
+    MarkedArgumentBuffer arguments;
+    arguments.append(target);
+    JSValue trapResult = call(exec, getPrototypeOfMethod, callType, callData, handler, arguments);
+    if (vm.exception())
+        return JSValue();
+
+    if (!trapResult.isObject() && !trapResult.isNull()) {
+        throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'getPrototypeOf' trap should either return an object or null."));
+        return JSValue();
+    }
+
+    bool targetIsExtensible = target->isExtensible(exec);
+    if (vm.exception())
+        return JSValue();
+    if (targetIsExtensible)
+        return trapResult;
+
+    JSValue targetPrototype = target->getPrototype(vm, exec);
+    if (vm.exception())
+        return JSValue();
+    if (!sameValue(exec, targetPrototype, trapResult)) {
+        throwVMTypeError(exec, ASCIILiteral("Proxy's 'getPrototypeOf' trap for a non-extensible target should return the same value as the target's prototype."));
+        return JSValue();
+    }
+
+    return trapResult;
+}
+
+JSValue ProxyObject::getPrototype(JSObject* object, ExecState* exec)
+{
+    return jsCast<ProxyObject*>(object)->performGetPrototype(exec);
+}
+
 void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
 {
     ProxyObject* thisObject = jsCast<ProxyObject*>(cell);

Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.h (197710 => 197711)


--- trunk/Source/_javascript_Core/runtime/ProxyObject.h	2016-03-07 23:24:47 UTC (rev 197710)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.h	2016-03-07 23:27:44 UTC (rev 197711)
@@ -65,6 +65,7 @@
     static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
     static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue, bool shouldThrow);
     void putByIndexCommon(ExecState*, JSValue thisValue, unsigned propertyName, JSValue putValue, bool shouldThrow);
+    JSValue performGetPrototype(ExecState*);
 
 private:
     ProxyObject(VM&, Structure*);
@@ -84,6 +85,7 @@
     static NO_RETURN_DUE_TO_CRASH void getStructurePropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
     static NO_RETURN_DUE_TO_CRASH void getGenericPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
     static bool setPrototype(JSObject*, ExecState*, JSValue prototype, bool shouldThrowIfCantSet);
+    static JSValue getPrototype(JSObject*, ExecState*);
     static void visitChildren(JSCell*, SlotVisitor&);
 
     bool getOwnPropertySlotCommon(ExecState*, PropertyName, PropertySlot&);

Modified: trunk/Source/_javascript_Core/tests/es6.yaml (197710 => 197711)


--- trunk/Source/_javascript_Core/tests/es6.yaml	2016-03-07 23:24:47 UTC (rev 197710)
+++ trunk/Source/_javascript_Core/tests/es6.yaml	2016-03-07 23:27:44 UTC (rev 197711)
@@ -927,7 +927,7 @@
 - path: es6/Proxy_getOwnPropertyDescriptor_handler.js
   cmd: runES6 :normal
 - path: es6/Proxy_getPrototypeOf_handler.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_has_handler.js
   cmd: runES6 :normal
 - path: es6/Proxy_has_handler_instances_of_proxies.js

Added: trunk/Source/_javascript_Core/tests/stress/proxy-get-prototype-of.js (0 => 197711)


--- trunk/Source/_javascript_Core/tests/stress/proxy-get-prototype-of.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/proxy-get-prototype-of.js	2016-03-07 23:27:44 UTC (rev 197711)
@@ -0,0 +1,442 @@
+function assert(b) {
+    if (!b)
+        throw new Error("Bad assertion.");
+}
+
+{
+    let target = {};
+    let error = null;
+    let handler = {
+        get getPrototypeOf() {
+            error = new Error;
+            throw error;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let threw = false;
+            try {
+                get();
+            } catch(e) {
+                assert(e === error);
+                threw = true;
+            }
+            assert(threw);
+        }
+    }
+}
+
+{
+    let target = {};
+    let error = null;
+    let handler = {
+        getPrototypeOf: function() {
+            error = new Error;
+            throw error;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let threw = false;
+            try {
+                get();
+            } catch(e) {
+                assert(e === error);
+                threw = true;
+            }
+            assert(threw);
+        }
+    }
+}
+
+{
+    let error = null;
+    let target = new Proxy({}, {
+        isExtensible: function() {
+            error = new Error;
+            throw error;
+        }
+    });
+
+    let handler = {
+        getPrototypeOf: function() {
+            return target.__proto__;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let threw = false;
+            try {
+                get();
+            } catch(e) {
+                assert(e === error);
+                threw = true;
+            }
+            assert(threw);
+        }
+    }
+}
+
+{
+    let target = {};
+    let handler = {
+        getPrototypeOf: 25
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let threw = false;
+            try {
+                get();
+            } catch(e) {
+                assert(e.toString() === "TypeError: 'getPrototypeOf' property of a Proxy's handler should be callable.");
+                threw = true;
+            }
+            assert(threw);
+        }
+    }
+}
+
+{
+    let target = {};
+    let handler = {
+        getPrototypeOf: function() {
+            return 25;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let threw = false;
+            try {
+                get();
+            } catch(e) {
+                assert(e.toString() === "TypeError: Proxy handler's 'getPrototypeOf' trap should either return an object or null.");
+                threw = true;
+            }
+            assert(threw);
+        }
+    }
+}
+
+{
+    let target = {};
+    let handler = {
+        getPrototypeOf: function() {
+            return Symbol();
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let threw = false;
+            try {
+                get();
+            } catch(e) {
+                assert(e.toString() === "TypeError: Proxy handler's 'getPrototypeOf' trap should either return an object or null.");
+                threw = true;
+            }
+            assert(threw);
+        }
+    }
+}
+
+{
+    let target = {};
+    Reflect.preventExtensions(target);
+    let handler = {
+        getPrototypeOf: function() {
+            return null;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let threw = false;
+            try {
+                get();
+            } catch(e) {
+                assert(e.toString() === "TypeError: Proxy's 'getPrototypeOf' trap for a non-extensible target should return the same value as the target's prototype.");
+                threw = true;
+            }
+            assert(threw);
+        }
+    }
+}
+
+{
+    let notProto = {};
+    let target = {};
+    Reflect.preventExtensions(target);
+    let handler = {
+        getPrototypeOf: function() {
+            return notProto;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let threw = false;
+            try {
+                get();
+            } catch(e) {
+                assert(e.toString() === "TypeError: Proxy's 'getPrototypeOf' trap for a non-extensible target should return the same value as the target's prototype.");
+                threw = true;
+            }
+            assert(threw);
+        }
+    }
+}
+
+{
+    let target = {};
+    Reflect.preventExtensions(target);
+    let called = false;
+    let handler = {
+        getPrototypeOf: function() {
+            called = true;
+            return Object.prototype;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let result = get();
+            assert(result === Object.prototype);
+            assert(called);
+            called = false;
+        }
+    }
+}
+
+{
+    let target = {};
+    let theProto = {x: 45};
+    target.__proto__ = theProto;
+    Reflect.preventExtensions(target);
+    let called = false;
+    let handler = {
+        getPrototypeOf: function(theTarget) {
+            assert(theTarget === target);
+            called = true;
+            return Reflect.getPrototypeOf(theTarget);
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            let result = get();
+            assert(result === theProto);
+            assert(called);
+            called = false;
+        }
+    }
+}
+
+{
+    let target = {};
+    let handler = {
+        getPrototypeOf: null
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let proto = Object.prototype;
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            assert(get() === proto);
+        }
+    }
+}
+
+{
+    let target = {};
+    let proto = {};
+    let called = false;
+    let handler = {
+        getPrototypeOf: function(theTarget) {
+            assert(theTarget === target);
+            called = true;
+            return proto;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            assert(get() === proto);
+            assert(called);
+            called = false;
+        }
+    }
+}
+
+{
+    let target = {};
+    let proto = null;
+    let called = false;
+    let handler = {
+        getPrototypeOf: function(theTarget) {
+            assert(theTarget === target);
+            called = true;
+            return proto;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            assert(get() === proto);
+            assert(called);
+            called = false;
+        }
+    }
+}
+
+{
+    let target = {};
+    let proto = null;
+    let called = false;
+    let handler = {
+        getPrototypeOf: function(theTarget) {
+            assert(theTarget === target);
+            called = true;
+            return proto;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let getters = [
+            () => Reflect.getPrototypeOf(proxy),
+            () => Object.getPrototypeOf(proxy),
+            () => proxy.__proto__,
+        ];
+        for (let get of getters) {
+            assert(get() === proto);
+            assert(called);
+            called = false;
+        }
+    }
+}
+
+{
+    let target = {};
+    let proto = null;
+    let called = false;
+    let handler = {
+        getPrototypeOf: function(theTarget) {
+            assert(theTarget === target);
+            called = true;
+            return proto;
+        },
+        has: function() {
+            return false;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let result = "x" in proxy;
+        assert(called);
+        called = false;
+    }
+}
+
+{
+    let target = {};
+    let proto = null;
+    let called = false;
+    let handler = {
+        getPrototypeOf: function(theTarget) {
+            called = true;
+            return proto;
+        },
+        has: function() {
+            return true;
+        }
+    };
+    
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let result = "x" in proxy;
+        assert(!called);
+    }
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to