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