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 288423 16b05a0fb83aa8a444d6afe0942291627c500960
parent 288422 bd22586cac8283289b3440bfe74d7ef79e1ef2bf
child 288424 7b19afd04625747ba9918b8f7a0bab85d985435b
push id30079
push userryanvm@gmail.com
push dateSat, 12 Mar 2016 20:24:19 +0000
treeherdermozilla-central@d1d47ba19ce9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1253016
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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)