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  ];
23}
24
25//TODO(conradw): add tests for non-inheritance once semantics are implemented.
26function getNonInheritingObjects() {
27  "use strong";
28  return [
29    Object(""),
30    [],
31    new Uint32Array(0)
32  ];
33}
34
35function readFromObjectElementSloppy(o) {
36  return o[0];
37}
38
39function readFromObjectElementSparseSloppy(o) {
40  return o[100000];
41}
42
43function readFromObjectElementNonSmiSloppy(o) {
44  return o[3000000000];
45}
46
47function readFromObjectNonIndexSloppy(o) {
48  return o[5000000000];
49}
50
51function readFromObjectElementVarSloppy(o) {
52  var a = 0;
53  return o[a];
54}
55
56function readFromObjectElementSparseVarSloppy(o) {
57  var a = 100000;
58  return o[a];
59}
60
61function readFromObjectElementNonSmiVarSloppy(o) {
62  var a = 3000000000;
63  return o[a];
64}
65
66function readFromObjectNonIndexVarSloppy(o) {
67  var a = 5000000000;
68  return o[a];
69}
70
71function readFromObjectElementStrong(o) {
72  "use strong";
73  return o[0];
74}
75
76function readFromObjectElementSparseStrong(o) {
77  "use strong";
78  return o[100000];
79}
80
81function readFromObjectElementNonSmiStrong(o) {
82  "use strong";
83  return o[3000000000];
84}
85
86function readFromObjectNonIndexStrong(o) {
87  "use strong";
88  return o[5000000000];
89}
90
91function readFromObjectElementLetStrong(o) {
92  "use strong";
93  let a = 0;
94  return o[a];
95}
96
97function readFromObjectElementSparseLetStrong(o) {
98  "use strong";
99  let a = 100000;
100  return o[a];
101}
102
103function readFromObjectElementNonSmiLetStrong(o) {
104  "use strong";
105  let a = 3000000000;
106  return o[a];
107}
108
109function readFromObjectNonIndexLetStrong(o) {
110  "use strong";
111  let a = 5000000000;
112  return o[a];
113}
114
115function getDescs(x) {
116  return [
117    {value: x},
118    {configurable: true, enumerable: true, writable: true, value: x},
119    {configurable: true, enumerable: true, get: (function() {return x}) },
120  ];
121}
122
123function assertStrongSemantics(func, object) {
124  %DeoptimizeFunction(func);
125  %ClearFunctionTypeFeedback(func);
126  assertThrows(function(){func(object)}, TypeError);
127  assertThrows(function(){func(object)}, TypeError);
128  assertThrows(function(){func(object)}, TypeError);
129  %OptimizeFunctionOnNextCall(func);
130  assertThrows(function(){func(object)}, TypeError);
131  %DeoptimizeFunction(func);
132  assertThrows(function(){func(object)}, TypeError);
133}
134
135function assertSloppySemantics(func, object) {
136  %DeoptimizeFunction(func);
137  %ClearFunctionTypeFeedback(func);
138  assertDoesNotThrow(function(){func(object)});
139  assertDoesNotThrow(function(){func(object)});
140  assertDoesNotThrow(function(){func(object)});
141  %OptimizeFunctionOnNextCall(func);
142  assertDoesNotThrow(function(){func(object)});
143  %DeoptimizeFunction(func);
144  assertDoesNotThrow(function(){func(object)});
145}
146
147(function () {
148  "use strict";
149
150  let goodKeys = [
151    "0",
152    "100000",
153    "3000000000",
154    "5000000000"
155  ]
156
157  let badKeys = [
158    "bar",
159    "1",
160    "100001",
161    "3000000001",
162    "5000000001"
163  ];
164
165  let values = [
166    "string",
167    1,
168    100001,
169    30000000001,
170    50000000001,
171    NaN,
172    {},
173    undefined
174  ];
175
176  let literals = [0, NaN, true, ""];
177
178  let badAccessorDescs = [
179    { set: (function(){}) },
180    { configurable: true, enumerable: true, set: (function(){}) }
181  ];
182
183  let readSloppy = [
184    readFromObjectElementSloppy,
185    readFromObjectElementSparseSloppy,
186    readFromObjectElementNonSmiSloppy,
187    readFromObjectNonIndexSloppy,
188    readFromObjectElementVarSloppy,
189    readFromObjectElementSparseVarSloppy,
190    readFromObjectElementNonSmiVarSloppy,
191    readFromObjectNonIndexVarSloppy
192  ];
193
194  let readStrong = [
195    readFromObjectElementStrong,
196    readFromObjectElementSparseStrong,
197    readFromObjectElementNonSmiStrong,
198    readFromObjectNonIndexStrong,
199    readFromObjectElementLetStrong,
200    readFromObjectElementSparseLetStrong,
201    readFromObjectElementNonSmiLetStrong,
202    readFromObjectNonIndexLetStrong
203  ];
204
205  let dummyProto = {};
206  for (let key of goodKeys) {
207    Object.defineProperty(dummyProto, key, { value: undefined });
208  }
209
210  let dummyAccessorProto = {};
211  for (let key of goodKeys) {
212    Object.defineProperty(dummyAccessorProto, key, { set: (function(){}) })
213  }
214
215  // String literals/objects should not throw on character index access
216  assertDoesNotThrow(function() {"use strong"; return "string"[0]; });
217  assertDoesNotThrow(function() {"use strong"; return Object("string")[0]; });
218
219  // Attempting to access a property on an object with no defined properties
220  // should throw.
221  for (let object of getObjects().concat(getNonInheritingObjects(), literals)) {
222    for (let func of readStrong) {
223      assertStrongSemantics(func, object);
224    }
225    for (let func of readSloppy) {
226      assertSloppySemantics(func, object);
227    }
228  }
229  for (let object of getObjects()) {
230    // Accessing a property which is on the prototype chain of the object should
231    // not throw.
232    object.__proto__ = dummyProto;
233    for (let key of goodKeys) {
234      for (let func of readStrong.concat(readSloppy)) {
235        assertSloppySemantics(func, object);
236      }
237    }
238  }
239  // Properties with accessor descriptors missing 'get' should throw on access.
240  for (let desc of badAccessorDescs) {
241    for (let key of goodKeys) {
242      for (let object of getObjects()) {
243        Object.defineProperty(object, key, desc);
244        for (let func of readStrong) {
245          assertStrongSemantics(func, object);
246        }
247        for (let func of readSloppy) {
248          assertSloppySemantics(func, object);
249        }
250      }
251    }
252  }
253  // The same behaviour should be expected for bad accessor properties on the
254  // prototype chain.
255  for (let object of getObjects()) {
256    object.__proto__ = dummyAccessorProto;
257    for (let func of readStrong) {
258      assertStrongSemantics(func, object);
259    }
260    for (let func of readSloppy) {
261      assertSloppySemantics(func, object);
262    }
263  }
264  assertThrows(function(){"use strong"; typeof ({})[1];}, TypeError);
265  assertThrows(
266    function(){"use strong"; typeof ({})[1] === "undefined"}, TypeError);
267})();
268