Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (197135 => 197136)
--- trunk/Source/_javascript_Core/ChangeLog 2016-02-25 22:44:30 UTC (rev 197135)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-02-25 22:58:23 UTC (rev 197136)
@@ -1,3 +1,52 @@
+2016-02-25 Saam barati <sbar...@apple.com>
+
+ [ES6] Implement Proxy.[[Set]]
+ https://bugs.webkit.org/show_bug.cgi?id=154511
+
+ Reviewed by Filip Pizlo.
+
+ This patch is mostly an implementation of
+ Proxy.[[Set]] with respect to section 9.5.9
+ of the ECMAScript spec.
+ https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-set-p-v-receiver
+
+ This patch also changes JSObject::putInline and JSObject::putByIndex
+ to be aware that a Proxy in the prototype chain will intercept
+ property accesses.
+
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::putInlineSlow):
+ (JSC::JSObject::attemptToInterceptPutByIndexOnHoleForPrototype):
+ * runtime/JSObject.h:
+ * runtime/JSObjectInlines.h:
+ (JSC::JSObject::canPerformFastPutInline):
+ (JSC::JSObject::putInline):
+ * runtime/JSType.h:
+ * runtime/ProxyObject.cpp:
+ (JSC::ProxyObject::getOwnPropertySlotByIndex):
+ (JSC::ProxyObject::performPut):
+ (JSC::ProxyObject::put):
+ (JSC::ProxyObject::putByIndexCommon):
+ (JSC::ProxyObject::putByIndex):
+ (JSC::performProxyCall):
+ (JSC::ProxyObject::getCallData):
+ (JSC::performProxyConstruct):
+ (JSC::ProxyObject::deletePropertyByIndex):
+ (JSC::ProxyObject::visitChildren):
+ * runtime/ProxyObject.h:
+ (JSC::ProxyObject::create):
+ (JSC::ProxyObject::createStructure):
+ (JSC::ProxyObject::target):
+ (JSC::ProxyObject::handler):
+ * tests/es6.yaml:
+ * tests/stress/proxy-set.js: Added.
+ (assert):
+ (throw.new.Error.let.handler.set 45):
+ (throw.new.Error):
+ (let.target.set x):
+ (let.target.get x):
+ (set let):
+
2016-02-25 Benjamin Poulain <bpoul...@apple.com>
[JSC] Remove a useless "Move" in the lowering of Select
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (197135 => 197136)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2016-02-25 22:44:30 UTC (rev 197135)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2016-02-25 22:58:23 UTC (rev 197136)
@@ -422,6 +422,11 @@
}
}
}
+ if (obj->type() == ProxyObjectType) {
+ ProxyObject* proxy = jsCast<ProxyObject*>(obj);
+ proxy->ProxyObject::put(proxy, exec, propertyName, value, slot);
+ return;
+ }
JSValue prototype = obj->prototype();
if (prototype.isNull())
break;
@@ -1916,6 +1921,12 @@
return true;
}
}
+
+ if (current->type() == ProxyObjectType) {
+ ProxyObject* proxy = jsCast<ProxyObject*>(current);
+ proxy->putByIndexCommon(exec, thisValue, i, value, shouldThrow);
+ return true;
+ }
JSValue prototypeValue = current->prototype();
if (prototypeValue.isNull())
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (197135 => 197136)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2016-02-25 22:44:30 UTC (rev 197135)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2016-02-25 22:58:23 UTC (rev 197136)
@@ -855,6 +855,7 @@
template<PutMode>
bool putDirectInternal(VM&, PropertyName, JSValue, unsigned attr, PutPropertySlot&);
+ bool canPerformFastPutInline(ExecState* exec, VM&, PropertyName);
JS_EXPORT_PRIVATE NEVER_INLINE void putInlineSlow(ExecState*, PropertyName, JSValue, PutPropertySlot&);
Modified: trunk/Source/_javascript_Core/runtime/JSObjectInlines.h (197135 => 197136)
--- trunk/Source/_javascript_Core/runtime/JSObjectInlines.h 2016-02-25 22:44:30 UTC (rev 197135)
+++ trunk/Source/_javascript_Core/runtime/JSObjectInlines.h 2016-02-25 22:58:23 UTC (rev 197136)
@@ -30,6 +30,28 @@
namespace JSC {
+ALWAYS_INLINE bool JSObject::canPerformFastPutInline(ExecState* exec, VM& vm, PropertyName propertyName)
+{
+ if (UNLIKELY(propertyName == exec->propertyNames().underscoreProto))
+ return false;
+
+ // Check if there are any setters or getters in the prototype chain
+ JSValue prototype;
+ JSObject* obj = this;
+ while (true) {
+ if (obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || obj->type() == ProxyObjectType)
+ return false;
+
+ prototype = obj->prototype();
+ if (prototype.isNull())
+ return true;
+
+ obj = asObject(prototype);
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
// ECMA 8.6.2.2
ALWAYS_INLINE void JSObject::putInline(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
{
@@ -44,23 +66,14 @@
putByIndex(thisObject, exec, index.value(), value, slot.isStrictMode());
return;
}
-
- // Check if there are any setters or getters in the prototype chain
- JSValue prototype;
- if (propertyName != exec->propertyNames().underscoreProto) {
- for (JSObject* obj = thisObject; !obj->structure(vm)->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
- prototype = obj->prototype();
- if (prototype.isNull()) {
- ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
- if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot)
- && slot.isStrictMode())
- throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
- return;
- }
- }
- }
- thisObject->putInlineSlow(exec, propertyName, value, slot);
+ if (thisObject->canPerformFastPutInline(exec, vm, propertyName)) {
+ ASSERT(!thisObject->structure(vm)->prototypeChainMayInterceptStoreTo(exec->vm(), propertyName));
+ if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot)
+ && slot.isStrictMode())
+ throwTypeError(exec, ASCIILiteral(StrictModeReadonlyPropertyWriteError));
+ } else
+ thisObject->putInlineSlow(exec, propertyName, value, slot);
}
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/JSType.h (197135 => 197136)
--- trunk/Source/_javascript_Core/runtime/JSType.h 2016-02-25 22:44:30 UTC (rev 197135)
+++ trunk/Source/_javascript_Core/runtime/JSType.h 2016-02-25 22:58:23 UTC (rev 197136)
@@ -78,7 +78,9 @@
GlobalObjectType,
ClosureObjectType,
- LastJSCObjectType = ClosureObjectType,
+ ProxyObjectType,
+
+ LastJSCObjectType = ProxyObjectType,
};
COMPILE_ASSERT(sizeof(JSType) == sizeof(uint8_t), sizeof_jstype_is_one_byte);
Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.cpp (197135 => 197136)
--- trunk/Source/_javascript_Core/runtime/ProxyObject.cpp 2016-02-25 22:44:30 UTC (rev 197135)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.cpp 2016-02-25 22:58:23 UTC (rev 197136)
@@ -300,6 +300,88 @@
return thisObject->getOwnPropertySlotCommon(exec, ident.impl(), slot);
}
+template <typename PerformDefaultPutFunction>
+void ProxyObject::performPut(ExecState* exec, JSValue putValue, JSValue thisValue, PropertyName propertyName, PerformDefaultPutFunction performDefaultPutFunction)
+{
+ VM& vm = exec->vm();
+ JSValue handlerValue = this->handler();
+ if (handlerValue.isNull()) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy 'handler' is null. It should be an Object."));
+ return;
+ }
+
+ JSObject* handler = jsCast<JSObject*>(handlerValue);
+ CallData callData;
+ CallType callType;
+ JSValue setMethod = handler->getMethod(exec, callData, callType, vm.propertyNames->set, ASCIILiteral("'set' property of a Proxy's handler should be callable."));
+ if (exec->hadException())
+ return;
+ JSObject* target = this->target();
+ if (setMethod.isUndefined()) {
+ performDefaultPutFunction();
+ return;
+ }
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(target);
+ arguments.append(identifierToSafePublicJSValue(vm, Identifier::fromUid(&vm, propertyName.uid())));
+ arguments.append(putValue);
+ arguments.append(thisValue);
+ JSValue trapResult = call(exec, setMethod, callType, callData, handler, arguments);
+ if (exec->hadException())
+ return;
+ bool trapResultAsBool = trapResult.toBoolean(exec);
+ if (exec->hadException())
+ return;
+ if (!trapResultAsBool)
+ return;
+
+ PropertyDescriptor descriptor;
+ if (target->getOwnPropertyDescriptor(exec, propertyName, descriptor)) {
+ if (descriptor.isDataDescriptor() && !descriptor.configurable() && !descriptor.writable()) {
+ if (!sameValue(exec, descriptor.value(), putValue)) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'set' on a non-configurable and non-writable property on 'target' should either return false or be the same value already on the 'target'."));
+ return;
+ }
+ } else if (descriptor.isAccessorDescriptor() && !descriptor.configurable() && descriptor.setter().isUndefined()) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy handler's 'set' method on a non-configurable accessor property without a setter should return false."));
+ return;
+ }
+ }
+}
+
+void ProxyObject::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+{
+ VM& vm = exec->vm();
+ ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
+ auto performDefaultPut = [&] () {
+ JSObject* target = jsCast<JSObject*>(thisObject->target());
+ target->methodTable(vm)->put(target, exec, propertyName, value, slot);
+ };
+ thisObject->performPut(exec, value, slot.thisValue(), propertyName, performDefaultPut);
+}
+
+void ProxyObject::putByIndexCommon(ExecState* exec, JSValue thisValue, unsigned propertyName, JSValue putValue, bool shouldThrow)
+{
+ VM& vm = exec->vm();
+ Identifier ident = Identifier::from(exec, propertyName);
+ if (exec->hadException())
+ return;
+ auto performDefaultPut = [&] () {
+ JSObject* target = this->target();
+ bool isStrictMode = shouldThrow;
+ PutPropertySlot slot(thisValue, isStrictMode); // We must preserve the "this" target of the putByIndex.
+ target->methodTable(vm)->put(target, exec, ident.impl(), putValue, slot);
+ };
+ performPut(exec, putValue, thisValue, ident.impl(), performDefaultPut);
+}
+
+void ProxyObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
+{
+ ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
+ thisObject->putByIndexCommon(exec, thisObject, propertyName, value, shouldThrow);
+}
+
static EncodedJSValue JSC_HOST_CALL performProxyCall(ExecState* exec)
{
VM& vm = exec->vm();
@@ -345,16 +427,6 @@
return CallTypeHost;
}
-void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
-{
- ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
- ASSERT_GC_OBJECT_INHERITS(thisObject, info());
- Base::visitChildren(thisObject, visitor);
-
- visitor.append(&thisObject->m_target);
- visitor.append(&thisObject->m_handler);
-}
-
static EncodedJSValue JSC_HOST_CALL performProxyConstruct(ExecState* exec)
{
VM& vm = exec->vm();
@@ -476,4 +548,14 @@
return thisObject->performDelete(exec, ident.impl(), defaultDelete);
}
+void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_target);
+ visitor.append(&thisObject->m_handler);
+}
+
} // namespace JSC
Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.h (197135 => 197136)
--- trunk/Source/_javascript_Core/runtime/ProxyObject.h 2016-02-25 22:44:30 UTC (rev 197135)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.h 2016-02-25 22:58:23 UTC (rev 197136)
@@ -35,7 +35,7 @@
public:
typedef JSNonFinalObject Base;
- const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData;
+ const static unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | TypeOfShouldCallGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
static ProxyObject* create(ExecState* exec, Structure* structure, JSValue target, JSValue handler)
{
@@ -47,7 +47,7 @@
static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
{
- return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+ return Structure::create(vm, globalObject, prototype, TypeInfo(ProxyObjectType, StructureFlags), info(), NonArray | MayHaveIndexedAccessors);
}
DECLARE_EXPORT_INFO;
@@ -55,6 +55,10 @@
JSObject* target() { return m_target.get(); }
JSValue handler() { return m_handler.get(); }
+ 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);
+
private:
ProxyObject(VM&, Structure*);
void finishCreation(VM&, ExecState*, JSValue target, JSValue handler);
@@ -72,6 +76,8 @@
bool performHasProperty(ExecState*, PropertyName, PropertySlot&);
template <typename DefaultDeleteFunction>
bool performDelete(ExecState*, PropertyName, DefaultDeleteFunction);
+ template <typename PerformDefaultPutFunction>
+ void performPut(ExecState*, JSValue putValue, JSValue thisValue, PropertyName, PerformDefaultPutFunction);
WriteBarrier<JSObject> m_target;
WriteBarrier<Unknown> m_handler;
Modified: trunk/Source/_javascript_Core/tests/es6.yaml (197135 => 197136)
--- trunk/Source/_javascript_Core/tests/es6.yaml 2016-02-25 22:44:30 UTC (rev 197135)
+++ trunk/Source/_javascript_Core/tests/es6.yaml 2016-02-25 22:58:23 UTC (rev 197136)
@@ -963,7 +963,7 @@
- path: es6/Proxy_internal_get_calls_Array.prototype.toString.js
cmd: runES6 :normal
- path: es6/Proxy_internal_get_calls_Array.prototype_iteration_methods.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_internal_get_calls_ClassDefinitionEvaluation.js
cmd: runES6 :normal
- path: es6/Proxy_internal_get_calls_CreateDynamicFunction.js
@@ -1033,27 +1033,27 @@
- path: es6/Proxy_internal_ownKeys_calls_TestIntegrityLevel.js
cmd: runES6 :fail
- path: es6/Proxy_internal_set_calls_Array.from.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_internal_set_calls_Array.of.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_internal_set_calls_Array.prototype.copyWithin.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_internal_set_calls_Array.prototype.fill.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_internal_set_calls_Array.prototype.pop.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_internal_set_calls_Array.prototype.push.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_internal_set_calls_Array.prototype.reverse.js
cmd: runES6 :fail
- path: es6/Proxy_internal_set_calls_Array.prototype.shift.js
cmd: runES6 :fail
- path: es6/Proxy_internal_set_calls_Array.prototype.splice.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_internal_set_calls_Array.prototype.unshift.js
cmd: runES6 :fail
- path: es6/Proxy_internal_set_calls_Object.assign.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_isExtensible_handler.js
cmd: runES6 :fail
- path: es6/Proxy_JSON.stringify_support.js
@@ -1065,9 +1065,9 @@
- path: es6/Proxy_Proxy.revocable.js
cmd: runES6 :fail
- path: es6/Proxy_set_handler.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_set_handler_instances_of_proxies.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_setPrototypeOf_handler.js
cmd: runES6 :fail
- path: es6/Reflect_Reflect.construct.js
Added: trunk/Source/_javascript_Core/tests/stress/proxy-set.js (0 => 197136)
--- trunk/Source/_javascript_Core/tests/stress/proxy-set.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/proxy-set.js 2016-02-25 22:58:23 UTC (rev 197136)
@@ -0,0 +1,646 @@
+function assert(b) {
+ if (!b)
+ throw new Error("Bad assertion");
+}
+
+{
+ let target = {
+ x: 30
+ };
+
+ let called = false;
+ let handler = {
+ set: 45
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ let threw = false;
+ try {
+ proxy.x = 40;
+ } catch(e) {
+ assert(e.toString() === "TypeError: 'set' property of a Proxy's handler should be callable.");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {
+ x: 30
+ };
+
+ let error = null;
+ let handler = {
+ get set() {
+ error = new Error;
+ throw error;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ let threw = false;
+ try {
+ proxy.x = 40;
+ } catch(e) {
+ assert(e === error);
+ threw = true;
+ }
+ assert(threw);
+ error = null;
+ }
+}
+
+{
+ let target = {
+ x: 30
+ };
+
+ let error = null;
+ let handler = {
+ set: function() {
+ error = new Error;
+ throw error;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ let threw = false;
+ try {
+ proxy.x = 40;
+ } catch(e) {
+ assert(e === error);
+ threw = true;
+ }
+ assert(threw);
+ error = null;
+ }
+}
+
+{
+ let target = { };
+ Object.defineProperty(target, "x", {
+ configurable: false,
+ writable: false,
+ value: 500
+ });
+
+ let called = false;
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(theTarget === target);
+ called = true;
+ theTarget[propName] = value;
+ return false;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ proxy.x = 40;
+ assert(called);
+ assert(proxy.x === 500);
+ assert(target.x === 500);
+ called = false;
+ }
+}
+
+{
+ let target = { };
+ Object.defineProperty(target, "x", {
+ configurable: false,
+ writable: false,
+ value: 500
+ });
+
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(theTarget === target);
+ theTarget[propName] = value;
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ let threw = false;
+ try {
+ proxy.x = 40;
+ } catch(e) {
+ threw = true;
+ assert(e.toString() === "TypeError: Proxy handler's 'set' on a non-configurable and non-writable property on 'target' should either return false or be the same value already on the 'target'.");
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = { };
+ Object.defineProperty(target, "x", {
+ configurable: false,
+ get: function() {
+ return 25;
+ }
+ });
+
+ let called = false;
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(theTarget === target);
+ called = true;
+ theTarget[propName] = value;
+ return false;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ proxy.x = 40;
+ assert(proxy.x === 25);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = { };
+ Object.defineProperty(target, "x", {
+ configurable: false,
+ get: function() {
+ return 25;
+ }
+ });
+
+ let called = false;
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(theTarget === target);
+ called = true;
+ theTarget[propName] = value;
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ let threw = false;
+ try {
+ proxy.x = 40;
+ } catch(e) {
+ threw = true;
+ assert(e.toString() === "TypeError: Proxy handler's 'set' method on a non-configurable accessor property without a setter should return false.");
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = { };
+ Object.defineProperty(target, "x", {
+ configurable: false,
+ writable: true,
+ value: 50
+ });
+
+ let called = false;
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(theTarget === target);
+ called = true;
+ theTarget[propName] = value;
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ proxy.x = i;
+ assert(called);
+ assert(proxy.x === i);
+ assert(target.x === i);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 30
+ };
+
+ let called = false;
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(target === theTarget);
+ assert(reciever === proxy);
+ called = true;
+ theTarget[propName] = value;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ proxy.x = i;
+ assert(called);
+ assert(proxy.x === i);
+ assert(target.x === i);
+ called = false;
+
+ proxy["y"] = i;
+ assert(called);
+ assert(proxy.y === i);
+ assert(target.y === i);
+ called = false;
+ }
+}
+
+{
+ let target = {
+ x: 30
+ };
+
+ let called = false;
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(target === theTarget);
+ assert(reciever === proxy);
+ called = true;
+ theTarget[propName] = value;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ proxy.x = i;
+ assert(called);
+ assert(proxy.x === i);
+ assert(target.x === i);
+ called = false;
+
+ proxy["y"] = i;
+ assert(called);
+ assert(proxy.y === i);
+ assert(target.y === i);
+ called = false;
+ }
+}
+
+{
+ let target = [];
+
+ let called = false;
+ let handler = { };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ proxy[i] = i;
+ assert(proxy[i] === i);
+ assert(target[i] === i);
+ }
+}
+
+{
+ let target = [];
+
+ let called = false;
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(target === theTarget);
+ assert(reciever === proxy);
+ called = true;
+ theTarget[propName] = value;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ proxy[i] = i;
+ assert(proxy[i] === i);
+ assert(target[i] === i);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = [];
+
+ let called = false;
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(target === theTarget);
+ assert(reciever === proxy);
+ called = true;
+ theTarget[propName] = value;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ proxy[i] = i;
+ assert(proxy[i] === i);
+ assert(target[i] === i);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let called = false;
+ let target = {
+ set x(v) {
+ assert(this === target);
+ this._x = v;
+ called = true;
+ },
+ get x() {
+ assert(this === target);
+ return this._x;
+ }
+ };
+
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(target === theTarget);
+ assert(reciever === proxy);
+ theTarget[propName] = value;
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 1000; i++) {
+ proxy.x = i;
+ assert(called);
+ assert(proxy.x === i);
+ assert(target.x === i);
+ assert(proxy._x === i);
+ assert(target._x === i);
+ called = false;
+ }
+}
+
+{
+ let called = false;
+ let target = {};
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(target === theTarget);
+ assert(reciever === obj);
+ theTarget[propName] = value;
+ called = true;
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ let obj = Object.create(proxy, {
+ own: {
+ writable: true,
+ configurable: true,
+ value: null
+ }
+ });
+ for (let i = 0; i < 1000; i++) {
+ obj.own = i;
+ assert(!called);
+ assert(obj.own === i);
+
+ obj.notOwn = i;
+ assert(target.notOwn === i);
+ assert(proxy.notOwn === i);
+ assert(obj.notOwn === i);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {};
+ let handler = { };
+
+ let proxy = new Proxy(target, handler);
+ let obj = Object.create(proxy, {
+ own: {
+ writable: true,
+ configurable: true,
+ value: null
+ }
+ });
+ for (let i = 0; i < 1000; i++) {
+ obj.own = i;
+ assert(obj.own === i);
+ assert(proxy.own === undefined);
+
+ obj.notOwn = i;
+ assert(target.notOwn === i);
+ assert(proxy.notOwn === i);
+ assert(obj.notOwn === i);
+ }
+}
+
+{
+ let called = false;
+ let target = {};
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(target === theTarget);
+ assert(reciever === obj);
+ theTarget[propName] = value;
+ called = true;
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ let obj = Object.create(proxy, {
+ [0]: {
+ writable: true,
+ configurable: true,
+ value: null
+ }
+ });
+ for (let i = 0; i < 1000; i++) {
+ obj[0] = i;
+ assert(!called);
+ assert(obj[0] === i);
+ assert(proxy[0] === undefined);
+
+ obj[1] = i;
+ assert(target[1] === i);
+ assert(proxy[1] === i);
+ assert(obj[1] === i);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {};
+ let handler = { };
+
+ let proxy = new Proxy(target, handler);
+ let obj = Object.create(proxy, {
+ [0]: {
+ writable: true,
+ configurable: true,
+ value: null
+ }
+ });
+ for (let i = 0; i < 1000; i++) {
+ obj[0] = i;
+ assert(obj[0] === i);
+ assert(proxy[0] === undefined);
+
+ obj[1] = i;
+ assert(target[1] === i);
+ assert(proxy[1] === i);
+ assert(obj[1] === i);
+ }
+}
+
+{
+ let called = false;
+ let target = {};
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(target === theTarget);
+ //assert(reciever === obj);
+ theTarget[propName] = value;
+ called = true;
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ let obj = Object.create(proxy, {
+ [0]: {
+ writable: true,
+ configurable: true,
+ value: null
+ }
+ });
+ for (let i = 0; i < 1000; i++) {
+ obj[0] = i;
+ assert(!called);
+ assert(obj[0] === i);
+ assert(proxy[0] === undefined);
+
+ obj[1] = i;
+ assert(target[1] === i);
+ assert(proxy[1] === i);
+ assert(obj[1] === i);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let called = false;
+ let target = [25];
+ let handler = {
+ set: function(theTarget, propName, value, reciever) {
+ assert(target === theTarget);
+ //assert(reciever === obj);
+ theTarget[propName] = value;
+ called = true;
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ let obj = Object.create(proxy, {
+ [0]: {
+ writable: true,
+ configurable: true,
+ value: null
+ }
+ });
+ for (let i = 0; i < 1000; i++) {
+ obj[0] = i;
+ assert(!called);
+ assert(obj[0] === i);
+ assert(proxy[0] === 25);
+
+ obj[1] = i;
+ assert(target[1] === i);
+ assert(proxy[1] === i);
+ assert(obj[1] === i);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let called = false;
+ let ogTarget = {};
+ let target = new Proxy(ogTarget, {
+ set: function(theTarget, propName, value, reciever) {
+ assert(theTarget === ogTarget);
+ assert(reciever === obj);
+ called = true;
+ theTarget[propName] = value;
+ }
+ });
+ let handler = { };
+
+ let proxy = new Proxy(target, handler);
+ let obj = Object.create(proxy, {
+ own: {
+ writable: true,
+ configurable: true,
+ value: null
+ }
+ });
+ for (let i = 0; i < 1000; i++) {
+ obj.own = i;
+ assert(!called);
+ assert(obj.own === i);
+ assert(proxy.own === undefined);
+
+ obj.notOwn = i;
+ assert(target.notOwn === i);
+ assert(proxy.notOwn === i);
+ assert(obj.notOwn === i);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let called = false;
+ let ogTarget = [25];
+ let target = new Proxy(ogTarget, {
+ set: function(theTarget, propName, value, reciever) {
+ assert(theTarget === ogTarget);
+ assert(reciever === obj);
+ called = true;
+ theTarget[propName] = value;
+ }
+ });
+ let handler = { };
+
+ let proxy = new Proxy(target, handler);
+ let obj = Object.create(proxy, {
+ [0]: {
+ writable: true,
+ configurable: true,
+ value: null
+ }
+ });
+ for (let i = 0; i < 1000; i++) {
+ obj[0] = i;
+ assert(!called);
+ assert(obj[0] === i);
+ assert(proxy[0] === 25);
+
+ obj[1] = i;
+ assert(target[1] === i);
+ assert(proxy[1] === i);
+ assert(obj[1] === i);
+ assert(called);
+ called = false;
+ }
+}