summaryrefslogtreecommitdiffstats
path: root/LayoutTests/fast/js
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-02-25 10:58:37 +0000
committerSteve Block <steveblock@google.com>2010-02-25 11:17:52 +0000
commitcfb0617749a64f2e177386b030d46007b8c4b179 (patch)
tree033b0b4e1b1eaa96831b52fc1ec6675132f33035 /LayoutTests/fast/js
parent4175d59b46f96005f0c64978b1a94e3fe60f1e8e (diff)
downloadexternal_webkit-cfb0617749a64f2e177386b030d46007b8c4b179.zip
external_webkit-cfb0617749a64f2e177386b030d46007b8c4b179.tar.gz
external_webkit-cfb0617749a64f2e177386b030d46007b8c4b179.tar.bz2
Adds layout tests for HTML5 features
The following layout tests should all pass on Android, as they are for recently implemented HTML5 features ... - fast/dom/Geolocation - storage - http/tests/appcache This change adds these tests to the Android tree, at the current WebKit revision r54731. This is so that we can easily keep track of which tests should always be green, and so that we can add Android-specific test results. We also add the following paths ... - fast/js/resources - used by the Geolocation tests - http/conf - used by the Appcache tests Tests that are currently failing are added to the DumpRenderTree skipped list temporarily, to keep all tests green. Change-Id: Id96c05e3746ed64e4e4c40c99567b8def688f90a
Diffstat (limited to 'LayoutTests/fast/js')
-rw-r--r--LayoutTests/fast/js/resources/JSON-parse.js576
-rw-r--r--LayoutTests/fast/js/resources/JSON-stringify.js508
-rw-r--r--LayoutTests/fast/js/resources/bom-in-file-retains-correct-offset.js2
-rw-r--r--LayoutTests/fast/js/resources/codegen-temporaries-multiple-global-blocks-1.js47
-rw-r--r--LayoutTests/fast/js/resources/codegen-temporaries-multiple-global-blocks-2.js43
-rw-r--r--LayoutTests/fast/js/resources/const.js120
-rw-r--r--LayoutTests/fast/js/resources/garbage-collect-after-string-appends.js-disabled39
-rw-r--r--LayoutTests/fast/js/resources/getOwnPropertyDescriptor.js95
-rw-r--r--LayoutTests/fast/js/resources/instanceof-operator-dummy-worker.js1
-rw-r--r--LayoutTests/fast/js/resources/js-test-post-function.js5
-rw-r--r--LayoutTests/fast/js/resources/js-test-post-n.js2
-rw-r--r--LayoutTests/fast/js/resources/js-test-post.js2
-rw-r--r--LayoutTests/fast/js/resources/js-test-pre.js256
-rw-r--r--LayoutTests/fast/js/resources/js-test-style.css12
-rw-r--r--LayoutTests/fast/js/resources/json2-es5-compat.js477
-rw-r--r--LayoutTests/fast/js/resources/lexical-lookup-in-function-constructor-child.html10
-rw-r--r--LayoutTests/fast/js/resources/select-options-remove.js232
-rw-r--r--LayoutTests/fast/js/resources/standalone-post.js2
-rw-r--r--LayoutTests/fast/js/resources/standalone-pre.js141
-rw-r--r--LayoutTests/fast/js/resources/string-concatenate-outofmemory.js52
20 files changed, 2622 insertions, 0 deletions
diff --git a/LayoutTests/fast/js/resources/JSON-parse.js b/LayoutTests/fast/js/resources/JSON-parse.js
new file mode 100644
index 0000000..b78df25
--- /dev/null
+++ b/LayoutTests/fast/js/resources/JSON-parse.js
@@ -0,0 +1,576 @@
+
+function createTests() {
+ var result = [];
+ result.push(function(jsonObject){
+ return jsonObject.parse();
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('1');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('-1');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('Infinity');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('NaN');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('null');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('undefined');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{}');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('({})');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{a}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{a:}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{a:5}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{a:5,}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{"a"}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{"a":}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{"a":5}');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('{"__proto__":5}');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('{"a":5,}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{"a":5,,}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{"a":5,"a",}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{"a":(5,"a"),}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('[]');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('[1]');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('[1,]');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('[1,2]');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('[1,2,,]');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('[1,2,,4]');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('""');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"\'"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\"');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\z"');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\\z"');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\\\z"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\tz"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\tz"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\nz"');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\nz"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\rz"');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\rz"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\/z"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\/z"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\bz"');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\bz"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\rz"');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\rz"');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\uz" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u0z" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u00z" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u000z" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u0000z" ');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u000Az" ');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u000az" ');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u000Gz" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u000gz" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u00A0z" ');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u00a0z" ');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u00G0z" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u00g0z" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u0A00z" ');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u0a00z" ');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u0G00z" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\u0g00z" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\uA000z" ');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\ua000z" ');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\uG000z" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a\\ug000z" ');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('00');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('01');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('0.a');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('0x0');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('2e1.3');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('2e-+10');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('2e+-10');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('2e3e4');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('-01.0');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('-01');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('-01.a');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('1.e1');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{/* block comments are not allowed */}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('{// line comments are not allowed \n}');
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.parse('true');
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('false');
+ });
+ var simpleArray = ['a', 'b', 'c'];
+ var simpleObject = {a:"1", b:"2", c:"3"};
+ var complexArray = ['a', 'b', 'c',,,simpleObject, simpleArray, [simpleObject,simpleArray]];
+ var complexObject = {a:"1", b:"2", c:"3", d:4.5e10, g: 0.45e-5, h: 0.0, i: 0, j:.5, k:0., l:-0, m:-0.0, n:-0., o:-.5, p:-0.45e-10, q:-4.5e10, e:null, "":12, f: simpleArray, array: complexArray};
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(simpleObject));
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObject);
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject));
+ });
+ result[result.length - 1].expected = JSON.stringify(complexObject);
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(simpleObject,null,100));
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObject);
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject,null,100));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject,null,100));
+ });
+ result[result.length - 1].expected = JSON.stringify(complexObject);
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(simpleObject,null," "));
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObject);
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject,null," "));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject,null," "));
+ });
+ result[result.length - 1].expected = JSON.stringify(complexObject);
+
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(simpleObject,null,"\t"));
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObject);
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject,null,"\t"));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject,null,"\t"));
+ });
+ result[result.length - 1].expected = JSON.stringify(complexObject);
+
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(simpleObject,null,"\n"));
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObject);
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject,null,"\n"));
+ });
+ result[result.length - 1].expected = JSON.stringify(complexObject);
+ function log(key, value) {
+ var o = {};
+ o[key] = value;
+ o.keyType = typeof key;
+ return o;
+ }
+ result.push(function(jsonObject){
+ return jsonObject.parse("true", log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse("false", log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse("null", log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse("1", log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse("1.5", log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('"a string"', log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(simpleArray), log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexArray), log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(simpleObject), log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(complexObject), log);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.parse('{"__proto__":{"a":5}}', log);
+ });
+ var logOrderString;
+ function logOrder(key, value) {
+ logOrderString += key +":"+JSON.stringify(value);
+ return null;
+ }
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse("true", logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse("false", logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse("null", logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse("1", logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse("1.5", logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse('"a string"', logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse(JSON.stringify(simpleArray), logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse(JSON.stringify(complexArray), logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse(JSON.stringify(simpleObject), logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ return jsonObject.parse(JSON.stringify(complexObject), logOrder);
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse("true", logOrder);
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse("false", logOrder);
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse("null", logOrder);
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse("1", logOrder);
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse("1.5", logOrder);
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse('"a string"', logOrder);
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse(JSON.stringify(simpleArray), logOrder);
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse(JSON.stringify(complexArray), logOrder);
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse(JSON.stringify(simpleObject), logOrder);
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ logOrderString = "";
+ jsonObject.parse(JSON.stringify(complexObject), logOrder);
+ return logOrderString;
+ });
+ var callCount = 0;
+ function throwAfterFifthCall(key, value) {
+ logOrder(key, value);
+ if (++callCount > 5)
+ throw "from reviver";
+ return null;
+ }
+ result.push(function(jsonObject){
+ callCount = 0;
+ logOrderString = "";
+ return jsonObject.parse(JSON.stringify(complexArray), throwAfterFifthCall);
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ callCount = 0;
+ logOrderString = "";
+ return jsonObject.parse(JSON.stringify(simpleObject), throwAfterFifthCall);
+ });
+ result.push(function(jsonObject){
+ callCount = 0;
+ logOrderString = "";
+ return jsonObject.parse(JSON.stringify(complexObject), throwAfterFifthCall);
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ callCount = 0;
+ logOrderString = "";
+ try { jsonObject.parse(JSON.stringify(complexArray), throwAfterFifthCall); } catch (e) {}
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ callCount = 0;
+ logOrderString = "";
+ try { jsonObject.parse(JSON.stringify(simpleObject), throwAfterFifthCall); } catch (e) {}
+ return logOrderString;
+ });
+ result.push(function(jsonObject){
+ callCount = 0;
+ logOrderString = "";
+ try { jsonObject.parse(JSON.stringify(complexObject), throwAfterFifthCall); } catch (e) {}
+ return logOrderString;
+ });
+ var unicode = "";
+ for (var i = 0; i < 1<<16; i++)
+ unicode += String.fromCharCode(i);
+ result.push(function(jsonObject){
+ return jsonObject.parse(JSON.stringify(unicode));
+ });
+ result[result.length - 1].unstringifiedExpected = unicode;
+ return result;
+}
+var tests = createTests();
+for (var i = 0; i < tests.length; i++) {
+ try {
+ debug(tests[i]);
+ if (tests[i].throws) {
+ shouldThrow('tests[i](nativeJSON)');
+ try {
+ var threw = false;
+ tests[i](JSON);
+ } catch(e) {
+ var threw = true;
+ }
+ if (!threw)
+ debug("json2.js did not throw for a test we expect to throw.");
+ } else if (tests[i].expected)
+ try { shouldBe('JSON.stringify(tests[i](nativeJSON))', "tests[i].expected") } catch(e) { debug("threw - " + e)}
+ else if (tests[i].unstringifiedExpected)
+ try { shouldBe('tests[i](nativeJSON)', "tests[i].unstringifiedExpected") } catch(e) { debug("threw - " + e)}
+ else
+ try { shouldBe('JSON.stringify(tests[i](nativeJSON))', 'JSON.stringify(tests[i](JSON))') } catch(e) { debug("threw - " + e) };
+ }catch(e){
+ debug(e);
+ }
+}
+successfullyParsed = true;
+
diff --git a/LayoutTests/fast/js/resources/JSON-stringify.js b/LayoutTests/fast/js/resources/JSON-stringify.js
new file mode 100644
index 0000000..d58b5fe
--- /dev/null
+++ b/LayoutTests/fast/js/resources/JSON-stringify.js
@@ -0,0 +1,508 @@
+
+function createTests() {
+ var simpleArray = ['a', 'b', 'c'];
+ var simpleObject = {a:"1", b:"2", c:"3"};
+ var complexArray = ['a', 'b', 'c',,,simpleObject, simpleArray, [simpleObject,simpleArray]];
+ var complexObject = {a:"1", b:"2", c:"3", d:undefined, e:null, "":12, get f(){ return simpleArray; }, array: complexArray};
+ var simpleArrayWithProto = ['d', 'e', 'f'];
+ simpleArrayWithProto.__proto__ = simpleObject;
+ var simpleObjectWithProto = {d:"4", e:"5", f:"6", __proto__:simpleObject};
+ var complexArrayWithProto = ['d', 'e', 'f',,,simpleObjectWithProto, simpleArrayWithProto, [simpleObjectWithProto,simpleArrayWithProto]];
+ complexArrayWithProto.__proto__ = simpleObjectWithProto;
+ var complexObjectWithProto = {d:"4", e:"5", f:"6", g:undefined, h:null, "":12, get i(){ return simpleArrayWithProto; }, array2: complexArrayWithProto, __proto__:complexObject};
+ var objectWithSideEffectGetter = {get b() {this.foo=1;}};
+ var objectWithSideEffectGetterAndProto = {__proto__:{foo:"bar"}, get b() {this.foo=1;}};
+ var arrayWithSideEffectGetter = [];
+ arrayWithSideEffectGetter.__defineGetter__("b", function(){this.foo=1;});
+ var arrayWithSideEffectGetterAndProto = [];
+ arrayWithSideEffectGetterAndProto.__defineGetter__("b", function(){this.foo=1;});
+ arrayWithSideEffectGetterAndProto.__proto__ = {foo:"bar"};
+ var result = [];
+ result.push(function(jsonObject){
+ return jsonObject.stringify(1);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(1.5);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(-1);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(-1.5);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(null);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify("string");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(new Number(0));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(new Number(1));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(new Number(1.5));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(new Number(-1));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(new Number(-1.5));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(new String("a string object"));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(new Boolean(true));
+ });
+ result.push(function(jsonObject){
+ var value = new Number(1);
+ value.valueOf = function() { return 2; }
+ return jsonObject.stringify(value);
+ });
+ result[result.length - 1].expected = '2';
+ result.push(function(jsonObject){
+ var value = new Boolean(true);
+ value.valueOf = function() { return 2; }
+ return jsonObject.stringify(value);
+ });
+ result[result.length - 1].expected = '2';
+ result.push(function(jsonObject){
+ var value = new String("fail");
+ value.toString = function() { return "converted string"; }
+ return jsonObject.stringify(value);
+ });
+ result[result.length - 1].expected = '"converted string"';
+ result.push(function(jsonObject){
+ return jsonObject.stringify(true);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(false);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(new Date(0));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({toJSON: Date.prototype.toJSON});
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.stringify({toJSON: Date.prototype.toJSON, toISOString: function(){ return "custom toISOString"; }});
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({toJSON: Date.prototype.toJSON, toISOString: function(){ return {}; }});
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ return jsonObject.stringify({toJSON: Date.prototype.toJSON, toISOString: function(){ throw "An exception"; }});
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ var d = new Date(0);
+ d.toISOString = null;
+ return jsonObject.stringify(d);
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ var d = new Date(0);
+ d.toJSON = undefined;
+ return jsonObject.stringify(d);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({get Foo() { return "bar"; }});
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({get Foo() { this.foo="wibble"; return "bar"; }});
+ });
+ result.push(function(jsonObject){
+ var count = 0;
+ jsonObject.stringify({get Foo() { count++; return "bar"; }});
+ return count;
+ });
+ result.push(function(jsonObject){
+ var count = 0;
+ return jsonObject.stringify({get Foo() { count++; delete this.bar; return "bar"; }, bar: "wibble"});
+ });
+ result.push(function(jsonObject){
+ var count = 0;
+ return jsonObject.stringify({a:"1", b:"2", c:"3", 5:4, 4:5, 2:6, 1:7});
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ jsonObject.stringify({a:"1", b:"2", c:"3", 5:4, 4:5, 2:6, 1:7}, function(k,v){allString = allString && (typeof k == "string"); return v});
+ return allString;
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ jsonObject.stringify([1,2,3,4,5], function(k,v){allString = allString && (typeof k == "string"); return v});
+ return allString;
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ var array = [];
+ return jsonObject.stringify({a:"1", b:"2", c:"3", 5:4, 4:5, 2:6, 1:7}, array);
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ var array = ["a"];
+ return jsonObject.stringify({get a(){return 1;array[1]="b";array[2]="c"}, b:"2", c:"3"}, array);
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ var array = [{toString:function(){array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}];
+ return jsonObject.stringify(simpleObject, array);
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ var array = [{toString:function(){array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}];
+ return jsonObject.stringify(simpleObjectWithProto, array);
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ var array = [1, new Number(2), NaN, Infinity, -Infinity, new String("str")];
+ return jsonObject.stringify({"1":"1","2":"2","NaN":"NaN","Infinity":"Infinity","-Infinity":"-Infinity","str":"str"}, array);
+ });
+ result[result.length - 1].expected = '{"1":"1","2":"2","NaN":"NaN","Infinity":"Infinity","-Infinity":"-Infinity","str":"str"}';
+ result.push(function(jsonObject){
+ var allString = true;
+ var array = ["1","2","3"];
+ return jsonObject.stringify({1:'a', 2:'b', 3:'c'}, array);
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ var array = ["1","2","3"];
+ return jsonObject.stringify(simpleArray, array);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleArray, null, " ");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleArray, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleArray, null, "ab");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleArray, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObject, null, " ");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObject, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObject, null, "ab");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObject, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObject, null, 10);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObject, null, 11);
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObject, null, 10);
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObject, null, " ");
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObject, null, 10);
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObject, null, " ");
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObject, null, 10);
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexArray, null, " ");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexArray, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexArray, null, "ab");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexArray, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexObject, null, " ");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexObject, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexObject, null, "ab");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexObject, null, 4);
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ var array = ["1","2","3"];
+ return jsonObject.stringify(simpleArrayWithProto, array);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleArrayWithProto, null, " ");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleArrayWithProto, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleArrayWithProto, null, "ab");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleArrayWithProto, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObjectWithProto, null, " ");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObjectWithProto, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObjectWithProto, null, "ab");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObjectWithProto, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObjectWithProto, null, 10);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObjectWithProto, null, 11);
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObjectWithProto, null, 10);
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObjectWithProto, null, " ");
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObjectWithProto, null, 10);
+ result.push(function(jsonObject){
+ return jsonObject.stringify(simpleObjectWithProto, null, " ");
+ });
+ result[result.length - 1].expected = JSON.stringify(simpleObjectWithProto, null, 10);
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexArrayWithProto, null, " ");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexArrayWithProto, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexArrayWithProto, null, "ab");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexArrayWithProto, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexObjectWithProto, null, " ");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexObjectWithProto, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexObjectWithProto, null, "ab");
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(complexObjectWithProto, null, 4);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(objectWithSideEffectGetter);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(objectWithSideEffectGetterAndProto);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(arrayWithSideEffectGetter);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(arrayWithSideEffectGetterAndProto);
+ });
+ var replaceTracker;
+ function replaceFunc(key, value) {
+ replaceTracker += key + "("+(typeof key)+")" + JSON.stringify(value) + ";";
+ return value;
+ }
+ result.push(function(jsonObject){
+ replaceTracker = "";
+ jsonObject.stringify([1,2,3,,,,4,5,6], replaceFunc);
+ return replaceTracker;
+ });
+ result[result.length - 1].expected = '(string)[1,2,3,null,null,null,4,5,6];0(number)1;1(number)2;2(number)3;3(number)undefined;4(number)undefined;5(number)undefined;6(number)4;7(number)5;8(number)6;'
+ result.push(function(jsonObject){
+ replaceTracker = "";
+ jsonObject.stringify({a:"a", b:"b", c:"c", 3: "d", 2: "e", 1: "f"}, replaceFunc);
+ return replaceTracker;
+ });
+ result[result.length - 1].expected = '(string){"a":"a","b":"b","c":"c","3":"d","2":"e","1":"f"};a(string)"a";b(string)"b";c(string)"c";3(string)"d";2(string)"e";1(string)"f";';
+ result.push(function(jsonObject){
+ var count = 0;
+ var array = [{toString:function(){count++; array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}];
+ jsonObject.stringify(simpleObject, array);
+ return count;
+ });
+ result.push(function(jsonObject){
+ var allString = true;
+ var array = [{toString:function(){array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}, 'b', 'c'];
+ return jsonObject.stringify(simpleObject, array);
+ });
+ result.push(function(jsonObject){
+ var count = 0;
+ var array = [{toString:function(){count++; array[0]='a'; array[1]='c'; array[2]='b'; return 'a'}}, 'b', 'c'];
+ jsonObject.stringify(simpleObject, array);
+ return count;
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({a:"1", get b() { this.a="foo"; return "getter"; }, c:"3"});
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({a:"1", get b() { this.c="foo"; return "getter"; }, c:"3"});
+ });
+ result.push(function(jsonObject){
+ var setterCalled = false;
+ jsonObject.stringify({a:"1", set b(s) { setterCalled = true; return "setter"; }, c:"3"});
+ return setterCalled;
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({a:"1", get b(){ return "getter"; }, set b(s) { return "setter"; }, c:"3"});
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(new Array(10));
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify([undefined,,null,0,false]);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({p1:undefined,p2:null,p3:0,p4:false});
+ });
+ var cycleTracker = "";
+ var cyclicObject = { get preSelf1() { cycleTracker+="preSelf1,"; return "preSelf1"; },
+ preSelf2: {toJSON:function(){cycleTracker+="preSelf2,"; return "preSelf2"}},
+ self: [],
+ get postSelf1() { cycleTracker+="postSelf1,"; return "postSelf1" },
+ postSelf2: {toJSON:function(){cycleTracker+="postSelf2,"; return "postSelf2"}},
+ toJSON : function(key) { cycleTracker += key + "("+(typeof key)+"):" + this; return this; }
+ };
+ cyclicObject.self = cyclicObject;
+ result.push(function(jsonObject){
+ cycleTracker = "";
+ return jsonObject.stringify(cyclicObject);
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ cycleTracker = "";
+ try { jsonObject.stringify(cyclicObject); } catch(e) { cycleTracker += " -> exception" }
+ return cycleTracker;
+ });
+ result[result.length - 1].expected = "(string):[object Object]preSelf1,preSelf2,self(string):[object Object] -> exception"
+ var cyclicArray = [{toJSON : function(key,value) { cycleTracker += key + "("+(typeof key)+"):" + this; cycleTracker += "first,"; return this; }},
+ cyclicArray,
+ {toJSON : function(key,value) { cycleTracker += key + "("+(typeof key)+"):" + this; cycleTracker += "second,"; return this; }}];
+ cyclicArray[1] = cyclicArray;
+ result.push(function(jsonObject){
+ cycleTracker = "";
+ return jsonObject.stringify(cyclicArray);
+ });
+ result[result.length - 1].throws = true;
+ result.push(function(jsonObject){
+ cycleTracker = "";
+ try { jsonObject.stringify(cyclicArray); } catch(e) { cycleTracker += " -> exception" }
+ return cycleTracker;
+ });
+ result[result.length - 1].expected = "0(number):[object Object]first, -> exception";
+ function createArray(len, o) { var r = []; for (var i = 0; i < len; i++) r[i] = o; return r; }
+ var getterCalls;
+ var magicObject = createArray(10, {abcdefg: [1,2,5,"ab", null, undefined, true, false,,],
+ get calls() {return ++getterCalls; },
+ "123":createArray(15, "foo"),
+ "":{a:"b"}});
+ result.push(function(jsonObject){
+ getterCalls = 0;
+ return jsonObject.stringify(magicObject) + " :: getter calls = " + getterCalls;
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(undefined);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify(null);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({toJSON:function(){ return undefined; }});
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({toJSON:function(){ return null; }});
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify([{toJSON:function(){ return undefined; }}]);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify([{toJSON:function(){ return null; }}]);
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({a:{toJSON:function(){ return undefined; }}});
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({a:{toJSON:function(){ return null; }}});
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({a:{toJSON:function(){ return function(){}; }}});
+ });
+ result.push(function(jsonObject){
+ return jsonObject.stringify({a:function(){}});
+ });
+ result.push(function(jsonObject){
+ var deepObject = {};
+ for (var i = 0; i < 2048; i++)
+ deepObject = {next:deepObject};
+ return jsonObject.stringify(deepObject);
+ });
+ result.push(function(jsonObject){
+ var deepArray = [];
+ for (var i = 0; i < 2048; i++)
+ deepArray = [deepArray];
+ return jsonObject.stringify(deepArray);
+ });
+ result.push(function(jsonObject){
+ var depth = 0;
+ function toDeepVirtualJSONObject() {
+ if (++depth >= 2048)
+ return {};
+ var r = {};
+ r.toJSON = toDeepVirtualJSONObject;
+ return {recurse: r};
+ }
+ return jsonObject.stringify(toDeepVirtualJSONObject());
+ });
+ result.push(function(jsonObject){
+ var depth = 0;
+ function toDeepVirtualJSONArray() {
+ if (++depth >= 2048)
+ return [];
+ var r = [];
+ r.toJSON = toDeepJSONArray;
+ return [r];
+ }
+ return jsonObject.stringify(toDeepVirtualJSONArray());
+ });
+ var fullCharsetString = "";
+ for (var i = 0; i < 65536; i++)
+ fullCharsetString += String.fromCharCode(i);
+ result.push(function(jsonObject){
+ return jsonObject.stringify(fullCharsetString);
+ });
+ return result;
+}
+var tests = createTests();
+for (var i = 0; i < tests.length; i++) {
+ try {
+ debug(tests[i]);
+ if (tests[i].throws)
+ shouldThrow('tests[i](nativeJSON)');
+ else if (tests[i].expected)
+ shouldBe('tests[i](nativeJSON)', "tests[i].expected");
+ else
+ shouldBe('tests[i](nativeJSON)', "tests[i](JSON)");
+ }catch(e){}
+}
+successfullyParsed = true;
+
diff --git a/LayoutTests/fast/js/resources/bom-in-file-retains-correct-offset.js b/LayoutTests/fast/js/resources/bom-in-file-retains-correct-offset.js
new file mode 100644
index 0000000..b62a250
--- /dev/null
+++ b/LayoutTests/fast/js/resources/bom-in-file-retains-correct-offset.js
@@ -0,0 +1,2 @@
+description("This ensures that BOM's scattered through a source file do not break parsing");
+function f(){successfullyReparsed=true;shouldBeTrue('successfullyReparsed');successfullyParsed=true}f();
diff --git a/LayoutTests/fast/js/resources/codegen-temporaries-multiple-global-blocks-1.js b/LayoutTests/fast/js/resources/codegen-temporaries-multiple-global-blocks-1.js
new file mode 100644
index 0000000..2871af3
--- /dev/null
+++ b/LayoutTests/fast/js/resources/codegen-temporaries-multiple-global-blocks-1.js
@@ -0,0 +1,47 @@
+function assign1()
+{
+ v1 = 0;
+ return 1;
+}
+
+function assign2()
+{
+ v2 = { a: 0 };
+ return 2;
+}
+
+function assign3()
+{
+ v3 = { a: 0 };
+ return 1;
+}
+
+function assign4()
+{
+ v4 = { a: 0 };
+ return "a";
+}
+
+function assign5()
+{
+ v5 = { a: 0 };
+ return "a";
+}
+
+function assign6()
+{
+ v6 = { a: 0 };
+ return 2;
+}
+
+function assign7()
+{
+ v7 = { a: 0 };
+ return "a";
+}
+
+function assign8()
+{
+ v8 = { a: 0 };
+ return 1;
+}
diff --git a/LayoutTests/fast/js/resources/codegen-temporaries-multiple-global-blocks-2.js b/LayoutTests/fast/js/resources/codegen-temporaries-multiple-global-blocks-2.js
new file mode 100644
index 0000000..bc92860
--- /dev/null
+++ b/LayoutTests/fast/js/resources/codegen-temporaries-multiple-global-blocks-2.js
@@ -0,0 +1,43 @@
+description(
+'Tests whether bytecode codegen properly handles temporaries across multiple global blocks.'
+);
+
+var v1 = 1;
+v1 += assign1();
+shouldBe("v1", "2");
+
+var o2 = { a: 1 };
+var v2 = o2;
+v2.a = assign2();
+shouldBe("o2.a", "2");
+
+var o3 = { a: 1 };
+var v3 = o3;
+v3.a += assign3();
+shouldBe("o3.a", "2");
+
+var v4 = { a: 1 };
+var r4 = v4[assign4()];
+shouldBe("r4", "1");
+
+var o5 = { a: 1 };
+var v5 = o5;
+v5[assign5()] = 2;
+shouldBe("o5.a", "2");
+
+var o6 = { a: 1 };
+var v6 = o6;
+v6["a"] = assign6();
+shouldBe("o6.a", "2");
+
+var o7 = { a: 1 };
+var v7 = o7;
+v7[assign7()] += 1;
+shouldBe("o7.a", "2");
+
+var o8 = { a: 1 };
+var v8 = o8;
+v8["a"] += assign8();
+shouldBe("o8.a", "2");
+
+var successfullyParsed = true;
diff --git a/LayoutTests/fast/js/resources/const.js b/LayoutTests/fast/js/resources/const.js
new file mode 100644
index 0000000..cc5e127
--- /dev/null
+++ b/LayoutTests/fast/js/resources/const.js
@@ -0,0 +1,120 @@
+description(
+"This test checks that const declarations in JavaScript work and are readonly."
+);
+
+
+shouldThrow("const redef='a'; const redef='a';");
+
+const x = "RIGHT";
+x = "WRONG";
+shouldBe("x", '"RIGHT"');
+
+const z = "RIGHT", y = "RIGHT";
+y = "WRONG";
+shouldBe("y", '"RIGHT"');
+
+const one = 1;
+
+var a;
+
+// PostIncResolveNode
+a = one++;
+shouldBe("a", "1");
+shouldBe("one", "1");
+
+// PostDecResolveNode
+a = one--;
+shouldBe("a", "1");
+shouldBe("one", "1");
+
+// PreIncResolveNode
+a = ++one;
+shouldBe("a", "2");
+shouldBe("one", "1");
+
+// PreDecResolveNode
+a = --one;
+shouldBe("a", "0");
+shouldBe("one", "1");
+
+// ReadModifyConstNode
+a = one += 2;
+shouldBe("a", "3");
+shouldBe("one", "1");
+
+// AssignConstNode
+a = one = 2;
+shouldBe("a", "2");
+shouldBe("one", "1");
+
+// PostIncResolveNode
+shouldBe("function f() { const one = 1; one++; return one; } f();", "1");
+shouldBe("function f() { const oneString = '1'; return oneString++; } f();", "1");
+shouldBe("function f() { const one = 1; return one++; } f();", "1");
+
+// PostDecResolveNode
+shouldBe("function f() { const one = 1; one--; return one; } f();", "1");
+shouldBe("function f() { const oneString = '1'; return oneString--; } f();", "1");
+shouldBe("function f() { const one = 1; return one--; } f();", "1");
+
+// PreIncResolveNode
+shouldBe("function f() { const one = 1; ++one; return one; } f();", "1");
+shouldBe("function f() { const one = 1; return ++one; } f();", "2");
+
+// PreDecResolveNode
+shouldBe("function f() { const one = 1; --one; return one; } f();", "1");
+shouldBe("function f() { const one = 1; return --one; } f();", "0");
+
+// ReadModifyConstNode
+shouldBe("function f() { const one = 1; one += 2; return one; } f();", "1");
+shouldBe("function f() { const one = 1; return one += 2; } f();", "3");
+
+// AssignConstNode
+shouldBe("function f() { const one = 1; one = 2; return one; } f();", "1");
+shouldBe("function f() { const one = 1; return one = 2; } f();", "2");
+
+// PostIncResolveNode
+shouldBe("one++", "1");
+shouldBe("one", "1");
+
+// PostDecResolveNode
+shouldBe("one--", "1");
+shouldBe("one", "1");
+
+// PreIncResolveNode
+shouldBe("++one", "2");
+shouldBe("one", "1");
+
+// PreDecResolveNode
+shouldBe("--one", "0");
+shouldBe("one", "1");
+
+// ReadModifyConstNode
+shouldBe("one += 1", "2");
+shouldBe("one", "1");
+
+// AssignConstNode
+shouldBe("one = 2", "2");
+shouldBe("one", "1");
+
+var object = { inWith1: "RIGHT", inWith2: ""}
+with (object) {
+ const inWith1 = "WRONG";
+ const inWith2 = "RIGHT";
+ inWith2 = "WRONG";
+}
+shouldBe("object.inWith1", "'RIGHT'");
+shouldBe("inWith2", "'RIGHT'");
+
+shouldBe("(function(){ one = 2; return one; })()", "1")
+var f = function g() { g="FAIL"; return g; };
+shouldBe("f()", "f");
+
+shouldBe("const a;", "undefined");
+
+// Make sure we don't override properties placed on the global object
+var ranConstInitialiser = false;
+const bodyId = (ranConstInitialiser = true, "Const initialiser overwrote existing property");
+shouldBe("bodyId", "document.getElementById('bodyId')");
+shouldBeTrue("ranConstInitialiser");
+var successfullyParsed = true;
diff --git a/LayoutTests/fast/js/resources/garbage-collect-after-string-appends.js-disabled b/LayoutTests/fast/js/resources/garbage-collect-after-string-appends.js-disabled
new file mode 100644
index 0000000..1ec03ce
--- /dev/null
+++ b/LayoutTests/fast/js/resources/garbage-collect-after-string-appends.js-disabled
@@ -0,0 +1,39 @@
+description(
+"This test checks whether the GC collects after string appends."
+);
+
+// FIXME: This test appears to be highly tied to the details of how JS strings report memory
+// cost to the garbage collector. It should be improved to be less tied to these implementation details.
+// <https://bugs.webkit.org/show_bug.cgi?id=20871>
+
+if (window.layoutTestController)
+ layoutTestController.dumpAsText();
+
+if (window.GCController)
+ GCController.collect();
+
+
+// str has 150 chars in it (which is greater than the limit of the GC to ignore which I believe is at 128).
+var str = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
+var count = 500;
+for (var i = 0; i < count; ++i) {
+ str += "b";
+}
+
+// str has 128 chars in it.
+str = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
+count = 10;
+for (var i = 0; i < count; ++i) {
+ str += str;
+}
+
+var jsObjCount = 0;
+if (window.GCController)
+ jsObjCount = GCController.getJSObjectCount();
+
+if (jsObjCount <= 500 && jsObjCount > 0)
+ testPassed("Garbage Collector triggered")
+else
+ testFailed("Garbage Collector NOT triggered. Number of JSObjects: " + jsObjCount);
+
+var successfullyParsed = true;
diff --git a/LayoutTests/fast/js/resources/getOwnPropertyDescriptor.js b/LayoutTests/fast/js/resources/getOwnPropertyDescriptor.js
new file mode 100644
index 0000000..880aed4
--- /dev/null
+++ b/LayoutTests/fast/js/resources/getOwnPropertyDescriptor.js
@@ -0,0 +1,95 @@
+description("Test to ensure correct behaviour of Object.getOwnPropertyDescriptor");
+
+function descriptorShouldBe(object, property, expected) {
+ var test = 'Object.getOwnPropertyDescriptor('+object+", "+property+')';
+ if ("writable" in expected) {
+ // shouldBe(test+'.writable', '' + expected.writable);
+ shouldBe(test+'.value', '' + expected.value);
+ shouldBeFalse(test+".hasOwnProperty('get')");
+ shouldBeFalse(test+".hasOwnProperty('set')");
+ } else {
+ shouldBe(test+'.get', '' + expected.get);
+ shouldBe(test+'.set', '' + expected.set);
+ shouldBeFalse(test+".hasOwnProperty('value')");
+ shouldBeFalse(test+".hasOwnProperty('writable')");
+ }
+ shouldBe(test+'.enumerable', '' + expected.enumerable);
+ shouldBe(test+'.configurable', '' + expected.configurable);
+}
+
+shouldBeUndefined("Object.getOwnPropertyDescriptor({}, 'undefinedProperty')");
+descriptorShouldBe("{definedProperty:'defined'}", "'definedProperty'", {writable: true, enumerable: true, configurable: true, value:'"defined"'});
+descriptorShouldBe("Array.prototype", "'concat'", {writable: true, enumerable: false, configurable: true, value:"Array.prototype.concat"});
+descriptorShouldBe("Date.prototype", "'toISOString'", {writable: true, enumerable: false, configurable: true, value: "Date.prototype.toISOString"});
+descriptorShouldBe("String.prototype", "'concat'", {writable: true, enumerable: false, configurable: true, value:"String.prototype.concat"});
+descriptorShouldBe("RegExp.prototype", "'exec'", {writable: true, enumerable: false, configurable: true, value:"RegExp.prototype.exec"});
+descriptorShouldBe("document.__proto__.__proto__", "'createElement'", {writable: true, enumerable: true, configurable: false, value:"document.createElement"});
+descriptorShouldBe("Number", "'NEGATIVE_INFINITY'", {writable: false, enumerable: false, configurable: false, value:"Number.NEGATIVE_INFINITY"});
+descriptorShouldBe("RegExp", "'$_'", {writable: true, enumerable: false, configurable: true, value:"RegExp.$_"});
+descriptorShouldBe("/a/g", "'global'", {writable: true, enumerable: false, configurable: false, value:true});
+descriptorShouldBe("Node", "'DOCUMENT_POSITION_DISCONNECTED'", {writable: false, enumerable: true, configurable: false, value:"Node.DOCUMENT_POSITION_DISCONNECTED"});
+descriptorShouldBe("Math", "'sin'", {writable: true, enumerable: false, configurable: true, value:"Math.sin"});
+descriptorShouldBe("[1,2,3]", "0", {writable: true, enumerable: true, configurable: true, value:"1"});
+descriptorShouldBe("[1,2,3]", "'length'", {writable: true, enumerable: false, configurable: false, value:"3"});
+descriptorShouldBe("[1,2,3]", "'length'", {writable: true, enumerable: false, configurable: false, value:"3"});
+descriptorShouldBe("/(a)*/g.exec('a')", "0", {writable: true, enumerable: true, configurable: true, value:"'a'"});
+descriptorShouldBe("/(a)*/g.exec('a')", "'length'", {writable: true, enumerable: false, configurable: false, value:2});
+descriptorShouldBe("function(){}", "'length'", {writable: false, enumerable: false, configurable: false, value:0});
+descriptorShouldBe("Math.sin", "'length'", {writable: false, enumerable: false, configurable: false, value:1});
+descriptorShouldBe("Math.sin", "'name'", {writable: false, enumerable: false, configurable: false, value:"'sin'"});
+var global = this;
+descriptorShouldBe("global", "'global'", {writable: true, enumerable: true, configurable: false, value:"global"});
+descriptorShouldBe("global", "'window'", {writable: false, enumerable: true, configurable: false, value:"global"});
+descriptorShouldBe("global", "'XMLHttpRequest'", {writable: true, enumerable: true, configurable: false, value:"XMLHttpRequest"});
+descriptorShouldBe("global", "'length'", {writable: true, enumerable: true, configurable: false, value:"global.length"});
+descriptorShouldBe("global", "0", {writable: true, enumerable: false, configurable: false, value:"global[0]"});
+descriptorShouldBe("document.getElementsByTagName('div')", "'length'", {writable: false, enumerable: true, configurable: false, value:"1"});
+descriptorShouldBe("document.getElementsByTagName('div')", "0", {writable: false, enumerable: true, configurable: false, value:"document.getElementsByTagName('div')[0]"});
+descriptorShouldBe("document.getElementsByClassName('pass')", "0", {writable: false, enumerable: true, configurable: false, value:"document.getElementsByClassName('pass')[0]"});
+descriptorShouldBe("document.getElementsByClassName('pass')", "'length'", {writable: false, enumerable: true, configurable: false, value:"document.getElementsByClassName('pass').length"});
+var canvas = document.createElement("canvas");
+var canvasPixelArray = canvas.getContext("2d").createImageData(10,10).data;
+descriptorShouldBe("canvasPixelArray", "'length'", {writable: false, enumerable: true, configurable: false, value:"canvasPixelArray.length"});
+descriptorShouldBe("canvasPixelArray", "0", {writable: true, enumerable: true, configurable: false, value:"canvasPixelArray[0]"});
+var select = document.createElement("select");
+select.innerHTML = "<option>foo</option>";
+descriptorShouldBe("select", "'length'", {writable: false, enumerable: true, configurable: false, value:"select.length"});
+descriptorShouldBe("select", "0", {writable: true, enumerable: true, configurable: false, value:"select[0]"});
+
+var objectWithGetter = {};
+function getterFunc(){};
+objectWithGetter.__defineGetter__("getter", getterFunc);
+descriptorShouldBe("objectWithGetter", "'getter'", {"get": "getterFunc", "set": undefined, enumerable: true, configurable: true});
+var objectWithSetter = {};
+function setterFunc(){};
+objectWithSetter.__defineSetter__("setter", setterFunc);
+descriptorShouldBe("objectWithSetter", "'setter'", {"set": "setterFunc", "get": undefined, enumerable: true, configurable: true});
+var objectWithAccessor = {};
+objectWithAccessor.__defineSetter__("accessor", setterFunc);
+objectWithAccessor.__defineGetter__("accessor", getterFunc);
+descriptorShouldBe("objectWithAccessor", "'accessor'", {"set": "setterFunc", "get": "getterFunc", enumerable: true, configurable: true});
+
+shouldThrow("Object.getOwnPropertyDescriptor(null)");
+shouldThrow("Object.getOwnPropertyDescriptor(undefined)");
+shouldThrow("Object.getOwnPropertyDescriptor(1)");
+shouldThrow("Object.getOwnPropertyDescriptor('')");
+shouldThrow("Object.getOwnPropertyDescriptor(true)");
+shouldThrow("Object.getOwnPropertyDescriptor(false)");
+
+debug("Checking property ordering");
+var normalOrder = ["'value'", "'writable'", "'enumerable'", "'configurable'"];
+var accessorOrder = ["'get'", "'set'", "'enumerable'", "'configurable'"];
+var i = 0;
+for (var property in Object.getOwnPropertyDescriptor(Math, "sin"))
+ shouldBe('property', normalOrder[i++]);
+i = 0;
+for (var property in Object.getOwnPropertyDescriptor(objectWithGetter, "getter"))
+ shouldBe('property', accessorOrder[i++]);
+i = 0;
+for (var property in Object.getOwnPropertyDescriptor(objectWithSetter, "setter"))
+ shouldBe('property', accessorOrder[i++]);
+i = 0;
+for (var property in Object.getOwnPropertyDescriptor(objectWithAccessor, "accessor"))
+ shouldBe('property', accessorOrder[i++]);
+
+successfullyParsed = true;
diff --git a/LayoutTests/fast/js/resources/instanceof-operator-dummy-worker.js b/LayoutTests/fast/js/resources/instanceof-operator-dummy-worker.js
new file mode 100644
index 0000000..9a65dba
--- /dev/null
+++ b/LayoutTests/fast/js/resources/instanceof-operator-dummy-worker.js
@@ -0,0 +1 @@
+// Empty JavaScript file.
diff --git a/LayoutTests/fast/js/resources/js-test-post-function.js b/LayoutTests/fast/js/resources/js-test-post-function.js
new file mode 100644
index 0000000..9be7bc0
--- /dev/null
+++ b/LayoutTests/fast/js/resources/js-test-post-function.js
@@ -0,0 +1,5 @@
+function isSuccessfullyParsed()
+{
+ shouldBeTrue("successfullyParsed");
+ debug('<br><span class="pass">TEST COMPLETE</span>');
+}
diff --git a/LayoutTests/fast/js/resources/js-test-post-n.js b/LayoutTests/fast/js/resources/js-test-post-n.js
new file mode 100644
index 0000000..d9bceae
--- /dev/null
+++ b/LayoutTests/fast/js/resources/js-test-post-n.js
@@ -0,0 +1,2 @@
+shouldBeUndefined("window.successfullyParsed");
+debug('<br><span class="pass">TEST COMPLETE</span>');
diff --git a/LayoutTests/fast/js/resources/js-test-post.js b/LayoutTests/fast/js/resources/js-test-post.js
new file mode 100644
index 0000000..6d8a68f
--- /dev/null
+++ b/LayoutTests/fast/js/resources/js-test-post.js
@@ -0,0 +1,2 @@
+shouldBeTrue("successfullyParsed");
+debug('<br /><span class="pass">TEST COMPLETE</span>');
diff --git a/LayoutTests/fast/js/resources/js-test-pre.js b/LayoutTests/fast/js/resources/js-test-pre.js
new file mode 100644
index 0000000..b91812f
--- /dev/null
+++ b/LayoutTests/fast/js/resources/js-test-pre.js
@@ -0,0 +1,256 @@
+if (window.layoutTestController)
+ layoutTestController.dumpAsText();
+
+function description(msg)
+{
+ // For MSIE 6 compatibility
+ var span = document.createElement("span");
+ span.innerHTML = '<p>' + msg + '</p><p>On success, you will see a series of "<span class="pass">PASS</span>" messages, followed by "<span class="pass">TEST COMPLETE</span>".</p>';
+ var description = document.getElementById("description");
+ if (description.firstChild)
+ description.replaceChild(span, description.firstChild);
+ else
+ description.appendChild(span);
+}
+
+function debug(msg)
+{
+ var span = document.createElement("span");
+ document.getElementById("console").appendChild(span); // insert it first so XHTML knows the namespace
+ span.innerHTML = msg + '<br />';
+}
+
+function escapeHTML(text)
+{
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;");
+}
+
+function testPassed(msg)
+{
+ debug('<span><span class="pass">PASS</span> ' + escapeHTML(msg) + '</span>');
+}
+
+function testFailed(msg)
+{
+ debug('<span><span class="fail">FAIL</span> ' + escapeHTML(msg) + '</span>');
+}
+
+function areArraysEqual(_a, _b)
+{
+ if (_a.length !== _b.length)
+ return false;
+ for (var i = 0; i < _a.length; i++)
+ if (_a[i] !== _b[i])
+ return false;
+ return true;
+}
+
+function isMinusZero(n)
+{
+ // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
+ // -Infinity instead of Infinity
+ return n === 0 && 1/n < 0;
+}
+
+function isResultCorrect(_actual, _expected)
+{
+ if (_expected === 0)
+ return _actual === _expected && (1/_actual) === (1/_expected);
+ if (_actual === _expected)
+ return true;
+ if (typeof(_expected) == "number" && isNaN(_expected))
+ return typeof(_actual) == "number" && isNaN(_actual);
+ if (Object.prototype.toString.call(_expected) == Object.prototype.toString.call([]))
+ return areArraysEqual(_actual, _expected);
+ return false;
+}
+
+function stringify(v)
+{
+ if (v === 0 && 1/v < 0)
+ return "-0";
+ else return "" + v;
+}
+
+function evalAndLog(_a)
+{
+ if (typeof _a != "string")
+ debug("WARN: tryAndLog() expects a string argument");
+
+ // Log first in case things go horribly wrong or this causes a sync event.
+ debug(_a);
+
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ testFailed(_a + " threw exception " + e);
+ }
+}
+
+function shouldBe(_a, _b)
+{
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBe() expects string arguments");
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (exception)
+ testFailed(_a + " should be " + _bv + ". Threw exception " + exception);
+ else if (isResultCorrect(_av, _bv))
+ testPassed(_a + " is " + _b);
+ else if (typeof(_av) == typeof(_bv))
+ testFailed(_a + " should be " + _bv + ". Was " + stringify(_av) + ".");
+ else
+ testFailed(_a + " should be " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
+}
+
+function shouldBeTrue(_a) { shouldBe(_a, "true"); }
+function shouldBeFalse(_a) { shouldBe(_a, "false"); }
+function shouldBeNaN(_a) { shouldBe(_a, "NaN"); }
+function shouldBeNull(_a) { shouldBe(_a, "null"); }
+
+function shouldBeEqualToString(a, b)
+{
+ var unevaledString = '"' + b.replace(/"/g, "\"") + '"';
+ shouldBe(a, unevaledString);
+}
+
+function shouldEvaluateTo(actual, expected) {
+ // A general-purpose comparator. 'actual' should be a string to be
+ // evaluated, as for shouldBe(). 'expected' may be any type and will be
+ // used without being eval'ed.
+ if (expected == null) {
+ // Do this before the object test, since null is of type 'object'.
+ shouldBeNull(actual);
+ } else if (typeof expected == "undefined") {
+ shouldBeUndefined(actual);
+ } else if (typeof expected == "function") {
+ // All this fuss is to avoid the string-arg warning from shouldBe().
+ try {
+ actualValue = eval(actual);
+ } catch (e) {
+ testFailed("Evaluating " + actual + ": Threw exception " + e);
+ return;
+ }
+ shouldBe("'" + actualValue.toString().replace(/\n/g, "") + "'",
+ "'" + expected.toString().replace(/\n/g, "") + "'");
+ } else if (typeof expected == "object") {
+ shouldBeTrue(actual + " == '" + expected + "'");
+ } else if (typeof expected == "string") {
+ shouldBe(actual, expected);
+ } else if (typeof expected == "boolean") {
+ shouldBe("typeof " + actual, "'boolean'");
+ if (expected)
+ shouldBeTrue(actual);
+ else
+ shouldBeFalse(actual);
+ } else if (typeof expected == "number") {
+ shouldBe(actual, stringify(expected));
+ } else {
+ debug(expected + " is unknown type " + typeof expected);
+ shouldBeTrue(actual, "'" +expected.toString() + "'");
+ }
+}
+
+function shouldBeNonZero(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be non-zero. Threw exception " + exception);
+ else if (_av != 0)
+ testPassed(_a + " is non-zero.");
+ else
+ testFailed(_a + " should be non-zero. Was " + _av);
+}
+
+function shouldBeNonNull(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be non-null. Threw exception " + exception);
+ else if (_av != null)
+ testPassed(_a + " is non-null.");
+ else
+ testFailed(_a + " should be non-null. Was " + _av);
+}
+
+function shouldBeUndefined(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be undefined. Threw exception " + exception);
+ else if (typeof _av == "undefined")
+ testPassed(_a + " is undefined.");
+ else
+ testFailed(_a + " should be undefined. Was " + _av);
+}
+
+
+function shouldThrow(_a, _e)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ var _ev;
+ if (_e)
+ _ev = eval(_e);
+
+ if (exception) {
+ if (typeof _e == "undefined" || exception == _ev)
+ testPassed(_a + " threw exception " + exception + ".");
+ else
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + exception + ".");
+ } else if (typeof _av == "undefined")
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
+ else
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
+}
+
+function gc() {
+ if (typeof GCController !== "undefined")
+ GCController.collect();
+ else {
+ function gcRec(n) {
+ if (n < 1)
+ return {};
+ var temp = {i: "ab" + i + (i / 100000)};
+ temp += "foo";
+ gcRec(n-1);
+ }
+ for (var i = 0; i < 1000; i++)
+ gcRec(10)
+ }
+}
diff --git a/LayoutTests/fast/js/resources/js-test-style.css b/LayoutTests/fast/js/resources/js-test-style.css
new file mode 100644
index 0000000..f12147c
--- /dev/null
+++ b/LayoutTests/fast/js/resources/js-test-style.css
@@ -0,0 +1,12 @@
+.pass {
+ font-weight: bold;
+ color: green;
+}
+.fail {
+ font-weight: bold;
+ color: red;
+}
+#console {
+ white-space: pre-wrap;
+ font-family: monospace;
+}
diff --git a/LayoutTests/fast/js/resources/json2-es5-compat.js b/LayoutTests/fast/js/resources/json2-es5-compat.js
new file mode 100644
index 0000000..047b3d4
--- /dev/null
+++ b/LayoutTests/fast/js/resources/json2-es5-compat.js
@@ -0,0 +1,477 @@
+/*
+ http://www.JSON.org/json2.js
+ 2009-04-16
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or '&nbsp;'),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the object holding the key.
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+*/
+
+/*jslint evil: true */
+
+/*global JSON */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+*/
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (!this.JSON) {
+ JSON = {};
+}
+(function () {
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ?
+ '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ if (value && ((typeof value) === "object")) {
+ if (value.constructor === String || value.constructor === Number || value.constructor === Boolean)
+ value = value.valueOf();
+ }
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+}());
diff --git a/LayoutTests/fast/js/resources/lexical-lookup-in-function-constructor-child.html b/LayoutTests/fast/js/resources/lexical-lookup-in-function-constructor-child.html
new file mode 100644
index 0000000..ec10581
--- /dev/null
+++ b/LayoutTests/fast/js/resources/lexical-lookup-in-function-constructor-child.html
@@ -0,0 +1,10 @@
+<script>
+message = "SUCCESS";
+function doTest(para) {
+ var f = new Function('para', 'para.innerHTML = message;');
+ f(para);
+}
+</script>
+<body>
+</body>
+
diff --git a/LayoutTests/fast/js/resources/select-options-remove.js b/LayoutTests/fast/js/resources/select-options-remove.js
new file mode 100644
index 0000000..029acb4
--- /dev/null
+++ b/LayoutTests/fast/js/resources/select-options-remove.js
@@ -0,0 +1,232 @@
+description("This test checks the behavior of the remove() method on the select.options object.");
+
+var select1 = document.getElementById("select1");
+var value;
+
+debug("1.1 Remove (object) from empty Options");
+value = document.createElement("DIV");
+shouldBe("select1.options.remove(value)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.2 Remove (string) from empty Options");
+value = "o";
+shouldBe("select1.options.remove(value)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.3 Remove (float) from empty Options");
+value = 3.14;
+shouldBe("select1.options.remove(value)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.4 Remove (boolean) from empty Options");
+value = true;
+shouldBe("select1.options.remove(value)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.5 Remove (undefined) from empty Options");
+value = undefined;
+shouldBe("select1.options.remove(value)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.6 Remove (null) from empty Options");
+value = null;
+shouldBe("select1.options.remove(value)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.7 Remove (negative infinity) from empty Options");
+value = -1/0;
+shouldBe("select1.options.remove(value)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.8 Remove (NaN) from empty Options");
+value = 0/0;
+shouldBe("select1.options.remove(value)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.9 Remove (positive infinity) from empty Options");
+value = 1/0;
+shouldBe("select1.options.remove(value)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.10 Remove no args from empty Options");
+shouldBe("select1.options.remove()", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.11 Remove too many args from empty Options");
+shouldBe("select1.options.remove(0, 'foo')", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.12 Remove invalid index -2 from empty Options");
+shouldBe("select1.options.remove(-2)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.13 Remove invalid index -1 from empty Options");
+shouldBe("select1.options.remove(-1)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.14 Remove index 0 from empty Options");
+shouldBe("select1.options.remove(0)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+debug("1.15 Remove index 1 from empty Options");
+shouldBe("select1.options.remove(1)", "undefined");
+shouldBe("select1.options.length", "0");
+shouldBe("select1.selectedIndex", "-1");
+debug("");
+
+// ------------------------------------------------
+
+i = 0;
+var select2 = document.getElementById("select2");
+
+debug("2.1 Remove (object) from non-empty Options");
+value = document.createElement("DIV");
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "15");
+shouldBe("select2.selectedIndex", "13");
+shouldBe("select2.options[0].value", "'B'");
+debug("");
+
+debug("2.2 Remove (string) from non-empty Options");
+value = "o";
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "14");
+shouldBe("select2.selectedIndex", "12");
+shouldBe("select2.options[0].value", "'C'");
+debug("");
+
+debug("2.3 Remove (float) from non-empty Options");
+value = 3.14;
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "13");
+shouldBe("select2.selectedIndex", "11");
+shouldBe("select2.options[3].value", "'G'");
+debug("");
+
+debug("2.4 Remove (boolean true) from non-empty Options");
+value = true;
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "12");
+shouldBe("select2.selectedIndex", "10");
+shouldBe("select2.options[1].value", "'E'");
+debug("");
+
+debug("2.5 Remove (boolean false) from non-empty Options");
+value = false;
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "11");
+shouldBe("select2.selectedIndex", "9");
+shouldBe("select2.options[1].value", "'G'");
+debug("");
+
+debug("2.6 Remove (undefined) from non-empty Options");
+value = undefined;
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "10");
+shouldBe("select2.selectedIndex", "8");
+shouldBe("select2.options[0].value", "'G'");
+debug("");
+
+debug("2.7 Remove (null) from non-empty Options");
+value = null;
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "9");
+shouldBe("select2.selectedIndex", "7");
+shouldBe("select2.options[0].value", "'H'");
+debug("");
+
+debug("2.8 Remove (negative infinity) from non-empty Options");
+value = -1/0;
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "8");
+shouldBe("select2.selectedIndex", "6");
+shouldBe("select2.options[0].value", "'I'");
+debug("");
+
+debug("2.9 Remove (NaN) from non-empty Options");
+value = 0/0;
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "7");
+shouldBe("select2.selectedIndex", "5");
+shouldBe("select2.options[0].value", "'J'");
+debug("");
+
+debug("2.10 Remove (positive infinity) from non-empty Options");
+value = 1/0;
+shouldBe("select2.options.remove(value)", "undefined");
+shouldBe("select2.options.length", "6");
+shouldBe("select2.selectedIndex", "4");
+shouldBe("select2.options[0].value", "'K'");
+debug("");
+
+debug("2.11 Remove no args from non-empty Options");
+shouldBe("select2.options.remove()", "undefined");
+shouldBe("select2.options.length", "5");
+shouldBe("select2.selectedIndex", "3");
+shouldBe("select2.options[0].value", "'L'");
+debug("");
+
+debug("2.12 Remove too many args from non-empty Options");
+shouldBe("select2.options.remove(0, 'foo')", "undefined");
+shouldBe("select2.options.length", "4");
+shouldBe("select2.selectedIndex", "2");
+shouldBe("select2.options[0].value", "'M'");
+debug("");
+
+debug("2.13 Remove invalid index -2 from non-empty Options");
+shouldBe("select2.options.remove(-2)", "undefined");
+shouldBe("select2.options.length", "4");
+shouldBe("select2.selectedIndex", "2");
+shouldBe("select2.options[2].value", "'O'");
+debug("");
+
+debug("2.14 Remove invalid index -1 from non-empty Options");
+shouldBe("select2.options.remove(-1)", "undefined");
+shouldBe("select2.options.length", "4");
+shouldBe("select2.selectedIndex", "2");
+shouldBe("select2.options[3].value", "'P'");
+debug("");
+
+debug("2.15 Remove index 0 from non-empty Options");
+shouldBe("select2.options.remove(0)", "undefined");
+shouldBe("select2.options.length", "3");
+shouldBe("select2.selectedIndex", "1");
+shouldBe("select2.options[0].value", "'N'");
+debug("");
+
+debug("2.16 Remove index 1 from non-empty Options");
+shouldBe("select2.options.remove(1)", "undefined");
+shouldBe("select2.options.length", "2");
+shouldBe("select2.selectedIndex", "0");
+shouldBe("select2.options[1].value", "'P'");
+debug("");
+
+successfullyParsed = true;
diff --git a/LayoutTests/fast/js/resources/standalone-post.js b/LayoutTests/fast/js/resources/standalone-post.js
new file mode 100644
index 0000000..4b8a56d
--- /dev/null
+++ b/LayoutTests/fast/js/resources/standalone-post.js
@@ -0,0 +1,2 @@
+shouldBeTrue("successfullyParsed");
+debug("\nTEST COMPLETE\n");
diff --git a/LayoutTests/fast/js/resources/standalone-pre.js b/LayoutTests/fast/js/resources/standalone-pre.js
new file mode 100644
index 0000000..692f1c1
--- /dev/null
+++ b/LayoutTests/fast/js/resources/standalone-pre.js
@@ -0,0 +1,141 @@
+function description(msg)
+{
+ print(msg);
+ print("\nOn success, you will see a series of \"PASS\" messages, followed by \"TEST COMPLETE\".\n");
+ print();
+}
+
+function debug(msg)
+{
+ print(msg);
+}
+
+function escapeString(text)
+{
+ return text.replace(/\0/g, "");
+}
+
+function testPassed(msg)
+{
+ print("PASS", escapeString(msg));
+}
+
+function testFailed(msg)
+{
+ print("FAIL", escapeString(msg));
+}
+
+function areArraysEqual(_a, _b)
+{
+ if (_a.length !== _b.length)
+ return false;
+ for (var i = 0; i < _a.length; i++)
+ if (_a[i] !== _b[i])
+ return false;
+ return true;
+}
+
+function isMinusZero(n)
+{
+ // the only way to tell 0 from -0 in JS is the fact that 1/-0 is
+ // -Infinity instead of Infinity
+ return n === 0 && 1/n < 0;
+}
+
+function isResultCorrect(_actual, _expected)
+{
+ if (_expected === 0)
+ return _actual === _expected && (1/_actual) === (1/_expected);
+ if (_actual === _expected)
+ return true;
+ if (typeof(_expected) == "number" && isNaN(_expected))
+ return typeof(_actual) == "number" && isNaN(_actual);
+ if (Object.prototype.toString.call(_expected) == Object.prototype.toString.call([]))
+ return areArraysEqual(_actual, _expected);
+ return false;
+}
+
+function stringify(v)
+{
+ if (v === 0 && 1/v < 0)
+ return "-0";
+ else return "" + v;
+}
+
+function shouldBe(_a, _b)
+{
+ if (typeof _a != "string" || typeof _b != "string")
+ debug("WARN: shouldBe() expects string arguments");
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+ var _bv = eval(_b);
+
+ if (exception)
+ testFailed(_a + " should be " + _bv + ". Threw exception " + exception);
+ else if (isResultCorrect(_av, _bv))
+ testPassed(_a + " is " + _b);
+ else if (typeof(_av) == typeof(_bv))
+ testFailed(_a + " should be " + _bv + ". Was " + stringify(_av) + ".");
+ else
+ testFailed(_a + " should be " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
+}
+
+function shouldBeTrue(_a) { shouldBe(_a, "true"); }
+function shouldBeFalse(_a) { shouldBe(_a, "false"); }
+function shouldBeNaN(_a) { shouldBe(_a, "NaN"); }
+function shouldBeNull(_a) { shouldBe(_a, "null"); }
+
+function shouldBeEqualToString(a, b)
+{
+ var unevaledString = '"' + b.replace(/"/g, "\"") + '"';
+ shouldBe(a, unevaledString);
+}
+
+function shouldBeUndefined(_a)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (exception)
+ testFailed(_a + " should be undefined. Threw exception " + exception);
+ else if (typeof _av == "undefined")
+ testPassed(_a + " is undefined.");
+ else
+ testFailed(_a + " should be undefined. Was " + _av);
+}
+
+
+function shouldThrow(_a, _e)
+{
+ var exception;
+ var _av;
+ try {
+ _av = eval(_a);
+ } catch (e) {
+ exception = e;
+ }
+
+ var _ev;
+ if (_e)
+ _ev = eval(_e);
+
+ if (exception) {
+ if (typeof _e == "undefined" || exception == _ev)
+ testPassed(_a + " threw exception " + exception + ".");
+ else
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Threw exception " + exception + ".");
+ } else if (typeof _av == "undefined")
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was undefined.");
+ else
+ testFailed(_a + " should throw " + (typeof _e == "undefined" ? "an exception" : _ev) + ". Was " + _av + ".");
+}
diff --git a/LayoutTests/fast/js/resources/string-concatenate-outofmemory.js b/LayoutTests/fast/js/resources/string-concatenate-outofmemory.js
new file mode 100644
index 0000000..db962e8
--- /dev/null
+++ b/LayoutTests/fast/js/resources/string-concatenate-outofmemory.js
@@ -0,0 +1,52 @@
+description(
+'This test checks if repeated string concatenation causes an exception (and not a crash). From WebKit Bug <a href="http://bugs.webkit.org/show_bug.cgi?id=11131">Repeated string concatenation results in OOM crash</a>.'
+);
+
+shouldThrow('s = "a"; while (1) { s += s; }', '"Error: Out of memory"'); // Expand at end of string
+shouldThrow('s = "a"; while (1) { s += ("a" + s); }', '"Error: Out of memory"'); // Expand at beginning of string
+shouldThrow('s = "a"; while (1) { s = [s, s].join(); }', '"Error: Out of memory"'); // Expand using UString::append.
+
+debug('');
+debug(
+'We also verify that the the string is stil functional after the out of memory exception is raised. In <a href="rdar://problem/5352887">rdar://problem/5352887</a>, accessing the string after the exception would crash.'
+);
+
+function ensureStringIsUsable(testName, stringName, str) {
+ str[str.length - 1];
+ try { [str, str].join(str); } catch (o) { }
+ try { "a" + str; } catch (o) { }
+ try { str + "a"; } catch (o) { }
+ debug('PASS: String ' + stringName + ' was functional after ' + testName + ' raised out of memory exception.');
+}
+
+var s = "a";
+try {
+ while (1)
+ s += s; // This will expand the string at the end using UString::expandCapacity
+} catch (o) {
+ ensureStringIsUsable('expandCapacity', 's', s);
+}
+
+s = "a";
+var t = "";
+try {
+ while (1) {
+ t = "a" + s;
+ s += t; // This will expand the string at the beginning using UString::expandPreCapacity
+ }
+} catch (o) {
+ // Ensure both strings involved are unharmed
+ ensureStringIsUsable('expandPreCapacity', 's', s);
+ ensureStringIsUsable('expandPreCapacity', 't', t);
+}
+delete t;
+
+s = "a";
+try {
+ while (1)
+ s = [s, s].join(); // This will expand the string using UString::append.
+} catch (o) {
+ ensureStringIsUsable('append', 's', s);
+}
+
+var successfullyParsed = true;