strict-mode.js revision 44f0eee88ff00398ff7f715fab053374d808c90d
1// Copyright 2011 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28function CheckStrictMode(code, exception) {
29  assertDoesNotThrow(code);
30  assertThrows("'use strict';\n" + code, exception);
31  assertThrows('"use strict";\n' + code, exception);
32  assertDoesNotThrow("\
33    function outer() {\
34      function inner() {\n"
35        + code +
36      "\n}\
37    }");
38  assertThrows("\
39    function outer() {\
40      'use strict';\
41      function inner() {\n"
42        + code +
43      "\n}\
44    }", exception);
45}
46
47function CheckFunctionConstructorStrictMode() {
48  var args = [];
49  for (var i = 0; i < arguments.length; i ++) {
50    args[i] = arguments[i];
51  }
52  // Create non-strict function. No exception.
53  args[arguments.length] = "";
54  assertDoesNotThrow(function() {
55    Function.apply(this, args);
56  });
57  // Create strict mode function. Exception expected.
58  args[arguments.length] = "'use strict';";
59  assertThrows(function() {
60    Function.apply(this, args);
61  }, SyntaxError);
62}
63
64// Incorrect 'use strict' directive.
65(function UseStrictEscape() {
66  "use\\x20strict";
67  with ({}) {};
68})();
69
70// 'use strict' in non-directive position.
71(function UseStrictNonDirective() {
72  void(0);
73  "use strict";
74  with ({}) {};
75})();
76
77// Multiple directives, including "use strict".
78assertThrows('\
79"directive 1";\
80"another directive";\
81"use strict";\
82"directive after strict";\
83"and one more";\
84with({}) {}', SyntaxError);
85
86// 'with' disallowed in strict mode.
87CheckStrictMode("with({}) {}", SyntaxError);
88
89// Function named 'eval'.
90CheckStrictMode("function eval() {}", SyntaxError);
91
92// Function named 'arguments'.
93CheckStrictMode("function arguments() {}", SyntaxError);
94
95// Function parameter named 'eval'.
96CheckStrictMode("function foo(a, b, eval, c, d) {}", SyntaxError);
97
98// Function parameter named 'arguments'.
99CheckStrictMode("function foo(a, b, arguments, c, d) {}", SyntaxError);
100
101// Property accessor parameter named 'eval'.
102CheckStrictMode("var o = { set foo(eval) {} }", SyntaxError);
103
104// Property accessor parameter named 'arguments'.
105CheckStrictMode("var o = { set foo(arguments) {} }", SyntaxError);
106
107// Duplicate function parameter name.
108CheckStrictMode("function foo(a, b, c, d, b) {}", SyntaxError);
109
110// Function constructor: eval parameter name.
111CheckFunctionConstructorStrictMode("eval");
112
113// Function constructor: arguments parameter name.
114CheckFunctionConstructorStrictMode("arguments");
115
116// Function constructor: duplicate parameter name.
117CheckFunctionConstructorStrictMode("a", "b", "c", "b");
118CheckFunctionConstructorStrictMode("a,b,c,b");
119
120// catch(eval)
121CheckStrictMode("try{}catch(eval){};", SyntaxError);
122
123// catch(arguments)
124CheckStrictMode("try{}catch(arguments){};", SyntaxError);
125
126// var eval
127CheckStrictMode("var eval;", SyntaxError);
128
129// var arguments
130CheckStrictMode("var arguments;", SyntaxError);
131
132// Strict mode applies to the function in which the directive is used..
133assertThrows('\
134function foo(eval) {\
135  "use strict";\
136}', SyntaxError);
137
138// Strict mode doesn't affect the outer stop of strict code.
139(function NotStrict(eval) {
140  function Strict() {
141    "use strict";
142  }
143  with ({}) {};
144})();
145
146// Octal literal
147CheckStrictMode("var x = 012");
148CheckStrictMode("012");
149CheckStrictMode("'Hello octal\\032'");
150CheckStrictMode("function octal() { return 012; }");
151CheckStrictMode("function octal() { return '\\032'; }");
152
153(function ValidEscape() {
154  "use strict";
155  var x = '\0';
156  var y = "\0";
157})();
158
159// Octal before "use strict"
160assertThrows('\
161  function strict() {\
162    "octal\\032directive";\
163    "use strict";\
164  }', SyntaxError);
165
166// Duplicate data properties.
167CheckStrictMode("var x = { dupe : 1, nondupe: 3, dupe : 2 };", SyntaxError);
168CheckStrictMode("var x = { '1234' : 1, '2345' : 2, '1234' : 3 };", SyntaxError);
169CheckStrictMode("var x = { '1234' : 1, '2345' : 2, 1234 : 3 };", SyntaxError);
170CheckStrictMode("var x = { 3.14 : 1, 2.71 : 2, 3.14 : 3 };", SyntaxError);
171CheckStrictMode("var x = { 3.14 : 1, '3.14' : 2 };", SyntaxError);
172CheckStrictMode("var x = { \
173  123: 1, \
174  123.00000000000000000000000000000000000000000000000000000000000000000001: 2 \
175}", SyntaxError);
176
177// Non-conflicting data properties.
178(function StrictModeNonDuplicate() {
179  "use strict";
180  var x = { 123 : 1, "0123" : 2 };
181  var x = {
182    123: 1,
183    '123.00000000000000000000000000000000000000000000000000000000000000000001':
184      2
185  };
186})();
187
188// Two getters (non-strict)
189assertThrows("var x = { get foo() { }, get foo() { } };", SyntaxError);
190assertThrows("var x = { get foo(){}, get 'foo'(){}};", SyntaxError);
191assertThrows("var x = { get 12(){}, get '12'(){}};", SyntaxError);
192
193// Two setters (non-strict)
194assertThrows("var x = { set foo(v) { }, set foo(v) { } };", SyntaxError);
195assertThrows("var x = { set foo(v) { }, set 'foo'(v) { } };", SyntaxError);
196assertThrows("var x = { set 13(v) { }, set '13'(v) { } };", SyntaxError);
197
198// Setter and data (non-strict)
199assertThrows("var x = { foo: 'data', set foo(v) { } };", SyntaxError);
200assertThrows("var x = { set foo(v) { }, foo: 'data' };", SyntaxError);
201assertThrows("var x = { foo: 'data', set 'foo'(v) { } };", SyntaxError);
202assertThrows("var x = { set foo(v) { }, 'foo': 'data' };", SyntaxError);
203assertThrows("var x = { 'foo': 'data', set foo(v) { } };", SyntaxError);
204assertThrows("var x = { set 'foo'(v) { }, foo: 'data' };", SyntaxError);
205assertThrows("var x = { 'foo': 'data', set 'foo'(v) { } };", SyntaxError);
206assertThrows("var x = { set 'foo'(v) { }, 'foo': 'data' };", SyntaxError);
207assertThrows("var x = { 12: 1, set '12'(v){}};", SyntaxError);
208assertThrows("var x = { 12: 1, set 12(v){}};", SyntaxError);
209assertThrows("var x = { '12': 1, set '12'(v){}};", SyntaxError);
210assertThrows("var x = { '12': 1, set 12(v){}};", SyntaxError);
211
212// Getter and data (non-strict)
213assertThrows("var x = { foo: 'data', get foo() { } };", SyntaxError);
214assertThrows("var x = { get foo() { }, foo: 'data' };", SyntaxError);
215assertThrows("var x = { 'foo': 'data', get foo() { } };", SyntaxError);
216assertThrows("var x = { get 'foo'() { }, 'foo': 'data' };", SyntaxError);
217assertThrows("var x = { '12': 1, get '12'(){}};", SyntaxError);
218assertThrows("var x = { '12': 1, get 12(){}};", SyntaxError);
219
220// Assignment to eval or arguments
221CheckStrictMode("function strict() { eval = undefined; }", SyntaxError);
222CheckStrictMode("function strict() { arguments = undefined; }", SyntaxError);
223CheckStrictMode("function strict() { print(eval = undefined); }", SyntaxError);
224CheckStrictMode("function strict() { print(arguments = undefined); }",
225                SyntaxError);
226CheckStrictMode("function strict() { var x = eval = undefined; }", SyntaxError);
227CheckStrictMode("function strict() { var x = arguments = undefined; }",
228                SyntaxError);
229
230// Compound assignment to eval or arguments
231CheckStrictMode("function strict() { eval *= undefined; }", SyntaxError);
232CheckStrictMode("function strict() { arguments /= undefined; }", SyntaxError);
233CheckStrictMode("function strict() { print(eval %= undefined); }", SyntaxError);
234CheckStrictMode("function strict() { print(arguments %= undefined); }",
235                SyntaxError);
236CheckStrictMode("function strict() { var x = eval += undefined; }",
237                SyntaxError);
238CheckStrictMode("function strict() { var x = arguments -= undefined; }",
239                SyntaxError);
240CheckStrictMode("function strict() { eval <<= undefined; }", SyntaxError);
241CheckStrictMode("function strict() { arguments >>= undefined; }", SyntaxError);
242CheckStrictMode("function strict() { print(eval >>>= undefined); }",
243                SyntaxError);
244CheckStrictMode("function strict() { print(arguments &= undefined); }",
245                SyntaxError);
246CheckStrictMode("function strict() { var x = eval ^= undefined; }",
247                SyntaxError);
248CheckStrictMode("function strict() { var x = arguments |= undefined; }",
249                SyntaxError);
250
251// Postfix increment with eval or arguments
252CheckStrictMode("function strict() { eval++; }", SyntaxError);
253CheckStrictMode("function strict() { arguments++; }", SyntaxError);
254CheckStrictMode("function strict() { print(eval++); }", SyntaxError);
255CheckStrictMode("function strict() { print(arguments++); }", SyntaxError);
256CheckStrictMode("function strict() { var x = eval++; }", SyntaxError);
257CheckStrictMode("function strict() { var x = arguments++; }", SyntaxError);
258
259// Postfix decrement with eval or arguments
260CheckStrictMode("function strict() { eval--; }", SyntaxError);
261CheckStrictMode("function strict() { arguments--; }", SyntaxError);
262CheckStrictMode("function strict() { print(eval--); }", SyntaxError);
263CheckStrictMode("function strict() { print(arguments--); }", SyntaxError);
264CheckStrictMode("function strict() { var x = eval--; }", SyntaxError);
265CheckStrictMode("function strict() { var x = arguments--; }", SyntaxError);
266
267// Prefix increment with eval or arguments
268CheckStrictMode("function strict() { ++eval; }", SyntaxError);
269CheckStrictMode("function strict() { ++arguments; }", SyntaxError);
270CheckStrictMode("function strict() { print(++eval); }", SyntaxError);
271CheckStrictMode("function strict() { print(++arguments); }", SyntaxError);
272CheckStrictMode("function strict() { var x = ++eval; }", SyntaxError);
273CheckStrictMode("function strict() { var x = ++arguments; }", SyntaxError);
274
275// Prefix decrement with eval or arguments
276CheckStrictMode("function strict() { --eval; }", SyntaxError);
277CheckStrictMode("function strict() { --arguments; }", SyntaxError);
278CheckStrictMode("function strict() { print(--eval); }", SyntaxError);
279CheckStrictMode("function strict() { print(--arguments); }", SyntaxError);
280CheckStrictMode("function strict() { var x = --eval; }", SyntaxError);
281CheckStrictMode("function strict() { var x = --arguments; }", SyntaxError);
282
283// Use of const in strict mode is disallowed in anticipation of ES Harmony.
284CheckStrictMode("const x = 0;", SyntaxError);
285CheckStrictMode("for (const x = 0; false;) {}", SyntaxError);
286CheckStrictMode("function strict() { const x = 0; }", SyntaxError);
287
288// Strict mode only allows functions in SourceElements
289CheckStrictMode("if (true) { function invalid() {} }", SyntaxError);
290CheckStrictMode("for (;false;) { function invalid() {} }", SyntaxError);
291CheckStrictMode("{ function invalid() {} }", SyntaxError);
292CheckStrictMode("try { function invalid() {} } catch(e) {}", SyntaxError);
293CheckStrictMode("try { } catch(e) { function invalid() {} }", SyntaxError);
294CheckStrictMode("function outer() {{ function invalid() {} }}", SyntaxError);
295
296// Delete of an unqualified identifier
297CheckStrictMode("delete unqualified;", SyntaxError);
298CheckStrictMode("function strict() { delete unqualified; }", SyntaxError);
299CheckStrictMode("function function_name() { delete function_name; }",
300                SyntaxError);
301CheckStrictMode("function strict(parameter) { delete parameter; }",
302                SyntaxError);
303CheckStrictMode("function strict() { var variable; delete variable; }",
304                SyntaxError);
305CheckStrictMode("var variable; delete variable;", SyntaxError);
306
307(function TestStrictDelete() {
308  "use strict";
309  // "delete this" is allowed in strict mode and should work.
310  function strict_delete() { delete this; }
311  strict_delete();
312})();
313
314// Prefix unary operators other than delete, ++, -- are valid in strict mode
315(function StrictModeUnaryOperators() {
316  "use strict";
317  var x = [void eval, typeof eval, +eval, -eval, ~eval, !eval];
318  var y = [void arguments, typeof arguments,
319           +arguments, -arguments, ~arguments, !arguments];
320})();
321
322// 7.6.1.2 Future Reserved Words
323var future_reserved_words = [
324  "class",
325  "enum",
326  "export",
327  "extends",
328  "import",
329  "super",
330  "implements",
331  "interface",
332  "let",
333  "package",
334  "private",
335  "protected",
336  "public",
337  "static",
338  "yield" ];
339
340function testFutureReservedWord(word) {
341  // Simple use of each reserved word
342  CheckStrictMode("var " + word + " = 1;", SyntaxError);
343
344  // object literal properties
345  eval("var x = { " + word + " : 42 };");
346  eval("var x = { get " + word + " () {} };");
347  eval("var x = { set " + word + " (value) {} };");
348
349  // object literal with string literal property names
350  eval("var x = { '" + word + "' : 42 };");
351  eval("var x = { get '" + word + "' () { } };");
352  eval("var x = { set '" + word + "' (value) { } };");
353  eval("var x = { get '" + word + "' () { 'use strict'; } };");
354  eval("var x = { set '" + word + "' (value) { 'use strict'; } };");
355
356  // Function names and arguments, strict and non-strict contexts
357  CheckStrictMode("function " + word + " () {}", SyntaxError);
358  CheckStrictMode("function foo (" + word + ") {}", SyntaxError);
359  CheckStrictMode("function foo (" + word + ", " + word + ") {}", SyntaxError);
360  CheckStrictMode("function foo (a, " + word + ") {}", SyntaxError);
361  CheckStrictMode("function foo (" + word + ", a) {}", SyntaxError);
362  CheckStrictMode("function foo (a, " + word + ", b) {}", SyntaxError);
363  CheckStrictMode("var foo = function (" + word + ") {}", SyntaxError);
364
365  // Function names and arguments when the body is strict
366  assertThrows("function " + word + " () { 'use strict'; }", SyntaxError);
367  assertThrows("function foo (" + word + ")  'use strict'; {}", SyntaxError);
368  assertThrows("function foo (" + word + ", " + word + ") { 'use strict'; }",
369               SyntaxError);
370  assertThrows("function foo (a, " + word + ") { 'use strict'; }", SyntaxError);
371  assertThrows("function foo (" + word + ", a) { 'use strict'; }", SyntaxError);
372  assertThrows("function foo (a, " + word + ", b) { 'use strict'; }",
373               SyntaxError);
374  assertThrows("var foo = function (" + word + ") { 'use strict'; }",
375               SyntaxError);
376
377  // get/set when the body is strict
378  eval("var x = { get " + word + " () { 'use strict'; } };");
379  eval("var x = { set " + word + " (value) { 'use strict'; } };");
380  assertThrows("var x = { get foo(" + word + ") { 'use strict'; } };",
381               SyntaxError);
382  assertThrows("var x = { set foo(" + word + ") { 'use strict'; } };",
383               SyntaxError);
384}
385
386for (var i = 0; i < future_reserved_words.length; i++) {
387  testFutureReservedWord(future_reserved_words[i]);
388}
389
390function testAssignToUndefined(should_throw) {
391  "use strict";
392  try {
393    possibly_undefined_variable_for_strict_mode_test = "should throw?";
394  } catch (e) {
395    assertTrue(should_throw, "strict mode");
396    assertInstanceof(e, ReferenceError, "strict mode");
397    return;
398  }
399  assertFalse(should_throw, "strict mode");
400}
401
402testAssignToUndefined(true);
403testAssignToUndefined(true);
404testAssignToUndefined(true);
405
406possibly_undefined_variable_for_strict_mode_test = "value";
407
408testAssignToUndefined(false);
409testAssignToUndefined(false);
410testAssignToUndefined(false);
411
412delete possibly_undefined_variable_for_strict_mode_test;
413
414testAssignToUndefined(true);
415testAssignToUndefined(true);
416testAssignToUndefined(true);
417
418function repeat(n, f) {
419 for (var i = 0; i < n; i ++) { f(); }
420}
421
422repeat(10, function() { testAssignToUndefined(true); });
423possibly_undefined_variable_for_strict_mode_test = "value";
424repeat(10, function() { testAssignToUndefined(false); });
425delete possibly_undefined_variable_for_strict_mode_test;
426repeat(10, function() { testAssignToUndefined(true); });
427possibly_undefined_variable_for_strict_mode_test = undefined;
428repeat(10, function() { testAssignToUndefined(false); });
429
430(function testDeleteNonConfigurable() {
431  function delete_property(o) {
432    "use strict";
433    delete o.property;
434  }
435  function delete_element(o, i) {
436    "use strict";
437    delete o[i];
438  }
439
440  var object = {};
441
442  Object.defineProperty(object, "property", { value: "property_value" });
443  Object.defineProperty(object, "1", { value: "one" });
444  Object.defineProperty(object, 7, { value: "seven" });
445  Object.defineProperty(object, 3.14, { value: "pi" });
446
447  assertThrows(function() { delete_property(object); }, TypeError);
448  assertEquals(object.property, "property_value");
449  assertThrows(function() { delete_element(object, "1"); }, TypeError);
450  assertThrows(function() { delete_element(object, 1); }, TypeError);
451  assertEquals(object[1], "one");
452  assertThrows(function() { delete_element(object, "7"); }, TypeError);
453  assertThrows(function() { delete_element(object, 7); }, TypeError);
454  assertEquals(object[7], "seven");
455  assertThrows(function() { delete_element(object, "3.14"); }, TypeError);
456  assertThrows(function() { delete_element(object, 3.14); }, TypeError);
457  assertEquals(object[3.14], "pi");
458})();
459
460// Not transforming this in Function.call and Function.apply.
461(function testThisTransformCallApply() {
462  function non_strict() {
463    return this;
464  }
465  function strict() {
466    "use strict";
467    return this;
468  }
469
470  var global_object = (function() { return this; })();
471  var object = {};
472
473  // Non-strict call.
474  assertTrue(non_strict.call(null) === global_object);
475  assertTrue(non_strict.call(undefined) === global_object);
476  assertEquals(typeof non_strict.call(7), "object");
477  assertEquals(typeof non_strict.call("Hello"), "object");
478  assertTrue(non_strict.call(object) === object);
479
480  // Non-strict apply.
481  assertTrue(non_strict.apply(null) === global_object);
482  assertTrue(non_strict.apply(undefined) === global_object);
483  assertEquals(typeof non_strict.apply(7), "object");
484  assertEquals(typeof non_strict.apply("Hello"), "object");
485  assertTrue(non_strict.apply(object) === object);
486
487  // Strict call.
488  assertTrue(strict.call(null) === null);
489  assertTrue(strict.call(undefined) === undefined);
490  assertEquals(typeof strict.call(7), "number");
491  assertEquals(typeof strict.call("Hello"), "string");
492  assertTrue(strict.call(object) === object);
493
494  // Strict apply.
495  assertTrue(strict.apply(null) === null);
496  assertTrue(strict.apply(undefined) === undefined);
497  assertEquals(typeof strict.apply(7), "number");
498  assertEquals(typeof strict.apply("Hello"), "string");
499  assertTrue(strict.apply(object) === object);
500})();
501
502(function testThisTransform() {
503  try {
504    function strict() {
505      "use strict";
506      return typeof(this);
507    }
508    function nonstrict() {
509      return typeof(this);
510    }
511
512    // Concat to avoid symbol.
513    var strict_name = "str" + "ict";
514    var nonstrict_name = "non" + "str" + "ict";
515    var strict_number = 17;
516    var nonstrict_number = 19;
517    var strict_name_get = "str" + "ict" + "get";
518    var nonstrict_name_get = "non" + "str" + "ict" + "get"
519    var strict_number_get = 23;
520    var nonstrict_number_get = 29;
521
522    function install(t) {
523      t.prototype.strict = strict;
524      t.prototype.nonstrict = nonstrict;
525      t.prototype[strict_number] = strict;
526      t.prototype[nonstrict_number] = nonstrict;
527      Object.defineProperty(t.prototype, strict_name_get,
528                            { get: function() { return strict; },
529                              configurable: true });
530      Object.defineProperty(t.prototype, nonstrict_name_get,
531                            { get: function() { return nonstrict; },
532                              configurable: true });
533      Object.defineProperty(t.prototype, strict_number_get,
534                            { get: function() { return strict; },
535                              configurable: true });
536      Object.defineProperty(t.prototype, nonstrict_number_get,
537                            { get: function() { return nonstrict; },
538                              configurable: true });
539    }
540
541    function cleanup(t) {
542      delete t.prototype.strict;
543      delete t.prototype.nonstrict;
544      delete t.prototype[strict_number];
545      delete t.prototype[nonstrict_number];
546      delete t.prototype[strict_name_get];
547      delete t.prototype[nonstrict_name_get];
548      delete t.prototype[strict_number_get];
549      delete t.prototype[nonstrict_number_get];
550    }
551
552    // Set up fakes
553    install(String);
554    install(Number);
555    install(Boolean)
556
557    function callStrict(o) {
558      return o.strict();
559    }
560    function callNonStrict(o) {
561      return o.nonstrict();
562    }
563    function callKeyedStrict(o) {
564      return o[strict_name]();
565    }
566    function callKeyedNonStrict(o) {
567      return o[nonstrict_name]();
568    }
569    function callIndexedStrict(o) {
570      return o[strict_number]();
571    }
572    function callIndexedNonStrict(o) {
573      return o[nonstrict_number]();
574    }
575    function callStrictGet(o) {
576      return o.strictget();
577    }
578    function callNonStrictGet(o) {
579      return o.nonstrictget();
580    }
581    function callKeyedStrictGet(o) {
582      return o[strict_name_get]();
583    }
584    function callKeyedNonStrictGet(o) {
585      return o[nonstrict_name_get]();
586    }
587    function callIndexedStrictGet(o) {
588      return o[strict_number_get]();
589    }
590    function callIndexedNonStrictGet(o) {
591      return o[nonstrict_number_get]();
592    }
593
594    for (var i = 0; i < 10; i ++) {
595      assertEquals(("hello").strict(), "string");
596      assertEquals(("hello").nonstrict(), "object");
597      assertEquals(("hello")[strict_name](), "string");
598      assertEquals(("hello")[nonstrict_name](), "object");
599      assertEquals(("hello")[strict_number](), "string");
600      assertEquals(("hello")[nonstrict_number](), "object");
601
602      assertEquals((10 + i).strict(), "number");
603      assertEquals((10 + i).nonstrict(), "object");
604      assertEquals((10 + i)[strict_name](), "number");
605      assertEquals((10 + i)[nonstrict_name](), "object");
606      assertEquals((10 + i)[strict_number](), "number");
607      assertEquals((10 + i)[nonstrict_number](), "object");
608
609      assertEquals((true).strict(), "boolean");
610      assertEquals((true).nonstrict(), "object");
611      assertEquals((true)[strict_name](), "boolean");
612      assertEquals((true)[nonstrict_name](), "object");
613      assertEquals((true)[strict_number](), "boolean");
614      assertEquals((true)[nonstrict_number](), "object");
615
616      assertEquals((false).strict(), "boolean");
617      assertEquals((false).nonstrict(), "object");
618      assertEquals((false)[strict_name](), "boolean");
619      assertEquals((false)[nonstrict_name](), "object");
620      assertEquals((false)[strict_number](), "boolean");
621      assertEquals((false)[nonstrict_number](), "object");
622
623      assertEquals(callStrict("howdy"), "string");
624      assertEquals(callNonStrict("howdy"), "object");
625      assertEquals(callKeyedStrict("howdy"), "string");
626      assertEquals(callKeyedNonStrict("howdy"), "object");
627      assertEquals(callIndexedStrict("howdy"), "string");
628      assertEquals(callIndexedNonStrict("howdy"), "object");
629
630      assertEquals(callStrict(17 + i), "number");
631      assertEquals(callNonStrict(17 + i), "object");
632      assertEquals(callKeyedStrict(17 + i), "number");
633      assertEquals(callKeyedNonStrict(17 + i), "object");
634      assertEquals(callIndexedStrict(17 + i), "number");
635      assertEquals(callIndexedNonStrict(17 + i), "object");
636
637      assertEquals(callStrict(true), "boolean");
638      assertEquals(callNonStrict(true), "object");
639      assertEquals(callKeyedStrict(true), "boolean");
640      assertEquals(callKeyedNonStrict(true), "object");
641      assertEquals(callIndexedStrict(true), "boolean");
642      assertEquals(callIndexedNonStrict(true), "object");
643
644      assertEquals(callStrict(false), "boolean");
645      assertEquals(callNonStrict(false), "object");
646      assertEquals(callKeyedStrict(false), "boolean");
647      assertEquals(callKeyedNonStrict(false), "object");
648      assertEquals(callIndexedStrict(false), "boolean");
649      assertEquals(callIndexedNonStrict(false), "object");
650
651      // All of the above, with getters
652      assertEquals(("hello").strictget(), "string");
653      assertEquals(("hello").nonstrictget(), "object");
654      assertEquals(("hello")[strict_name_get](), "string");
655      assertEquals(("hello")[nonstrict_name_get](), "object");
656      assertEquals(("hello")[strict_number_get](), "string");
657      assertEquals(("hello")[nonstrict_number_get](), "object");
658
659      assertEquals((10 + i).strictget(), "number");
660      assertEquals((10 + i).nonstrictget(), "object");
661      assertEquals((10 + i)[strict_name_get](), "number");
662      assertEquals((10 + i)[nonstrict_name_get](), "object");
663      assertEquals((10 + i)[strict_number_get](), "number");
664      assertEquals((10 + i)[nonstrict_number_get](), "object");
665
666      assertEquals((true).strictget(), "boolean");
667      assertEquals((true).nonstrictget(), "object");
668      assertEquals((true)[strict_name_get](), "boolean");
669      assertEquals((true)[nonstrict_name_get](), "object");
670      assertEquals((true)[strict_number_get](), "boolean");
671      assertEquals((true)[nonstrict_number_get](), "object");
672
673      assertEquals((false).strictget(), "boolean");
674      assertEquals((false).nonstrictget(), "object");
675      assertEquals((false)[strict_name_get](), "boolean");
676      assertEquals((false)[nonstrict_name_get](), "object");
677      assertEquals((false)[strict_number_get](), "boolean");
678      assertEquals((false)[nonstrict_number_get](), "object");
679
680      assertEquals(callStrictGet("howdy"), "string");
681      assertEquals(callNonStrictGet("howdy"), "object");
682      assertEquals(callKeyedStrictGet("howdy"), "string");
683      assertEquals(callKeyedNonStrictGet("howdy"), "object");
684      assertEquals(callIndexedStrictGet("howdy"), "string");
685      assertEquals(callIndexedNonStrictGet("howdy"), "object");
686
687      assertEquals(callStrictGet(17 + i), "number");
688      assertEquals(callNonStrictGet(17 + i), "object");
689      assertEquals(callKeyedStrictGet(17 + i), "number");
690      assertEquals(callKeyedNonStrictGet(17 + i), "object");
691      assertEquals(callIndexedStrictGet(17 + i), "number");
692      assertEquals(callIndexedNonStrictGet(17 + i), "object");
693
694      assertEquals(callStrictGet(true), "boolean");
695      assertEquals(callNonStrictGet(true), "object");
696      assertEquals(callKeyedStrictGet(true), "boolean");
697      assertEquals(callKeyedNonStrictGet(true), "object");
698      assertEquals(callIndexedStrictGet(true), "boolean");
699      assertEquals(callIndexedNonStrictGet(true), "object");
700
701      assertEquals(callStrictGet(false), "boolean");
702      assertEquals(callNonStrictGet(false), "object");
703      assertEquals(callKeyedStrictGet(false), "boolean");
704      assertEquals(callKeyedNonStrictGet(false), "object");
705      assertEquals(callIndexedStrictGet(false), "boolean");
706      assertEquals(callIndexedNonStrictGet(false), "object");
707
708    }
709  } finally {
710    // Cleanup
711    cleanup(String);
712    cleanup(Number);
713    cleanup(Boolean);
714  }
715})();
716
717
718(function ObjectEnvironment() {
719  var o = {};
720  Object.defineProperty(o, "foo", { value: "FOO", writable: false });
721  assertThrows(
722    function () {
723      with (o) {
724        (function() {
725          "use strict";
726          foo = "Hello";
727        })();
728      }
729    },
730    TypeError);
731})();
732
733
734(function TestSetPropertyWithoutSetter() {
735  var o = { get foo() { return "Yey"; } };
736  assertThrows(
737    function broken() {
738      "use strict";
739      o.foo = (0xBADBAD00 >> 1);
740    },
741    TypeError);
742})();
743
744
745(function TestSetPropertyNonConfigurable() {
746  var frozen = Object.freeze({});
747  var sealed = Object.seal({});
748
749  function strict(o) {
750    "use strict";
751    o.property = "value";
752  }
753
754  assertThrows(function() { strict(frozen); }, TypeError);
755  assertThrows(function() { strict(sealed); }, TypeError);
756})();
757
758
759(function TestAssignmentToReadOnlyProperty() {
760  "use strict";
761
762  var o = {};
763  Object.defineProperty(o, "property", { value: 7 });
764
765  assertThrows(function() { o.property = "new value"; }, TypeError);
766  assertThrows(function() { o.property += 10; }, TypeError);
767  assertThrows(function() { o.property -= 10; }, TypeError);
768  assertThrows(function() { o.property *= 10; }, TypeError);
769  assertThrows(function() { o.property /= 10; }, TypeError);
770  assertThrows(function() { o.property++; }, TypeError);
771  assertThrows(function() { o.property--; }, TypeError);
772  assertThrows(function() { ++o.property; }, TypeError);
773  assertThrows(function() { --o.property; }, TypeError);
774
775  var name = "prop" + "erty"; // to avoid symbol path.
776  assertThrows(function() { o[name] = "new value"; }, TypeError);
777  assertThrows(function() { o[name] += 10; }, TypeError);
778  assertThrows(function() { o[name] -= 10; }, TypeError);
779  assertThrows(function() { o[name] *= 10; }, TypeError);
780  assertThrows(function() { o[name] /= 10; }, TypeError);
781  assertThrows(function() { o[name]++; }, TypeError);
782  assertThrows(function() { o[name]--; }, TypeError);
783  assertThrows(function() { ++o[name]; }, TypeError);
784  assertThrows(function() { --o[name]; }, TypeError);
785
786  assertEquals(o.property, 7);
787})();
788
789
790(function TestAssignmentToReadOnlyLoop() {
791  var name = "prop" + "erty"; // to avoid symbol path.
792  var o = {};
793  Object.defineProperty(o, "property", { value: 7 });
794
795  function strict(o, name) {
796    "use strict";
797    o[name] = "new value";
798  }
799
800  for (var i = 0; i < 10; i ++) {
801    try {
802      strict(o, name);
803      assertUnreachable();
804    } catch(e) {
805      assertInstanceof(e, TypeError);
806    }
807  }
808})();
809
810
811// Specialized KeyedStoreIC experiencing miss.
812(function testKeyedStoreICStrict() {
813  var o = [9,8,7,6,5,4,3,2,1];
814
815  function test(o, i, v) {
816    "use strict";
817    o[i] = v;
818  }
819
820  for (var i = 0; i < 10; i ++) {
821    test(o, 5, 17);        // start specialized for smi indices
822    assertEquals(o[5], 17);
823    test(o, "a", 19);
824    assertEquals(o["a"], 19);
825    test(o, "5", 29);
826    assertEquals(o[5], 29);
827    test(o, 100000, 31);
828    assertEquals(o[100000], 31);
829  }
830})();
831
832
833(function TestSetElementWithoutSetter() {
834  "use strict";
835
836  var o = { };
837  Object.defineProperty(o, 0, { get : function() { } });
838
839  var zero_smi = 0;
840  var zero_number = new Number(0);
841  var zero_symbol = "0";
842  var zero_string = "-0-".substring(1,2);
843
844  assertThrows(function() { o[zero_smi] = "new value"; }, TypeError);
845  assertThrows(function() { o[zero_number] = "new value"; }, TypeError);
846  assertThrows(function() { o[zero_symbol] = "new value"; }, TypeError);
847  assertThrows(function() { o[zero_string] = "new value"; }, TypeError);
848})();
849
850
851(function TestSetElementNonConfigurable() {
852  "use strict";
853  var frozen = Object.freeze({});
854  var sealed = Object.seal({});
855
856  var zero_number = 0;
857  var zero_symbol = "0";
858  var zero_string = "-0-".substring(1,2);
859
860  assertThrows(function() { frozen[zero_number] = "value"; }, TypeError);
861  assertThrows(function() { sealed[zero_number] = "value"; }, TypeError);
862  assertThrows(function() { frozen[zero_symbol] = "value"; }, TypeError);
863  assertThrows(function() { sealed[zero_symbol] = "value"; }, TypeError);
864  assertThrows(function() { frozen[zero_string] = "value"; }, TypeError);
865  assertThrows(function() { sealed[zero_string] = "value"; }, TypeError);
866})();
867
868
869(function TestAssignmentToReadOnlyElement() {
870  "use strict";
871
872  var o = {};
873  Object.defineProperty(o, 7, { value: 17 });
874
875  var seven_smi = 7;
876  var seven_number = new Number(7);
877  var seven_symbol = "7";
878  var seven_string = "-7-".substring(1,2);
879
880  // Index with number.
881  assertThrows(function() { o[seven_smi] = "value"; }, TypeError);
882  assertThrows(function() { o[seven_smi] += 10; }, TypeError);
883  assertThrows(function() { o[seven_smi] -= 10; }, TypeError);
884  assertThrows(function() { o[seven_smi] *= 10; }, TypeError);
885  assertThrows(function() { o[seven_smi] /= 10; }, TypeError);
886  assertThrows(function() { o[seven_smi]++; }, TypeError);
887  assertThrows(function() { o[seven_smi]--; }, TypeError);
888  assertThrows(function() { ++o[seven_smi]; }, TypeError);
889  assertThrows(function() { --o[seven_smi]; }, TypeError);
890
891  assertThrows(function() { o[seven_number] = "value"; }, TypeError);
892  assertThrows(function() { o[seven_number] += 10; }, TypeError);
893  assertThrows(function() { o[seven_number] -= 10; }, TypeError);
894  assertThrows(function() { o[seven_number] *= 10; }, TypeError);
895  assertThrows(function() { o[seven_number] /= 10; }, TypeError);
896  assertThrows(function() { o[seven_number]++; }, TypeError);
897  assertThrows(function() { o[seven_number]--; }, TypeError);
898  assertThrows(function() { ++o[seven_number]; }, TypeError);
899  assertThrows(function() { --o[seven_number]; }, TypeError);
900
901  assertThrows(function() { o[seven_symbol] = "value"; }, TypeError);
902  assertThrows(function() { o[seven_symbol] += 10; }, TypeError);
903  assertThrows(function() { o[seven_symbol] -= 10; }, TypeError);
904  assertThrows(function() { o[seven_symbol] *= 10; }, TypeError);
905  assertThrows(function() { o[seven_symbol] /= 10; }, TypeError);
906  assertThrows(function() { o[seven_symbol]++; }, TypeError);
907  assertThrows(function() { o[seven_symbol]--; }, TypeError);
908  assertThrows(function() { ++o[seven_symbol]; }, TypeError);
909  assertThrows(function() { --o[seven_symbol]; }, TypeError);
910
911  assertThrows(function() { o[seven_string] = "value"; }, TypeError);
912  assertThrows(function() { o[seven_string] += 10; }, TypeError);
913  assertThrows(function() { o[seven_string] -= 10; }, TypeError);
914  assertThrows(function() { o[seven_string] *= 10; }, TypeError);
915  assertThrows(function() { o[seven_string] /= 10; }, TypeError);
916  assertThrows(function() { o[seven_string]++; }, TypeError);
917  assertThrows(function() { o[seven_string]--; }, TypeError);
918  assertThrows(function() { ++o[seven_string]; }, TypeError);
919  assertThrows(function() { --o[seven_string]; }, TypeError);
920
921  assertEquals(o[seven_number], 17);
922  assertEquals(o[seven_symbol], 17);
923  assertEquals(o[seven_string], 17);
924})();
925
926
927(function TestAssignmentToReadOnlyLoop() {
928  "use strict";
929
930  var o = {};
931  Object.defineProperty(o, 7, { value: 17 });
932
933  var seven_smi = 7;
934  var seven_number = new Number(7);
935  var seven_symbol = "7";
936  var seven_string = "-7-".substring(1,2);
937
938  for (var i = 0; i < 10; i ++) {
939    assertThrows(function() { o[seven_smi] = "value" }, TypeError);
940    assertThrows(function() { o[seven_number] = "value" }, TypeError);
941    assertThrows(function() { o[seven_symbol] = "value" }, TypeError);
942    assertThrows(function() { o[seven_string] = "value" }, TypeError);
943  }
944
945  assertEquals(o[7], 17);
946})();
947
948
949(function TestAssignmentToStringLength() {
950  "use strict";
951
952  var str_val = "string";
953  var str_obj = new String(str_val);
954  var str_cat = str_val + str_val + str_obj;
955
956  assertThrows(function() { str_val.length = 1; }, TypeError);
957  assertThrows(function() { str_obj.length = 1; }, TypeError);
958  assertThrows(function() { str_cat.length = 1; }, TypeError);
959})();
960
961
962(function TestArgumentsAliasing() {
963  function strict(a, b) {
964    "use strict";
965    a = "c";
966    b = "d";
967    return [a, b, arguments[0], arguments[1]];
968  }
969
970  function nonstrict(a, b) {
971    a = "c";
972    b = "d";
973    return [a, b, arguments[0], arguments[1]];
974  }
975
976  assertEquals(["c", "d", "a", "b"], strict("a", "b"));
977  assertEquals(["c", "d", "c", "d"], nonstrict("a", "b"));
978})();
979
980
981function CheckPillDescriptor(func, name) {
982
983  function CheckPill(pill) {
984    assertEquals("function", typeof pill);
985    assertInstanceof(pill, Function);
986    pill.property = "value";
987    assertEquals(pill.value, undefined);
988    assertThrows(function() { 'use strict'; pill.property = "value"; },
989                 TypeError);
990    assertThrows(pill, TypeError);
991    assertEquals(pill.prototype, (function(){}).prototype);
992    var d = Object.getOwnPropertyDescriptor(pill, "prototype");
993    assertFalse(d.writable);
994    assertFalse(d.configurable);
995    assertFalse(d.enumerable);
996  }
997
998  var descriptor = Object.getOwnPropertyDescriptor(func, name);
999  CheckPill(descriptor.get)
1000  CheckPill(descriptor.set);
1001  assertFalse(descriptor.enumerable);
1002  assertFalse(descriptor.configurable);
1003}
1004
1005
1006(function TestStrictFunctionPills() {
1007  function strict() {
1008    "use strict";
1009  }
1010  assertThrows(function() { strict.caller; }, TypeError);
1011  assertThrows(function() { strict.arguments; }, TypeError);
1012
1013  var another = new Function("'use strict'");
1014  assertThrows(function() { another.caller; }, TypeError);
1015  assertThrows(function() { another.arguments; }, TypeError);
1016
1017  var third = (function() { "use strict"; return function() {}; })();
1018  assertThrows(function() { third.caller; }, TypeError);
1019  assertThrows(function() { third.arguments; }, TypeError);
1020
1021  CheckPillDescriptor(strict, "caller");
1022  CheckPillDescriptor(strict, "arguments");
1023  CheckPillDescriptor(another, "caller");
1024  CheckPillDescriptor(another, "arguments");
1025  CheckPillDescriptor(third, "caller");
1026  CheckPillDescriptor(third, "arguments");
1027})();
1028
1029
1030(function TestStrictFunctionWritablePrototype() {
1031  "use strict";
1032  function TheClass() {
1033  }
1034  assertThrows(function() { TheClass.caller; }, TypeError);
1035  assertThrows(function() { TheClass.arguments; }, TypeError);
1036
1037  // Strict functions must have writable prototype.
1038  TheClass.prototype = {
1039    func: function() { return "func_value"; },
1040    get accessor() { return "accessor_value"; },
1041    property: "property_value",
1042  };
1043
1044  var o = new TheClass();
1045  assertEquals(o.func(), "func_value");
1046  assertEquals(o.accessor, "accessor_value");
1047  assertEquals(o.property, "property_value");
1048})();
1049
1050
1051(function TestStrictArgumentPills() {
1052  function strict() {
1053    "use strict";
1054    return arguments;
1055  }
1056
1057  var args = strict();
1058  CheckPillDescriptor(args, "caller");
1059  CheckPillDescriptor(args, "callee");
1060
1061  args = strict(17, "value", strict);
1062  assertEquals(17, args[0])
1063  assertEquals("value", args[1])
1064  assertEquals(strict, args[2]);
1065  CheckPillDescriptor(args, "caller");
1066  CheckPillDescriptor(args, "callee");
1067
1068  function outer() {
1069    "use strict";
1070    function inner() {
1071      return arguments;
1072    }
1073    return inner;
1074  }
1075
1076  var args = outer()();
1077  CheckPillDescriptor(args, "caller");
1078  CheckPillDescriptor(args, "callee");
1079
1080  args = outer()(17, "value", strict);
1081  assertEquals(17, args[0])
1082  assertEquals("value", args[1])
1083  assertEquals(strict, args[2]);
1084  CheckPillDescriptor(args, "caller");
1085  CheckPillDescriptor(args, "callee");
1086})();
1087
1088
1089(function TestNonStrictFunctionCallerPillSimple() {
1090  function return_my_caller() {
1091    return return_my_caller.caller;
1092  }
1093
1094  function strict() {
1095    "use strict";
1096    return_my_caller();
1097  }
1098  assertThrows(strict, TypeError);
1099
1100  function non_strict() {
1101    return return_my_caller();
1102  }
1103  assertSame(non_strict(), non_strict);
1104})();
1105
1106
1107(function TestNonStrictFunctionCallerPill() {
1108  function strict(n) {
1109    "use strict";
1110    non_strict(n);
1111  }
1112
1113  function recurse(n, then) {
1114    if (n > 0) {
1115      recurse(n - 1);
1116    } else {
1117      return then();
1118    }
1119  }
1120
1121  function non_strict(n) {
1122    recurse(n, function() { non_strict.caller; });
1123  }
1124
1125  function test(n) {
1126    try {
1127      recurse(n, function() { strict(n); });
1128    } catch(e) {
1129      return e instanceof TypeError;
1130    }
1131    return false;
1132  }
1133
1134  for (var i = 0; i < 10; i ++) {
1135    assertEquals(test(i), true);
1136  }
1137})();
1138