strict-mode.js revision 257744e915dfc84d6d07a6b2accf8402d9ffc708
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(test, should_throw) {
391  try {
392    test();
393  } catch (e) {
394    assertTrue(should_throw, "strict mode");
395    assertInstanceof(e, ReferenceError, "strict mode");
396    return;
397  }
398  assertFalse(should_throw, "strict mode");
399}
400
401function repeat(n, f) {
402  for (var i = 0; i < n; i ++) { f(); }
403}
404
405function assignToUndefined() {
406  "use strict";
407  possibly_undefined_variable_for_strict_mode_test = "should throw?";
408}
409
410testAssignToUndefined(assignToUndefined, true);
411testAssignToUndefined(assignToUndefined, true);
412testAssignToUndefined(assignToUndefined, true);
413
414possibly_undefined_variable_for_strict_mode_test = "value";
415
416testAssignToUndefined(assignToUndefined, false);
417testAssignToUndefined(assignToUndefined, false);
418testAssignToUndefined(assignToUndefined, false);
419
420delete possibly_undefined_variable_for_strict_mode_test;
421
422testAssignToUndefined(assignToUndefined, true);
423testAssignToUndefined(assignToUndefined, true);
424testAssignToUndefined(assignToUndefined, true);
425
426repeat(10, function() { testAssignToUndefined(assignToUndefined, true); });
427possibly_undefined_variable_for_strict_mode_test = "value";
428repeat(10, function() { testAssignToUndefined(assignToUndefined, false); });
429delete possibly_undefined_variable_for_strict_mode_test;
430repeat(10, function() { testAssignToUndefined(assignToUndefined, true); });
431possibly_undefined_variable_for_strict_mode_test = undefined;
432repeat(10, function() { testAssignToUndefined(assignToUndefined, false); });
433
434function assignToUndefinedWithEval() {
435  "use strict";
436  possibly_undefined_variable_for_strict_mode_test_with_eval = "should throw?";
437  eval("");
438}
439
440testAssignToUndefined(assignToUndefinedWithEval, true);
441testAssignToUndefined(assignToUndefinedWithEval, true);
442testAssignToUndefined(assignToUndefinedWithEval, true);
443
444possibly_undefined_variable_for_strict_mode_test_with_eval = "value";
445
446testAssignToUndefined(assignToUndefinedWithEval, false);
447testAssignToUndefined(assignToUndefinedWithEval, false);
448testAssignToUndefined(assignToUndefinedWithEval, false);
449
450delete possibly_undefined_variable_for_strict_mode_test_with_eval;
451
452testAssignToUndefined(assignToUndefinedWithEval, true);
453testAssignToUndefined(assignToUndefinedWithEval, true);
454testAssignToUndefined(assignToUndefinedWithEval, true);
455
456repeat(10, function() {
457             testAssignToUndefined(assignToUndefinedWithEval, true);
458           });
459possibly_undefined_variable_for_strict_mode_test_with_eval = "value";
460repeat(10, function() {
461             testAssignToUndefined(assignToUndefinedWithEval, false);
462           });
463delete possibly_undefined_variable_for_strict_mode_test_with_eval;
464repeat(10, function() {
465             testAssignToUndefined(assignToUndefinedWithEval, true);
466           });
467possibly_undefined_variable_for_strict_mode_test_with_eval = undefined;
468repeat(10, function() {
469             testAssignToUndefined(assignToUndefinedWithEval, false);
470           });
471
472
473
474(function testDeleteNonConfigurable() {
475  function delete_property(o) {
476    "use strict";
477    delete o.property;
478  }
479  function delete_element(o, i) {
480    "use strict";
481    delete o[i];
482  }
483
484  var object = {};
485
486  Object.defineProperty(object, "property", { value: "property_value" });
487  Object.defineProperty(object, "1", { value: "one" });
488  Object.defineProperty(object, 7, { value: "seven" });
489  Object.defineProperty(object, 3.14, { value: "pi" });
490
491  assertThrows(function() { delete_property(object); }, TypeError);
492  assertEquals(object.property, "property_value");
493  assertThrows(function() { delete_element(object, "1"); }, TypeError);
494  assertThrows(function() { delete_element(object, 1); }, TypeError);
495  assertEquals(object[1], "one");
496  assertThrows(function() { delete_element(object, "7"); }, TypeError);
497  assertThrows(function() { delete_element(object, 7); }, TypeError);
498  assertEquals(object[7], "seven");
499  assertThrows(function() { delete_element(object, "3.14"); }, TypeError);
500  assertThrows(function() { delete_element(object, 3.14); }, TypeError);
501  assertEquals(object[3.14], "pi");
502})();
503
504// Not transforming this in Function.call and Function.apply.
505(function testThisTransformCallApply() {
506  function non_strict() {
507    return this;
508  }
509  function strict() {
510    "use strict";
511    return this;
512  }
513
514  var global_object = (function() { return this; })();
515  var object = {};
516
517  // Non-strict call.
518  assertTrue(non_strict.call(null) === global_object);
519  assertTrue(non_strict.call(undefined) === global_object);
520  assertEquals(typeof non_strict.call(7), "object");
521  assertEquals(typeof non_strict.call("Hello"), "object");
522  assertTrue(non_strict.call(object) === object);
523
524  // Non-strict apply.
525  assertTrue(non_strict.apply(null) === global_object);
526  assertTrue(non_strict.apply(undefined) === global_object);
527  assertEquals(typeof non_strict.apply(7), "object");
528  assertEquals(typeof non_strict.apply("Hello"), "object");
529  assertTrue(non_strict.apply(object) === object);
530
531  // Strict call.
532  assertTrue(strict.call(null) === null);
533  assertTrue(strict.call(undefined) === undefined);
534  assertEquals(typeof strict.call(7), "number");
535  assertEquals(typeof strict.call("Hello"), "string");
536  assertTrue(strict.call(object) === object);
537
538  // Strict apply.
539  assertTrue(strict.apply(null) === null);
540  assertTrue(strict.apply(undefined) === undefined);
541  assertEquals(typeof strict.apply(7), "number");
542  assertEquals(typeof strict.apply("Hello"), "string");
543  assertTrue(strict.apply(object) === object);
544})();
545
546(function testThisTransform() {
547  try {
548    function strict() {
549      "use strict";
550      return typeof(this);
551    }
552    function nonstrict() {
553      return typeof(this);
554    }
555
556    // Concat to avoid symbol.
557    var strict_name = "str" + "ict";
558    var nonstrict_name = "non" + "str" + "ict";
559    var strict_number = 17;
560    var nonstrict_number = 19;
561    var strict_name_get = "str" + "ict" + "get";
562    var nonstrict_name_get = "non" + "str" + "ict" + "get"
563    var strict_number_get = 23;
564    var nonstrict_number_get = 29;
565
566    function install(t) {
567      t.prototype.strict = strict;
568      t.prototype.nonstrict = nonstrict;
569      t.prototype[strict_number] = strict;
570      t.prototype[nonstrict_number] = nonstrict;
571      Object.defineProperty(t.prototype, strict_name_get,
572                            { get: function() { return strict; },
573                              configurable: true });
574      Object.defineProperty(t.prototype, nonstrict_name_get,
575                            { get: function() { return nonstrict; },
576                              configurable: true });
577      Object.defineProperty(t.prototype, strict_number_get,
578                            { get: function() { return strict; },
579                              configurable: true });
580      Object.defineProperty(t.prototype, nonstrict_number_get,
581                            { get: function() { return nonstrict; },
582                              configurable: true });
583    }
584
585    function cleanup(t) {
586      delete t.prototype.strict;
587      delete t.prototype.nonstrict;
588      delete t.prototype[strict_number];
589      delete t.prototype[nonstrict_number];
590      delete t.prototype[strict_name_get];
591      delete t.prototype[nonstrict_name_get];
592      delete t.prototype[strict_number_get];
593      delete t.prototype[nonstrict_number_get];
594    }
595
596    // Set up fakes
597    install(String);
598    install(Number);
599    install(Boolean)
600
601    function callStrict(o) {
602      return o.strict();
603    }
604    function callNonStrict(o) {
605      return o.nonstrict();
606    }
607    function callKeyedStrict(o) {
608      return o[strict_name]();
609    }
610    function callKeyedNonStrict(o) {
611      return o[nonstrict_name]();
612    }
613    function callIndexedStrict(o) {
614      return o[strict_number]();
615    }
616    function callIndexedNonStrict(o) {
617      return o[nonstrict_number]();
618    }
619    function callStrictGet(o) {
620      return o.strictget();
621    }
622    function callNonStrictGet(o) {
623      return o.nonstrictget();
624    }
625    function callKeyedStrictGet(o) {
626      return o[strict_name_get]();
627    }
628    function callKeyedNonStrictGet(o) {
629      return o[nonstrict_name_get]();
630    }
631    function callIndexedStrictGet(o) {
632      return o[strict_number_get]();
633    }
634    function callIndexedNonStrictGet(o) {
635      return o[nonstrict_number_get]();
636    }
637
638    for (var i = 0; i < 10; i ++) {
639      assertEquals(("hello").strict(), "string");
640      assertEquals(("hello").nonstrict(), "object");
641      assertEquals(("hello")[strict_name](), "string");
642      assertEquals(("hello")[nonstrict_name](), "object");
643      assertEquals(("hello")[strict_number](), "string");
644      assertEquals(("hello")[nonstrict_number](), "object");
645
646      assertEquals((10 + i).strict(), "number");
647      assertEquals((10 + i).nonstrict(), "object");
648      assertEquals((10 + i)[strict_name](), "number");
649      assertEquals((10 + i)[nonstrict_name](), "object");
650      assertEquals((10 + i)[strict_number](), "number");
651      assertEquals((10 + i)[nonstrict_number](), "object");
652
653      assertEquals((true).strict(), "boolean");
654      assertEquals((true).nonstrict(), "object");
655      assertEquals((true)[strict_name](), "boolean");
656      assertEquals((true)[nonstrict_name](), "object");
657      assertEquals((true)[strict_number](), "boolean");
658      assertEquals((true)[nonstrict_number](), "object");
659
660      assertEquals((false).strict(), "boolean");
661      assertEquals((false).nonstrict(), "object");
662      assertEquals((false)[strict_name](), "boolean");
663      assertEquals((false)[nonstrict_name](), "object");
664      assertEquals((false)[strict_number](), "boolean");
665      assertEquals((false)[nonstrict_number](), "object");
666
667      assertEquals(callStrict("howdy"), "string");
668      assertEquals(callNonStrict("howdy"), "object");
669      assertEquals(callKeyedStrict("howdy"), "string");
670      assertEquals(callKeyedNonStrict("howdy"), "object");
671      assertEquals(callIndexedStrict("howdy"), "string");
672      assertEquals(callIndexedNonStrict("howdy"), "object");
673
674      assertEquals(callStrict(17 + i), "number");
675      assertEquals(callNonStrict(17 + i), "object");
676      assertEquals(callKeyedStrict(17 + i), "number");
677      assertEquals(callKeyedNonStrict(17 + i), "object");
678      assertEquals(callIndexedStrict(17 + i), "number");
679      assertEquals(callIndexedNonStrict(17 + i), "object");
680
681      assertEquals(callStrict(true), "boolean");
682      assertEquals(callNonStrict(true), "object");
683      assertEquals(callKeyedStrict(true), "boolean");
684      assertEquals(callKeyedNonStrict(true), "object");
685      assertEquals(callIndexedStrict(true), "boolean");
686      assertEquals(callIndexedNonStrict(true), "object");
687
688      assertEquals(callStrict(false), "boolean");
689      assertEquals(callNonStrict(false), "object");
690      assertEquals(callKeyedStrict(false), "boolean");
691      assertEquals(callKeyedNonStrict(false), "object");
692      assertEquals(callIndexedStrict(false), "boolean");
693      assertEquals(callIndexedNonStrict(false), "object");
694
695      // All of the above, with getters
696      assertEquals(("hello").strictget(), "string");
697      assertEquals(("hello").nonstrictget(), "object");
698      assertEquals(("hello")[strict_name_get](), "string");
699      assertEquals(("hello")[nonstrict_name_get](), "object");
700      assertEquals(("hello")[strict_number_get](), "string");
701      assertEquals(("hello")[nonstrict_number_get](), "object");
702
703      assertEquals((10 + i).strictget(), "number");
704      assertEquals((10 + i).nonstrictget(), "object");
705      assertEquals((10 + i)[strict_name_get](), "number");
706      assertEquals((10 + i)[nonstrict_name_get](), "object");
707      assertEquals((10 + i)[strict_number_get](), "number");
708      assertEquals((10 + i)[nonstrict_number_get](), "object");
709
710      assertEquals((true).strictget(), "boolean");
711      assertEquals((true).nonstrictget(), "object");
712      assertEquals((true)[strict_name_get](), "boolean");
713      assertEquals((true)[nonstrict_name_get](), "object");
714      assertEquals((true)[strict_number_get](), "boolean");
715      assertEquals((true)[nonstrict_number_get](), "object");
716
717      assertEquals((false).strictget(), "boolean");
718      assertEquals((false).nonstrictget(), "object");
719      assertEquals((false)[strict_name_get](), "boolean");
720      assertEquals((false)[nonstrict_name_get](), "object");
721      assertEquals((false)[strict_number_get](), "boolean");
722      assertEquals((false)[nonstrict_number_get](), "object");
723
724      assertEquals(callStrictGet("howdy"), "string");
725      assertEquals(callNonStrictGet("howdy"), "object");
726      assertEquals(callKeyedStrictGet("howdy"), "string");
727      assertEquals(callKeyedNonStrictGet("howdy"), "object");
728      assertEquals(callIndexedStrictGet("howdy"), "string");
729      assertEquals(callIndexedNonStrictGet("howdy"), "object");
730
731      assertEquals(callStrictGet(17 + i), "number");
732      assertEquals(callNonStrictGet(17 + i), "object");
733      assertEquals(callKeyedStrictGet(17 + i), "number");
734      assertEquals(callKeyedNonStrictGet(17 + i), "object");
735      assertEquals(callIndexedStrictGet(17 + i), "number");
736      assertEquals(callIndexedNonStrictGet(17 + i), "object");
737
738      assertEquals(callStrictGet(true), "boolean");
739      assertEquals(callNonStrictGet(true), "object");
740      assertEquals(callKeyedStrictGet(true), "boolean");
741      assertEquals(callKeyedNonStrictGet(true), "object");
742      assertEquals(callIndexedStrictGet(true), "boolean");
743      assertEquals(callIndexedNonStrictGet(true), "object");
744
745      assertEquals(callStrictGet(false), "boolean");
746      assertEquals(callNonStrictGet(false), "object");
747      assertEquals(callKeyedStrictGet(false), "boolean");
748      assertEquals(callKeyedNonStrictGet(false), "object");
749      assertEquals(callIndexedStrictGet(false), "boolean");
750      assertEquals(callIndexedNonStrictGet(false), "object");
751
752    }
753  } finally {
754    // Cleanup
755    cleanup(String);
756    cleanup(Number);
757    cleanup(Boolean);
758  }
759})();
760
761
762(function ObjectEnvironment() {
763  var o = {};
764  Object.defineProperty(o, "foo", { value: "FOO", writable: false });
765  assertThrows(
766    function () {
767      with (o) {
768        (function() {
769          "use strict";
770          foo = "Hello";
771        })();
772      }
773    },
774    TypeError);
775})();
776
777
778(function TestSetPropertyWithoutSetter() {
779  var o = { get foo() { return "Yey"; } };
780  assertThrows(
781    function broken() {
782      "use strict";
783      o.foo = (0xBADBAD00 >> 1);
784    },
785    TypeError);
786})();
787
788
789(function TestSetPropertyNonConfigurable() {
790  var frozen = Object.freeze({});
791  var sealed = Object.seal({});
792
793  function strict(o) {
794    "use strict";
795    o.property = "value";
796  }
797
798  assertThrows(function() { strict(frozen); }, TypeError);
799  assertThrows(function() { strict(sealed); }, TypeError);
800})();
801
802
803(function TestAssignmentToReadOnlyProperty() {
804  "use strict";
805
806  var o = {};
807  Object.defineProperty(o, "property", { value: 7 });
808
809  assertThrows(function() { o.property = "new value"; }, TypeError);
810  assertThrows(function() { o.property += 10; }, TypeError);
811  assertThrows(function() { o.property -= 10; }, TypeError);
812  assertThrows(function() { o.property *= 10; }, TypeError);
813  assertThrows(function() { o.property /= 10; }, TypeError);
814  assertThrows(function() { o.property++; }, TypeError);
815  assertThrows(function() { o.property--; }, TypeError);
816  assertThrows(function() { ++o.property; }, TypeError);
817  assertThrows(function() { --o.property; }, TypeError);
818
819  var name = "prop" + "erty"; // to avoid symbol path.
820  assertThrows(function() { o[name] = "new value"; }, TypeError);
821  assertThrows(function() { o[name] += 10; }, TypeError);
822  assertThrows(function() { o[name] -= 10; }, TypeError);
823  assertThrows(function() { o[name] *= 10; }, TypeError);
824  assertThrows(function() { o[name] /= 10; }, TypeError);
825  assertThrows(function() { o[name]++; }, TypeError);
826  assertThrows(function() { o[name]--; }, TypeError);
827  assertThrows(function() { ++o[name]; }, TypeError);
828  assertThrows(function() { --o[name]; }, TypeError);
829
830  assertEquals(o.property, 7);
831})();
832
833
834(function TestAssignmentToReadOnlyLoop() {
835  var name = "prop" + "erty"; // to avoid symbol path.
836  var o = {};
837  Object.defineProperty(o, "property", { value: 7 });
838
839  function strict(o, name) {
840    "use strict";
841    o[name] = "new value";
842  }
843
844  for (var i = 0; i < 10; i ++) {
845    try {
846      strict(o, name);
847      assertUnreachable();
848    } catch(e) {
849      assertInstanceof(e, TypeError);
850    }
851  }
852})();
853
854
855// Specialized KeyedStoreIC experiencing miss.
856(function testKeyedStoreICStrict() {
857  var o = [9,8,7,6,5,4,3,2,1];
858
859  function test(o, i, v) {
860    "use strict";
861    o[i] = v;
862  }
863
864  for (var i = 0; i < 10; i ++) {
865    test(o, 5, 17);        // start specialized for smi indices
866    assertEquals(o[5], 17);
867    test(o, "a", 19);
868    assertEquals(o["a"], 19);
869    test(o, "5", 29);
870    assertEquals(o[5], 29);
871    test(o, 100000, 31);
872    assertEquals(o[100000], 31);
873  }
874})();
875
876
877(function TestSetElementWithoutSetter() {
878  "use strict";
879
880  var o = { };
881  Object.defineProperty(o, 0, { get : function() { } });
882
883  var zero_smi = 0;
884  var zero_number = new Number(0);
885  var zero_symbol = "0";
886  var zero_string = "-0-".substring(1,2);
887
888  assertThrows(function() { o[zero_smi] = "new value"; }, TypeError);
889  assertThrows(function() { o[zero_number] = "new value"; }, TypeError);
890  assertThrows(function() { o[zero_symbol] = "new value"; }, TypeError);
891  assertThrows(function() { o[zero_string] = "new value"; }, TypeError);
892})();
893
894
895(function TestSetElementNonConfigurable() {
896  "use strict";
897  var frozen = Object.freeze({});
898  var sealed = Object.seal({});
899
900  var zero_number = 0;
901  var zero_symbol = "0";
902  var zero_string = "-0-".substring(1,2);
903
904  assertThrows(function() { frozen[zero_number] = "value"; }, TypeError);
905  assertThrows(function() { sealed[zero_number] = "value"; }, TypeError);
906  assertThrows(function() { frozen[zero_symbol] = "value"; }, TypeError);
907  assertThrows(function() { sealed[zero_symbol] = "value"; }, TypeError);
908  assertThrows(function() { frozen[zero_string] = "value"; }, TypeError);
909  assertThrows(function() { sealed[zero_string] = "value"; }, TypeError);
910})();
911
912
913(function TestAssignmentToReadOnlyElement() {
914  "use strict";
915
916  var o = {};
917  Object.defineProperty(o, 7, { value: 17 });
918
919  var seven_smi = 7;
920  var seven_number = new Number(7);
921  var seven_symbol = "7";
922  var seven_string = "-7-".substring(1,2);
923
924  // Index with number.
925  assertThrows(function() { o[seven_smi] = "value"; }, TypeError);
926  assertThrows(function() { o[seven_smi] += 10; }, TypeError);
927  assertThrows(function() { o[seven_smi] -= 10; }, TypeError);
928  assertThrows(function() { o[seven_smi] *= 10; }, TypeError);
929  assertThrows(function() { o[seven_smi] /= 10; }, TypeError);
930  assertThrows(function() { o[seven_smi]++; }, TypeError);
931  assertThrows(function() { o[seven_smi]--; }, TypeError);
932  assertThrows(function() { ++o[seven_smi]; }, TypeError);
933  assertThrows(function() { --o[seven_smi]; }, TypeError);
934
935  assertThrows(function() { o[seven_number] = "value"; }, TypeError);
936  assertThrows(function() { o[seven_number] += 10; }, TypeError);
937  assertThrows(function() { o[seven_number] -= 10; }, TypeError);
938  assertThrows(function() { o[seven_number] *= 10; }, TypeError);
939  assertThrows(function() { o[seven_number] /= 10; }, TypeError);
940  assertThrows(function() { o[seven_number]++; }, TypeError);
941  assertThrows(function() { o[seven_number]--; }, TypeError);
942  assertThrows(function() { ++o[seven_number]; }, TypeError);
943  assertThrows(function() { --o[seven_number]; }, TypeError);
944
945  assertThrows(function() { o[seven_symbol] = "value"; }, TypeError);
946  assertThrows(function() { o[seven_symbol] += 10; }, TypeError);
947  assertThrows(function() { o[seven_symbol] -= 10; }, TypeError);
948  assertThrows(function() { o[seven_symbol] *= 10; }, TypeError);
949  assertThrows(function() { o[seven_symbol] /= 10; }, TypeError);
950  assertThrows(function() { o[seven_symbol]++; }, TypeError);
951  assertThrows(function() { o[seven_symbol]--; }, TypeError);
952  assertThrows(function() { ++o[seven_symbol]; }, TypeError);
953  assertThrows(function() { --o[seven_symbol]; }, TypeError);
954
955  assertThrows(function() { o[seven_string] = "value"; }, TypeError);
956  assertThrows(function() { o[seven_string] += 10; }, TypeError);
957  assertThrows(function() { o[seven_string] -= 10; }, TypeError);
958  assertThrows(function() { o[seven_string] *= 10; }, TypeError);
959  assertThrows(function() { o[seven_string] /= 10; }, TypeError);
960  assertThrows(function() { o[seven_string]++; }, TypeError);
961  assertThrows(function() { o[seven_string]--; }, TypeError);
962  assertThrows(function() { ++o[seven_string]; }, TypeError);
963  assertThrows(function() { --o[seven_string]; }, TypeError);
964
965  assertEquals(o[seven_number], 17);
966  assertEquals(o[seven_symbol], 17);
967  assertEquals(o[seven_string], 17);
968})();
969
970
971(function TestAssignmentToReadOnlyLoop() {
972  "use strict";
973
974  var o = {};
975  Object.defineProperty(o, 7, { value: 17 });
976
977  var seven_smi = 7;
978  var seven_number = new Number(7);
979  var seven_symbol = "7";
980  var seven_string = "-7-".substring(1,2);
981
982  for (var i = 0; i < 10; i ++) {
983    assertThrows(function() { o[seven_smi] = "value" }, TypeError);
984    assertThrows(function() { o[seven_number] = "value" }, TypeError);
985    assertThrows(function() { o[seven_symbol] = "value" }, TypeError);
986    assertThrows(function() { o[seven_string] = "value" }, TypeError);
987  }
988
989  assertEquals(o[7], 17);
990})();
991
992
993(function TestAssignmentToStringLength() {
994  "use strict";
995
996  var str_val = "string";
997  var str_obj = new String(str_val);
998  var str_cat = str_val + str_val + str_obj;
999
1000  assertThrows(function() { str_val.length = 1; }, TypeError);
1001  assertThrows(function() { str_obj.length = 1; }, TypeError);
1002  assertThrows(function() { str_cat.length = 1; }, TypeError);
1003})();
1004
1005
1006(function TestArgumentsAliasing() {
1007  function strict(a, b) {
1008    "use strict";
1009    a = "c";
1010    b = "d";
1011    return [a, b, arguments[0], arguments[1]];
1012  }
1013
1014  function nonstrict(a, b) {
1015    a = "c";
1016    b = "d";
1017    return [a, b, arguments[0], arguments[1]];
1018  }
1019
1020  assertEquals(["c", "d", "a", "b"], strict("a", "b"));
1021  assertEquals(["c", "d", "c", "d"], nonstrict("a", "b"));
1022})();
1023
1024
1025function CheckPillDescriptor(func, name) {
1026
1027  function CheckPill(pill) {
1028    assertEquals("function", typeof pill);
1029    assertInstanceof(pill, Function);
1030    pill.property = "value";
1031    assertEquals(pill.value, undefined);
1032    assertThrows(function() { 'use strict'; pill.property = "value"; },
1033                 TypeError);
1034    assertThrows(pill, TypeError);
1035    assertEquals(pill.prototype, (function(){}).prototype);
1036    var d = Object.getOwnPropertyDescriptor(pill, "prototype");
1037    assertFalse(d.writable);
1038    assertFalse(d.configurable);
1039    assertFalse(d.enumerable);
1040  }
1041
1042  var descriptor = Object.getOwnPropertyDescriptor(func, name);
1043  CheckPill(descriptor.get)
1044  CheckPill(descriptor.set);
1045  assertFalse(descriptor.enumerable);
1046  assertFalse(descriptor.configurable);
1047}
1048
1049
1050(function TestStrictFunctionPills() {
1051  function strict() {
1052    "use strict";
1053  }
1054  assertThrows(function() { strict.caller; }, TypeError);
1055  assertThrows(function() { strict.arguments; }, TypeError);
1056
1057  var another = new Function("'use strict'");
1058  assertThrows(function() { another.caller; }, TypeError);
1059  assertThrows(function() { another.arguments; }, TypeError);
1060
1061  var third = (function() { "use strict"; return function() {}; })();
1062  assertThrows(function() { third.caller; }, TypeError);
1063  assertThrows(function() { third.arguments; }, TypeError);
1064
1065  CheckPillDescriptor(strict, "caller");
1066  CheckPillDescriptor(strict, "arguments");
1067  CheckPillDescriptor(another, "caller");
1068  CheckPillDescriptor(another, "arguments");
1069  CheckPillDescriptor(third, "caller");
1070  CheckPillDescriptor(third, "arguments");
1071})();
1072
1073
1074(function TestStrictFunctionWritablePrototype() {
1075  "use strict";
1076  function TheClass() {
1077  }
1078  assertThrows(function() { TheClass.caller; }, TypeError);
1079  assertThrows(function() { TheClass.arguments; }, TypeError);
1080
1081  // Strict functions must have writable prototype.
1082  TheClass.prototype = {
1083    func: function() { return "func_value"; },
1084    get accessor() { return "accessor_value"; },
1085    property: "property_value",
1086  };
1087
1088  var o = new TheClass();
1089  assertEquals(o.func(), "func_value");
1090  assertEquals(o.accessor, "accessor_value");
1091  assertEquals(o.property, "property_value");
1092})();
1093
1094
1095(function TestStrictArgumentPills() {
1096  function strict() {
1097    "use strict";
1098    return arguments;
1099  }
1100
1101  var args = strict();
1102  CheckPillDescriptor(args, "caller");
1103  CheckPillDescriptor(args, "callee");
1104
1105  args = strict(17, "value", strict);
1106  assertEquals(17, args[0])
1107  assertEquals("value", args[1])
1108  assertEquals(strict, args[2]);
1109  CheckPillDescriptor(args, "caller");
1110  CheckPillDescriptor(args, "callee");
1111
1112  function outer() {
1113    "use strict";
1114    function inner() {
1115      return arguments;
1116    }
1117    return inner;
1118  }
1119
1120  var args = outer()();
1121  CheckPillDescriptor(args, "caller");
1122  CheckPillDescriptor(args, "callee");
1123
1124  args = outer()(17, "value", strict);
1125  assertEquals(17, args[0])
1126  assertEquals("value", args[1])
1127  assertEquals(strict, args[2]);
1128  CheckPillDescriptor(args, "caller");
1129  CheckPillDescriptor(args, "callee");
1130})();
1131
1132
1133(function TestNonStrictFunctionCallerPillSimple() {
1134  function return_my_caller() {
1135    return return_my_caller.caller;
1136  }
1137
1138  function strict() {
1139    "use strict";
1140    return_my_caller();
1141  }
1142  assertThrows(strict, TypeError);
1143
1144  function non_strict() {
1145    return return_my_caller();
1146  }
1147  assertSame(non_strict(), non_strict);
1148})();
1149
1150
1151(function TestNonStrictFunctionCallerPill() {
1152  function strict(n) {
1153    "use strict";
1154    non_strict(n);
1155  }
1156
1157  function recurse(n, then) {
1158    if (n > 0) {
1159      recurse(n - 1);
1160    } else {
1161      return then();
1162    }
1163  }
1164
1165  function non_strict(n) {
1166    recurse(n, function() { non_strict.caller; });
1167  }
1168
1169  function test(n) {
1170    try {
1171      recurse(n, function() { strict(n); });
1172    } catch(e) {
1173      return e instanceof TypeError;
1174    }
1175    return false;
1176  }
1177
1178  for (var i = 0; i < 10; i ++) {
1179    assertEquals(test(i), true);
1180  }
1181})();
1182
1183
1184(function TestStrictModeEval() {
1185  "use strict";
1186  eval("var eval_local = 10;");
1187  assertThrows(function() { return eval_local; }, ReferenceError);
1188})();
1189