Bug 887016 - Part 12: Implement RegExp[@@species] getter. r=evilpie,bholley
authorTooru Fujisawa <arai_a@mac.com>
Sun, 25 Oct 2015 02:19:03 +0900
changeset 292178 cd13c095d3764559d2eb23d380ef5a72a6fbfc06
parent 292177 c5e0ea1a1ed23ef4e9ca8e1fbdf3f8fcef1242c5
child 292179 1a3a6133271c6072773e399eac66426ddcd3bfaf
push id74764
push userarai_a@mac.com
push dateThu, 07 Apr 2016 10:49:15 +0000
treeherdermozilla-inbound@4d0f975a2311 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersevilpie, bholley
bugs887016
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 887016 - Part 12: Implement RegExp[@@species] getter. r=evilpie,bholley
js/src/builtin/RegExp.cpp
js/src/builtin/RegExp.js
js/src/tests/ecma_6/Symbol/species.js
js/xpconnect/tests/chrome/test_xrayToJS.xul
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -742,16 +742,17 @@ const JSPropertySpec js::regexp_static_p
     JS_PSG("$7", static_paren7_getter, JSPROP_PERMANENT | JSPROP_ENUMERATE),
     JS_PSG("$8", static_paren8_getter, JSPROP_PERMANENT | JSPROP_ENUMERATE),
     JS_PSG("$9", static_paren9_getter, JSPROP_PERMANENT | JSPROP_ENUMERATE),
     JS_PSGS("$_", static_input_getter, static_input_setter, JSPROP_PERMANENT),
     JS_PSG("$&", static_lastMatch_getter, JSPROP_PERMANENT),
     JS_PSG("$+", static_lastParen_getter, JSPROP_PERMANENT),
     JS_PSG("$`", static_leftContext_getter, JSPROP_PERMANENT),
     JS_PSG("$'", static_rightContext_getter, JSPROP_PERMANENT),
+    JS_SELF_HOSTED_SYM_GET(species, "RegExpSpecies", 0),
     JS_PS_END
 };
 
 JSObject*
 js::CreateRegExpPrototype(JSContext* cx, JSProtoKey key)
 {
     MOZ_ASSERT(key == JSProto_RegExp);
 
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -597,8 +597,14 @@ function RegExpTest(string) {
         ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, R === null ? "null" : typeof R);
 
     // Steps 3-4.
     var S = ToString(string);
 
     // Steps 5-6.
     return RegExpExec(R, S, true);
 }
+
+// ES 2016 draft Mar 25, 2016 21.2.4.2.
+function RegExpSpecies() {
+    // Step 1.
+    return this;
+}
--- a/js/src/tests/ecma_6/Symbol/species.js
+++ b/js/src/tests/ecma_6/Symbol/species.js
@@ -1,24 +1,24 @@
 var BUGNUMBER = 1131043;
 var summary = "Implement @@species getter for builtin types";
 
 print(BUGNUMBER + ": " + summary);
 
 var TypedArray = Object.getPrototypeOf(Int8Array);
 
-for (var C of [Array, Map, Set,
+for (var C of [Array, Map, Set, RegExp,
                Int8Array, Uint8Array, Uint8ClampedArray,
                Int16Array, Uint16Array, Int32Array, Uint32Array,
                Float32Array, Float64Array,
                ArrayBuffer]) {
   assertEq(C[Symbol.species], C);
 }
 
-for (C of [Array, Map, Set,
+for (C of [Array, Map, Set, RegExp,
            TypedArray,
            ArrayBuffer]) {
   var desc = Object.getOwnPropertyDescriptor(C, Symbol.species);
   assertDeepEq(Object.keys(desc).sort(), ["configurable", "enumerable", "get", "set"]);
   assertEq(desc.set, undefined);
   assertEq(desc.enumerable, false);
   assertEq(desc.configurable, true);
   assertEq(desc.get.apply(null), null);
--- a/js/xpconnect/tests/chrome/test_xrayToJS.xul
+++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul
@@ -221,17 +221,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     ["constructor", "toSource", "toString", "compile", "exec", "test",
      Symbol.match, Symbol.replace, Symbol.search,
      "flags", "global", "ignoreCase", "multiline", "source", "sticky", "unicode",
      "lastIndex"];
   gConstructorProperties['RegExp'] =
     constructorProps(["input", "lastMatch", "lastParen",
                       "leftContext", "rightContext", "$1", "$2", "$3", "$4",
                       "$5", "$6", "$7", "$8", "$9", "$_", "$&", "$+",
-                      "$`", "$'"])
+                      "$`", "$'", Symbol.species])
 
   // Sort an array that may contain symbols as well as strings.
   function sortProperties(arr) {
     function sortKey(prop) {
       return typeof prop + ":" + prop.toString();
     }
     arr.sort((a, b) => sortKey(a) < sortKey(b) ? -1 : +1);
   }
@@ -388,30 +388,32 @@ https://bugzilla.mozilla.org/show_bug.cg
     // We already checked that this is the same as iwin[classname]
 
     let desiredCtorProps =
         Object.getOwnPropertyNames(localCtor).sort();
     is(desiredCtorProps.toSource(),
        gConstructorProperties[classname].filter(id => typeof id === "string").toSource(),
        "A property on the " + classname +
        " constructor has changed! You need a security audit from an XPConnect peer");
-    is(Object.getOwnPropertySymbols(localCtor).map(uneval).sort().toSource(),
+    let desiredCtorSymbols =
+        Object.getOwnPropertySymbols(localCtor).map(uneval).sort()
+    is(desiredCtorSymbols.toSource(),
        gConstructorProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(),
        "A symbol-keyed property on the " + classname +
        " constructor has been changed! You need a security audit from an XPConnect peer");
 
     let ctorProps = filterOut(desiredCtorProps, ctorPropsToSkip);
+    let ctorSymbols = filterOut(desiredCtorSymbols, ctorPropsToSkip.map(uneval));
     let ctorCallables = ctorProps.filter(name => propertyIsGetter(localCtor, name, classname) ||
                                          typeof localCtor[name] == 'function');
     testCtorCallables(ctorCallables, xrayCtor, localCtor);
     is(Object.getOwnPropertyNames(xrayCtor).sort().toSource(),
        ctorProps.toSource(), "getOwnPropertyNames works on Xrayed ctors");
     is(Object.getOwnPropertySymbols(xrayCtor).map(uneval).sort().toSource(),
-       gConstructorProperties[classname].filter(id => typeof id !== "string").map(uneval).sort().toSource(),
-       "getOwnPropertySymbols works on Xrayed ctors");
+       ctorSymbols.toSource(), "getOwnPropertySymbols works on Xrayed ctors");
   }
 
   // We will need arraysEqual and testArrayIterators both in this global scope
   // and in sandboxes, so define them as strings up front.
   var arraysEqualSource = `function arraysEqual(arr1, arr2, reason) {
     is(arr1.length, arr2.length, \`\${reason}; lengths should be equal\`)
     for (var i = 0; i < arr1.length; ++i) {
       if (Array.isArray(arr2[i])) {
@@ -752,20 +754,23 @@ https://bugzilla.mozilla.org/show_bug.cg
     }
   }
 
   function testRegExp() {
     // RegExp statics are very weird, and in particular RegExp has static
     // properties that have to do with the last regexp execution in the global.
     // Xraying those makes no sense, so we just skip constructor properties for
     // RegExp xrays.
+    // RegExp[@@species] is affected by above skip, but we don't fix it until
+    // compelling use-case appears, as supporting RegExp[@@species] while
+    // skipping other static properties makes things complicated.
     let ctorPropsToSkip = ["input", "lastMatch", "lastParen",
                            "leftContext", "rightContext", "$1", "$2", "$3",
                            "$4", "$5", "$6", "$7", "$8", "$9", "$_", "$&",
-                           "$+", "$`", "$'"];
+                           "$+", "$`", "$'", Symbol.species];
     testXray('RegExp', new iwin.RegExp('foo'), new iwin.RegExp(), [],
              ctorPropsToSkip);
 
     // Test the self-hosted |flags| property, toString, and toSource.
     for (var flags of ["", "g", "i", "m", "y", "gimy"]) {
       var re = new iwin.RegExp("foo", flags);
       is(re.flags, re.wrappedJSObject.flags, "Results match");