- Revision
- 197418
- Author
- [email protected]
- Date
- 2016-03-01 15:42:33 -0800 (Tue, 01 Mar 2016)
Log Message
[ES6] Implement Proxy.[[PreventExtensions]]
https://bugs.webkit.org/show_bug.cgi?id=154873
Reviewed by Oliver Hunt.
This patch is a direct implementation of Proxy.[[PreventExtensions]] with respect to section 9.5.4
of the ECMAScript 6 spec.
https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-preventextensions
* runtime/ProxyObject.cpp:
(JSC::ProxyObject::deletePropertyByIndex):
(JSC::ProxyObject::performPreventExtensions):
(JSC::ProxyObject::preventExtensions):
(JSC::ProxyObject::visitChildren):
* runtime/ProxyObject.h:
* tests/es6.yaml:
* tests/stress/proxy-prevent-extensions.js: Added.
(assert):
(throw.new.Error.let.handler.get preventExtensions):
(throw.new.Error):
(assert.let.handler.preventExtensions):
(assert.):
(let.handler.preventExtensions):
(assert.Object.isSealed.let.handler.preventExtensions):
(assert.Object.isSealed):
Modified Paths
Added Paths
Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (197417 => 197418)
--- trunk/Source/_javascript_Core/ChangeLog 2016-03-01 23:40:46 UTC (rev 197417)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-03-01 23:42:33 UTC (rev 197418)
@@ -1,3 +1,31 @@
+2016-03-01 Saam barati <[email protected]>
+
+ [ES6] Implement Proxy.[[PreventExtensions]]
+ https://bugs.webkit.org/show_bug.cgi?id=154873
+
+ Reviewed by Oliver Hunt.
+
+ This patch is a direct implementation of Proxy.[[PreventExtensions]] with respect to section 9.5.4
+ of the ECMAScript 6 spec.
+ https://tc39.github.io/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-preventextensions
+
+ * runtime/ProxyObject.cpp:
+ (JSC::ProxyObject::deletePropertyByIndex):
+ (JSC::ProxyObject::performPreventExtensions):
+ (JSC::ProxyObject::preventExtensions):
+ (JSC::ProxyObject::visitChildren):
+ * runtime/ProxyObject.h:
+ * tests/es6.yaml:
+ * tests/stress/proxy-prevent-extensions.js: Added.
+ (assert):
+ (throw.new.Error.let.handler.get preventExtensions):
+ (throw.new.Error):
+ (assert.let.handler.preventExtensions):
+ (assert.):
+ (let.handler.preventExtensions):
+ (assert.Object.isSealed.let.handler.preventExtensions):
+ (assert.Object.isSealed):
+
2016-03-01 Filip Pizlo <[email protected]>
FTL should simplify StringReplace with an empty replacement string
Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.cpp (197417 => 197418)
--- trunk/Source/_javascript_Core/runtime/ProxyObject.cpp 2016-03-01 23:40:46 UTC (rev 197417)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.cpp 2016-03-01 23:42:33 UTC (rev 197418)
@@ -597,6 +597,54 @@
return thisObject->performDelete(exec, ident.impl(), performDefaultDelete);
}
+bool ProxyObject::performPreventExtensions(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 preventExtensionsMethod = handler->getMethod(exec, callData, callType, makeIdentifier(vm, "preventExtensions"), ASCIILiteral("'preventExtensions' property of a Proxy's handler should be callable."));
+ if (exec->hadException())
+ return false;
+ JSObject* target = this->target();
+ if (preventExtensionsMethod.isUndefined())
+ return target->methodTable(vm)->preventExtensions(target, exec);
+
+ MarkedArgumentBuffer arguments;
+ arguments.append(target);
+ JSValue trapResult = call(exec, preventExtensionsMethod, callType, callData, handler, arguments);
+ if (exec->hadException())
+ return false;
+
+ bool trapResultAsBool = trapResult.toBoolean(exec);
+ if (exec->hadException())
+ return false;
+
+ if (trapResultAsBool) {
+ bool targetIsExtensible = target->isExtensibleInline(exec);
+ if (exec->hadException())
+ return false;
+ if (targetIsExtensible) {
+ throwVMTypeError(exec, ASCIILiteral("Proxy's 'preventExtensions' trap returned true even though its target is extensible. It should have returned false."));
+ return false;
+ }
+ }
+
+ return trapResultAsBool;
+}
+
+bool ProxyObject::preventExtensions(JSObject* object, ExecState* exec)
+{
+ return jsCast<ProxyObject*>(object)->performPreventExtensions(exec);
+}
+
void ProxyObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
Modified: trunk/Source/_javascript_Core/runtime/ProxyObject.h (197417 => 197418)
--- trunk/Source/_javascript_Core/runtime/ProxyObject.h 2016-03-01 23:40:46 UTC (rev 197417)
+++ trunk/Source/_javascript_Core/runtime/ProxyObject.h 2016-03-01 23:42:33 UTC (rev 197418)
@@ -69,6 +69,7 @@
static ConstructType getConstructData(JSCell*, ConstructData&);
static bool deleteProperty(JSCell*, ExecState*, PropertyName);
static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
+ static bool preventExtensions(JSObject*, ExecState*);
static void visitChildren(JSCell*, SlotVisitor&);
bool getOwnPropertySlotCommon(ExecState*, PropertyName, PropertySlot&);
@@ -78,6 +79,7 @@
bool performDelete(ExecState*, PropertyName, DefaultDeleteFunction);
template <typename PerformDefaultPutFunction>
void performPut(ExecState*, JSValue putValue, JSValue thisValue, PropertyName, PerformDefaultPutFunction);
+ bool performPreventExtensions(ExecState*);
WriteBarrier<JSObject> m_target;
WriteBarrier<Unknown> m_handler;
Modified: trunk/Source/_javascript_Core/tests/es6.yaml (197417 => 197418)
--- trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-01 23:40:46 UTC (rev 197417)
+++ trunk/Source/_javascript_Core/tests/es6.yaml 2016-03-01 23:42:33 UTC (rev 197418)
@@ -1061,7 +1061,7 @@
- path: es6/Proxy_ownKeys_handler.js
cmd: runES6 :fail
- path: es6/Proxy_preventExtensions_handler.js
- cmd: runES6 :fail
+ cmd: runES6 :normal
- path: es6/Proxy_Proxy.revocable.js
cmd: runES6 :fail
- path: es6/Proxy_set_handler.js
Added: trunk/Source/_javascript_Core/tests/stress/proxy-prevent-extensions.js (0 => 197418)
--- trunk/Source/_javascript_Core/tests/stress/proxy-prevent-extensions.js (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/proxy-prevent-extensions.js 2016-03-01 23:42:33 UTC (rev 197418)
@@ -0,0 +1,280 @@
+function assert(b) {
+ if (!b)
+ throw new Error("Bad assertion.");
+}
+
+{
+ let target = {};
+ let error = null;
+ let handler = {
+ get preventExtensions() {
+ error = new Error;
+ throw error;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.preventExtensions(proxy);
+ } catch(e) {
+ assert(e === error);
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ let error = null;
+ let handler = {
+ preventExtensions: function() {
+ error = new Error;
+ throw error;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.preventExtensions(proxy);
+ } catch(e) {
+ assert(e === error);
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let error = null;
+ let target = new Proxy({}, {
+ preventExtensions: function() {
+ error = new Error;
+ throw error;
+ }
+ });
+ let handler = {
+ preventExtensions: function(theTarget) {
+ return Reflect.preventExtensions(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.preventExtensions(proxy);
+ } catch(e) {
+ assert(e === error);
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ let handler = {
+ preventExtensions: 45
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.preventExtensions(proxy);
+ } catch(e) {
+ assert(e.toString() === "TypeError: 'preventExtensions' property of a Proxy's handler should be callable.");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ let handler = {
+ preventExtensions: null
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Reflect.preventExtensions(proxy);
+ assert(result);
+ assert(!Reflect.isExtensible(target));
+ }
+}
+
+{
+ let target = {};
+ let handler = {
+ preventExtensions: undefined
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Reflect.preventExtensions(proxy);
+ assert(result);
+ assert(!Reflect.isExtensible(target));
+ }
+}
+
+{
+ let target = {};
+ let handler = {
+ preventExtensions: function(theTarget) {
+ return true;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let threw = false;
+ try {
+ Reflect.preventExtensions(proxy);
+ } catch(e) {
+ assert(e.toString() === "TypeError: Proxy's 'preventExtensions' trap returned true even though its target is extensible. It should have returned false.");
+ threw = true;
+ }
+ assert(threw);
+ }
+}
+
+{
+ let target = {};
+ let called = false;
+ let handler = {
+ preventExtensions: function(theTarget) {
+ assert(theTarget === target);
+ called = true;
+ return Reflect.preventExtensions(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Reflect.preventExtensions(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {};
+ let called = false;
+ let handler = {
+ preventExtensions: function(theTarget) {
+ assert(theTarget === target);
+ called = true;
+ return false;
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Reflect.preventExtensions(proxy);
+ assert(!result);
+ assert(called);
+ called = false;
+ }
+}
+
+{
+ let target = {};
+ let called = false;
+ let handler = {
+ preventExtensions: function(theTarget) {
+ assert(theTarget === target);
+ called = true;
+ return Reflect.preventExtensions(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+ for (let i = 0; i < 500; i++) {
+ let result = Reflect.preventExtensions(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+
+ // FIXME: This is true once we implement Proxy.[[IsExtensible]]
+ // https://bugs.webkit.org/show_bug.cgi?id=154872
+ /*
+ assert(!Reflect.isExtensible(proxy));
+ */
+
+ assert(!Reflect.isExtensible(target));
+ assert(!Object.isExtensible(target));
+ assert(Object.isFrozen(target));
+ assert(Object.isSealed(target));
+ }
+}
+
+{
+ for (let i = 0; i < 500; i++) {
+ let target = {};
+ let called = false;
+ let handler = {
+ preventExtensions: function(theTarget) {
+ assert(theTarget === target);
+ called = true;
+ return Reflect.preventExtensions(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+
+ let result = Reflect.preventExtensions(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+
+ // FIXME: This is true once we implement Proxy.[[IsExtensible]]
+ // https://bugs.webkit.org/show_bug.cgi?id=154872
+ /*
+ assert(!Reflect.isExtensible(proxy));
+ */
+
+ assert(!Reflect.isExtensible(target));
+ assert(!Object.isExtensible(target));
+ assert(Object.isFrozen(target));
+ assert(Object.isSealed(target));
+ }
+}
+
+{
+ for (let i = 0; i < 500; i++) {
+ let target = {};
+ let called = false;
+ let handler = {
+ preventExtensions: function(theTarget) {
+ assert(theTarget === target);
+ called = true;
+ return Object.preventExtensions(theTarget);
+ }
+ };
+
+ let proxy = new Proxy(target, handler);
+
+ let result = Reflect.preventExtensions(proxy);
+ assert(result);
+ assert(called);
+ called = false;
+
+ // FIXME: This is true once we implement Proxy.[[IsExtensible]]
+ // https://bugs.webkit.org/show_bug.cgi?id=154872
+ /*
+ assert(!Reflect.isExtensible(proxy));
+ */
+
+ assert(!Reflect.isExtensible(target));
+ assert(!Object.isExtensible(target));
+ assert(Object.isFrozen(target));
+ assert(Object.isSealed(target));
+ }
+}