Bug 645416, part 16 - Implement Symbol.prototype.valueOf. r=sfink.
authorJason Orendorff <jorendorff@mozilla.com>
Mon, 23 Jun 2014 10:56:51 -0500
changeset 190283 db9d35e7c4fd4665c7f508239bb4e0103561a866
parent 190282 4ad5047763c05acfd90ce97c0d07ad6380f15efe
child 190284 1870f6bc071b1a8cbc1386c6534aa2b81316df16
push id27004
push user[email protected]
push dateTue, 24 Jun 2014 15:52:34 +0000
treeherdermozilla-central@7b174d47f3cc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs645416
milestone33.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 645416, part 16 - Implement Symbol.prototype.valueOf. r=sfink.
js/src/builtin/SymbolObject.cpp
js/src/builtin/SymbolObject.h
js/src/tests/ecma_6/Symbol/as-base-value.js
js/src/tests/ecma_6/Symbol/constructor.js
js/src/tests/ecma_6/Symbol/surfaces.js
js/src/tests/ecma_6/Symbol/valueOf.js
--- a/js/src/builtin/SymbolObject.cpp
+++ b/js/src/builtin/SymbolObject.cpp
@@ -39,16 +39,17 @@ SymbolObject::create(JSContext *cx, JS::
 }
 
 const JSPropertySpec SymbolObject::properties[] = {
     JS_PS_END
 };
 
 const JSFunctionSpec SymbolObject::methods[] = {
     JS_FN(js_toString_str, toString, 0, 0),
+    JS_FN(js_valueOf_str, valueOf, 0, 0),
     JS_FS_END
 };
 
 const JSFunctionSpec SymbolObject::staticMethods[] = {
     JS_FN("for", for_, 1, 0),
     JS_FS_END
 };
 
@@ -178,13 +179,34 @@ SymbolObject::toString_impl(JSContext *c
 
 bool
 SymbolObject::toString(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsSymbol, toString_impl>(cx, args);
 }
 
+//ES6 rev 24 (2014 Apr 27) 19.4.3.3
+bool
+SymbolObject::valueOf_impl(JSContext *cx, CallArgs args)
+{
+    // Step 3, the error case, is handled by CallNonGenericMethod.
+    HandleValue thisv = args.thisv();
+    MOZ_ASSERT(IsSymbol(thisv));
+    if (thisv.isSymbol())
+        args.rval().set(thisv);
+    else
+        args.rval().setSymbol(thisv.toObject().as<SymbolObject>().unbox());
+    return true;
+}
+
+bool
+SymbolObject::valueOf(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return CallNonGenericMethod<IsSymbol, valueOf_impl>(cx, args);
+}
+
 JSObject *
 js_InitSymbolClass(JSContext *cx, HandleObject obj)
 {
     return SymbolObject::initClass(cx, obj);
 }
--- a/js/src/builtin/SymbolObject.h
+++ b/js/src/builtin/SymbolObject.h
@@ -43,16 +43,18 @@ class SymbolObject : public JSObject
     static bool construct(JSContext *cx, unsigned argc, Value *vp);
 
     // Static methods.
     static bool for_(JSContext *cx, unsigned argc, Value *vp);
 
     // Methods defined on Symbol.prototype.
     static bool toString_impl(JSContext *cx, CallArgs args);
     static bool toString(JSContext *cx, unsigned argc, Value *vp);
+    static bool valueOf_impl(JSContext *cx, CallArgs args);
+    static bool valueOf(JSContext *cx, unsigned argc, Value *vp);
 
     static const JSPropertySpec properties[];
     static const JSFunctionSpec methods[];
     static const JSFunctionSpec staticMethods[];
 };
 
 } /* namespace js */
 
--- a/js/src/tests/ecma_6/Symbol/as-base-value.js
+++ b/js/src/tests/ecma_6/Symbol/as-base-value.js
@@ -17,38 +17,41 @@ var symbols = [
 // Test accessor property, used below.
 var gets, sets;
 Object.defineProperty(Symbol.prototype, "prop", {
     get: function () {
         "use strict";
         gets++;
         assertEq(typeof this, "object");
         assertEq(this instanceof Symbol, true);
+        assertEq(this.valueOf(), sym);
         return "got";
     },
     set: function (v) {
         "use strict";
         sets++;
         assertEq(typeof this, "object");
         assertEq(this instanceof Symbol, true);
+        assertEq(this.valueOf(), sym);
         assertEq(v, "newvalue");
     }
 });
 
 for (var sym of symbols) {
     assertEq(sym.constructor, Symbol);
 
     // method on Object.prototype
     assertEq(sym.hasOwnProperty("constructor"), false);
     assertEq(sym.toLocaleString(), sym.toString()); // once .toString() exists
 
     // custom method monkeypatched onto Symbol.prototype
     Symbol.prototype.nonStrictMethod = function (arg) {
         assertEq(arg, "ok");
         assertEq(this instanceof Symbol, true);
+        assertEq(this.valueOf(), sym);
         return 13;
     };
     assertEq(sym.nonStrictMethod("ok"), 13);
 
     // the same, but strict mode
     Symbol.prototype.strictMethod = function (arg) {
         "use strict";
         assertEq(arg, "ok2");
--- a/js/src/tests/ecma_6/Symbol/constructor.js
+++ b/js/src/tests/ecma_6/Symbol/constructor.js
@@ -21,10 +21,13 @@ var obj = {
         return "ponies";
     }
 };
 assertEq(Symbol(obj).toString(), "Symbol(ponies)");
 assertEq(hits, 1);
 
 assertEq(Object.getPrototypeOf(Symbol.prototype), Object.prototype);
 
+// Symbol.prototype is not itself a Symbol object.
+assertThrowsInstanceOf(() => Symbol.prototype.valueOf(), TypeError);
+
 if (typeof reportCompare === "function")
     reportCompare(0, 0);
--- a/js/src/tests/ecma_6/Symbol/surfaces.js
+++ b/js/src/tests/ecma_6/Symbol/surfaces.js
@@ -18,11 +18,12 @@ assertEq(desc.writable, false);
 assertEq(Symbol.prototype.constructor, Symbol);
 desc = Object.getOwnPropertyDescriptor(Symbol.prototype, "constructor");
 assertEq(desc.configurable, true);
 assertEq(desc.enumerable, false);
 assertEq(desc.writable, true);
 
 assertEq(Symbol.for.length, 1);
 assertEq(Symbol.prototype.toString.length, 0);
+assertEq(Symbol.prototype.valueOf.length, 0);
 
 if (typeof reportCompare === "function")
     reportCompare(0, 0);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Symbol/valueOf.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/ */
+
+var symbols = [
+    Symbol(),
+    Symbol("ok"),
+    Symbol.for("dummies"),
+    Symbol.iterator
+];
+
+for (var sym of symbols) {
+    assertEq(sym.valueOf(), sym);
+    assertEq(Object(sym).valueOf(), sym);
+}
+
+// Any other value throws.
+var nonsymbols = [undefined, null, NaN, {}, Symbol.prototype];
+for (var nonsym of nonsymbols)
+    assertThrowsInstanceOf(() => Symbol.prototype.valueOf.call(nonsym), TypeError);
+
+if (typeof reportCompare === "function")
+    reportCompare(0, 0);