Bug 1253016 - Implement and test the new spec for legacy functions. r=till
authorTom Schuster <evilpies@gmail.com>
Sat, 12 Mar 2016 15:02:12 +0100
changeset 339765 16b05a0fb83aa8a444d6afe0942291627c500960
parent 339764 bd22586cac8283289b3440bfe74d7ef79e1ef2bf
child 339766 7b19afd04625747ba9918b8f7a0bab85d985435b
push id12803
push userjbeich@FreeBSD.org
push dateSun, 13 Mar 2016 09:48:54 +0000
reviewerstill
bugs1253016
milestone48.0a1
Bug 1253016 - Implement and test the new spec for legacy functions. r=till
js/src/builtin/Object.js
js/src/tests/ecma_7/Object/defineGetter-defineSetter.js
js/src/vm/SelfHosting.cpp
--- a/js/src/builtin/Object.js
+++ b/js/src/builtin/Object.js
@@ -55,83 +55,127 @@ function ObjectIsExtensible(obj) {
 function Object_toLocaleString() {
     // Step 1.
     var O = this;
 
     // Step 2.
     return callContentFunction(O.toString, O);
 }
 
+// ES7 draft (2016 March 8) B.2.2.3
 function ObjectDefineSetter(name, setter) {
     if (this === null || this === undefined)
         AddContentTelemetry(TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED, 1);
     else
         AddContentTelemetry(TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED, 0);
 
+    // Step 1.
     var object = ToObject(this);
 
+    // Step 2.
     if (!IsCallable(setter))
         ThrowTypeError(JSMSG_BAD_GETTER_OR_SETTER, "setter");
 
-    var key = ToPropertyKey(name);
-
+    // Step 3.
     var desc = {
         __proto__: null,
         enumerable: true,
         configurable: true,
         set: setter
     };
 
+    // Step 4.
+    var key = ToPropertyKey(name);
+
+    // Step 5.
     std_Object_defineProperty(object, key, desc);
+
+    // Step 6. (implicit)
 }
 
+// ES7 draft (2016 March 8) B.2.2.2
 function ObjectDefineGetter(name, getter) {
     if (this === null || this === undefined)
         AddContentTelemetry(TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED, 1);
     else
         AddContentTelemetry(TELEMETRY_DEFINE_GETTER_SETTER_THIS_NULL_UNDEFINED, 0);
 
+    // Step 1.
     var object = ToObject(this);
 
+    // Step 2.
     if (!IsCallable(getter))
         ThrowTypeError(JSMSG_BAD_GETTER_OR_SETTER, "getter");
 
-    var key = ToPropertyKey(name);
-
+    // Step 3.
     var desc = {
         __proto__: null,
         enumerable: true,
         configurable: true,
         get: getter
     };
 
+    // Step 4.
+    var key = ToPropertyKey(name);
+
+    // Step 5.
     std_Object_defineProperty(object, key, desc);
+
+    // Step 6. (implicit)
 }
 
+// ES7 draft (2016 March 8) B.2.2.5
 function ObjectLookupSetter(name) {
-    var key = ToPropertyKey(name);
+    // Step 1.
     var object = ToObject(this);
 
+    // Step 2.
+    var key = ToPropertyKey(name)
+
     do {
+        // Step 3.a.
         var desc = std_Object_getOwnPropertyDescriptor(object, key);
+
+        // Step 3.b.
         if (desc) {
+            // Step.b.i.
             if (callFunction(std_Object_hasOwnProperty, desc, "set"))
                 return desc.set;
+
+            // Step.b.ii.
             return undefined;
         }
+
+        // Step 3.c.
         object = std_Reflect_getPrototypeOf(object);
     } while (object !== null);
+
+    // Step 3.d. (implicit)
 }
 
+// ES7 draft (2016 March 8) B.2.2.4
 function ObjectLookupGetter(name) {
-    var key = ToPropertyKey(name);
+    // Step 1.
     var object = ToObject(this);
 
+    // Step 2.
+    var key = ToPropertyKey(name)
+
     do {
+        // Step 3.a.
         var desc = std_Object_getOwnPropertyDescriptor(object, key);
+
+        // Step 3.b.
         if (desc) {
+            // Step.b.i.
             if (callFunction(std_Object_hasOwnProperty, desc, "get"))
                 return desc.get;
+
+            // Step.b.ii.
             return undefined;
         }
+
+        // Step 3.c.
         object = std_Reflect_getPrototypeOf(object);
     } while (object !== null);
+
+    // Step 3.d. (implicit)
 }
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/Object/defineGetter-defineSetter.js
@@ -0,0 +1,92 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+let count = 0;
+let verifyProxy = new Proxy({}, {
+    defineProperty(target, property, descriptor) {
+        assertEq(property, "x");
+
+        assertEq(descriptor.enumerable, true);
+        assertEq(descriptor.configurable, true);
+
+        if ("set" in descriptor)
+            assertEq(descriptor.set, Object.prototype.__defineSetter__);
+        else
+            assertEq(descriptor.get, Object.prototype.__defineGetter__);
+
+        assertEq(Object.keys(descriptor).length, 3);
+
+        count++;
+        return true;
+    }
+});
+
+for (let define of [Object.prototype.__defineGetter__, Object.prototype.__defineSetter__]) {
+    // null/undefined |this| value
+    for (let thisv of [undefined, null])
+        assertThrowsInstanceOf(() => define.call(thisv, "x", define), TypeError);
+
+    // non-callable getter/setter
+    let nonCallable = [{}, [], new Proxy({}, {})];
+    for (let value of nonCallable)
+        assertThrowsInstanceOf(() => define.call(verifyProxy, "x", value), TypeError);
+
+    // ToPropertyKey
+    let key = {
+        [Symbol.toPrimitive](hint) {
+            assertEq(hint, "string");
+            // Throws, because non-primitive is returned
+            return {};
+        },
+        valueOf() { throw "wrongly invoked"; },
+        toString() { throw "wrongly invoked"; }
+    };
+    assertThrowsInstanceOf(() => define.call(verifyProxy, key, define), TypeError);
+
+    key = {
+        [Symbol.toPrimitive](hint) {
+            assertEq(hint, "string");
+            return "x";
+        },
+        valueOf() { throw "wrongly invoked"; },
+        toString() { throw "wrongly invoked"; }
+    }
+    define.call(verifyProxy, key, define);
+
+    key = {
+        [Symbol.toPrimitive]: undefined,
+
+        valueOf() { throw "wrongly invoked"; },
+        toString() { return "x"; }
+    }
+    define.call(verifyProxy, key, define);
+
+    // Bog standard call
+    define.call(verifyProxy, "x", define);
+
+    let obj = {};
+    define.call(obj, "x", define);
+    let descriptor = Object.getOwnPropertyDescriptor(obj, "x");
+
+    assertEq(descriptor.enumerable, true);
+    assertEq(descriptor.configurable, true);
+
+    if (define == Object.prototype.__defineSetter__) {
+        assertEq(descriptor.get, undefined);
+        assertEq(descriptor.set, define);
+    } else {
+        assertEq(descriptor.get, define);
+        assertEq(descriptor.set, undefined);
+    }
+
+    assertEq(Object.keys(descriptor).length, 4);
+
+
+}
+
+// Number of calls that should succeed
+assertEq(count, 6);
+
+reportCompare(0, 0);
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -37,16 +37,17 @@
 #include "js/Date.h"
 #include "vm/Compression.h"
 #include "vm/GeneratorObject.h"
 #include "vm/Interpreter.h"
 #include "vm/String.h"
 #include "vm/TypedArrayCommon.h"
 
 #include "jsfuninlines.h"
+#include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/BooleanObject-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/StringObject-inl.h"
 
 using namespace js;
@@ -109,17 +110,17 @@ intrinsic_ToString(JSContext* cx, unsign
     return true;
 }
 
 static bool
 intrinsic_ToPropertyKey(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedId id(cx);
-    if (!ValueToId<CanGC>(cx, args[0], &id))
+    if (!ToPropertyKey(cx, args[0], &id))
         return false;
 
     args.rval().set(IdToValue(id));
     return true;
 }
 
 static bool
 intrinsic_IsCallable(JSContext* cx, unsigned argc, Value* vp)