OLD | NEW |
| (Empty) |
1 // Copyright 2012 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 | |
28 // Flags: --allow-natives-syntax --inline-accessors | |
29 | |
30 var accessorCallCount, setterArgument, setterValue, obj, forceDeopt; | |
31 | |
32 // ----------------------------------------------------------------------------- | |
33 // Helpers for testing inlining of getters. | |
34 | |
35 function TestInlinedGetter(context, obj, expected) { | |
36 forceDeopt = { deopt: 0 }; | |
37 accessorCallCount = 0; | |
38 | |
39 assertEquals(expected, context(obj)); | |
40 assertEquals(1, accessorCallCount); | |
41 | |
42 assertEquals(expected, context(obj)); | |
43 assertEquals(2, accessorCallCount); | |
44 | |
45 %OptimizeFunctionOnNextCall(context); | |
46 assertEquals(expected, context(obj)); | |
47 assertEquals(3, accessorCallCount); | |
48 | |
49 forceDeopt = { /* empty*/ }; | |
50 assertEquals(expected, context(obj)); | |
51 assertEquals(4, accessorCallCount); | |
52 } | |
53 | |
54 | |
55 function value_context_for_getter(obj) { | |
56 return obj.getterProperty; | |
57 } | |
58 | |
59 function test_context_for_getter(obj) { | |
60 if (obj.getterProperty) { | |
61 return 111; | |
62 } else { | |
63 return 222; | |
64 } | |
65 } | |
66 | |
67 function effect_context_for_getter(obj) { | |
68 obj.getterProperty; | |
69 return 5678; | |
70 } | |
71 | |
72 function TryGetter(context, getter, obj, expected, expectException) { | |
73 try { | |
74 TestInlinedGetter(context, obj, expected); | |
75 assertFalse(expectException); | |
76 } catch (exception) { | |
77 assertTrue(expectException); | |
78 assertEquals(7, exception.stack.split('\n').length); | |
79 } | |
80 %DeoptimizeFunction(context); | |
81 %ClearFunctionFeedback(context); | |
82 %ClearFunctionFeedback(getter); | |
83 } | |
84 | |
85 function TestGetterInAllContexts(getter, obj, expected, expectException) { | |
86 TryGetter(value_context_for_getter, getter, obj, expected, expectException); | |
87 TryGetter(test_context_for_getter, getter, obj, expected ? 111 : 222, | |
88 expectException); | |
89 TryGetter(effect_context_for_getter, getter, obj, 5678, expectException); | |
90 } | |
91 | |
92 // ----------------------------------------------------------------------------- | |
93 // Test getter returning something 'true'ish in all contexts. | |
94 | |
95 function getter1() { | |
96 assertSame(obj, this); | |
97 accessorCallCount++; | |
98 forceDeopt.deopt; | |
99 return 1234; | |
100 } | |
101 | |
102 function ConstrG1() { } | |
103 obj = Object.defineProperty(new ConstrG1(), "getterProperty", { get: getter1 }); | |
104 TestGetterInAllContexts(getter1, obj, 1234, false); | |
105 obj = Object.create(obj); | |
106 TestGetterInAllContexts(getter1, obj, 1234, false); | |
107 | |
108 // ----------------------------------------------------------------------------- | |
109 // Test getter returning false in all contexts. | |
110 | |
111 function getter2() { | |
112 assertSame(obj, this); | |
113 accessorCallCount++; | |
114 forceDeopt.deopt; | |
115 return false; | |
116 } | |
117 | |
118 function ConstrG2() { } | |
119 obj = Object.defineProperty(new ConstrG2(), "getterProperty", { get: getter2 }); | |
120 TestGetterInAllContexts(getter2, obj, false, false); | |
121 obj = Object.create(obj); | |
122 TestGetterInAllContexts(getter2, obj, false, false); | |
123 | |
124 // ----------------------------------------------------------------------------- | |
125 // Test getter without a return in all contexts. | |
126 | |
127 function getter3() { | |
128 assertSame(obj, this); | |
129 accessorCallCount++; | |
130 forceDeopt.deopt; | |
131 } | |
132 | |
133 function ConstrG3() { } | |
134 obj = Object.defineProperty(new ConstrG3(), "getterProperty", { get: getter3 }); | |
135 TestGetterInAllContexts(getter3, obj, undefined, false); | |
136 obj = Object.create(obj); | |
137 TestGetterInAllContexts(getter3, obj, undefined, false); | |
138 | |
139 // ----------------------------------------------------------------------------- | |
140 // Test getter with too many arguments without a return in all contexts. | |
141 | |
142 function getter4(a) { | |
143 assertSame(obj, this); | |
144 assertEquals(undefined, a); | |
145 accessorCallCount++; | |
146 forceDeopt.deopt; | |
147 } | |
148 | |
149 function ConstrG4() { } | |
150 obj = Object.defineProperty(new ConstrG4(), "getterProperty", { get: getter4 }); | |
151 TestGetterInAllContexts(getter4, obj, undefined, false); | |
152 obj = Object.create(obj); | |
153 TestGetterInAllContexts(getter4, obj, undefined, false); | |
154 | |
155 // ----------------------------------------------------------------------------- | |
156 // Test getter with too many arguments with a return in all contexts. | |
157 | |
158 function getter5(a) { | |
159 assertSame(obj, this); | |
160 assertEquals(undefined, a); | |
161 accessorCallCount++; | |
162 forceDeopt.deopt; | |
163 return 9876; | |
164 } | |
165 | |
166 function ConstrG5() { } | |
167 obj = Object.defineProperty(new ConstrG5(), "getterProperty", { get: getter5 }); | |
168 TestGetterInAllContexts(getter5, obj, 9876, false); | |
169 obj = Object.create(obj); | |
170 TestGetterInAllContexts(getter5, obj, 9876, false); | |
171 | |
172 // ----------------------------------------------------------------------------- | |
173 // Test getter which throws from optimized code. | |
174 | |
175 function getter6() { | |
176 assertSame(obj, this); | |
177 accessorCallCount++; | |
178 forceDeopt.deopt; | |
179 if (accessorCallCount == 4) { 123 in null; } | |
180 return 13579; | |
181 } | |
182 | |
183 function ConstrG6() { } | |
184 obj = Object.defineProperty(new ConstrG6(), "getterProperty", { get: getter6 }); | |
185 TestGetterInAllContexts(getter6, obj, 13579, true); | |
186 obj = Object.create(obj); | |
187 TestGetterInAllContexts(getter6, obj, 13579, true); | |
188 | |
189 // ----------------------------------------------------------------------------- | |
190 // Helpers for testing inlining of setters. | |
191 | |
192 function TestInlinedSetter(context, obj, value, expected) { | |
193 forceDeopt = { deopt: 0 }; | |
194 accessorCallCount = 0; | |
195 setterArgument = value; | |
196 | |
197 assertEquals(expected, context(obj, value)); | |
198 assertEquals(value, setterValue); | |
199 assertEquals(1, accessorCallCount); | |
200 | |
201 assertEquals(expected, context(obj, value)); | |
202 assertEquals(value, setterValue); | |
203 assertEquals(2, accessorCallCount); | |
204 | |
205 %OptimizeFunctionOnNextCall(context); | |
206 assertEquals(expected, context(obj, value)); | |
207 assertEquals(value, setterValue); | |
208 assertEquals(3, accessorCallCount); | |
209 | |
210 forceDeopt = { /* empty*/ }; | |
211 assertEquals(expected, context(obj, value)); | |
212 assertEquals(value, setterValue); | |
213 assertEquals(4, accessorCallCount); | |
214 } | |
215 | |
216 function value_context_for_setter(obj, value) { | |
217 return obj.setterProperty = value; | |
218 } | |
219 | |
220 function test_context_for_setter(obj, value) { | |
221 if (obj.setterProperty = value) { | |
222 return 333; | |
223 } else { | |
224 return 444; | |
225 } | |
226 } | |
227 | |
228 function effect_context_for_setter(obj, value) { | |
229 obj.setterProperty = value; | |
230 return 666; | |
231 } | |
232 | |
233 function TrySetter(context, setter, obj, expectException, value, expected) { | |
234 try { | |
235 TestInlinedSetter(context, obj, value, expected); | |
236 assertFalse(expectException); | |
237 } catch (exception) { | |
238 assertTrue(expectException); | |
239 assertEquals(7, exception.stack.split('\n').length); | |
240 } | |
241 %DeoptimizeFunction(context); | |
242 %ClearFunctionFeedback(context); | |
243 %ClearFunctionFeedback(setter); | |
244 } | |
245 | |
246 function TestSetterInAllContexts(setter, obj, expectException) { | |
247 TrySetter(value_context_for_setter, setter, obj, expectException, 111, 111); | |
248 TrySetter(test_context_for_setter, setter, obj, expectException, true, 333); | |
249 TrySetter(test_context_for_setter, setter, obj, expectException, false, 444); | |
250 TrySetter(effect_context_for_setter, setter, obj, expectException, 555, 666); | |
251 } | |
252 | |
253 // ----------------------------------------------------------------------------- | |
254 // Test setter without a return in all contexts. | |
255 | |
256 function setter1(value) { | |
257 assertSame(obj, this); | |
258 accessorCallCount++; | |
259 forceDeopt.deopt; | |
260 setterValue = value; | |
261 } | |
262 | |
263 function ConstrS1() { } | |
264 obj = Object.defineProperty(new ConstrS1(), "setterProperty", { set: setter1 }); | |
265 TestSetterInAllContexts(setter1, obj, false); | |
266 obj = Object.create(obj); | |
267 TestSetterInAllContexts(setter1, obj, false); | |
268 | |
269 // ----------------------------------------------------------------------------- | |
270 // Test setter returning something different than the RHS in all contexts. | |
271 | |
272 function setter2(value) { | |
273 assertSame(obj, this); | |
274 accessorCallCount++; | |
275 forceDeopt.deopt; | |
276 setterValue = value; | |
277 return 1000000; | |
278 } | |
279 | |
280 function ConstrS2() { } | |
281 obj = Object.defineProperty(new ConstrS2(), "setterProperty", { set: setter2 }); | |
282 TestSetterInAllContexts(setter2, obj, false); | |
283 obj = Object.create(obj); | |
284 TestSetterInAllContexts(setter2, obj, false); | |
285 | |
286 // ----------------------------------------------------------------------------- | |
287 // Test setter with too few arguments without a return in all contexts. | |
288 | |
289 function setter3() { | |
290 assertSame(obj, this); | |
291 accessorCallCount++; | |
292 forceDeopt.deopt; | |
293 setterValue = setterArgument; | |
294 } | |
295 | |
296 function ConstrS3() { } | |
297 obj = Object.defineProperty(new ConstrS3(), "setterProperty", { set: setter3 }); | |
298 TestSetterInAllContexts(setter3, obj, false); | |
299 obj = Object.create(obj); | |
300 TestSetterInAllContexts(setter3, obj, false); | |
301 | |
302 // ----------------------------------------------------------------------------- | |
303 // Test setter with too few arguments with a return in all contexts. | |
304 | |
305 function setter4() { | |
306 assertSame(obj, this); | |
307 accessorCallCount++; | |
308 forceDeopt.deopt; | |
309 setterValue = setterArgument; | |
310 return 2000000; | |
311 } | |
312 | |
313 function ConstrS4() { } | |
314 obj = Object.defineProperty(new ConstrS4(), "setterProperty", { set: setter4 }); | |
315 TestSetterInAllContexts(setter4, obj, false); | |
316 obj = Object.create(obj); | |
317 TestSetterInAllContexts(setter4, obj, false); | |
318 | |
319 // ----------------------------------------------------------------------------- | |
320 // Test setter with too many arguments without a return in all contexts. | |
321 | |
322 function setter5(value, foo) { | |
323 assertSame(obj, this); | |
324 assertEquals(undefined, foo); | |
325 accessorCallCount++; | |
326 forceDeopt.deopt; | |
327 setterValue = value; | |
328 } | |
329 | |
330 function ConstrS5() { } | |
331 obj = Object.defineProperty(new ConstrS5(), "setterProperty", { set: setter5 }); | |
332 TestSetterInAllContexts(setter5, obj, false); | |
333 obj = Object.create(obj); | |
334 TestSetterInAllContexts(setter5, obj, false); | |
335 | |
336 // ----------------------------------------------------------------------------- | |
337 // Test setter with too many arguments with a return in all contexts. | |
338 | |
339 function setter6(value, foo) { | |
340 assertSame(obj, this); | |
341 assertEquals(undefined, foo); | |
342 accessorCallCount++; | |
343 forceDeopt.deopt; | |
344 setterValue = value; | |
345 return 3000000; | |
346 } | |
347 | |
348 function ConstrS6() { } | |
349 obj = Object.defineProperty(new ConstrS6(), "setterProperty", { set: setter6 }); | |
350 TestSetterInAllContexts(setter6, obj, false); | |
351 obj = Object.create(obj); | |
352 TestSetterInAllContexts(setter6, obj, false); | |
353 | |
354 // ----------------------------------------------------------------------------- | |
355 // Test setter which throws from optimized code. | |
356 | |
357 function setter7(value) { | |
358 accessorCallCount++; | |
359 forceDeopt.deopt; | |
360 if (accessorCallCount == 4) { 123 in null; } | |
361 setterValue = value; | |
362 } | |
363 | |
364 function ConstrS7() { } | |
365 obj = Object.defineProperty(new ConstrS7(), "setterProperty", { set: setter7 }); | |
366 TestSetterInAllContexts(setter7, obj, true); | |
367 obj = Object.create(obj); | |
368 TestSetterInAllContexts(setter7, obj, true); | |
OLD | NEW |