Bug 1052358 - Support copying over symbol properties in Object.assign. r=jwalden
authorNathan Braswell <miloignis@gmail.com>
Tue, 12 Aug 2014 16:07:47 -0700
changeset 199360 cd27648dc4a75eb80440d2331749ac2eb992a13a
parent 199359 1d2c0c5edb7428b69925ab12ea588eeb0aba8e1a
child 199361 93c38f9959529d7b2d1fff889127ad343f032bce
push id27305
push useremorley@mozilla.com
push dateThu, 14 Aug 2014 07:35:52 +0000
treeherdermozilla-central@8f922378fab0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalden
bugs1052358
milestone34.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 1052358 - Support copying over symbol properties in Object.assign. r=jwalden
js/src/builtin/Object.cpp
js/src/builtin/Object.h
js/src/builtin/Object.js
js/src/tests/ecma_6/Object/assign.js
js/src/vm/SelfHosting.cpp
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -908,19 +908,21 @@ js::IdToStringOrSymbol(JSContext *cx, Ha
     } else if (JSID_IS_ATOM(id)) {
         result.setString(JSID_TO_STRING(id));
     } else {
         result.setSymbol(JSID_TO_SYMBOL(id));
     }
     return true;
 }
 
+namespace js {
+
 /* ES6 draft rev 25 (2014 May 22) 19.1.2.8.1 */
-static bool
-GetOwnPropertyKeys(JSContext *cx, const CallArgs &args, unsigned flags, const char *fnname)
+bool
+GetOwnPropertyKeys(JSContext *cx, const CallArgs &args, unsigned flags)
 {
     // steps 1-2
     RootedObject obj(cx, ToObject(cx, args.get(0)));
     if (!obj)
         return false;
 
     // steps 3-10
     AutoIdVector keys(cx);
@@ -942,32 +944,32 @@ GetOwnPropertyKeys(JSContext *cx, const 
     JSObject *aobj = NewDenseCopiedArray(cx, vals.length(), vals.begin());
     if (!aobj)
         return false;
 
     args.rval().setObject(*aobj);
     return true;
 }
 
+} // namespace js
+
 static bool
 obj_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    return GetOwnPropertyKeys(cx, args, JSITER_OWNONLY | JSITER_HIDDEN,
-                              "Object.getOwnPropertyNames");
+    return GetOwnPropertyKeys(cx, args, JSITER_OWNONLY | JSITER_HIDDEN);
 }
 
 /* ES6 draft rev 25 (2014 May 22) 19.1.2.8 */
 static bool
 obj_getOwnPropertySymbols(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return GetOwnPropertyKeys(cx, args,
-                              JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY,
-                              "Object.getOwnPropertySymbols");
+                              JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS | JSITER_SYMBOLSONLY);
 }
 
 /* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */
 static bool
 obj_defineProperty(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     RootedObject obj(cx);
--- a/js/src/builtin/Object.h
+++ b/js/src/builtin/Object.h
@@ -17,16 +17,19 @@ extern const JSFunctionSpec object_metho
 extern const JSPropertySpec object_properties[];
 extern const JSFunctionSpec object_static_methods[];
 extern const JSFunctionSpec object_static_selfhosted_methods[];
 
 // Object constructor native. Exposed only so the JIT can know its address.
 bool
 obj_construct(JSContext *cx, unsigned argc, JS::Value *vp);
 
+// Exposed so SelfHosting.cpp can use it in the OwnPropertyKeys intrinsic
+bool GetOwnPropertyKeys(JSContext *cx, const CallArgs &args, unsigned flags);
+
 /*
  * Like IdToValue, but convert int jsids to strings. This is used when
  * exposing a jsid to script for Object.getOwnProperty{Names,Symbols}
  * or scriptable proxy traps.
  */
 bool
 IdToStringOrSymbol(JSContext *cx, JS::HandleId id, JS::MutableHandleValue result);
 
--- a/js/src/builtin/Object.js
+++ b/js/src/builtin/Object.js
@@ -14,17 +14,17 @@ function ObjectStaticAssign(target, firs
     // Step 4.
     var i = 1;
     do {
         // Step 5.a-b.
         var nextSource = arguments[i];
         var from = ToObject(nextSource);
 
         // Step 5.c-d.
-        var keysArray = std_Object_getOwnPropertyNames(from);
+        var keysArray = OwnPropertyKeys(from);
 
         // Steps 5.e-f.
         var len = keysArray.length;
 
         // Step 5.h.
         var nextIndex = 0;
 
         // Step 5.i (Modified a bit because we can't catch and store the
--- a/js/src/tests/ecma_6/Object/assign.js
+++ b/js/src/tests/ecma_6/Object/assign.js
@@ -21,16 +21,28 @@ function basicMultipleSources() {
     var b = { bProp : 7 };
     var c = { cProp : 8 };
     Object.assign(a, b, c);
     assertEq(a.bProp, 7);
     assertEq(a.cProp, 8);
 }
 basicMultipleSources();
 
+// Basic functionality works with symbols (Bug 1052358)
+function basicSymbols() {
+    var a = {};
+    var b = { bProp : 7 };
+    var aSymbol = Symbol("aSymbol");
+    b[aSymbol] = 22;
+    Object.assign(a, b);
+    assertEq(a.bProp, 7);
+    assertEq(a[aSymbol], 22);
+}
+basicSymbols();
+
 // Calls ToObject() for target and source
 function testToObject() {
     assertThrowsInstanceOf(() => Object.assign(null, null), TypeError);
     assertThrowsInstanceOf(() => Object.assign(), TypeError);
     assertThrowsInstanceOf(() => Object.assign(null, {}), TypeError);
     assertThrowsInstanceOf(() => Object.assign({}, null), TypeError);
     assertEq(Object.assign(true, {}) instanceof Boolean, true);
     assertEq(Object.assign(1, {}) instanceof Number, true);
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -10,16 +10,17 @@
 #include "jscompartment.h"
 #include "jsfriendapi.h"
 #include "jshashutil.h"
 #include "jsobj.h"
 #include "jswrapper.h"
 #include "selfhosted.out.h"
 
 #include "builtin/Intl.h"
+#include "builtin/Object.h"
 #include "builtin/SelfHostingDefines.h"
 #include "builtin/TypedObject.h"
 #include "gc/Marking.h"
 #include "vm/Compression.h"
 #include "vm/ForkJoin.h"
 #include "vm/Interpreter.h"
 #include "vm/String.h"
 
@@ -107,16 +108,24 @@ js::intrinsic_IsCallable(JSContext *cx, 
 static bool
 intrinsic_IsConstructor(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setBoolean(IsConstructor(args[0]));
     return true;
 }
 
+static bool
+intrinsic_OwnPropertyKeys(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return GetOwnPropertyKeys(cx, args,
+                              JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS);
+}
+
 bool
 js::intrinsic_ThrowError(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     JS_ASSERT(args.length() >= 1);
     uint32_t errorNumber = args[0].toInt32();
 
 #ifdef DEBUG
@@ -771,16 +780,17 @@ intrinsic_RuntimeDefaultLocale(JSContext
 
 static const JSFunctionSpec intrinsic_functions[] = {
     JS_FN("ToObject",                intrinsic_ToObject,                1,0),
     JS_FN("IsObject",                intrinsic_IsObject,                1,0),
     JS_FN("ToInteger",               intrinsic_ToInteger,               1,0),
     JS_FN("ToString",                intrinsic_ToString,                1,0),
     JS_FN("IsCallable",              intrinsic_IsCallable,              1,0),
     JS_FN("IsConstructor",           intrinsic_IsConstructor,           1,0),
+    JS_FN("OwnPropertyKeys",         intrinsic_OwnPropertyKeys,         1,0),
     JS_FN("ThrowError",              intrinsic_ThrowError,              4,0),
     JS_FN("AssertionFailed",         intrinsic_AssertionFailed,         1,0),
     JS_FN("SetScriptHints",          intrinsic_SetScriptHints,          2,0),
     JS_FN("MakeConstructible",       intrinsic_MakeConstructible,       1,0),
     JS_FN("DecompileArg",            intrinsic_DecompileArg,            2,0),
     JS_FN("RuntimeDefaultLocale",    intrinsic_RuntimeDefaultLocale,    0,0),
 
     JS_FN("UnsafePutElements",       intrinsic_UnsafePutElements,       3,0),