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
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.
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.
28 // Flags: --allow-natives-syntax --expose-gc
29 // Flags: --noalways-opt
32 fast_smi_only : 'fast smi only elements',
33 fast : 'fast elements',
34 fast_double : 'fast double elements',
35 dictionary : 'dictionary elements',
36 external_byte : 'external byte elements',
37 external_unsigned_byte : 'external unsigned byte elements',
38 external_short : 'external short elements',
39 external_unsigned_short : 'external unsigned short elements',
40 external_int : 'external int elements',
41 external_unsigned_int : 'external unsigned int elements',
42 external_float : 'external float elements',
43 external_double : 'external double elements',
44 external_pixel : 'external pixel elements'
47 function getKind(obj) {
48 if (%HasFastSmiElements(obj)) return elements_kind.fast_smi_only;
49 if (%HasFastObjectElements(obj)) return elements_kind.fast;
50 if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
51 if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
54 function isHoley(obj) {
55 if (%HasFastHoleyElements(obj)) return true;
59 function assertKind(expected, obj, name_opt) {
60 assertEquals(expected, getKind(obj), name_opt);
63 function assertHoley(obj, name_opt) {
64 assertEquals(true, isHoley(obj), name_opt);
67 function assertNotHoley(obj, name_opt) {
68 assertEquals(false, isHoley(obj), name_opt);
73 assertKind(elements_kind.fast_smi_only, obj);
77 assertKind(elements_kind.fast_smi_only, obj);
81 assertKind(elements_kind.fast_smi_only, obj);
85 assertKind(elements_kind.fast_smi_only, obj);
89 assertKind(elements_kind.fast_smi_only, obj);
91 obj = new Array(1,2,3);
93 assertKind(elements_kind.fast_smi_only, obj);
95 obj = new Array(1, "hi", 2, undefined);
97 assertKind(elements_kind.fast, obj);
99 function fastliteralcase(literal, value) {
104 function get_standard_literal() {
105 var literal = [1, 2, 3];
109 // Case: [1,2,3] as allocation site
110 obj = fastliteralcase(get_standard_literal(), 1);
111 assertKind(elements_kind.fast_smi_only, obj);
112 obj = fastliteralcase(get_standard_literal(), 1.5);
113 assertKind(elements_kind.fast_double, obj);
114 obj = fastliteralcase(get_standard_literal(), 2);
115 assertKind(elements_kind.fast_double, obj);
117 // The test below is in a loop because arrays that live
118 // at global scope without the chance of being recreated
119 // don't have allocation site information attached.
120 for (i = 0; i < 2; i++) {
121 obj = fastliteralcase([5, 3, 2], 1.5);
122 assertKind(elements_kind.fast_double, obj);
123 obj = fastliteralcase([3, 6, 2], 1.5);
124 assertKind(elements_kind.fast_double, obj);
126 // Note: thanks to pessimistic transition store stubs, we'll attempt
127 // to transition to the most general elements kind seen at a particular
128 // store site. So, the elements kind will be double.
129 obj = fastliteralcase([2, 6, 3], 2);
130 assertKind(elements_kind.fast_double, obj);
133 // Verify that we will not pretransition the double->fast path.
134 obj = fastliteralcase(get_standard_literal(), "elliot");
135 assertKind(elements_kind.fast, obj);
136 obj = fastliteralcase(get_standard_literal(), 3);
137 assertKind(elements_kind.fast, obj);
139 // Make sure this works in crankshafted code too.
140 %OptimizeFunctionOnNextCall(get_standard_literal);
141 get_standard_literal();
142 obj = get_standard_literal();
143 assertKind(elements_kind.fast, obj);
145 function fastliteralcase_smifast(value) {
146 var literal = [1, 2, 3, 4];
151 obj = fastliteralcase_smifast(1);
152 assertKind(elements_kind.fast_smi_only, obj);
153 obj = fastliteralcase_smifast("carter");
154 assertKind(elements_kind.fast, obj);
155 obj = fastliteralcase_smifast(2);
156 assertKind(elements_kind.fast, obj);
158 // Case: make sure transitions from packed to holey are tracked
159 function fastliteralcase_smiholey(index, value) {
160 var literal = [1, 2, 3, 4];
161 literal[index] = value;
165 obj = fastliteralcase_smiholey(5, 1);
166 assertKind(elements_kind.fast_smi_only, obj);
168 obj = fastliteralcase_smiholey(0, 1);
169 assertKind(elements_kind.fast_smi_only, obj);
172 function newarraycase_smidouble(value) {
178 // Case: new Array() as allocation site, smi->double
179 obj = newarraycase_smidouble(1);
180 assertKind(elements_kind.fast_smi_only, obj);
181 obj = newarraycase_smidouble(1.5);
182 assertKind(elements_kind.fast_double, obj);
183 obj = newarraycase_smidouble(2);
184 assertKind(elements_kind.fast_double, obj);
186 function newarraycase_smiobj(value) {
192 // Case: new Array() as allocation site, smi->fast
193 obj = newarraycase_smiobj(1);
194 assertKind(elements_kind.fast_smi_only, obj);
195 obj = newarraycase_smiobj("gloria");
196 assertKind(elements_kind.fast, obj);
197 obj = newarraycase_smiobj(2);
198 assertKind(elements_kind.fast, obj);
200 function newarraycase_length_smidouble(value) {
201 var a = new Array(3);
206 // Case: new Array(length) as allocation site
207 obj = newarraycase_length_smidouble(1);
208 assertKind(elements_kind.fast_smi_only, obj);
209 obj = newarraycase_length_smidouble(1.5);
210 assertKind(elements_kind.fast_double, obj);
211 obj = newarraycase_length_smidouble(2);
212 assertKind(elements_kind.fast_double, obj);
214 // Try to continue the transition to fast object.
215 // TODO(mvstanton): re-enable commented out code when
216 // FLAG_pretenuring_call_new is turned on in the build.
217 obj = newarraycase_length_smidouble("coates");
218 assertKind(elements_kind.fast, obj);
219 obj = newarraycase_length_smidouble(2);
220 // assertKind(elements_kind.fast, obj);
222 function newarraycase_length_smiobj(value) {
223 var a = new Array(3);
228 // Case: new Array(<length>) as allocation site, smi->fast
229 obj = newarraycase_length_smiobj(1);
230 assertKind(elements_kind.fast_smi_only, obj);
231 obj = newarraycase_length_smiobj("gloria");
232 assertKind(elements_kind.fast, obj);
233 obj = newarraycase_length_smiobj(2);
234 assertKind(elements_kind.fast, obj);
236 function newarraycase_list_smidouble(value) {
237 var a = new Array(1, 2, 3);
242 obj = newarraycase_list_smidouble(1);
243 assertKind(elements_kind.fast_smi_only, obj);
244 obj = newarraycase_list_smidouble(1.5);
245 assertKind(elements_kind.fast_double, obj);
246 obj = newarraycase_list_smidouble(2);
247 assertKind(elements_kind.fast_double, obj);
249 function newarraycase_list_smiobj(value) {
250 var a = new Array(4, 5, 6);
255 obj = newarraycase_list_smiobj(1);
256 assertKind(elements_kind.fast_smi_only, obj);
257 obj = newarraycase_list_smiobj("coates");
258 assertKind(elements_kind.fast, obj);
259 obj = newarraycase_list_smiobj(2);
260 assertKind(elements_kind.fast, obj);
262 // Case: array constructor calls with out of date feedback.
263 // The boilerplate should incorporate all feedback, but the input array
264 // should be minimally transitioned based on immediate need.
267 // We have two cases, one for literals one for constructed arrays.
270 : new Array(1, 2, 3);
274 for (i = 0; i < 2; i++) {
277 b[5] = 1; // boilerplate goes holey
279 a[0] = 3.5; // boilerplate goes holey double
280 assertKind(elements_kind.fast_double, a);
283 assertKind(elements_kind.fast_double, c);
288 function newarraycase_onearg(len, value) {
289 var a = new Array(len);
294 obj = newarraycase_onearg(5, 3.5);
295 assertKind(elements_kind.fast_double, obj);
296 obj = newarraycase_onearg(10, 5);
297 assertKind(elements_kind.fast_double, obj);
298 obj = newarraycase_onearg(0, 5);
299 assertKind(elements_kind.fast_double, obj);
301 // Verify that cross context calls work
302 var realmA = Realm.current();
303 var realmB = Realm.create();
304 assertEquals(0, realmA);
305 assertEquals(1, realmB);
307 function instanceof_check(type) {
308 assertTrue(new type() instanceof type);
309 assertTrue(new type(5) instanceof type);
310 assertTrue(new type(1,2,3) instanceof type);
313 function instanceof_check2(type) {
314 assertTrue(new type() instanceof type);
315 assertTrue(new type(5) instanceof type);
316 assertTrue(new type(1,2,3) instanceof type);
319 var realmBArray = Realm.eval(realmB, "Array");
320 instanceof_check(Array);
321 instanceof_check(realmBArray);
323 // instanceof_check2 is here because the call site goes through a state.
324 // Since instanceof_check(Array) was first called with the current context
325 // Array function, it went from (uninit->Array) then (Array->megamorphic).
326 // We'll get a different state traversal if we start with realmBArray.
327 // It'll go (uninit->realmBArray) then (realmBArray->megamorphic). Recognize
328 // that state "Array" implies an AllocationSite is present, and code is
329 // configured to use it.
330 instanceof_check2(realmBArray);
331 instanceof_check2(Array);
333 %OptimizeFunctionOnNextCall(instanceof_check);
335 // No de-opt will occur because HCallNewArray wasn't selected, on account of
336 // the call site not being monomorphic to Array.
337 instanceof_check(Array);
338 assertOptimized(instanceof_check);
339 instanceof_check(realmBArray);
340 assertOptimized(instanceof_check);
342 // Try to optimize again, but first clear all type feedback, and allow it
343 // to be monomorphic on first call. Only after crankshafting do we introduce
344 // realmBArray. This should deopt the method.
345 %DeoptimizeFunction(instanceof_check);
346 %ClearFunctionTypeFeedback(instanceof_check);
347 instanceof_check(Array);
348 instanceof_check(Array);
349 %OptimizeFunctionOnNextCall(instanceof_check);
350 instanceof_check(Array);
351 assertOptimized(instanceof_check);
353 instanceof_check(realmBArray);
354 assertUnoptimized(instanceof_check);
356 // Case: make sure nested arrays benefit from allocation site feedback as
359 // Make sure we handle nested arrays
360 function get_nested_literal() {
361 var literal = [[1,2,3,4], [2], [3]];
365 obj = get_nested_literal();
366 assertKind(elements_kind.fast, obj);
369 obj = get_nested_literal();
370 assertKind(elements_kind.fast_double, obj[0]);
371 assertKind(elements_kind.fast_smi_only, obj[1]);
372 assertKind(elements_kind.fast, obj[2]);
374 // A more complex nested literal case.
375 function get_deep_nested_literal() {
376 var literal = [[1], [[2], "hello"], 3, [4]];
380 obj = get_deep_nested_literal();
381 assertKind(elements_kind.fast_smi_only, obj[1][0]);
383 obj[1][0][0] = "goodbye";
384 assertKind(elements_kind.fast_double, obj[0]);
385 assertKind(elements_kind.fast, obj[1][0]);
387 obj = get_deep_nested_literal();
388 assertKind(elements_kind.fast_double, obj[0]);
389 assertKind(elements_kind.fast, obj[1][0]);
392 // Perform a gc because without it the test below can experience an
393 // allocation failure at an inconvenient point. Allocation mementos get
394 // cleared on gc, and they can't deliver elements kind feedback when that
398 // Make sure object literals with array fields benefit from the type feedback
399 // that allocation mementos provide.
401 // A literal in an object
402 function get_object_literal() {
410 obj = get_object_literal();
411 assertKind(elements_kind.fast_smi_only, obj.array);
413 assertKind(elements_kind.fast_double, obj.array);
414 obj = get_object_literal();
415 assertKind(elements_kind.fast_double, obj.array);
417 function get_nested_object_literal() {
419 array: [[1],[2],[3]],
425 obj = get_nested_object_literal();
426 assertKind(elements_kind.fast, obj.array);
427 assertKind(elements_kind.fast_smi_only, obj.array[1]);
428 obj.array[1][0] = 3.5;
429 assertKind(elements_kind.fast_double, obj.array[1]);
430 obj = get_nested_object_literal();
431 assertKind(elements_kind.fast_double, obj.array[1]);
433 %OptimizeFunctionOnNextCall(get_nested_object_literal);
434 get_nested_object_literal();
435 obj = get_nested_object_literal();
436 assertKind(elements_kind.fast_double, obj.array[1]);
438 // Make sure we handle nested arrays
439 function get_nested_literal() {
440 var literal = [[1,2,3,4], [2], [3]];
444 obj = get_nested_literal();
445 assertKind(elements_kind.fast, obj);
448 obj = get_nested_literal();
449 assertKind(elements_kind.fast_double, obj[0]);
450 assertKind(elements_kind.fast_smi_only, obj[1]);
451 assertKind(elements_kind.fast, obj[2]);
453 // A more complex nested literal case.
454 function get_deep_nested_literal() {
455 var literal = [[1], [[2], "hello"], 3, [4]];
459 obj = get_deep_nested_literal();
460 assertKind(elements_kind.fast_smi_only, obj[1][0]);
462 obj[1][0][0] = "goodbye";
463 assertKind(elements_kind.fast_double, obj[0]);
464 assertKind(elements_kind.fast, obj[1][0]);
466 obj = get_deep_nested_literal();
467 assertKind(elements_kind.fast_double, obj[0]);
468 assertKind(elements_kind.fast, obj[1][0]);