1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Flags: --strong-mode --allow-natives-syntax
6
7function getSloppyArguments() {
8  return arguments;
9}
10
11function getObjects() {
12  "use strict";
13  return [
14    {},
15    Object(""),
16    [],
17    (function(){}),
18    (class Foo {}),
19    getSloppyArguments(),
20    arguments,
21    new Date(),
22    new Uint32Array(0)
23  ];
24}
25
26function readFromObjectSloppy(o) {
27    return o.foo;
28}
29
30function readFromObjectKeyedSloppy(o) {
31    return o["foo"];
32}
33
34function readFromObjectKeyedVarSloppy(o) {
35  var a = "foo";
36  return o[a];
37}
38
39function readFromObjectKeyedComputedSloppy(o) {
40  var a = "o";
41  return o["fo" + a];
42}
43
44function readFromObjectStrong(o) {
45  "use strong";
46  return o.foo;
47}
48
49function readFromObjectKeyedStrong(o) {
50  "use strong";
51  return o["foo"];
52}
53
54function readFromObjectKeyedLetStrong(o) {
55  "use strong";
56  let a = "foo";
57  return o[a];
58}
59
60function readFromObjectKeyedComputedStrong(o) {
61  "use strong";
62  let a = "o";
63  return o["fo" + a];
64}
65
66function getDescs(x) {
67  return [
68    {value: x},
69    {configurable: true, enumerable: true, writable: true, value: x},
70    {configurable: true, enumerable: true, get: (function() {return x}) },
71  ];
72}
73
74function assertStrongSemantics(func, object) {
75  %DeoptimizeFunction(func);
76  %ClearFunctionTypeFeedback(func);
77  assertThrows(function(){func(object)}, TypeError);
78  assertThrows(function(){func(object)}, TypeError);
79  assertThrows(function(){func(object)}, TypeError);
80  %OptimizeFunctionOnNextCall(func);
81  assertThrows(function(){func(object)}, TypeError);
82  %DeoptimizeFunction(func);
83  assertThrows(function(){func(object)}, TypeError);
84}
85
86function assertSloppySemantics(func, object) {
87  %DeoptimizeFunction(func);
88  %ClearFunctionTypeFeedback(func);
89  assertDoesNotThrow(function(){func(object)});
90  assertDoesNotThrow(function(){func(object)});
91  assertDoesNotThrow(function(){func(object)});
92  %OptimizeFunctionOnNextCall(func);
93  assertDoesNotThrow(function(){func(object)});
94  %DeoptimizeFunction(func);
95  assertDoesNotThrow(function(){func(object)});
96}
97
98(function () {
99  "use strict";
100
101  let goodKeys = [
102    "foo"
103  ]
104
105  let badKeys = [
106    "bar",
107    "1",
108    "100001",
109    "3000000001",
110    "5000000001"
111  ];
112
113  let values = [
114    "string",
115    1,
116    100001,
117    30000000001,
118    50000000001,
119    NaN,
120    {},
121    undefined
122  ];
123
124  let literals = [0, NaN, true, "string"];
125
126  let badAccessorDescs = [
127    { set: (function(){}) },
128    { configurable: true, enumerable: true, set: (function(){}) }
129  ];
130
131  let readSloppy = [
132    readFromObjectSloppy,
133    readFromObjectKeyedSloppy,
134    readFromObjectKeyedVarSloppy,
135    readFromObjectKeyedComputedSloppy
136  ];
137
138  let readStrong = [
139    readFromObjectStrong,
140    readFromObjectKeyedStrong,
141    readFromObjectKeyedLetStrong,
142    readFromObjectKeyedComputedStrong
143  ];
144
145  let dummyProto = {};
146  for (let key of goodKeys) {
147    Object.defineProperty(dummyProto, key, { value: undefined });
148  }
149
150  let dummyAccessorProto = {};
151  for (let key of goodKeys) {
152    Object.defineProperty(dummyAccessorProto, key, { set: (function(){}) })
153  }
154
155  // Attempting to access a property on an object with no defined properties
156  // should throw.
157  for (let object of getObjects().concat(literals)) {
158    for (let func of readStrong) {
159      assertStrongSemantics(func, object);
160    }
161    for (let func of readSloppy) {
162      assertSloppySemantics(func, object);
163    }
164  }
165  for (let object of getObjects()) {
166    // Accessing a property which is on the prototype chain of the object should
167    // not throw.
168    object.__proto__ = dummyProto;
169    for (let key of goodKeys) {
170      for (let func of readStrong.concat(readSloppy)) {
171        assertSloppySemantics(func, object);
172      }
173    }
174  }
175  // Properties with accessor descriptors missing 'get' should throw on access.
176  for (let desc of badAccessorDescs) {
177    for (let key of goodKeys) {
178      for (let object of getObjects()) {
179        Object.defineProperty(object, key, desc);
180        for (let func of readStrong) {
181          assertStrongSemantics(func, object);
182        }
183        for (let func of readSloppy) {
184          assertSloppySemantics(func, object);
185        }
186      }
187    }
188  }
189  // The same behaviour should be expected for bad accessor properties on the
190  // prototype chain.
191  for (let object of getObjects()) {
192    object.__proto__ = dummyAccessorProto;
193    for (let func of readStrong) {
194      assertStrongSemantics(func, object);
195    }
196    for (let func of readSloppy) {
197      assertSloppySemantics(func, object);
198    }
199  }
200  assertThrows(function(){"use strong"; typeof ({}).foo;}, TypeError);
201  assertThrows(
202    function(){"use strong"; typeof ({}).foo === "undefined"}, TypeError);
203})();
204