Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (197419 => 197420)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-01 23:44:50 UTC (rev 197419)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-01 23:51:53 UTC (rev 197420)
@@ -1,5 +1,31 @@
2016-03-01 Saam barati <[email protected]>
+ [ES6] Implement Proxy.[[IsExtensible]]
+ https://bugs.webkit.org/show_bug.cgi?id=154872
+
+ Reviewed by Oliver Hunt.
+
+ This patch is a direct implementation of Proxy.[[IsExtensible]] with respect to section 9.5.3
+ of the ECMAScript 6 spec.
+ https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-isextensible
+
+ * runtime/ProxyObject.cpp:
+ (JSC::ProxyObject::preventExtensions):
+ (JSC::ProxyObject::performIsExtensible):
+ (JSC::ProxyObject::isExtensible):
+ (JSC::ProxyObject::visitChildren):
+ * runtime/ProxyObject.h:
+ * tests/es6.yaml:
+ * tests/stress/proxy-is-extensible.js: Added.
+ (assert):
+ (throw.new.Error.let.handler.get isExtensible):
+ (throw.new.Error):
+ (assert.let.handler.isExtensible):
+ (assert.):
+ (let.handler.isExtensible):
+
+2016-03-01 Saam barati <[email protected]>
+
[ES6] Implement Proxy.[[PreventExtensions]]
https://bugs.webkit.org/show_bug.cgi?id=154873
Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.cpp (197419 => 197420)
--- trunk/Source/_javascript_Core/runtime/ProxyObject.cpp 2016-03-01 23:44:50 UTC (rev 197419)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.cpp 2016-03-01 23:51:53 UTC (rev 197420)
@@ -645,6 +645,60 @@
return jsCast<ProxyObject*>(object)->performPreventExtensions(exec);
}
+bool ProxyObject::performIsExtensible(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 false;
+ }
+
+ JSObject* handler = jsCast<JSObject*>(handlerValue);
+ CallData callData;
+ CallType callType;
+ JSValue isExtensibleMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "isExtensible"), ASCIILiteral("'isExtensible' property of a Proxy's handler should be callable."));
+ if (exec->hadException())
+ return false;
+
+ JSObject* target = this->target();
+ if (isExtensibleMethod.isUndefined())
+ return target->isExtensibleInline(exec);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(target);
+ JSValue trapResult = call(exec, isExtensibleMethod, callType, callData, handler, arguments);
+ if (exec->hadException())
+ return false;
+
+ bool trapResultAsBool = trapResult.toBoolean(exec);
+ if (exec->hadException())
+ return false;
+
+ bool isTargetExtensible = target->isExtensibleInline(exec);
+ if (exec->hadException())
+ return false;
+
+ if (trapResultAsBool != isTargetExtensible) {
+ if (isTargetExtensible) {
+ ASSERT(!trapResultAsBool);
+ throwVMTypeError(exec, ASCIILiteral("Proxy object's 'isExtensible' trap returned false when the target is extensible. It should have returned true."));
+ } else {
+ ASSERT(!isTargetExtensible);
+ ASSERT(trapResultAsBool);
+ throwVMTypeError(exec, ASCIILiteral("Proxy object's 'isExtensible' trap returned true when the target is non-extensible. It should have returned false."));
+ }
+ }
+
+ return trapResultAsBool;
+}
+
+bool ProxyObject::isExtensible(JSObject* object, ExecState* exec)
+{
+ return jsCast<ProxyObject*>(object)->performIsExtensible(exec);
+}
+
void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.h (197419 => 197420)
--- trunk/Source/_javascript_Core/runtime/ProxyObject.h 2016-03-01 23:44:50 UTC (rev 197419)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.h 2016-03-01 23:51:53 UTC (rev 197420)
@@ -70,6 +70,7 @@
static bool deleteProperty(JSCell*, ExecState*, PropertyName);
static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
static bool preventExtensions(JSObject*, ExecState*);
+ static bool isExtensible(JSObject*, ExecState*);
static void visitChildren(JSCell*, SlotVisitor&);
bool getOwnPropertySlotCommon(ExecState*, PropertyName, PropertySlot&);
@@ -80,6 +81,7 @@
template <typename PerformDefaultPutFunction>
void performPut(ExecState*, JSValue putValue, JSValue thisValue, PropertyName, PerformDefaultPutFunction);
bool performPreventExtensions(ExecState*);
+ bool performIsExtensible(ExecState*);
WriteBarrier<JSObject> m_target;
WriteBarrier<Unknown> m_handler;
Modified: trunk/Source/_javascript_Core/tests/es6.yaml (197419 => 197420)
--- trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-01 23:44:50 UTC (rev 197419)
+++ trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-01 23:51:53 UTC (rev 197420)
@@ -1055,7 +1055,7 @@
- path: es6/Proxy_internal_set_calls_Object.assign.js
cmd: runES6 :normal
- path: es6/Proxy_isExtensible_handler.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_JSON.stringify_support.js
cmd: runES6 :fail
- path: es6/Proxy_ownKeys_handler.js
Added: trunk/Source/_javascript_Core/tests/stress/proxy-is-extensible.js (0 => 197420)
--- trunk/Source/_javascript_Core/tests/stress/proxy-is-extensible.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/proxy-is-extensible.js 2016-03-01 23:51:53 UTC (rev 197420)
@@ -0,0 +1,345 @@
+function assert(b) {
+ if (!b)
+ throw new Error("Bad assertion");
+}
+
+{
+ let target = {};
+ let error = null;
+ let handler = {
+ get isExtensible() {
+ error = new Error;
+ throw error;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.isExtensible(proxy);
+ } catch(e) {
+ assert(e === error);
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ let error = null;
+ let handler = {
+ isExtensible: function() {
+ error = new Error;
+ throw error;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.isExtensible(proxy);
+ } 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 = {
+ isExtensible: function(theTarget) {
+ return Reflect.isExtensible(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.isExtensible(proxy);
+ } catch(e) {
+ assert(e === error);
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ let handler = {
+ isExtensible: function(theTarget) {
+ return false;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.isExtensible(proxy);
+ } catch(e) {
+ assert(e.toString() === "TypeError: Proxy object's 'isExtensible' trap returned false when the target is extensible. It should have returned true.");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ Reflect.preventExtensions(target);
+ let handler = {
+ isExtensible: function(theTarget) {
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.isExtensible(proxy);
+ } catch(e) {
+ assert(e.toString() === "TypeError: Proxy object's 'isExtensible' trap returned true when the target is non-extensible. It should have returned false.");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ Object.freeze(target);
+ let handler = {
+ isExtensible: function(theTarget) {
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.isExtensible(proxy);
+ } catch(e) {
+ assert(e.toString() === "TypeError: Proxy object's 'isExtensible' trap returned true when the target is non-extensible. It should have returned false.");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ Object.seal(target);
+ let handler = {
+ isExtensible: function(theTarget) {
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.isExtensible(proxy);
+ } catch(e) {
+ assert(e.toString() === "TypeError: Proxy object's 'isExtensible' trap returned true when the target is non-extensible. It should have returned false.");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ Object.preventExtensions(target);
+ let handler = {
+ isExtensible: function(theTarget) {
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.isExtensible(proxy);
+ } catch(e) {
+ assert(e.toString() === "TypeError: Proxy object's 'isExtensible' trap returned true when the target is non-extensible. It should have returned false.");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ let called = false;
+ let handler = {
+ isExtensible: function(theTarget) {
+ called = true;
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ let result = Reflect.isExtensible(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {};
+ let called = false;
+ Reflect.preventExtensions(target);
+ let handler = {
+ isExtensible: function(theTarget) {
+ assert(theTarget === target);
+ called = true;
+ return Reflect.isExtensible(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ let result = Object.isExtensible(proxy);
+ assert(!result);
+ assert(called);
+ called = false;
+
+ result = Object.isFrozen(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+
+ result = Object.isSealed(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {};
+ let called = false;
+ Object.freeze(target);
+ let handler = {
+ isExtensible: function(theTarget) {
+ assert(theTarget === target);
+ called = true;
+ return Reflect.isExtensible(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ let result = Object.isExtensible(proxy);
+ assert(!result);
+ assert(called);
+ called = false;
+
+ result = Object.isFrozen(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+
+ result = Object.isSealed(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {};
+ let called = false;
+ Object.seal(target);
+ let handler = {
+ isExtensible: function(theTarget) {
+ assert(theTarget === target);
+ called = true;
+ return Reflect.isExtensible(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ let result = Object.isExtensible(proxy);
+ assert(!result);
+ assert(called);
+ called = false;
+
+ result = Object.isFrozen(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+
+ result = Object.isSealed(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+ }
+}
+
+// FIXME: https://bugs.webkit.org/show_bug.cgi?id=154650
+// needs to land for this test to pass because it depends on Proxy.[[OwnPropertyKeys]].
+/*
+{
+ let target = {};
+ Object.defineProperty(target, "x", {
+ writable: true,
+ configurable: true,
+ value: 45,
+ enumerable: true
+ });
+ let called = false;
+ Reflect.preventExtensions(target);
+ let handler = {
+ isExtensible: function(theTarget) {
+ assert(theTarget === target);
+ called = true;
+ return Reflect.isExtensible(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ let result = Object.isExtensible(proxy);
+ assert(!result);
+ assert(called);
+ called = false;
+
+ result = Object.isFrozen(proxy);
+ assert(!result);
+ assert(called);
+ called = false;
+
+ result = Object.isSealed(proxy);
+ assert(!result);
+ assert(called);
+ called = false;
+ }
+}
+*/
+