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);
+ }
+}