summaryrefslogtreecommitdiffstats
path: root/js/src/tests/non262/JSON
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/non262/JSON')
-rw-r--r--js/src/tests/non262/JSON/browser.js0
-rw-r--r--js/src/tests/non262/JSON/cyclic-stringify-unrelated.js39
-rw-r--r--js/src/tests/non262/JSON/cyclic-stringify.js100
-rw-r--r--js/src/tests/non262/JSON/parse-arguments.js30
-rw-r--r--js/src/tests/non262/JSON/parse-array-gc.js34
-rw-r--r--js/src/tests/non262/JSON/parse-crockford-01.js121
-rw-r--r--js/src/tests/non262/JSON/parse-mega-huge-array.js28
-rw-r--r--js/src/tests/non262/JSON/parse-number-syntax.js32
-rw-r--r--js/src/tests/non262/JSON/parse-octal-syntax-error.js8
-rw-r--r--js/src/tests/non262/JSON/parse-primitives.js62
-rw-r--r--js/src/tests/non262/JSON/parse-reviver-array-delete.js89
-rw-r--r--js/src/tests/non262/JSON/parse-reviver.js45
-rw-r--r--js/src/tests/non262/JSON/parse-syntax-errors-01.js13
-rw-r--r--js/src/tests/non262/JSON/parse-syntax-errors-02.js43
-rw-r--r--js/src/tests/non262/JSON/parse-syntax-errors-03.js55
-rw-r--r--js/src/tests/non262/JSON/parse.js175
-rw-r--r--js/src/tests/non262/JSON/regress-458959.js29
-rw-r--r--js/src/tests/non262/JSON/regress-459293.js25
-rw-r--r--js/src/tests/non262/JSON/shell.js110
-rw-r--r--js/src/tests/non262/JSON/small-codepoints.js16
-rw-r--r--js/src/tests/non262/JSON/stringify-boxed-primitives.js127
-rw-r--r--js/src/tests/non262/JSON/stringify-call-replacer-once.js34
-rw-r--r--js/src/tests/non262/JSON/stringify-call-toJSON-once.js32
-rw-r--r--js/src/tests/non262/JSON/stringify-dropping-elements.js20
-rw-r--r--js/src/tests/non262/JSON/stringify-gap.js61
-rw-r--r--js/src/tests/non262/JSON/stringify-ignore-noncallable-toJSON.js28
-rw-r--r--js/src/tests/non262/JSON/stringify-large-replacer-array.js26
-rw-r--r--js/src/tests/non262/JSON/stringify-missing-arguments.js22
-rw-r--r--js/src/tests/non262/JSON/stringify-nonarray-noncallable-replacer.js41
-rw-r--r--js/src/tests/non262/JSON/stringify-primitives.js39
-rw-r--r--js/src/tests/non262/JSON/stringify-replacer-array-boxed-elements.js60
-rw-r--r--js/src/tests/non262/JSON/stringify-replacer-array-duplicated-element.js69
-rw-r--r--js/src/tests/non262/JSON/stringify-replacer-array-edgecase-jsid-elements.js77
-rw-r--r--js/src/tests/non262/JSON/stringify-replacer-array-hijinks.js59
-rw-r--r--js/src/tests/non262/JSON/stringify-replacer-array-skipped-element.js62
-rw-r--r--js/src/tests/non262/JSON/stringify-replacer-array-trailing-holes.js49
-rw-r--r--js/src/tests/non262/JSON/stringify-replacer-with-array-indexes.js56
-rw-r--r--js/src/tests/non262/JSON/stringify-replacer.js155
-rw-r--r--js/src/tests/non262/JSON/stringify-special-escapes.js277
-rw-r--r--js/src/tests/non262/JSON/stringify-toJSON-arguments.js34
-rw-r--r--js/src/tests/non262/JSON/stringify.js87
-rw-r--r--js/src/tests/non262/JSON/trailing-comma.js32
42 files changed, 2501 insertions, 0 deletions
diff --git a/js/src/tests/non262/JSON/browser.js b/js/src/tests/non262/JSON/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/non262/JSON/browser.js
diff --git a/js/src/tests/non262/JSON/cyclic-stringify-unrelated.js b/js/src/tests/non262/JSON/cyclic-stringify-unrelated.js
new file mode 100644
index 0000000000..127c2ca600
--- /dev/null
+++ b/js/src/tests/non262/JSON/cyclic-stringify-unrelated.js
@@ -0,0 +1,39 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 1197097;
+var summary = "JSON.stringify shouldn't use context-wide cycle detection";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var arr;
+
+// Nested yet separate JSON.stringify is okay.
+arr = [{}];
+assertEq(JSON.stringify(arr, function(k, v) {
+ assertEq(JSON.stringify(arr), "[{}]");
+ return v;
+}), "[{}]");
+
+// SpiderMonkey censors cycles in array-joining. This mechanism must not
+// interfere with the cycle detection in JSON.stringify.
+arr = [{
+ toString: function() {
+ var s = JSON.stringify(arr);
+ assertEq(s, "[{}]");
+ return s;
+ }
+}];
+assertEq(arr.join(), "[{}]");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/cyclic-stringify.js b/js/src/tests/non262/JSON/cyclic-stringify.js
new file mode 100644
index 0000000000..5eb6273a97
--- /dev/null
+++ b/js/src/tests/non262/JSON/cyclic-stringify.js
@@ -0,0 +1,100 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 578273;
+var summary =
+ "ES5: Properly detect cycles in JSON.stringify (throw TypeError, check for " +
+ "cycles rather than imprecisely rely on recursion limits)";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+// objects
+
+var count = 0;
+var desc =
+ {
+ get: function() { count++; return obj; },
+ enumerable: true,
+ configurable: true
+ };
+var obj = Object.defineProperty({ p1: 0 }, "p2", desc);
+
+try
+{
+ var str = JSON.stringify(obj);
+ assertEq(false, true, "should have thrown, got " + str);
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true,
+ "wrong error type: " + e.constructor.name);
+ assertEq(count, 1,
+ "cyclic data structures not detected immediately");
+}
+
+count = 0;
+var obj2 = Object.defineProperty({}, "obj", desc);
+try
+{
+ var str = JSON.stringify(obj2);
+ assertEq(false, true, "should have thrown, got " + str);
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true,
+ "wrong error type: " + e.constructor.name);
+ assertEq(count, 2,
+ "cyclic data structures not detected immediately");
+}
+
+
+// arrays
+
+var count = 0;
+var desc =
+ {
+ get: function() { count++; return arr; },
+ enumerable: true,
+ configurable: true
+ };
+var arr = Object.defineProperty([], "0", desc);
+
+try
+{
+ var str = JSON.stringify(arr);
+ assertEq(false, true, "should have thrown, got " + str);
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true,
+ "wrong error type: " + e.constructor.name);
+ assertEq(count, 1,
+ "cyclic data structures not detected immediately");
+}
+
+count = 0;
+var arr2 = Object.defineProperty([], "0", desc);
+try
+{
+ var str = JSON.stringify(arr2);
+ assertEq(false, true, "should have thrown, got " + str);
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true,
+ "wrong error type: " + e.constructor.name);
+ assertEq(count, 2,
+ "cyclic data structures not detected immediately");
+}
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-arguments.js b/js/src/tests/non262/JSON/parse-arguments.js
new file mode 100644
index 0000000000..d7ed6d73bd
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-arguments.js
@@ -0,0 +1,30 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'parse-arguments.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 653847;
+var summary = "JSON.parse handling of omitted arguments";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+try
+{
+ var r = JSON.parse();
+ throw new Error("didn't throw, returned " + r);
+}
+catch (e)
+{
+ assertEq(e instanceof SyntaxError, true, "expected syntax error, got: " + e);
+}
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-array-gc.js b/js/src/tests/non262/JSON/parse-array-gc.js
new file mode 100644
index 0000000000..f617ea66dc
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-array-gc.js
@@ -0,0 +1,34 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = "parse-array-gc.js";
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 852563;
+var summary =
+ "IdValuePair::value should be initialized to avoid GC sequence-point issues";
+
+print(BUGNUMBER + ": " + summary);
+
+print("Note: You must run this test under valgrind to be certain it passes");
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var x;
+
+if (typeof gczeal === "function")
+ gczeal(2, 1);
+x = JSON.parse('{"foo":[]}');
+Object.getPrototypeOf(x.foo) == Array.prototype;
+x = JSON.parse('{"foo":[], "bar":[]}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+if (typeof gczeal === "function")
+ gczeal(0);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-crockford-01.js b/js/src/tests/non262/JSON/parse-crockford-01.js
new file mode 100644
index 0000000000..5be9e90edb
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-crockford-01.js
@@ -0,0 +1,121 @@
+var str =
+ '[\n' +
+ ' "JSON Test Pattern pass1",\n' +
+ ' {"object with 1 member":["array with 1 element"]},\n' +
+ ' {},\n' +
+ ' [],\n' +
+ ' -42,\n' +
+ ' true,\n' +
+ ' false,\n' +
+ ' null,\n' +
+ ' {\n' +
+ ' "integer": 1234567890,\n' +
+ ' "real": -9876.543210,\n' +
+ ' "e": 0.123456789e-12,\n' +
+ ' "E": 1.234567890E+34,\n' +
+ ' "": 23456789012E66,\n' +
+ ' "zero": 0,\n' +
+ ' "one": 1,\n' +
+ ' "space": " ",\n' +
+ ' "quote": "\\"",\n' +
+ ' "backslash": "\\\\",\n' +
+ ' "controls": "\\b\\f\\n\\r\\t",\n' +
+ ' "slash": "/ & \\/",\n' +
+ ' "alpha": "abcdefghijklmnopqrstuvwyz",\n' +
+ ' "ALPHA": "ABCDEFGHIJKLMNOPQRSTUVWYZ",\n' +
+ ' "digit": "0123456789",\n' +
+ ' "0123456789": "digit",\n' +
+ ' "special": "`1~!@#$%^&*()_+-={\':[,]}|;.</>?",\n' +
+ ' "hex": "\\u0123\\u4567\\u89AB\\uCDEF\\uabcd\\uef4A",\n' +
+ ' "true": true,\n' +
+ ' "false": false,\n' +
+ ' "null": null,\n' +
+ ' "array":[ ],\n' +
+ ' "object":{ },\n' +
+ ' "address": "50 St. James Street",\n' +
+ ' "url": "http://www.JSON.org/",\n' +
+ ' "comment": "// /* <!-- --",\n' +
+ ' "# -- --> */": " ",\n' +
+ ' " s p a c e d " :[1,2 , 3\n' +
+ '\n' +
+ ',\n' +
+ '\n' +
+ '4 , 5 , 6 ,7 ],"compact":[1,2,3,4,5,6,7],\n' +
+ ' "jsontext": "{\\"object with 1 member\\":[\\"array with 1 element\\"]}",\n' +
+ ' "quotes": "&#34; \\u0022 %22 0x22 034 &#x22;",\n' +
+ ' "\\/\\\\\\"\\uCAFE\\uBABE\\uAB98\\uFCDE\\ubcda\\uef4A\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"\n' +
+ ': "A key can be any string"\n' +
+ ' },\n' +
+ ' 0.5 ,98.6\n' +
+ ',\n' +
+ '99.44\n' +
+ ',\n' +
+ '\n' +
+ '1066,\n' +
+ '1e1,\n' +
+ '0.1e1,\n' +
+ '1e-1,\n' +
+ '1e00,2e+00,2e-00\n' +
+ ',"rosebud"]\n';
+
+var x = JSON.parse(str);
+
+assertEq(x[0], "JSON Test Pattern pass1");
+assertEq(x[1]["object with 1 member"][0], "array with 1 element");
+assertEq(x[2].constructor, Object);
+assertEq(x[3].constructor, Array);
+assertEq(x[4], -42);
+assertEq(x[5], true);
+assertEq(x[6], false);
+assertEq(x[7], null);
+assertEq(x[8].constructor, Object);
+assertEq(x[8]["integer"], 1234567890);
+assertEq(x[8]["real"], -9876.543210);
+assertEq(x[8]["e"], 0.123456789e-12);
+assertEq(x[8]["E"], 1.234567890E+34);
+assertEq(x[8][""], 23456789012E66);
+assertEq(x[8]["zero"], 0);
+assertEq(x[8]["one"], 1);
+assertEq(x[8]["space"], " ");
+assertEq(x[8]["quote"], "\"");
+assertEq(x[8]["backslash"], "\\");
+assertEq(x[8]["controls"], "\b\f\n\r\t");
+assertEq(x[8]["slash"], "/ & /");
+assertEq(x[8]["alpha"], "abcdefghijklmnopqrstuvwyz");
+assertEq(x[8]["ALPHA"], "ABCDEFGHIJKLMNOPQRSTUVWYZ");
+assertEq(x[8]["digit"], "0123456789");
+assertEq(x[8]["0123456789"], "digit");
+assertEq(x[8]["special"], "`1~!@#$%^&*()_+-={':[,]}|;.</>?");
+assertEq(x[8]["hex"], "\u0123\u4567\u89AB\uCDEF\uabcd\uef4A");
+assertEq(x[8]["true"], true);
+assertEq(x[8]["false"], false);
+assertEq(x[8]["null"], null);
+assertEq(x[8]["array"].length, 0);
+assertEq(x[8]["object"].constructor, Object);
+assertEq(x[8]["address"], "50 St. James Street");
+assertEq(x[8]["url"], "http://www.JSON.org/");
+assertEq(x[8]["comment"], "// /* <!-- --");
+assertEq(x[8]["# -- --> */"], " ");
+assertEq(x[8][" s p a c e d "].length, 7);
+assertEq(x[8]["compact"].length, 7);
+assertEq(x[8]["jsontext"], "{\"object with 1 member\":[\"array with 1 element\"]}");
+assertEq(x[8]["quotes"], "&#34; \u0022 %22 0x22 034 &#x22;");
+assertEq(x[8]["\/\\\"\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?"], "A key can be any string");
+assertEq(x[9], 0.5);
+assertEq(x[10], 98.6);
+assertEq(x[11], 99.44);
+assertEq(x[12], 1066);
+assertEq(x[13], 1e1);
+assertEq(x[14], 0.1e1);
+assertEq(x[15], 1e-1);
+assertEq(x[16], 1e00);
+assertEq(x[17], 2e+00);
+assertEq(x[18], 2e-00);
+assertEq(x[19], "rosebud");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-mega-huge-array.js b/js/src/tests/non262/JSON/parse-mega-huge-array.js
new file mode 100644
index 0000000000..8f1c192c1e
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-mega-huge-array.js
@@ -0,0 +1,28 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'parse-mega-huge-array.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 667527;
+var summary = "JSON.parse should parse arrays of essentially unlimited size";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var body = "0,";
+for (var i = 0; i < 21; i++)
+ body = body + body;
+var str = '[' + body + '0]';
+
+var arr = JSON.parse(str);
+assertEq(arr.length, Math.pow(2, 21) + 1);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-number-syntax.js b/js/src/tests/non262/JSON/parse-number-syntax.js
new file mode 100644
index 0000000000..42dbbe0b45
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-number-syntax.js
@@ -0,0 +1,32 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+testJSON('-', true);
+testJSON('+', true);
+testJSON('-f', true);
+testJSON('+f', true);
+testJSON('00', true);
+testJSON('01', true);
+testJSON('1.', true);
+testJSON('1.0e', true);
+testJSON('1.0e+', true);
+testJSON('1.0e-', true);
+testJSON('1.0e+z', true);
+testJSON('1.0e-z', true);
+testJSON('1.0ee', true);
+testJSON('1.e1', true);
+testJSON('1.e+1', true);
+testJSON('1.e-1', true);
+testJSON('.', true);
+testJSON('.1', true);
+testJSON('.1e', true);
+testJSON('.1e1', true);
+testJSON('.1e+1', true);
+testJSON('.1e-1', true);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-octal-syntax-error.js b/js/src/tests/non262/JSON/parse-octal-syntax-error.js
new file mode 100644
index 0000000000..f7b0a13a6f
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-octal-syntax-error.js
@@ -0,0 +1,8 @@
+testJSON('{"Numbers cannot have leading zeroes": 013}', true);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-primitives.js b/js/src/tests/non262/JSON/parse-primitives.js
new file mode 100644
index 0000000000..450e1a6577
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-primitives.js
@@ -0,0 +1,62 @@
+var x;
+
+// check an empty object, just for sanity
+var emptyObject = "{}";
+x = JSON.parse(emptyObject);
+assertEq(typeof x, "object");
+assertEq(x instanceof Object, true);
+
+x = JSON.parse(emptyObject);
+assertEq(typeof x, "object");
+
+// booleans and null
+x = JSON.parse("true");
+assertEq(x, true);
+
+x = JSON.parse("true ");
+assertEq(x, true);
+
+x = JSON.parse("false");
+assertEq(x, false);
+
+x = JSON.parse(" null ");
+assertEq(x, null);
+
+// numbers
+x = JSON.parse("1234567890");
+assertEq(x, 1234567890);
+
+x = JSON.parse("-9876.543210");
+assertEq(x, -9876.543210);
+
+x = JSON.parse("0.123456789e-12");
+assertEq(x, 0.123456789e-12);
+
+x = JSON.parse("1.234567890E+34");
+assertEq(x, 1.234567890E+34);
+
+x = JSON.parse(" 23456789012E66 \r\r\r\r \n\n\n\n ");
+assertEq(x, 23456789012E66);
+
+// strings
+x = JSON.parse('"foo"');
+assertEq(x, "foo");
+
+x = JSON.parse('"\\r\\n"');
+assertEq(x, "\r\n");
+
+x = JSON.parse(' "\\uabcd\uef4A"');
+assertEq(x, "\uabcd\uef4A");
+
+x = JSON.parse('"\\uabcd" ');
+assertEq(x, "\uabcd");
+
+x = JSON.parse('"\\f"');
+assertEq(x, "\f");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-reviver-array-delete.js b/js/src/tests/non262/JSON/parse-reviver-array-delete.js
new file mode 100644
index 0000000000..c343058785
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-reviver-array-delete.js
@@ -0,0 +1,89 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'parse-reviver-array-delete.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 999999;
+var summary = "JSON.parse with a reviver which elides array elements";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+/*
+ * The reviver deletes all properties from the to-be-returned array. Thus
+ * stringification reveals properties on the prototype chain -- but there are
+ * none, so this result is unsurprising.
+ */
+assertEq(JSON.parse('[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]',
+ function revive(k, v)
+ {
+ if (k === "")
+ return v;
+ return undefined;
+ }) + "",
+ ",,,,,,,,,,,,,,,,,,,");
+
+/*
+ * Now let's try a reviver that deletes every property but a mega-huge one.
+ */
+var str = "[";
+var expected = "";
+var expected2 = "";
+for (var i = 0; i < 2048; i++)
+{
+ str += "1,";
+ if (i === 2047)
+ {
+ expected += "1";
+ expected2 += "1";
+ }
+ if (i === 3)
+ expected2 += "17";
+ expected += ",";
+ expected2 += ",";
+}
+str += "1]";
+
+assertEq(JSON.parse(str,
+ function reviver(k, v)
+ {
+ if (k === "" || k === "2047")
+ return v;
+ return undefined;
+ }) + "",
+ expected);
+
+
+Array.prototype[3] = 17;
+
+/* Now, with a property on the prototype chain, it'll show through. */
+assertEq(JSON.parse('[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]',
+ function revive(k, v)
+ {
+ if (k === "")
+ return v;
+ return undefined;
+ }) + "",
+ ",,,17,,,,,,,,,,,,,,,,");
+
+
+/* And here too. */
+assertEq(JSON.parse(str,
+ function reviver(k, v)
+ {
+ if (k === "" || k === "2047")
+ return v;
+ return undefined;
+ }) + "",
+ expected2);
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-reviver.js b/js/src/tests/non262/JSON/parse-reviver.js
new file mode 100644
index 0000000000..41e3daf704
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-reviver.js
@@ -0,0 +1,45 @@
+function doubler(k, v)
+{
+ assertEq(typeof k, "string");
+
+ if (typeof v == "number")
+ return 2 * v;
+
+ return v;
+}
+
+var x = JSON.parse('{"a":5,"b":6}', doubler);
+assertEq(x.hasOwnProperty('a'), true);
+assertEq(x.hasOwnProperty('b'), true);
+assertEq(x.a, 10);
+assertEq(x.b, 12);
+
+x = JSON.parse('[3, 4, 5]', doubler);
+assertEq(x[0], 6);
+assertEq(x[1], 8);
+assertEq(x[2], 10);
+
+// make sure reviver isn't called after a failed parse
+var called = false;
+function dontCallMe(k, v)
+{
+ called = true;
+}
+
+try
+{
+ JSON.parse('{{{{{{{}}}}', dontCallMe);
+ throw new Error("didn't throw?");
+}
+catch (e)
+{
+ assertEq(e instanceof SyntaxError, true, "wrong exception: " + e);
+}
+assertEq(called, false);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-syntax-errors-01.js b/js/src/tests/non262/JSON/parse-syntax-errors-01.js
new file mode 100644
index 0000000000..cbb49b0eb7
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-syntax-errors-01.js
@@ -0,0 +1,13 @@
+testJSON("{}...", true);
+testJSON('{"foo": truBBBB}', true);
+testJSON('{foo: truBBBB}', true);
+testJSON('{"foo": undefined}', true);
+testJSON('{"foo": ]', true);
+testJSON('{"foo', true);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-syntax-errors-02.js b/js/src/tests/non262/JSON/parse-syntax-errors-02.js
new file mode 100644
index 0000000000..b304e07ca0
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-syntax-errors-02.js
@@ -0,0 +1,43 @@
+testJSON('"Unterminated string literal', true);
+testJSON('["Unclosed array"', true);
+testJSON('{unquoted_key: "keys must be quoted"}', true);
+testJSON('["extra comma",]', true);
+testJSON('["double extra comma",,]', true);
+testJSON('[ , "<-- missing value"]', true);
+testJSON('["Comma after the close"],', true);
+testJSON('["Extra close"]]', true);
+testJSON('{"Extra comma": true,}', true);
+testJSON('{"Extra value after close": true} "misplaced quoted value"', true);
+testJSON('{"Illegal expression": 1 + 2}', true);
+testJSON('{"Illegal invocation": alert()}', true);
+testJSON('{"Numbers cannot be hex": 0x14}', true);
+testJSON('["Illegal backslash escape: \\x15"]', true);
+testJSON('[\\naked]', true);
+testJSON('["Illegal backslash escape: \\017"]', true);
+testJSON('{"Missing colon" null}', true);
+testJSON('{"Double colon":: null}', true);
+testJSON('{"Comma instead of colon", null}', true);
+testJSON('["Colon instead of comma": false]', true);
+testJSON('["Bad value", truth]', true);
+testJSON("['single quote']", true);
+testJSON('[" tab character in string "]', true);
+testJSON('["tab\\ character\\ in\\ string\\ "]', true);
+testJSON('["line\rbreak"]', true);
+testJSON('["line\nbreak"]', true);
+testJSON('["line\r\nbreak"]', true);
+testJSON('["line\\\rbreak"]', true);
+testJSON('["line\\\nbreak"]', true);
+testJSON('["line\\\r\nbreak"]', true);
+testJSON('[0e]', true);
+testJSON('[0e+]', true);
+testJSON('[0e+-1]', true);
+testJSON('{"Comma instead of closing brace": true,', true);
+testJSON('["mismatch"}', true);
+testJSON('0{', true);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse-syntax-errors-03.js b/js/src/tests/non262/JSON/parse-syntax-errors-03.js
new file mode 100644
index 0000000000..5cdf585a40
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse-syntax-errors-03.js
@@ -0,0 +1,55 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+testJSON('[', true);
+testJSON('[1', true);
+testJSON('[1,]', true);
+testJSON('[1,{', true);
+testJSON('[1,}', true);
+testJSON('[1,{]', true);
+testJSON('[1,}]', true);
+testJSON('[1,{"', true);
+testJSON('[1,}"', true);
+testJSON('[1,{"\\', true);
+testJSON('[1,}"\\', true);
+testJSON('[1,"', true);
+testJSON('[1,"\\', true);
+
+testJSON('{', true);
+testJSON('{1', true);
+testJSON('{,', true);
+testJSON('{"', true);
+testJSON('{"\\', true);
+testJSON('{"\\u', true);
+testJSON('{"\\uG', true);
+testJSON('{"\\u0', true);
+testJSON('{"\\u01', true);
+testJSON('{"\\u012', true);
+testJSON('{"\\u0123', true);
+testJSON('{"\\u0123"', true);
+testJSON('{"a"', true);
+testJSON('{"a"}', true);
+testJSON('{"a":', true);
+testJSON('{"a",}', true);
+testJSON('{"a":}', true);
+testJSON('{"a":,}', true);
+testJSON('{"a":5,}', true);
+testJSON('{"a":5,[', true);
+testJSON('{"a":5,"', true);
+testJSON('{"a":5,"', true);
+testJSON('{"a":5,"\\', true);
+testJSON("a[false ]".substring(1, 7) /* "[false" */, true);
+
+testJSON('this', true);
+
+testJSON('[1,{}]', false);
+testJSON('{}', false);
+testJSON('{"a":5}', false);
+testJSON('{"\\u0123":5}', false);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/parse.js b/js/src/tests/non262/JSON/parse.js
new file mode 100644
index 0000000000..ff9dc51a79
--- /dev/null
+++ b/js/src/tests/non262/JSON/parse.js
@@ -0,0 +1,175 @@
+function assertIsObject(x)
+{
+ assertEq(typeof x, "object");
+ assertEq(x instanceof Object, true);
+}
+
+function assertIsArray(x)
+{
+ assertIsObject(x);
+ assertEq(Array.isArray(x), true);
+ assertEq(Object.getPrototypeOf(x), Array.prototype);
+ assertEq(x instanceof Array, true);
+ assertEq(x.constructor, Array);
+}
+
+var x;
+var props;
+
+// empty object
+x = JSON.parse("{}");
+assertIsObject(x);
+assertEq(Object.getOwnPropertyNames(x).length, 0);
+
+// empty array
+x = JSON.parse("[]");
+assertIsArray(x);
+assertEq(x.length, 0);
+
+// one element array
+x = JSON.parse("[[]]");
+assertIsArray(x);
+assertEq(x.length, 1);
+assertIsArray(x[0]);
+assertEq(x[0].length, 0);
+
+// multiple arrays
+x = JSON.parse("[[],[],[]]");
+assertIsArray(x);
+assertEq(x.length, 3);
+assertIsArray(x[0]);
+assertEq(x[0].length, 0);
+assertIsArray(x[1]);
+assertEq(x[1].length, 0);
+assertIsArray(x[2]);
+assertEq(x[2].length, 0);
+
+// array key/value
+x = JSON.parse('{"foo":[]}');
+assertIsObject(x);
+props = Object.getOwnPropertyNames(x);
+assertEq(props.length, 1);
+assertEq(props[0], "foo");
+assertIsArray(x.foo);
+assertEq(x.foo.length, 0);
+
+x = JSON.parse('{"foo":[], "bar":[]}');
+assertIsObject(x);
+props = Object.getOwnPropertyNames(x).sort();
+assertEq(props.length, 2);
+assertEq(props[0], "bar");
+assertEq(props[1], "foo");
+assertIsArray(x.foo);
+assertEq(x.foo.length, 0);
+assertIsArray(x.bar);
+assertEq(x.bar.length, 0);
+
+// nesting
+x = JSON.parse('{"foo":[{}]}');
+assertIsObject(x);
+props = Object.getOwnPropertyNames(x);
+assertEq(props.length, 1);
+assertEq(props[0], "foo");
+assertIsArray(x.foo);
+assertEq(x.foo.length, 1);
+assertIsObject(x.foo[0]);
+assertEq(Object.getOwnPropertyNames(x.foo[0]).length, 0);
+
+x = JSON.parse('{"foo":[{"foo":[{"foo":{}}]}]}');
+assertIsObject(x.foo[0].foo[0].foo);
+
+x = JSON.parse('{"foo":[{"foo":[{"foo":[]}]}]}');
+assertIsArray(x.foo[0].foo[0].foo);
+
+// strings
+x = JSON.parse('{"foo":"bar"}');
+assertIsObject(x);
+props = Object.getOwnPropertyNames(x);
+assertEq(props.length, 1);
+assertEq(props[0], "foo");
+assertEq(x.foo, "bar");
+
+x = JSON.parse('["foo", "bar", "baz"]');
+assertIsArray(x);
+assertEq(x.length, 3);
+assertEq(x[0], "foo");
+assertEq(x[1], "bar");
+assertEq(x[2], "baz");
+
+// numbers
+x = JSON.parse('{"foo":5.5, "bar":5}');
+assertIsObject(x);
+props = Object.getOwnPropertyNames(x).sort();
+assertEq(props.length, 2);
+assertEq(props[0], "bar");
+assertEq(props[1], "foo");
+assertEq(x.foo, 5.5);
+assertEq(x.bar, 5);
+
+// keywords
+x = JSON.parse('{"foo": true, "bar":false, "baz":null}');
+assertIsObject(x);
+props = Object.getOwnPropertyNames(x).sort();
+assertEq(props.length, 3);
+assertEq(props[0], "bar");
+assertEq(props[1], "baz");
+assertEq(props[2], "foo");
+assertEq(x.foo, true);
+assertEq(x.bar, false);
+assertEq(x.baz, null);
+
+// short escapes
+x = JSON.parse('{"foo": "\\"", "bar":"\\\\", "baz":"\\b","qux":"\\f", "quux":"\\n", "quuux":"\\r","quuuux":"\\t"}');
+props = Object.getOwnPropertyNames(x).sort();
+assertEq(props.length, 7);
+assertEq(props[0], "bar");
+assertEq(props[1], "baz");
+assertEq(props[2], "foo");
+assertEq(props[3], "quuuux");
+assertEq(props[4], "quuux");
+assertEq(props[5], "quux");
+assertEq(props[6], "qux");
+assertEq(x.foo, '"');
+assertEq(x.bar, '\\');
+assertEq(x.baz, '\b');
+assertEq(x.qux, '\f');
+assertEq(x.quux, "\n");
+assertEq(x.quuux, "\r");
+assertEq(x.quuuux, "\t");
+
+// unicode escape
+x = JSON.parse('{"foo":"hmm\\u006dmm"}');
+assertIsObject(x);
+props = Object.getOwnPropertyNames(x);
+assertEq(props.length, 1);
+assertEq(props[0], "foo");
+assertEq("hmm\u006dmm", x.foo);
+
+x = JSON.parse('{"hmm\\u006dmm":"foo"}');
+assertIsObject(x);
+props = Object.getOwnPropertyNames(x);
+assertEq(props.length, 1);
+assertEq(props[0], "hmmmmm");
+assertEq(x.hmm\u006dmm, "foo");
+
+// miscellaneous
+x = JSON.parse('{"JSON Test Pattern pass3": {"The outermost value": "must be an object or array.","In this test": "It is an object." }}');
+assertIsObject(x);
+props = Object.getOwnPropertyNames(x);
+assertEq(props.length, 1);
+assertEq(props[0], "JSON Test Pattern pass3");
+assertIsObject(x["JSON Test Pattern pass3"]);
+props = Object.getOwnPropertyNames(x["JSON Test Pattern pass3"]).sort();
+assertEq(props.length, 2);
+assertEq(props[0], "In this test");
+assertEq(props[1], "The outermost value");
+assertEq(x["JSON Test Pattern pass3"]["The outermost value"],
+ "must be an object or array.");
+assertEq(x["JSON Test Pattern pass3"]["In this test"], "It is an object.");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/regress-458959.js b/js/src/tests/non262/JSON/regress-458959.js
new file mode 100644
index 0000000000..648918e8ed
--- /dev/null
+++ b/js/src/tests/non262/JSON/regress-458959.js
@@ -0,0 +1,29 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 458959;
+var summary = 'this.JSON should not be enumerable';
+var actual = '';
+var expect = '';
+
+
+//-----------------------------------------------------------------------------
+test();
+//-----------------------------------------------------------------------------
+
+function test()
+{
+ printBugNumber(BUGNUMBER);
+ printStatus (summary);
+
+ for (var i in this)
+ {
+ if (i.toString() == 'JSON')
+ actual = i;
+ }
+
+ reportCompare(expect, actual, summary);
+}
diff --git a/js/src/tests/non262/JSON/regress-459293.js b/js/src/tests/non262/JSON/regress-459293.js
new file mode 100644
index 0000000000..fbd46589ca
--- /dev/null
+++ b/js/src/tests/non262/JSON/regress-459293.js
@@ -0,0 +1,25 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ * Contributor: Robert Sayre
+ */
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 459293;
+var summary = 'Allow redeclaration of JSON';
+var actual = '';
+var expect = '';
+
+ printBugNumber(BUGNUMBER);
+ printStatus (summary);
+
+ try
+ {
+ eval('var JSON = "foo";');
+ }
+ catch(ex)
+ {
+ actual = ex + '';
+ }
+ reportCompare(expect, actual, summary);
diff --git a/js/src/tests/non262/JSON/shell.js b/js/src/tests/non262/JSON/shell.js
new file mode 100644
index 0000000000..00f3243dac
--- /dev/null
+++ b/js/src/tests/non262/JSON/shell.js
@@ -0,0 +1,110 @@
+function testJSON(str, expectSyntaxError)
+{
+ // Leading and trailing whitespace never affect parsing, so test the string
+ // multiple times with and without whitespace around it as it's easy and can
+ // potentially detect bugs.
+
+ // Try the provided string
+ try
+ {
+ JSON.parse(str);
+ reportCompare(false, expectSyntaxError,
+ "string <" + str + "> " +
+ "should" + (expectSyntaxError ? "n't" : "") + " " +
+ "have parsed as JSON");
+ }
+ catch (e)
+ {
+ if (!(e instanceof SyntaxError))
+ {
+ reportCompare(true, false,
+ "parsing string <" + str + "> threw a non-SyntaxError " +
+ "exception: " + e);
+ }
+ else
+ {
+ reportCompare(true, expectSyntaxError,
+ "string <" + str + "> " +
+ "should" + (expectSyntaxError ? "n't" : "") + " " +
+ "have parsed as JSON, exception: " + e);
+ }
+ }
+
+ // Now try the provided string with trailing whitespace
+ try
+ {
+ JSON.parse(str + " ");
+ reportCompare(false, expectSyntaxError,
+ "string <" + str + " > " +
+ "should" + (expectSyntaxError ? "n't" : "") + " " +
+ "have parsed as JSON");
+ }
+ catch (e)
+ {
+ if (!(e instanceof SyntaxError))
+ {
+ reportCompare(true, false,
+ "parsing string <" + str + " > threw a non-SyntaxError " +
+ "exception: " + e);
+ }
+ else
+ {
+ reportCompare(true, expectSyntaxError,
+ "string <" + str + " > " +
+ "should" + (expectSyntaxError ? "n't" : "") + " " +
+ "have parsed as JSON, exception: " + e);
+ }
+ }
+
+ // Now try the provided string with leading whitespace
+ try
+ {
+ JSON.parse(" " + str);
+ reportCompare(false, expectSyntaxError,
+ "string < " + str + "> " +
+ "should" + (expectSyntaxError ? "n't" : "") + " " +
+ "have parsed as JSON");
+ }
+ catch (e)
+ {
+ if (!(e instanceof SyntaxError))
+ {
+ reportCompare(true, false,
+ "parsing string < " + str + "> threw a non-SyntaxError " +
+ "exception: " + e);
+ }
+ else
+ {
+ reportCompare(true, expectSyntaxError,
+ "string < " + str + "> " +
+ "should" + (expectSyntaxError ? "n't" : "") + " " +
+ "have parsed as JSON, exception: " + e);
+ }
+ }
+
+ // Now try the provided string with whitespace surrounding it
+ try
+ {
+ JSON.parse(" " + str + " ");
+ reportCompare(false, expectSyntaxError,
+ "string < " + str + " > " +
+ "should" + (expectSyntaxError ? "n't" : "") + " " +
+ "have parsed as JSON");
+ }
+ catch (e)
+ {
+ if (!(e instanceof SyntaxError))
+ {
+ reportCompare(true, false,
+ "parsing string < " + str + " > threw a non-SyntaxError " +
+ "exception: " + e);
+ }
+ else
+ {
+ reportCompare(true, expectSyntaxError,
+ "string < " + str + " > " +
+ "should" + (expectSyntaxError ? "n't" : "") + " " +
+ "have parsed as JSON, exception: " + e);
+ }
+ }
+}
diff --git a/js/src/tests/non262/JSON/small-codepoints.js b/js/src/tests/non262/JSON/small-codepoints.js
new file mode 100644
index 0000000000..6afa5f8ce8
--- /dev/null
+++ b/js/src/tests/non262/JSON/small-codepoints.js
@@ -0,0 +1,16 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'small-codepoints.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 554079;
+var summary = 'JSON.parse should reject U+0000 through U+001F';
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+for (var i = 0; i <= 0x1F; i++)
+ testJSON('["a' + String.fromCharCode(i) + 'c"]', true);
diff --git a/js/src/tests/non262/JSON/stringify-boxed-primitives.js b/js/src/tests/non262/JSON/stringify-boxed-primitives.js
new file mode 100644
index 0000000000..0769c2ec6f
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-boxed-primitives.js
@@ -0,0 +1,127 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-boxed-primitives.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 584909;
+var summary = "Stringification of Boolean/String/Number objects";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+function redefine(obj, prop, fun)
+{
+ var desc =
+ { value: fun, writable: true, configurable: true, enumerable: false };
+ Object.defineProperty(obj, prop, desc);
+}
+
+assertEq(JSON.stringify(new Boolean(false)), "false");
+
+assertEq(JSON.stringify(new Number(5)), "5");
+
+assertEq(JSON.stringify(new String("foopy")), '"foopy"');
+
+
+var numToString = Number.prototype.toString;
+var numValueOf = Number.prototype.valueOf;
+var objToString = Object.prototype.toString;
+var objValueOf = Object.prototype.valueOf;
+var boolToString = Boolean.prototype.toString;
+var boolValueOf = Boolean.prototype.valueOf;
+
+redefine(Boolean.prototype, "toString", function() { return 17; });
+assertEq(JSON.stringify(new Boolean(false)), "false")
+delete Boolean.prototype.toString;
+assertEq(JSON.stringify(new Boolean(false)), "false");
+delete Object.prototype.toString;
+assertEq(JSON.stringify(new Boolean(false)), "false");
+delete Boolean.prototype.valueOf;
+assertEq(JSON.stringify(new Boolean(false)), "false");
+delete Object.prototype.valueOf;
+assertEq(JSON.stringify(new Boolean(false)), "false");
+
+
+redefine(Boolean.prototype, "toString", boolToString);
+redefine(Boolean.prototype, "valueOf", boolValueOf);
+redefine(Object.prototype, "toString", objToString);
+redefine(Object.prototype, "valueOf", objValueOf);
+
+redefine(Number.prototype, "toString", function() { return 42; });
+assertEq(JSON.stringify(new Number(5)), "5");
+redefine(Number.prototype, "valueOf", function() { return 17; });
+assertEq(JSON.stringify(new Number(5)), "17");
+delete Number.prototype.toString;
+assertEq(JSON.stringify(new Number(5)), "17");
+delete Number.prototype.valueOf;
+assertEq(JSON.stringify(new Number(5)), "null"); // isNaN(Number("[object Number]"))
+delete Object.prototype.toString;
+try
+{
+ JSON.stringify(new Number(5));
+ throw new Error("didn't throw");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true,
+ "ToNumber failure, should throw TypeError");
+}
+delete Object.prototype.valueOf;
+try
+{
+ JSON.stringify(new Number(5));
+ throw new Error("didn't throw");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true,
+ "ToNumber failure, should throw TypeError");
+}
+
+
+redefine(Number.prototype, "toString", numToString);
+redefine(Number.prototype, "valueOf", numValueOf);
+redefine(Object.prototype, "toString", objToString);
+redefine(Object.prototype, "valueOf", objValueOf);
+
+
+redefine(String.prototype, "valueOf", function() { return 17; });
+assertEq(JSON.stringify(new String(5)), '"5"');
+redefine(String.prototype, "toString", function() { return 42; });
+assertEq(JSON.stringify(new String(5)), '"42"');
+delete String.prototype.toString;
+assertEq(JSON.stringify(new String(5)), '"[object String]"');
+delete Object.prototype.toString;
+assertEq(JSON.stringify(new String(5)), '"17"');
+delete String.prototype.valueOf;
+try
+{
+ JSON.stringify(new String(5));
+ throw new Error("didn't throw");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true,
+ "ToString failure, should throw TypeError");
+}
+delete Object.prototype.valueOf;
+try
+{
+ JSON.stringify(new String(5));
+ throw new Error("didn't throw");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true,
+ "ToString failure, should throw TypeError");
+}
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("All tests passed!");
diff --git a/js/src/tests/non262/JSON/stringify-call-replacer-once.js b/js/src/tests/non262/JSON/stringify-call-replacer-once.js
new file mode 100644
index 0000000000..34e549b6e6
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-call-replacer-once.js
@@ -0,0 +1,34 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-call-replacer-once.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 584909;
+var summary = "Call replacer function exactly once per value";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var factor = 1;
+function replacer(k, v)
+{
+ if (k === "")
+ return v;
+
+ return v * ++factor;
+}
+
+var obj = { a: 1, b: 2, c: 3 };
+
+assertEq(JSON.stringify(obj, replacer), '{"a":2,"b":6,"c":12}');
+assertEq(factor, 4);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-call-toJSON-once.js b/js/src/tests/non262/JSON/stringify-call-toJSON-once.js
new file mode 100644
index 0000000000..23917975d9
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-call-toJSON-once.js
@@ -0,0 +1,32 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-call-toJSON-once.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 584909;
+var summary = "Stringification of Boolean/String/Number objects";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var obj =
+ {
+ p: {
+ toJSON: function()
+ {
+ return { toJSON: function() { return 17; } };
+ }
+ }
+ };
+
+assertEq(JSON.stringify(obj), '{"p":{}}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-dropping-elements.js b/js/src/tests/non262/JSON/stringify-dropping-elements.js
new file mode 100644
index 0000000000..58838e10d1
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-dropping-elements.js
@@ -0,0 +1,20 @@
+assertEq(JSON.stringify({foo: 123}),
+ '{"foo":123}');
+assertEq(JSON.stringify({foo: 123, bar: function () {}}),
+ '{"foo":123}');
+assertEq(JSON.stringify({foo: 123, bar: function () {}, baz: 123}),
+ '{"foo":123,"baz":123}');
+
+assertEq(JSON.stringify([123]),
+ '[123]');
+assertEq(JSON.stringify([123, function () {}]),
+ '[123,null]');
+assertEq(JSON.stringify([123, function () {}, 456]),
+ '[123,null,456]');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-gap.js b/js/src/tests/non262/JSON/stringify-gap.js
new file mode 100644
index 0000000000..8480b4b3ee
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-gap.js
@@ -0,0 +1,61 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-gap.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 584909;
+var summary =
+ "JSON.stringify(_1, _2, numberGreaterThanOne) produces wrong output";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var LF = "\n";
+var GAP = " ";
+
+var obj = { a: { b: [1, 2], c: { d: 3, e: 4 }, f: [], g: {}, h: [5], i: { j: 6 } } };
+
+var expected =
+ '{\n' +
+ ' "a": {\n' +
+ ' "b": [\n' +
+ ' 1,\n' +
+ ' 2\n' +
+ ' ],\n' +
+ ' "c": {\n' +
+ ' "d": 3,\n' +
+ ' "e": 4\n' +
+ ' },\n' +
+ ' "f": [],\n' +
+ ' "g": {},\n' +
+ ' "h": [\n' +
+ ' 5\n' +
+ ' ],\n' +
+ ' "i": {\n' +
+ ' "j": 6\n' +
+ ' }\n' +
+ ' }\n' +
+ '}';
+
+assertEq(JSON.stringify(obj, null, 3), expected);
+assertEq(JSON.stringify(obj, null, " "), expected);
+
+obj = [1, 2, 3];
+
+String.prototype.toString = function() { return "--"; };
+
+assertEq(JSON.stringify(obj, null, new String(" ")), "[\n--1,\n--2,\n--3\n]");
+
+Number.prototype.valueOf = function() { return 0; };
+
+assertEq(JSON.stringify(obj, null, new Number(3)), "[1,2,3]");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("All tests passed!");
diff --git a/js/src/tests/non262/JSON/stringify-ignore-noncallable-toJSON.js b/js/src/tests/non262/JSON/stringify-ignore-noncallable-toJSON.js
new file mode 100644
index 0000000000..e4ce0ce945
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-ignore-noncallable-toJSON.js
@@ -0,0 +1,28 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-ignore-noncallable-toJSON.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 584909;
+var summary = "If the toJSON property isn't callable, don't try to call it";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var obj =
+ {
+ p: { toJSON: null },
+ m: { toJSON: {} }
+ };
+
+assertEq(JSON.stringify(obj), '{"p":{"toJSON":null},"m":{"toJSON":{}}}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-large-replacer-array.js b/js/src/tests/non262/JSON/stringify-large-replacer-array.js
new file mode 100644
index 0000000000..28180b4bf1
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-large-replacer-array.js
@@ -0,0 +1,26 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-large-replacer-array.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 816033;
+var summary = "JSON.stringify with a large replacer array";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var replacer = [];
+for (var i = 0; i < 4096; i++)
+ replacer.push(i);
+
+assertEq(JSON.stringify({ "foopy": "FAIL", "4093": 17 }, replacer), '{"4093":17}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-missing-arguments.js b/js/src/tests/non262/JSON/stringify-missing-arguments.js
new file mode 100644
index 0000000000..18ca608357
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-missing-arguments.js
@@ -0,0 +1,22 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-missing-arguments.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 648471;
+var summary = "JSON.stringify with no arguments";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+assertEq(JSON.stringify(), undefined);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("All tests passed!");
diff --git a/js/src/tests/non262/JSON/stringify-nonarray-noncallable-replacer.js b/js/src/tests/non262/JSON/stringify-nonarray-noncallable-replacer.js
new file mode 100644
index 0000000000..440fbc0aae
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-nonarray-noncallable-replacer.js
@@ -0,0 +1,41 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-nonarray-noncallable-replacer.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 653782;
+var summary =
+ "Treat non-array, non-callable replacers as if none had been specified";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var obj = { p: 2 };
+var str = '{"p":2}';
+
+assertEq(JSON.stringify(obj), str);
+assertEq(JSON.stringify(obj, ["p"]), str);
+assertEq(JSON.stringify(obj, null), str);
+assertEq(JSON.stringify(obj, undefined), str);
+assertEq(JSON.stringify(obj, 2), str);
+assertEq(JSON.stringify(obj, Math.PI), str);
+assertEq(JSON.stringify(obj, NaN), str);
+assertEq(JSON.stringify(obj, true), str);
+assertEq(JSON.stringify(obj, false), str);
+assertEq(JSON.stringify(obj, Infinity), str);
+assertEq(JSON.stringify(obj, "foopy"), str);
+assertEq(JSON.stringify(obj, {}), str);
+assertEq(JSON.stringify(obj, /abcd/), str);
+assertEq(JSON.stringify(obj, new Boolean(true)), str);
+assertEq(JSON.stringify(obj, new Number(42)), str);
+assertEq(JSON.stringify(obj, new String("aequorin")), str);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-primitives.js b/js/src/tests/non262/JSON/stringify-primitives.js
new file mode 100644
index 0000000000..3f48638b8b
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-primitives.js
@@ -0,0 +1,39 @@
+// sanity
+var x = JSON.stringify({});
+assertEq(x, "{}");
+
+// booleans and null
+x = JSON.stringify(true);
+assertEq(x, "true");
+
+x = JSON.stringify(false);
+assertEq(x, "false");
+
+x = JSON.stringify(new Boolean(false));
+assertEq(x, "false");
+
+x = JSON.stringify(null);
+assertEq(x, "null");
+
+x = JSON.stringify(1234);
+assertEq(x, "1234");
+
+x = JSON.stringify(new Number(1234));
+assertEq(x, "1234");
+
+x = JSON.stringify("asdf");
+assertEq(x, '"asdf"');
+
+x = JSON.stringify(new String("asdf"));
+assertEq(x, '"asdf"');
+
+assertEq(JSON.stringify(undefined), undefined);
+assertEq(JSON.stringify(function(){}), undefined);
+assertEq(JSON.stringify(JSON.stringify), undefined);
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-replacer-array-boxed-elements.js b/js/src/tests/non262/JSON/stringify-replacer-array-boxed-elements.js
new file mode 100644
index 0000000000..561f7009c7
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-replacer-array-boxed-elements.js
@@ -0,0 +1,60 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-replacer-array-boxed-elements.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 648471;
+var summary = "Boxed-string/number objects in replacer arrays";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var S = new String(3);
+var N = new Number(4);
+
+assertEq(JSON.stringify({ 3: 3, 4: 4 }, [S]),
+ '{"3":3}');
+assertEq(JSON.stringify({ 3: 3, 4: 4 }, [N]),
+ '{"4":4}');
+
+Number.prototype.toString = function() { return 3; };
+assertEq(JSON.stringify({ 3: 3, 4: 4 }, [N]),
+ '{"3":3}');
+
+String.prototype.toString = function() { return 4; };
+assertEq(JSON.stringify({ 3: 3, 4: 4 }, [S]),
+ '{"4":4}');
+
+Number.prototype.toString = function() { return new String(42); };
+assertEq(JSON.stringify({ 3: 3, 4: 4 }, [N]),
+ '{"4":4}');
+
+String.prototype.toString = function() { return new Number(17); };
+assertEq(JSON.stringify({ 3: 3, 4: 4 }, [S]),
+ '{"3":3}');
+
+Number.prototype.toString = null;
+assertEq(JSON.stringify({ 3: 3, 4: 4 }, [N]),
+ '{"4":4}');
+
+String.prototype.toString = null;
+assertEq(JSON.stringify({ 3: 3, 4: 4 }, [S]),
+ '{"3":3}');
+
+Number.prototype.valueOf = function() { return 17; };
+assertEq(JSON.stringify({ 4: 4, 17: 17 }, [N]),
+ '{"17":17}');
+
+String.prototype.valueOf = function() { return 42; };
+assertEq(JSON.stringify({ 3: 3, 42: 42 }, [S]),
+ '{"42":42}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-replacer-array-duplicated-element.js b/js/src/tests/non262/JSON/stringify-replacer-array-duplicated-element.js
new file mode 100644
index 0000000000..69192e6cae
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-replacer-array-duplicated-element.js
@@ -0,0 +1,69 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-replacer-array-hijinks.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 648471;
+var summary =
+ "Better/more correct handling for replacer arrays with getter array index " +
+ "properties";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var bigOdd = Math.pow(2, 50) + 1;
+
+function two()
+{
+ return Math.random() < 0.5 ? 2 : "2";
+}
+
+assertEq(JSON.stringify({ 1: 1 }, [1, 1]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [1, "1"]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [1, bigOdd % two()]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, ["1", 1]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, ["1", "1"]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, ["1", bigOdd % two()]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [bigOdd % two(), 1]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [bigOdd % two(), "1"]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [bigOdd % two(), bigOdd % two()]), '{"1":1}');
+
+
+assertEq(JSON.stringify({ 1: 1 }, [1, new String(1)]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [1, new Number(1)]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, ["1", new Number(1)]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, ["1", new String(1)]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [bigOdd % two(), new Number(1)]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [bigOdd % two(), new String(1)]), '{"1":1}');
+
+
+assertEq(JSON.stringify({ 1: 1 }, [new String(1), new String(1)]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [new String(1), new Number(1)]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [new Number(1), new String(1)]), '{"1":1}');
+
+assertEq(JSON.stringify({ 1: 1 }, [new Number(1), new Number(1)]), '{"1":1}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-replacer-array-edgecase-jsid-elements.js b/js/src/tests/non262/JSON/stringify-replacer-array-edgecase-jsid-elements.js
new file mode 100644
index 0000000000..e7be4c6e11
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-replacer-array-edgecase-jsid-elements.js
@@ -0,0 +1,77 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-replacer-array-edgecase-jsid-elements.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 648471;
+var summary =
+ "Better/more correct handling for replacer arrays with getter array index " +
+ "properties";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+/* JSID_INT_MIN/MAX copied from jsapi.h. */
+
+var obj =
+ {
+ /* [JSID_INT_MIN - 1, JSID_INT_MIN + 1] */
+ "-1073741825": -1073741825,
+ "-1073741824": -1073741824,
+ "-1073741823": -1073741823,
+
+ "-2.5": -2.5,
+ "-1": -1,
+
+ 0: 0,
+
+ 1: 1,
+ 2.5: 2.5,
+
+ /* [JSID_INT_MAX - 1, JSID_INT_MAX + 1] */
+ 1073741822: 1073741822,
+ 1073741823: 1073741823,
+ 1073741824: 1073741824,
+ };
+
+for (var s in obj)
+{
+ var n = obj[s];
+ assertEq(+s, n);
+ assertEq(JSON.stringify(obj, [n]),
+ '{"' + s + '":' + n + '}',
+ "Failed to stringify numeric property " + n + "correctly");
+ assertEq(JSON.stringify(obj, [s]),
+ '{"' + s + '":' + n + '}',
+ "Failed to stringify string property " + n + "correctly");
+ assertEq(JSON.stringify(obj, [s, ]),
+ '{"' + s + '":' + n + '}',
+ "Failed to stringify string then number properties ('" + s + "', " + n + ") correctly");
+ assertEq(JSON.stringify(obj, [n, s]),
+ '{"' + s + '":' + n + '}',
+ "Failed to stringify number then string properties (" + n + ", '" + s + "') correctly");
+}
+
+// -0 is tricky, because ToString(-0) === "0", so test it specially.
+assertEq(JSON.stringify({ "-0": 17, 0: 42 }, [-0]),
+ '{"0":42}',
+ "Failed to stringify numeric property -0 correctly");
+assertEq(JSON.stringify({ "-0": 17, 0: 42 }, ["-0"]),
+ '{"-0":17}',
+ "Failed to stringify string property -0 correctly");
+assertEq(JSON.stringify({ "-0": 17, 0: 42 }, ["-0", -0]),
+ '{"-0":17,"0":42}',
+ "Failed to stringify string then number properties ('-0', -0) correctly");
+assertEq(JSON.stringify({ "-0": 17, 0: 42 }, [-0, "-0"]),
+ '{"0":42,"-0":17}',
+ "Failed to stringify number then string properties (-0, '-0) correctly");
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-replacer-array-hijinks.js b/js/src/tests/non262/JSON/stringify-replacer-array-hijinks.js
new file mode 100644
index 0000000000..60c949a5f1
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-replacer-array-hijinks.js
@@ -0,0 +1,59 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-replacer-array-hijinks.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 648471;
+var summary =
+ "Better/more correct handling for replacer arrays with getter array index " +
+ "properties";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var replacer = [0, 1, 2, 3];
+Object.prototype[3] = 3;
+Object.defineProperty(replacer, 1, {
+ get: function()
+ {
+ Object.defineProperty(replacer, 4, { value: 4 });
+ delete replacer[2];
+ delete replacer[3];
+ replacer[5] = 5;
+ return 1;
+ }
+});
+
+var s =
+ JSON.stringify({0: { 1: { 3: { 4: { 5: { 2: "omitted" } } } } } }, replacer);
+
+// The replacer array's length is as seen on first query, so property names are
+// accumulated for indexes i ∈ {0, 1, 2, 3}, but index 1 deletes 2 and 3, so 2
+// isn't seen but 3 is seen as Object.prototype[3].
+assertEq('{"0":{"1":{"3":{"3":3}},"3":3},"3":3}', s);
+
+
+var replacer = [0, 1, 2, 3];
+Object.defineProperty(replacer, 0, {
+ get: function()
+ {
+ replacer.length = 0;
+ return {};
+ }
+});
+
+// The replacer.length truncation means only properties on the prototype chain
+// shine through, but it doesn't affect the original bounds of the iteration
+// used to determine property names which will be included in the final string.
+assertEq(JSON.stringify({ 0: 0, 1: 1, 2: 2, 3: 3 }, replacer),
+ '{"3":3}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-replacer-array-skipped-element.js b/js/src/tests/non262/JSON/stringify-replacer-array-skipped-element.js
new file mode 100644
index 0000000000..6297c3a5bf
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-replacer-array-skipped-element.js
@@ -0,0 +1,62 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-replacer-array-skipped-element.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 648471;
+var summary =
+ "Better/more correct handling for replacer arrays with getter array index " +
+ "properties";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+assertEq(JSON.stringify({ 3: 3, 4: 4 },
+ ["3", { toString: function() { return "4" } }]),
+ '{"3":3}');
+
+assertEq(JSON.stringify({ 3: 3, true: 4 }, ["3", true]),
+ '{"3":3}');
+
+assertEq(JSON.stringify({ 3: 3, true: 4 }, ["3", "true", true]),
+ '{"3":3,"true":4}');
+
+assertEq(JSON.stringify({ 3: 3, true: 4 }, ["3", true, "true"]),
+ '{"3":3,"true":4}');
+
+assertEq(JSON.stringify({ 3: 3, false: 4 }, ["3", false]),
+ '{"3":3}');
+
+assertEq(JSON.stringify({ 3: 3, false: 4 }, ["3", "false", false]),
+ '{"3":3,"false":4}');
+
+assertEq(JSON.stringify({ 3: 3, false: 4 }, ["3", false, "false"]),
+ '{"3":3,"false":4}');
+
+assertEq(JSON.stringify({ 3: 3, undefined: 4 }, ["3", undefined]),
+ '{"3":3}');
+
+assertEq(JSON.stringify({ 3: 3, undefined: 4 }, ["3", "undefined", undefined]),
+ '{"3":3,"undefined":4}');
+
+assertEq(JSON.stringify({ 3: 3, undefined: 4 }, ["3", undefined, "undefined"]),
+ '{"3":3,"undefined":4}');
+
+assertEq(JSON.stringify({ 3: 3, null: 4 }, ["3", null]),
+ '{"3":3}');
+
+assertEq(JSON.stringify({ 3: 3, null: 4 }, ["3", "null", null]),
+ '{"3":3,"null":4}');
+
+assertEq(JSON.stringify({ 3: 3, null: 4 }, ["3", null, "null"]),
+ '{"3":3,"null":4}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-replacer-array-trailing-holes.js b/js/src/tests/non262/JSON/stringify-replacer-array-trailing-holes.js
new file mode 100644
index 0000000000..6eb09855fa
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-replacer-array-trailing-holes.js
@@ -0,0 +1,49 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = "stringify-replacer-array-trailing-holes.js";
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 1217069;
+var summary =
+ "Better/more correct handling for replacer arrays with trailing holes " +
+ "through which inherited elements might appear";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var obj = { 0: "hi", 1: "n-nao", 2: "run away!", 3: "bye" };
+
+var s;
+
+var replacer = [0, /* 1 */, /* 2 */, /* 3 */, ];
+
+assertEq(JSON.stringify(obj, replacer),
+ '{"0":"hi"}');
+
+var nobj = new Number(0);
+nobj.toString = () => { replacer[1] = 1; return 0; };
+replacer[0] = nobj;
+
+assertEq(JSON.stringify(obj, replacer),
+ '{"0":"hi","1":"n-nao"}');
+
+delete replacer[1];
+replacer[0] = 0;
+
+Object.prototype[0] = 0;
+Object.prototype[1] = 1;
+Object.prototype[2] = 2;
+Object.prototype[3] = 3;
+
+assertEq(JSON.stringify(obj, replacer),
+ '{"0":"hi","1":"n-nao","2":"run away!","3":"bye"}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-replacer-with-array-indexes.js b/js/src/tests/non262/JSON/stringify-replacer-with-array-indexes.js
new file mode 100644
index 0000000000..0b3f6896e5
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-replacer-with-array-indexes.js
@@ -0,0 +1,56 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-replacer-with-array-indexes.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 584909;
+var summary =
+ "Call the replacer function for array elements with stringified indexes";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var arr = [0, 1, 2, 3, 4];
+
+var seenTopmost = false;
+var index = 0;
+function replacer()
+{
+ assertEq(arguments.length, 2);
+
+ var key = arguments[0], value = arguments[1];
+
+ // Topmost array: ignore replacer call.
+ if (key === "")
+ {
+ assertEq(seenTopmost, false);
+ seenTopmost = true;
+ return value;
+ }
+
+ assertEq(seenTopmost, true);
+
+ assertEq(typeof key, "string");
+ assertEq(key === index, false);
+ assertEq(key === index + "", true);
+
+ assertEq(value, index);
+
+ index++;
+
+ assertEq(this, arr);
+
+ return value;
+}
+
+assertEq(JSON.stringify(arr, replacer), '[0,1,2,3,4]');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-replacer.js b/js/src/tests/non262/JSON/stringify-replacer.js
new file mode 100644
index 0000000000..37497fd348
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-replacer.js
@@ -0,0 +1,155 @@
+/**
+ * These return* functions are used by the
+ * replacer tests taken from bug 512447
+ */
+function returnObjectFor1(k, v)
+{
+ if (k == "1")
+ return {};
+ return v;
+}
+function returnArrayFor1(k, v)
+{
+ if (k == "1")
+ return [];
+ return v;
+}
+function returnNullFor1(k, v)
+{
+ if (k == "1")
+ return null;
+ return v;
+}
+function returnStringForUndefined(k, v)
+{
+ if (v === undefined)
+ return "undefined value";
+ return v;
+}
+var cycleObject = {}; cycleObject.cycle = cycleObject;
+function returnCycleObjectFor1(k, v)
+{
+ if (k == "1")
+ return cycleObject;
+ return v;
+}
+var array = [0, 1, 2]; array[3] = array;
+function returnCycleArrayFor1(k, v)
+{
+ if (k == "1")
+ return array;
+ return v;
+}
+
+// BEGIN TEST
+var x;
+
+x = JSON.stringify({ key: 2 },
+ function(k,v) { return k ? undefined : v; });
+assertEq(x, "{}");
+
+x = JSON.stringify(["hmm", "hmm"],
+ function(k,v) { return k !== "" ? undefined : v; });
+assertEq(x, "[null,null]");
+
+var foo = ["hmm"];
+function censor(k, v)
+{
+ if (v !== foo)
+ return "XXX";
+ return v;
+}
+x = JSON.stringify(foo, censor);
+assertEq(x, '["XXX"]');
+
+foo = ["bar", ["baz"], "qux"];
+x = JSON.stringify(foo, censor);
+assertEq(x, '["XXX","XXX","XXX"]');
+
+function censor2(k, v)
+{
+ if (typeof(v) == "string")
+ return "XXX";
+ return v;
+}
+
+foo = ["bar", ["baz"], "qux"];
+x = JSON.stringify(foo, censor2);
+assertEq(x, '["XXX",["XXX"],"XXX"]');
+
+foo = { bar: 42, qux: 42, quux: 42 };
+x = JSON.stringify(foo, ["bar"]);
+assertEq(x, '{"bar":42}');
+
+foo = {bar: {bar: 42, schmoo:[]}, qux: 42, quux: 42};
+x = JSON.stringify(foo, ["bar", "schmoo"]);
+assertEq(x, '{"bar":{"bar":42,"schmoo":[]}}');
+
+x = JSON.stringify(foo, null, "");
+assertEq(x, '{"bar":{"bar":42,"schmoo":[]},"qux":42,"quux":42}');
+
+x = JSON.stringify(foo, null, " ");
+assertEq(x, '{\n "bar": {\n "bar": 42,\n "schmoo": []\n },\n "qux": 42,\n "quux": 42\n}');
+
+foo = {bar:{bar:{}}}
+x = JSON.stringify(foo, null, " ");
+assertEq(x, '{\n "bar": {\n "bar": {}\n }\n}');
+
+x = JSON.stringify({ x: 1, arr: [1] },
+ function (k,v) { return typeof v === 'number' ? 3 : v; });
+assertEq(x, '{"x":3,"arr":[3]}');
+
+foo = ['e'];
+x = JSON.stringify(foo, null, '\t');
+assertEq(x, '[\n\t"e"\n]');
+
+foo = {0:0, 1:1, 2:2, 3:undefined};
+x = JSON.stringify(foo, returnObjectFor1);
+assertEq(x, '{"0":0,"1":{},"2":2}');
+
+x = JSON.stringify(foo, returnArrayFor1);
+assertEq(x, '{"0":0,"1":[],"2":2}');
+
+x = JSON.stringify(foo, returnNullFor1);
+assertEq(x, '{"0":0,"1":null,"2":2}');
+
+x = JSON.stringify(foo, returnStringForUndefined);
+assertEq(x, '{"0":0,"1":1,"2":2,"3":"undefined value"}');
+
+try
+{
+ JSON.stringify(foo, returnCycleObjectFor1);
+ throw new Error("no error thrown");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true, "no TypeError thrown: " + e);
+}
+
+try
+{
+ JSON.stringify(foo, returnCycleArrayFor1);
+ throw new Error("no error thrown");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true, "no TypeError thrown: " + e);
+}
+
+foo = [0, 1, 2, undefined];
+try
+{
+ JSON.stringify(foo, returnCycleObjectFor1);
+ throw new Error("no error thrown");
+}
+catch (e)
+{
+ assertEq(e instanceof TypeError, true, "no TypeError thrown: " + e);
+}
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-special-escapes.js b/js/src/tests/non262/JSON/stringify-special-escapes.js
new file mode 100644
index 0000000000..c8a2e83815
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-special-escapes.js
@@ -0,0 +1,277 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-special-escapes.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 512266;
+var summary =
+ "JSON.stringify of \\b\\f\\n\\r\\t should use one-character escapes, not hex";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+assertEq(JSON.stringify("\u0000"), '"\\u0000"');
+assertEq(JSON.stringify("\u0001"), '"\\u0001"');
+assertEq(JSON.stringify("\u0002"), '"\\u0002"');
+assertEq(JSON.stringify("\u0003"), '"\\u0003"');
+assertEq(JSON.stringify("\u0004"), '"\\u0004"');
+assertEq(JSON.stringify("\u0005"), '"\\u0005"');
+assertEq(JSON.stringify("\u0006"), '"\\u0006"');
+assertEq(JSON.stringify("\u0007"), '"\\u0007"');
+assertEq(JSON.stringify("\u0008"), '"\\b"');
+assertEq(JSON.stringify("\u0009"), '"\\t"');
+assertEq(JSON.stringify("\u000A"), '"\\n"');
+assertEq(JSON.stringify("\u000B"), '"\\u000b"');
+assertEq(JSON.stringify("\u000C"), '"\\f"');
+assertEq(JSON.stringify("\u000D"), '"\\r"');
+assertEq(JSON.stringify("\u000E"), '"\\u000e"');
+assertEq(JSON.stringify("\u000F"), '"\\u000f"');
+assertEq(JSON.stringify("\u0010"), '"\\u0010"');
+assertEq(JSON.stringify("\u0011"), '"\\u0011"');
+assertEq(JSON.stringify("\u0012"), '"\\u0012"');
+assertEq(JSON.stringify("\u0013"), '"\\u0013"');
+assertEq(JSON.stringify("\u0014"), '"\\u0014"');
+assertEq(JSON.stringify("\u0015"), '"\\u0015"');
+assertEq(JSON.stringify("\u0016"), '"\\u0016"');
+assertEq(JSON.stringify("\u0017"), '"\\u0017"');
+assertEq(JSON.stringify("\u0018"), '"\\u0018"');
+assertEq(JSON.stringify("\u0019"), '"\\u0019"');
+assertEq(JSON.stringify("\u001A"), '"\\u001a"');
+assertEq(JSON.stringify("\u001B"), '"\\u001b"');
+assertEq(JSON.stringify("\u001C"), '"\\u001c"');
+assertEq(JSON.stringify("\u001D"), '"\\u001d"');
+assertEq(JSON.stringify("\u001E"), '"\\u001e"');
+assertEq(JSON.stringify("\u001F"), '"\\u001f"');
+assertEq(JSON.stringify("\u0020"), '" "');
+
+assertEq(JSON.stringify("\\u0000"), '"\\\\u0000"');
+assertEq(JSON.stringify("\\u0001"), '"\\\\u0001"');
+assertEq(JSON.stringify("\\u0002"), '"\\\\u0002"');
+assertEq(JSON.stringify("\\u0003"), '"\\\\u0003"');
+assertEq(JSON.stringify("\\u0004"), '"\\\\u0004"');
+assertEq(JSON.stringify("\\u0005"), '"\\\\u0005"');
+assertEq(JSON.stringify("\\u0006"), '"\\\\u0006"');
+assertEq(JSON.stringify("\\u0007"), '"\\\\u0007"');
+assertEq(JSON.stringify("\\u0008"), '"\\\\u0008"');
+assertEq(JSON.stringify("\\u0009"), '"\\\\u0009"');
+assertEq(JSON.stringify("\\u000A"), '"\\\\u000A"');
+assertEq(JSON.stringify("\\u000B"), '"\\\\u000B"');
+assertEq(JSON.stringify("\\u000C"), '"\\\\u000C"');
+assertEq(JSON.stringify("\\u000D"), '"\\\\u000D"');
+assertEq(JSON.stringify("\\u000E"), '"\\\\u000E"');
+assertEq(JSON.stringify("\\u000F"), '"\\\\u000F"');
+assertEq(JSON.stringify("\\u0010"), '"\\\\u0010"');
+assertEq(JSON.stringify("\\u0011"), '"\\\\u0011"');
+assertEq(JSON.stringify("\\u0012"), '"\\\\u0012"');
+assertEq(JSON.stringify("\\u0013"), '"\\\\u0013"');
+assertEq(JSON.stringify("\\u0014"), '"\\\\u0014"');
+assertEq(JSON.stringify("\\u0015"), '"\\\\u0015"');
+assertEq(JSON.stringify("\\u0016"), '"\\\\u0016"');
+assertEq(JSON.stringify("\\u0017"), '"\\\\u0017"');
+assertEq(JSON.stringify("\\u0018"), '"\\\\u0018"');
+assertEq(JSON.stringify("\\u0019"), '"\\\\u0019"');
+assertEq(JSON.stringify("\\u001A"), '"\\\\u001A"');
+assertEq(JSON.stringify("\\u001B"), '"\\\\u001B"');
+assertEq(JSON.stringify("\\u001C"), '"\\\\u001C"');
+assertEq(JSON.stringify("\\u001D"), '"\\\\u001D"');
+assertEq(JSON.stringify("\\u001E"), '"\\\\u001E"');
+assertEq(JSON.stringify("\\u001F"), '"\\\\u001F"');
+assertEq(JSON.stringify("\\u0020"), '"\\\\u0020"');
+
+
+assertEq(JSON.stringify("a\u0000"), '"a\\u0000"');
+assertEq(JSON.stringify("a\u0001"), '"a\\u0001"');
+assertEq(JSON.stringify("a\u0002"), '"a\\u0002"');
+assertEq(JSON.stringify("a\u0003"), '"a\\u0003"');
+assertEq(JSON.stringify("a\u0004"), '"a\\u0004"');
+assertEq(JSON.stringify("a\u0005"), '"a\\u0005"');
+assertEq(JSON.stringify("a\u0006"), '"a\\u0006"');
+assertEq(JSON.stringify("a\u0007"), '"a\\u0007"');
+assertEq(JSON.stringify("a\u0008"), '"a\\b"');
+assertEq(JSON.stringify("a\u0009"), '"a\\t"');
+assertEq(JSON.stringify("a\u000A"), '"a\\n"');
+assertEq(JSON.stringify("a\u000B"), '"a\\u000b"');
+assertEq(JSON.stringify("a\u000C"), '"a\\f"');
+assertEq(JSON.stringify("a\u000D"), '"a\\r"');
+assertEq(JSON.stringify("a\u000E"), '"a\\u000e"');
+assertEq(JSON.stringify("a\u000F"), '"a\\u000f"');
+assertEq(JSON.stringify("a\u0010"), '"a\\u0010"');
+assertEq(JSON.stringify("a\u0011"), '"a\\u0011"');
+assertEq(JSON.stringify("a\u0012"), '"a\\u0012"');
+assertEq(JSON.stringify("a\u0013"), '"a\\u0013"');
+assertEq(JSON.stringify("a\u0014"), '"a\\u0014"');
+assertEq(JSON.stringify("a\u0015"), '"a\\u0015"');
+assertEq(JSON.stringify("a\u0016"), '"a\\u0016"');
+assertEq(JSON.stringify("a\u0017"), '"a\\u0017"');
+assertEq(JSON.stringify("a\u0018"), '"a\\u0018"');
+assertEq(JSON.stringify("a\u0019"), '"a\\u0019"');
+assertEq(JSON.stringify("a\u001A"), '"a\\u001a"');
+assertEq(JSON.stringify("a\u001B"), '"a\\u001b"');
+assertEq(JSON.stringify("a\u001C"), '"a\\u001c"');
+assertEq(JSON.stringify("a\u001D"), '"a\\u001d"');
+assertEq(JSON.stringify("a\u001E"), '"a\\u001e"');
+assertEq(JSON.stringify("a\u001F"), '"a\\u001f"');
+assertEq(JSON.stringify("a\u0020"), '"a "');
+
+assertEq(JSON.stringify("a\\u0000"), '"a\\\\u0000"');
+assertEq(JSON.stringify("a\\u0001"), '"a\\\\u0001"');
+assertEq(JSON.stringify("a\\u0002"), '"a\\\\u0002"');
+assertEq(JSON.stringify("a\\u0003"), '"a\\\\u0003"');
+assertEq(JSON.stringify("a\\u0004"), '"a\\\\u0004"');
+assertEq(JSON.stringify("a\\u0005"), '"a\\\\u0005"');
+assertEq(JSON.stringify("a\\u0006"), '"a\\\\u0006"');
+assertEq(JSON.stringify("a\\u0007"), '"a\\\\u0007"');
+assertEq(JSON.stringify("a\\u0008"), '"a\\\\u0008"');
+assertEq(JSON.stringify("a\\u0009"), '"a\\\\u0009"');
+assertEq(JSON.stringify("a\\u000A"), '"a\\\\u000A"');
+assertEq(JSON.stringify("a\\u000B"), '"a\\\\u000B"');
+assertEq(JSON.stringify("a\\u000C"), '"a\\\\u000C"');
+assertEq(JSON.stringify("a\\u000D"), '"a\\\\u000D"');
+assertEq(JSON.stringify("a\\u000E"), '"a\\\\u000E"');
+assertEq(JSON.stringify("a\\u000F"), '"a\\\\u000F"');
+assertEq(JSON.stringify("a\\u0010"), '"a\\\\u0010"');
+assertEq(JSON.stringify("a\\u0011"), '"a\\\\u0011"');
+assertEq(JSON.stringify("a\\u0012"), '"a\\\\u0012"');
+assertEq(JSON.stringify("a\\u0013"), '"a\\\\u0013"');
+assertEq(JSON.stringify("a\\u0014"), '"a\\\\u0014"');
+assertEq(JSON.stringify("a\\u0015"), '"a\\\\u0015"');
+assertEq(JSON.stringify("a\\u0016"), '"a\\\\u0016"');
+assertEq(JSON.stringify("a\\u0017"), '"a\\\\u0017"');
+assertEq(JSON.stringify("a\\u0018"), '"a\\\\u0018"');
+assertEq(JSON.stringify("a\\u0019"), '"a\\\\u0019"');
+assertEq(JSON.stringify("a\\u001A"), '"a\\\\u001A"');
+assertEq(JSON.stringify("a\\u001B"), '"a\\\\u001B"');
+assertEq(JSON.stringify("a\\u001C"), '"a\\\\u001C"');
+assertEq(JSON.stringify("a\\u001D"), '"a\\\\u001D"');
+assertEq(JSON.stringify("a\\u001E"), '"a\\\\u001E"');
+assertEq(JSON.stringify("a\\u001F"), '"a\\\\u001F"');
+assertEq(JSON.stringify("a\\u0020"), '"a\\\\u0020"');
+
+
+assertEq(JSON.stringify("\u0000Q"), '"\\u0000Q"');
+assertEq(JSON.stringify("\u0001Q"), '"\\u0001Q"');
+assertEq(JSON.stringify("\u0002Q"), '"\\u0002Q"');
+assertEq(JSON.stringify("\u0003Q"), '"\\u0003Q"');
+assertEq(JSON.stringify("\u0004Q"), '"\\u0004Q"');
+assertEq(JSON.stringify("\u0005Q"), '"\\u0005Q"');
+assertEq(JSON.stringify("\u0006Q"), '"\\u0006Q"');
+assertEq(JSON.stringify("\u0007Q"), '"\\u0007Q"');
+assertEq(JSON.stringify("\u0008Q"), '"\\bQ"');
+assertEq(JSON.stringify("\u0009Q"), '"\\tQ"');
+assertEq(JSON.stringify("\u000AQ"), '"\\nQ"');
+assertEq(JSON.stringify("\u000BQ"), '"\\u000bQ"');
+assertEq(JSON.stringify("\u000CQ"), '"\\fQ"');
+assertEq(JSON.stringify("\u000DQ"), '"\\rQ"');
+assertEq(JSON.stringify("\u000EQ"), '"\\u000eQ"');
+assertEq(JSON.stringify("\u000FQ"), '"\\u000fQ"');
+assertEq(JSON.stringify("\u0010Q"), '"\\u0010Q"');
+assertEq(JSON.stringify("\u0011Q"), '"\\u0011Q"');
+assertEq(JSON.stringify("\u0012Q"), '"\\u0012Q"');
+assertEq(JSON.stringify("\u0013Q"), '"\\u0013Q"');
+assertEq(JSON.stringify("\u0014Q"), '"\\u0014Q"');
+assertEq(JSON.stringify("\u0015Q"), '"\\u0015Q"');
+assertEq(JSON.stringify("\u0016Q"), '"\\u0016Q"');
+assertEq(JSON.stringify("\u0017Q"), '"\\u0017Q"');
+assertEq(JSON.stringify("\u0018Q"), '"\\u0018Q"');
+assertEq(JSON.stringify("\u0019Q"), '"\\u0019Q"');
+assertEq(JSON.stringify("\u001AQ"), '"\\u001aQ"');
+assertEq(JSON.stringify("\u001BQ"), '"\\u001bQ"');
+assertEq(JSON.stringify("\u001CQ"), '"\\u001cQ"');
+assertEq(JSON.stringify("\u001DQ"), '"\\u001dQ"');
+assertEq(JSON.stringify("\u001EQ"), '"\\u001eQ"');
+assertEq(JSON.stringify("\u001FQ"), '"\\u001fQ"');
+assertEq(JSON.stringify("\u0020Q"), '" Q"');
+
+assertEq(JSON.stringify("\\u0000Q"), '"\\\\u0000Q"');
+assertEq(JSON.stringify("\\u0001Q"), '"\\\\u0001Q"');
+assertEq(JSON.stringify("\\u0002Q"), '"\\\\u0002Q"');
+assertEq(JSON.stringify("\\u0003Q"), '"\\\\u0003Q"');
+assertEq(JSON.stringify("\\u0004Q"), '"\\\\u0004Q"');
+assertEq(JSON.stringify("\\u0005Q"), '"\\\\u0005Q"');
+assertEq(JSON.stringify("\\u0006Q"), '"\\\\u0006Q"');
+assertEq(JSON.stringify("\\u0007Q"), '"\\\\u0007Q"');
+assertEq(JSON.stringify("\\u0008Q"), '"\\\\u0008Q"');
+assertEq(JSON.stringify("\\u0009Q"), '"\\\\u0009Q"');
+assertEq(JSON.stringify("\\u000AQ"), '"\\\\u000AQ"');
+assertEq(JSON.stringify("\\u000BQ"), '"\\\\u000BQ"');
+assertEq(JSON.stringify("\\u000CQ"), '"\\\\u000CQ"');
+assertEq(JSON.stringify("\\u000DQ"), '"\\\\u000DQ"');
+assertEq(JSON.stringify("\\u000EQ"), '"\\\\u000EQ"');
+assertEq(JSON.stringify("\\u000FQ"), '"\\\\u000FQ"');
+assertEq(JSON.stringify("\\u0010Q"), '"\\\\u0010Q"');
+assertEq(JSON.stringify("\\u0011Q"), '"\\\\u0011Q"');
+assertEq(JSON.stringify("\\u0012Q"), '"\\\\u0012Q"');
+assertEq(JSON.stringify("\\u0013Q"), '"\\\\u0013Q"');
+assertEq(JSON.stringify("\\u0014Q"), '"\\\\u0014Q"');
+assertEq(JSON.stringify("\\u0015Q"), '"\\\\u0015Q"');
+assertEq(JSON.stringify("\\u0016Q"), '"\\\\u0016Q"');
+assertEq(JSON.stringify("\\u0017Q"), '"\\\\u0017Q"');
+assertEq(JSON.stringify("\\u0018Q"), '"\\\\u0018Q"');
+assertEq(JSON.stringify("\\u0019Q"), '"\\\\u0019Q"');
+assertEq(JSON.stringify("\\u001AQ"), '"\\\\u001AQ"');
+assertEq(JSON.stringify("\\u001BQ"), '"\\\\u001BQ"');
+assertEq(JSON.stringify("\\u001CQ"), '"\\\\u001CQ"');
+assertEq(JSON.stringify("\\u001DQ"), '"\\\\u001DQ"');
+assertEq(JSON.stringify("\\u001EQ"), '"\\\\u001EQ"');
+assertEq(JSON.stringify("\\u001FQ"), '"\\\\u001FQ"');
+assertEq(JSON.stringify("\\u0020Q"), '"\\\\u0020Q"');
+
+// https://tc39.github.io/proposal-well-formed-stringify/
+
+assertEq(JSON.stringify("\ud7ff"), '"\ud7ff"');
+assertEq(JSON.stringify("\ud800"), '"\\ud800"');
+assertEq(JSON.stringify("\ud937"), '"\\ud937"');
+assertEq(JSON.stringify("\uda20"), '"\\uda20"');
+assertEq(JSON.stringify("\udbff"), '"\\udbff"');
+
+assertEq(JSON.stringify("\udc00"), '"\\udc00"');
+assertEq(JSON.stringify("\udddd"), '"\\udddd"');
+assertEq(JSON.stringify("\udeaf"), '"\\udeaf"');
+assertEq(JSON.stringify("\udfff"), '"\\udfff"');
+assertEq(JSON.stringify("\ue000"), '"\ue000"');
+
+assertEq(JSON.stringify("\ud7ffa"), '"\ud7ffa"');
+assertEq(JSON.stringify("\ud800a"), '"\\ud800a"');
+assertEq(JSON.stringify("\ud937a"), '"\\ud937a"');
+assertEq(JSON.stringify("\uda20a"), '"\\uda20a"');
+assertEq(JSON.stringify("\udbffa"), '"\\udbffa"');
+
+assertEq(JSON.stringify("\udc00a"), '"\\udc00a"');
+assertEq(JSON.stringify("\udddda"), '"\\udddda"');
+assertEq(JSON.stringify("\udeafa"), '"\\udeafa"');
+assertEq(JSON.stringify("\udfffa"), '"\\udfffa"');
+assertEq(JSON.stringify("\ue000a"), '"\ue000a"');
+
+assertEq(JSON.stringify("\ud7ff\ud800"), '"\ud7ff\\ud800"');
+assertEq(JSON.stringify("\ud800\ud800"), '"\\ud800\\ud800"');
+assertEq(JSON.stringify("\ud937\ud800"), '"\\ud937\\ud800"');
+assertEq(JSON.stringify("\uda20\ud800"), '"\\uda20\\ud800"');
+assertEq(JSON.stringify("\udbff\ud800"), '"\\udbff\\ud800"');
+
+assertEq(JSON.stringify("\udc00\ud800"), '"\\udc00\\ud800"');
+assertEq(JSON.stringify("\udddd\ud800"), '"\\udddd\\ud800"');
+assertEq(JSON.stringify("\udeaf\ud800"), '"\\udeaf\\ud800"');
+assertEq(JSON.stringify("\udfff\ud800"), '"\\udfff\\ud800"');
+assertEq(JSON.stringify("\ue000\ud800"), '"\ue000\\ud800"');
+
+assertEq(JSON.stringify("\ud7ff\udc00"), '"\ud7ff\\udc00"');
+assertEq(JSON.stringify("\ud800\udc00"), '"\ud800\udc00"');
+assertEq(JSON.stringify("\ud937\udc00"), '"\ud937\udc00"');
+assertEq(JSON.stringify("\uda20\udc00"), '"\uda20\udc00"');
+assertEq(JSON.stringify("\udbff\udc00"), '"\udbff\udc00"');
+
+assertEq(JSON.stringify("\udc00\udc00"), '"\\udc00\\udc00"');
+assertEq(JSON.stringify("\udddd\udc00"), '"\\udddd\\udc00"');
+assertEq(JSON.stringify("\udeaf\udc00"), '"\\udeaf\\udc00"');
+assertEq(JSON.stringify("\udfff\udc00"), '"\\udfff\\udc00"');
+assertEq(JSON.stringify("\ue000\udc00"), '"\ue000\\udc00"');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify-toJSON-arguments.js b/js/src/tests/non262/JSON/stringify-toJSON-arguments.js
new file mode 100644
index 0000000000..7c2013d588
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify-toJSON-arguments.js
@@ -0,0 +1,34 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'stringify-toJSON-arguments.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 584909;
+var summary = "Arguments when an object's toJSON method is called";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+var obj =
+ {
+ p: {
+ toJSON: function(key)
+ {
+ assertEq(arguments.length, 1);
+ assertEq(key, "p");
+ return 17;
+ }
+ }
+ };
+
+assertEq(JSON.stringify(obj), '{"p":17}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/stringify.js b/js/src/tests/non262/JSON/stringify.js
new file mode 100644
index 0000000000..3b21474206
--- /dev/null
+++ b/js/src/tests/non262/JSON/stringify.js
@@ -0,0 +1,87 @@
+function assertStringify(v, expect)
+{
+ assertEq(JSON.stringify(v), expect);
+}
+
+assertStringify({}, "{}");
+assertStringify([], "[]");
+assertStringify({"foo":"bar"}, '{"foo":"bar"}');
+assertStringify({"null":null}, '{"null":null}');
+assertStringify({"five":5}, '{"five":5}');
+assertStringify({"five":5, "six":6}, '{"five":5,"six":6}');
+assertStringify({"x":{"y":"z"}}, '{"x":{"y":"z"}}');
+assertStringify({"w":{"x":{"y":"z"}}}, '{"w":{"x":{"y":"z"}}}');
+assertStringify([1,2,3], '[1,2,3]');
+assertStringify({"w":{"x":{"y":[1,2,3]}}}, '{"w":{"x":{"y":[1,2,3]}}}');
+assertStringify({"false":false}, '{"false":false}');
+assertStringify({"true":true}, '{"true":true}');
+assertStringify({"child has two members": {"this":"one", 2:"and this one"}},
+ '{"child has two members":{"2":"and this one","this":"one"}}');
+assertStringify({"x":{"a":"b","c":{"y":"z"},"f":"g"}},
+ '{"x":{"a":"b","c":{"y":"z"},"f":"g"}}');
+assertStringify({"x":[1,{"y":"z"},3]}, '{"x":[1,{"y":"z"},3]}');
+assertStringify([new String("hmm")], '["hmm"]');
+assertStringify([new Boolean(true)], '[true]');
+assertStringify([new Number(42)], '[42]');
+assertStringify([new Date(Date.UTC(1978, 8, 13, 12, 24, 34, 23))],
+ '["1978-09-13T12:24:34.023Z"]');
+assertStringify([1,,3], '[1,null,3]');
+assertStringify({"mm\"mm":"hmm"}, '{"mm\\\"mm":"hmm"}');
+assertStringify({"mm\"mm\"mm":"hmm"}, '{"mm\\\"mm\\\"mm":"hmm"}');
+assertStringify({'"':"hmm"}, '{"\\\"":"hmm"}');
+assertStringify({'\\':"hmm"}, '{"\\\\":"hmm"}');
+assertStringify({'mmm\\mmm':"hmm"}, '{"mmm\\\\mmm":"hmm"}');
+assertStringify({'mmm\\mmm\\mmm':"hmm"}, '{"mmm\\\\mmm\\\\mmm":"hmm"}');
+assertStringify({"mm\u000bmm":"hmm"}, '{"mm\\u000bmm":"hmm"}');
+assertStringify({"mm\u0000mm":"hmm"}, '{"mm\\u0000mm":"hmm"}');
+assertStringify({"\u0000\u000b":""}, '{"\\u0000\\u000b":""}');
+assertStringify({"\u000b\ufdfd":"hmm"}, '{"\\u000b\ufdfd":"hmm"}');
+assertStringify({"\u000b\ufdfd":"h\xfc\ufdfdm"}, '{"\\u000b\ufdfd":"h\xfc\ufdfdm"}');
+
+var x = {"free":"variable"};
+assertStringify(x, '{"free":"variable"}');
+assertStringify({"y":x}, '{"y":{"free":"variable"}}');
+
+// array prop
+assertStringify({ a: [1,2,3] }, '{"a":[1,2,3]}');
+
+assertStringify({"y": { foo: function(hmm) { return hmm; } } }, '{"y":{}}');
+
+// test toJSON
+var hmm = { toJSON: function() { return {"foo":"bar"} } };
+assertStringify({"hmm":hmm}, '{"hmm":{"foo":"bar"}}');
+assertStringify(hmm, '{"foo":"bar"}'); // on the root
+
+// toJSON on prototype
+var Y = function() {
+ this.not = "there?";
+ this.d = "e";
+};
+Y.prototype = {
+ not: "there?",
+ toJSON: function() { return {"foo":"bar"}}
+};
+var y = new Y();
+assertStringify(y.toJSON(), '{"foo":"bar"}');
+assertStringify(y, '{"foo":"bar"}');
+
+// return undefined from toJSON
+assertStringify({"hmm": { toJSON: function() { return; } } }, '{}');
+
+// array with named prop
+var x = new Array();
+x[0] = 1;
+x.foo = "bar";
+assertStringify(x, '[1]');
+
+// prototype
+var X = function() { this.a = "b" };
+X.prototype = { c: "d" };
+assertStringify(new X(), '{"a":"b"}');
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
diff --git a/js/src/tests/non262/JSON/trailing-comma.js b/js/src/tests/non262/JSON/trailing-comma.js
new file mode 100644
index 0000000000..0dc20e71a0
--- /dev/null
+++ b/js/src/tests/non262/JSON/trailing-comma.js
@@ -0,0 +1,32 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+var gTestfile = 'trailing-comma.js';
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 564621;
+var summary = 'JSON.parse should reject {"a" : "b",} or [1,]';
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+testJSON('[]', false);
+testJSON('[1]', false);
+testJSON('["a"]', false);
+testJSON('{}', false);
+testJSON('{"a":1}', false);
+testJSON('{"a":"b"}', false);
+testJSON('{"a":true}', false);
+testJSON('[{}]', false);
+
+testJSON('[1,]', true);
+testJSON('["a",]', true);
+testJSON('{,}', true);
+testJSON('{"a":1,}', true);
+testJSON('{"a":"b",}', true);
+testJSON('{"a":true,}', true);
+testJSON('[{,}]', true);
+testJSON('[[1,]]', true);
+testJSON('[{"a":"b",}]', true);