Title: [196772] trunk/Source/_javascript_Core
Revision
196772
Author
[email protected]
Date
2016-02-18 12:29:35 -0800 (Thu, 18 Feb 2016)

Log Message

Implement Proxy.[[GetOwnProperty]]
https://bugs.webkit.org/show_bug.cgi?id=154314

Reviewed by Filip Pizlo.

This patch implements Proxy.[[GetOwnProperty]].
It's a straight forward implementation as described
in section 9.5.5 of the specification:
http://www.ecma-international.org/ecma-262/6.0/index.html#sec-proxy-object-internal-methods-and-internal-slots-getownproperty-p

* runtime/FunctionPrototype.cpp:
(JSC::functionProtoFuncBind):
* runtime/JSObject.cpp:
(JSC::validateAndApplyPropertyDescriptor):
(JSC::JSObject::defineOwnNonIndexProperty):
(JSC::JSObject::defineOwnProperty):
(JSC::JSObject::getGenericPropertyNames):
(JSC::JSObject::getMethod):
* runtime/JSObject.h:
(JSC::JSObject::butterflyAddress):
(JSC::makeIdentifier):
* runtime/ProxyObject.cpp:
(JSC::performProxyGet):
(JSC::ProxyObject::performInternalMethodGetOwnProperty):
(JSC::ProxyObject::getOwnPropertySlotCommon):
(JSC::ProxyObject::getOwnPropertySlot):
(JSC::ProxyObject::getOwnPropertySlotByIndex):
(JSC::ProxyObject::visitChildren):
* runtime/ProxyObject.h:
* tests/es6.yaml:
* tests/stress/proxy-basic.js:
(let.handler.get null):
* tests/stress/proxy-get-own-property.js: Added.
(assert):
(throw.new.Error.let.handler.getOwnPropertyDescriptor):
(throw.new.Error):
(let.handler.getOwnPropertyDescriptor):
(i.catch):
(assert.let.handler.getOwnPropertyDescriptor):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (196771 => 196772)


--- trunk/Source/_javascript_Core/ChangeLog	2016-02-18 20:23:51 UTC (rev 196771)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-02-18 20:29:35 UTC (rev 196772)
@@ -1,3 +1,45 @@
+2016-02-18  Saam Barati  <[email protected]>
+
+        Implement Proxy.[[GetOwnProperty]]
+        https://bugs.webkit.org/show_bug.cgi?id=154314
+
+        Reviewed by Filip Pizlo.
+
+        This patch implements Proxy.[[GetOwnProperty]].
+        It's a straight forward implementation as described
+        in section 9.5.5 of the specification:
+        http://www.ecma-international.org/ecma-262/6.0/index.html#sec-proxy-object-internal-methods-and-internal-slots-getownproperty-p
+
+        * runtime/FunctionPrototype.cpp:
+        (JSC::functionProtoFuncBind):
+        * runtime/JSObject.cpp:
+        (JSC::validateAndApplyPropertyDescriptor):
+        (JSC::JSObject::defineOwnNonIndexProperty):
+        (JSC::JSObject::defineOwnProperty):
+        (JSC::JSObject::getGenericPropertyNames):
+        (JSC::JSObject::getMethod):
+        * runtime/JSObject.h:
+        (JSC::JSObject::butterflyAddress):
+        (JSC::makeIdentifier):
+        * runtime/ProxyObject.cpp:
+        (JSC::performProxyGet):
+        (JSC::ProxyObject::performInternalMethodGetOwnProperty):
+        (JSC::ProxyObject::getOwnPropertySlotCommon):
+        (JSC::ProxyObject::getOwnPropertySlot):
+        (JSC::ProxyObject::getOwnPropertySlotByIndex):
+        (JSC::ProxyObject::visitChildren):
+        * runtime/ProxyObject.h:
+        * tests/es6.yaml:
+        * tests/stress/proxy-basic.js:
+        (let.handler.get null):
+        * tests/stress/proxy-get-own-property.js: Added.
+        (assert):
+        (throw.new.Error.let.handler.getOwnPropertyDescriptor):
+        (throw.new.Error):
+        (let.handler.getOwnPropertyDescriptor):
+        (i.catch):
+        (assert.let.handler.getOwnPropertyDescriptor):
+
 2016-02-18  Andreas Kling  <[email protected]>
 
         JSString resolution of substrings should use StringImpl sharing optimization.

Modified: trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp (196771 => 196772)


--- trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp	2016-02-18 20:23:51 UTC (rev 196771)
+++ trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp	2016-02-18 20:29:35 UTC (rev 196772)
@@ -153,13 +153,18 @@
     // If the [[Class]] internal property of Target is "Function", then ...
     // Else set the length own property of F to 0.
     unsigned length = 0;
-    if (targetObject->inherits(JSFunction::info())) {
-        ASSERT(target.get(exec, exec->propertyNames().length).isNumber());
+    if (targetObject->hasOwnProperty(exec, exec->propertyNames().length)) {
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+
         // a. Let L be the length property of Target minus the length of A.
         // b. Set the length own property of F to either 0 or L, whichever is larger.
-        unsigned targetLength = (unsigned)target.get(exec, exec->propertyNames().length).asNumber();
-        if (targetLength > numBoundArgs)
-            length = targetLength - numBoundArgs;
+        JSValue lengthValue = target.get(exec, exec->propertyNames().length);
+        if (lengthValue.isNumber()) {
+            unsigned targetLength = (unsigned)lengthValue.asNumber();
+            if (targetLength > numBoundArgs)
+                length = targetLength - numBoundArgs;
+        }
     }
 
     JSString* name = target.get(exec, exec->propertyNames().name).toString(exec);

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (196771 => 196772)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2016-02-18 20:23:51 UTC (rev 196771)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2016-02-18 20:29:35 UTC (rev 196772)
@@ -2655,34 +2655,38 @@
     VM& m_vm;
 };
 
-bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
+
+// 9.1.6.3 of the spec
+// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-validateandapplypropertydescriptor
+bool validateAndApplyPropertyDescriptor(ExecState* exec, JSObject* object, PropertyName propertyName, bool isExtensible,
+    const PropertyDescriptor& descriptor, bool isCurrentDefined, const PropertyDescriptor& current, bool throwException)
 {
-    // Track on the globaldata that we're in define property.
-    // Currently DefineOwnProperty uses delete to remove properties when they are being replaced
-    // (particularly when changing attributes), however delete won't allow non-configurable (i.e.
-    // DontDelete) properties to be deleted. For now, we can use this flag to make this work.
-    DefineOwnPropertyScope scope(exec);
-    
     // If we have a new property we can just put it on normally
-    PropertyDescriptor current;
-    if (!getOwnPropertyDescriptor(exec, propertyName, current)) {
+    // Step 2.
+    if (!isCurrentDefined) {
         // unless extensions are prevented!
-        if (!isExtensible()) {
+        // Step 2.a
+        if (!isExtensible) {
             if (throwException)
                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to define property on object that is not extensible.")));
             return false;
         }
+        if (!object)
+            return true;
+        // Step 2.c/d
         PropertyDescriptor oldDescriptor;
         oldDescriptor.setValue(jsUndefined());
-        return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
+        // FIXME: spec says to always return true here.
+        return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
     }
-
+    // Step 3.
     if (descriptor.isEmpty())
         return true;
-
+    // Step 4.
     if (current.equalTo(exec, descriptor))
         return true;
 
+    // Step 5.
     // Filter out invalid changes
     if (!current.configurable()) {
         if (descriptor.configurable()) {
@@ -2696,16 +2700,18 @@
             return false;
         }
     }
-
+    
+    // Step 6.
     // A generic descriptor is simply changing the attributes of an existing property
     if (descriptor.isGenericDescriptor()) {
-        if (!current.attributesEqual(descriptor)) {
-            methodTable(exec->vm())->deleteProperty(this, exec, propertyName);
-            return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
+        if (!current.attributesEqual(descriptor) && object) {
+            object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
+            return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
         }
         return true;
     }
-
+    
+    // Step 7.
     // Changing between a normal property or an accessor property
     if (descriptor.isDataDescriptor() != current.isDataDescriptor()) {
         if (!current.configurable()) {
@@ -2713,10 +2719,15 @@
                 exec->vm().throwException(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property.")));
             return false;
         }
-        methodTable(exec->vm())->deleteProperty(this, exec, propertyName);
-        return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
+
+        if (!object)
+            return true;
+
+        object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
+        return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
     }
 
+    // Step 8.
     // Changing the value and attributes of an existing property
     if (descriptor.isDataDescriptor()) {
         if (!current.configurable()) {
@@ -2735,10 +2746,13 @@
         }
         if (current.attributesEqual(descriptor) && !descriptor.value())
             return true;
-        methodTable(exec->vm())->deleteProperty(this, exec, propertyName);
-        return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
+        if (!object)
+            return true;
+        object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
+        return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributesOverridingCurrent(current), current);
     }
 
+    // Step 9.
     // Changing the accessor functions of an existing accessor property
     ASSERT(descriptor.isAccessorDescriptor());
     if (!current.configurable()) {
@@ -2758,7 +2772,11 @@
             return false;
         }
     }
-    JSValue accessor = getDirect(exec->vm(), propertyName);
+
+    // Step 10/11.
+    if (!object)
+        return true;
+    JSValue accessor = object->getDirect(exec->vm(), propertyName);
     if (!accessor)
         return false;
     GetterSetter* getterSetter;
@@ -2779,12 +2797,24 @@
     }
     if (current.attributesEqual(descriptor) && !getterSetterChanged)
         return true;
-    methodTable(exec->vm())->deleteProperty(this, exec, propertyName);
+    object->methodTable(exec->vm())->deleteProperty(object, exec, propertyName);
     unsigned attrs = descriptor.attributesOverridingCurrent(current);
-    putDirectAccessor(exec, propertyName, getterSetter, attrs | Accessor);
+    object->putDirectAccessor(exec, propertyName, getterSetter, attrs | Accessor);
     return true;
 }
 
+bool JSObject::defineOwnNonIndexProperty(ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
+{
+    // Track on the globaldata that we're in define property.
+    // Currently DefineOwnProperty uses delete to remove properties when they are being replaced
+    // (particularly when changing attributes), however delete won't allow non-configurable (i.e.
+    // DontDelete) properties to be deleted. For now, we can use this flag to make this work.
+    DefineOwnPropertyScope scope(exec);
+    PropertyDescriptor current;
+    bool isCurrentDefined = getOwnPropertyDescriptor(exec, propertyName, current);
+    return validateAndApplyPropertyDescriptor(exec, this, propertyName, isExtensible(), descriptor, isCurrentDefined, current, throwException);
+}
+
 bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
 {
     // If it's an array index, then use the indexed property storage.
@@ -2904,4 +2934,29 @@
     }
 }
 
+// Implements GetMethod(O, P) in section 7.3.9 of the spec.
+// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-getmethod
+JSValue JSObject::getMethod(ExecState* exec, CallData& callData, CallType& callType, const Identifier& ident, const String& errorMessage)
+{
+    JSValue method = get(exec, ident);
+    if (exec->hadException())
+        return jsUndefined();
+
+    if (method.isUndefined() || method.isNull())
+        return jsUndefined();
+
+    if (!method.isCell()) {
+        throwVMTypeError(exec, errorMessage);
+        return jsUndefined();
+    }
+
+    callType = method.asCell()->methodTable()->getCallData(method.asCell(), callData);
+    if (callType == CallTypeNone) {
+        throwVMTypeError(exec, errorMessage);
+        return jsUndefined();
+    }
+
+    return method;
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (196771 => 196772)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2016-02-18 20:23:51 UTC (rev 196771)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2016-02-18 20:29:35 UTC (rev 196772)
@@ -717,6 +717,8 @@
         return &m_butterfly;
     }
 
+    JSValue getMethod(ExecState* exec, CallData& callData, CallType& callType, const Identifier& ident, const String& errorMessage);
+
     DECLARE_EXPORT_INFO;
 
 protected:
@@ -1471,6 +1473,9 @@
     return name;
 }
 
+bool validateAndApplyPropertyDescriptor(ExecState*, JSObject*, PropertyName, bool isExtensible,
+    const PropertyDescriptor& descriptor, bool isCurrentDefined, const PropertyDescriptor& current, bool throwException);
+
 // Helper for defining native functions, if you're not using a static hash table.
 // Use this macro from within finishCreation() methods in prototypes. This assumes
 // you've defined variables called exec, globalObject, and vm, and they

Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.cpp (196771 => 196772)


--- trunk/Source/_javascript_Core/runtime/ProxyObject.cpp	2016-02-18 20:23:51 UTC (rev 196771)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.cpp	2016-02-18 20:29:35 UTC (rev 196772)
@@ -27,8 +27,10 @@
 #include "ProxyObject.h"
 
 #include "Error.h"
+#include "IdentifierInlines.h"
 #include "JSCJSValueInlines.h"
 #include "JSCellInlines.h"
+#include "ObjectConstructor.h"
 #include "SlotVisitorInlines.h"
 #include "StructureInlines.h"
 
@@ -90,25 +92,21 @@
         return throwVMTypeError(exec, ASCIILiteral("Proxy 'handler' is null. It should be an Object."));
 
     JSObject* handler = jsCast<JSObject*>(handlerValue);
-    JSObject* target = proxyObject->target();
-    JSValue getHandler = handler->get(exec, vm.propertyNames->get);
+    CallData callData;
+    CallType callType;
+    JSValue getHandler = handler->getMethod(exec, callData, callType, vm.propertyNames->get, ASCIILiteral("'get' property of a Proxy's handler object should be callable."));
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
+    JSObject* target = proxyObject->target();
     if (getHandler.isUndefined())
         return JSValue::encode(target->get(exec, propertyName));
 
-    if (!getHandler.isCell())
-        return throwVMTypeError(exec, ASCIILiteral("'get' property of Proxy's handler should be callable."));
-
-    CallData callData;
-    CallType callType = getHandler.asCell()->methodTable()->getCallData(getHandler.asCell(), callData);
-    if (callType == CallTypeNone)
-        return throwVMTypeError(exec, ASCIILiteral("'get' property of Proxy's handler should be callable."));
-
     MarkedArgumentBuffer arguments;
     arguments.append(target);
     arguments.append(jsString(exec, propertyName.uid()));
+    if (exec->hadException())
+        return JSValue::encode(jsUndefined());
     arguments.append(thisObject);
     JSValue trapResult = call(exec, getHandler, callType, callData, handler, arguments);
     if (exec->hadException())
@@ -125,39 +123,123 @@
         }
     }
 
-    // FIXME: when implementing Proxy.[[GetOwnProperty]] it would be a good test to
-    // have handler be another Proxy where its handler throws on [[GetOwnProperty]]
-    // right here.
-    // https://bugs.webkit.org/show_bug.cgi?id=154314
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
     return JSValue::encode(trapResult);
 }
 
-bool ProxyObject::getOwnPropertySlotCommon(ExecState*, PropertySlot& slot)
+bool ProxyObject::performInternalMethodGetOwnProperty(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
 {
-    if (slot.internalMethodType() == PropertySlot::InternalMethodType::Get) {
+    VM& vm = exec->vm();
+    slot.setValue(this, None, jsUndefined()); // We do this to protect against any bad actors. Nobody should depend on this value.
+    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 getOwnPropertyDescriptorMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "getOwnPropertyDescriptor"), ASCIILiteral("'getOwnPropertyDescriptor' property of a Proxy's handler should be callable."));
+    JSObject* target = this->target();
+    if (getOwnPropertyDescriptorMethod.isUndefined())
+        return target->methodTable(vm)->getOwnPropertySlot(target, exec, propertyName, slot);
+
+    MarkedArgumentBuffer arguments;
+    arguments.append(target);
+    arguments.append(jsString(exec, propertyName.uid()));
+    if (exec->hadException())
+        return false;
+    JSValue trapResult = call(exec, getOwnPropertyDescriptorMethod, callType, callData, handler, arguments);
+    if (exec->hadException())
+        return false;
+
+    if (!trapResult.isUndefined() && !trapResult.isObject()) {
+        throwVMTypeError(exec, ASCIILiteral("result of 'getOwnPropertyDescriptor' call should either be an Object or undefined."));
+        return false;
+    }
+
+    PropertyDescriptor targetPropertyDescriptor;
+    bool isTargetPropertyDescriptorDefined = target->getOwnPropertyDescriptor(exec, propertyName, targetPropertyDescriptor);
+    if (exec->hadException())
+        return false;
+
+    if (trapResult.isUndefined()) {
+        if (!isTargetPropertyDescriptorDefined)
+            return false;
+        if (!targetPropertyDescriptor.configurable()) {
+            throwVMTypeError(exec, ASCIILiteral("When the result of 'getOwnPropertyDescriptor' is undefined the target must be configurable."));
+            return false;
+        }
+        // FIXME: this doesn't work if 'target' is another Proxy. We don't have isExtensible implemented in a way that fits w/ Proxys.
+        // https://bugs.webkit.org/show_bug.cgi?id=154375
+        if (!target->isExtensible()) {
+            // FIXME: Come up with a test for this error. I'm not sure how to because
+            // Object.seal(o) will make all fields [[Configurable]] false.
+            // https://bugs.webkit.org/show_bug.cgi?id=154376
+            throwVMTypeError(exec, ASCIILiteral("When 'getOwnPropertyDescriptor' returns undefined, the 'target' of a Proxy should be extensible."));
+            return false;
+        }
+
+        return false;
+    }
+
+    PropertyDescriptor trapResultAsDescriptor;
+    toPropertyDescriptor(exec, trapResult, trapResultAsDescriptor);
+    if (exec->hadException())
+        return false;
+    bool throwException = false;
+    bool valid = validateAndApplyPropertyDescriptor(exec, nullptr, propertyName, target->isExtensible(),
+        trapResultAsDescriptor, isTargetPropertyDescriptorDefined, targetPropertyDescriptor, throwException);
+    if (!valid) {
+        throwVMTypeError(exec, ASCIILiteral("Result from 'getOwnPropertyDescriptor' fails the IsCompatiblePropertyDescriptor test."));
+        return false;
+    }
+
+    if (!trapResultAsDescriptor.configurable()) {
+        if (!isTargetPropertyDescriptorDefined || targetPropertyDescriptor.configurable()) {
+            throwVMTypeError(exec, ASCIILiteral("Result from 'getOwnPropertyDescriptor' can't be non-configurable when the 'target' doesn't have it as an own property or if it is a configurable own property on 'target'."));
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool ProxyObject::getOwnPropertySlotCommon(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
+{
+    switch (slot.internalMethodType()) {
+    case PropertySlot::InternalMethodType::Get:
         slot.setCustom(this, CustomAccessor, performProxyGet);
         slot.disableCaching();
         return true;
+    case PropertySlot::InternalMethodType::GetOwnProperty:
+        return performInternalMethodGetOwnProperty(exec, propertyName, slot);
+    default:
+        // FIXME: Implement Proxy.[[HasProperty]].
+        // https://bugs.webkit.org/show_bug.cgi?id=154313
+        return false;
     }
 
-    // FIXME: Implement Proxy.[[HasProperty]] and Proxy.[[GetOwnProperty]]
-    // https://bugs.webkit.org/show_bug.cgi?id=154313
-    // https://bugs.webkit.org/show_bug.cgi?id=154314
+    RELEASE_ASSERT_NOT_REACHED();
     return false;
 }
-bool ProxyObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName, PropertySlot& slot)
+
+bool ProxyObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
 {
     ProxyObject* thisObject = jsCast<ProxyObject*>(object);
-    return thisObject->getOwnPropertySlotCommon(exec, slot);
+    return thisObject->getOwnPropertySlotCommon(exec, propertyName, slot);
 }
 
-bool ProxyObject::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned, PropertySlot& slot)
+bool ProxyObject::getOwnPropertySlotByIndex(JSObject* object, ExecState* exec, unsigned propertyName, PropertySlot& slot)
 {
     ProxyObject* thisObject = jsCast<ProxyObject*>(object);
-    return thisObject->getOwnPropertySlotCommon(exec, slot);
+    Identifier ident = Identifier::from(exec, propertyName); 
+    if (exec->hadException())
+        return false;
+    return thisObject->getOwnPropertySlotCommon(exec, ident.impl(), slot);
 }
 
 void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)

Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.h (196771 => 196772)


--- trunk/Source/_javascript_Core/runtime/ProxyObject.h	2016-02-18 20:23:51 UTC (rev 196771)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.h	2016-02-18 20:29:35 UTC (rev 196772)
@@ -63,7 +63,8 @@
     static bool getOwnPropertySlotByIndex(JSObject*, ExecState*, unsigned propertyName, PropertySlot&);
     static void visitChildren(JSCell*, SlotVisitor&);
 
-    bool getOwnPropertySlotCommon(ExecState*, PropertySlot&);
+    bool getOwnPropertySlotCommon(ExecState*, PropertyName, PropertySlot&);
+    bool performInternalMethodGetOwnProperty(ExecState*, PropertyName, PropertySlot&);
 
     WriteBarrier<JSObject> m_target;
     WriteBarrier<Unknown> m_handler;

Modified: trunk/Source/_javascript_Core/tests/es6.yaml (196771 => 196772)


--- trunk/Source/_javascript_Core/tests/es6.yaml	2016-02-18 20:23:51 UTC (rev 196771)
+++ trunk/Source/_javascript_Core/tests/es6.yaml	2016-02-18 20:29:35 UTC (rev 196772)
@@ -1025,7 +1025,7 @@
 - path: es6/Proxy_internal_getOwnPropertyDescriptor_calls_Object.assign.js
   cmd: runES6 :fail
 - path: es6/Proxy_internal_getOwnPropertyDescriptor_calls_Object.prototype.hasOwnProperty.js
-  cmd: runES6 :fail
+  cmd: runES6 :normal
 - path: es6/Proxy_internal_ownKeys_calls_SerializeJSONObject.js
   cmd: runES6 :fail
 - path: es6/Proxy_internal_ownKeys_calls_SetIntegrityLevel.js

Modified: trunk/Source/_javascript_Core/tests/stress/proxy-basic.js (196771 => 196772)


--- trunk/Source/_javascript_Core/tests/stress/proxy-basic.js	2016-02-18 20:23:51 UTC (rev 196771)
+++ trunk/Source/_javascript_Core/tests/stress/proxy-basic.js	2016-02-18 20:29:35 UTC (rev 196772)
@@ -63,9 +63,8 @@
                 proxy["foo"];
         } catch(e) {
             threw = true;
-            assert(e.toString() === "TypeError: 'get' property of Proxy's handler should be callable.");
         }
-        assert(threw);
+        assert(!threw);
     }
 }
 
@@ -82,7 +81,7 @@
                 proxy["foo"];
         } catch(e) {
             threw = true;
-            assert(e.toString() === "TypeError: 'get' property of Proxy's handler should be callable.");
+            assert(e.toString() === "TypeError: 'get' property of a Proxy's handler object should be callable.");
         }
         assert(threw);
     }
@@ -185,3 +184,28 @@
         assert(proxy.x === 40);
     }
 }
+
+{
+    let error = null;
+    let theTarget = new Proxy({}, {
+        getOwnPropertyDescriptor: function(theTarget, propName) {
+            error = new Error("hello!")
+            throw error;
+        }
+    });
+
+    let handler = {
+        get: function(target, propName, proxyArg) {
+            return 30;
+        }
+    };
+
+    let proxy = new Proxy(theTarget, handler);
+    for (let i = 0; i < 500; i++) {
+        try {
+            proxy.x;
+        } catch(e) {
+            assert(e === error);
+        }
+    }
+}

Added: trunk/Source/_javascript_Core/tests/stress/proxy-get-own-property.js (0 => 196772)


--- trunk/Source/_javascript_Core/tests/stress/proxy-get-own-property.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/proxy-get-own-property.js	2016-02-18 20:29:35 UTC (rev 196772)
@@ -0,0 +1,188 @@
+function assert(b) {
+    if (!b)
+        throw new Error("bad assertion.");
+}
+
+{
+    let target = {x: 20};
+    let called = false;
+    let handler = {
+        getOwnPropertyDescriptor: function(theTarget, propName) {
+            called = true;
+            assert(theTarget === target);
+            assert(propName === "x");
+            return undefined;
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        assert(Object.getOwnPropertyDescriptor(proxy, "x") === undefined);
+        assert(called);
+        called = false;
+    }
+}
+
+{
+    let target = {};
+    let handler = {
+        getOwnPropertyDescriptor: function(theTarget, propName) {
+            return 25;
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        try {
+            Object.getOwnPropertyDescriptor(proxy, "x");
+        } catch(e) {
+            assert(e.toString() === "TypeError: result of 'getOwnPropertyDescriptor' call should either be an Object or undefined.");
+            threw = true;
+        }
+        assert(threw);
+    }
+}
+
+{
+    let target = {};
+    Object.defineProperty(target, "x", {
+        enumerable: true,
+        configurable: false
+    });
+    let handler = {
+        getOwnPropertyDescriptor: function(theTarget, propName) {
+            assert(theTarget === target);
+            assert(propName === "x");
+            return undefined;
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        try {
+            Object.getOwnPropertyDescriptor(proxy, "x");
+        } catch(e) {
+            assert(e.toString() === "TypeError: When the result of 'getOwnPropertyDescriptor' is undefined the target must be configurable.");
+            threw = true;
+        }
+        assert(threw);
+    }
+}
+
+{
+    let target = {};
+    Object.defineProperty(target, "x", {
+        enumerable: true,
+        configurable: true
+    });
+    let handler = {
+        getOwnPropertyDescriptor: function(theTarget, propName) {
+            assert(theTarget === target);
+            assert(propName === "x");
+            return {configurable: false};
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        try {
+            Object.getOwnPropertyDescriptor(proxy, "x");
+        } catch(e) {
+            assert(e.toString() === "TypeError: Result from 'getOwnPropertyDescriptor' can't be non-configurable when the 'target' doesn't have it as an own property or if it is a configurable own property on 'target'.");
+            threw = true;
+        }
+        assert(threw);
+    }
+}
+
+{
+    let target = {};
+    Object.defineProperty(target, "x", {
+        enumerable: false,
+        configurable: false
+    });
+    let handler = {
+        getOwnPropertyDescriptor: function(theTarget, propName) {
+            assert(theTarget === target);
+            assert(propName === "x");
+            return {enumerable: true};
+        }
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        try {
+            Object.getOwnPropertyDescriptor(proxy, "x");
+        } catch(e) {
+            assert(e.toString() === "TypeError: Result from 'getOwnPropertyDescriptor' fails the IsCompatiblePropertyDescriptor test.");
+            threw = true;
+        }
+        assert(threw);
+    }
+}
+
+{
+    let target = {};
+    let handler = {
+        getOwnPropertyDescriptor: 45
+    };
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let threw = false;
+        try {
+            Object.getOwnPropertyDescriptor(proxy, "x");
+        } catch(e) {
+            assert(e.toString() === "TypeError: 'getOwnPropertyDescriptor' property of a Proxy's handler should be callable.");
+            threw = true;
+        }
+        assert(threw);
+    }
+}
+
+{
+    let target = {};
+    let handler = {
+        getOwnPropertyDescriptor: null
+    };
+    Object.defineProperty(target, "x", {
+        enumerable: true,
+        configurable: false
+    });
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let pDesc = Object.getOwnPropertyDescriptor(proxy, "x");
+        assert(pDesc.configurable === false);
+        assert(pDesc.enumerable === true);
+    }
+}
+
+{
+    let target = {};
+    let handler = {
+        getOwnPropertyDescriptor: undefined
+    };
+    Object.defineProperty(target, "x", {
+        enumerable: true,
+        configurable: false
+    });
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let pDesc = Object.getOwnPropertyDescriptor(proxy, "x");
+        assert(pDesc.configurable === false);
+        assert(pDesc.enumerable === true);
+    }
+}
+
+{
+    let target = {};
+    let handler = { };
+    Object.defineProperty(target, "x", {
+        enumerable: true,
+        configurable: false
+    });
+    let proxy = new Proxy(target, handler);
+    for (let i = 0; i < 500; i++) {
+        let pDesc = Object.getOwnPropertyDescriptor(proxy, "x");
+        assert(pDesc.configurable === false);
+        assert(pDesc.enumerable === true);
+    }
+}
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to