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 --expose-gc
29
30// Test element kind of objects.
31
32var elements_kind = {
33  fast_smi_only            :  'fast smi only elements',
34  fast                     :  'fast elements',
35  fast_double              :  'fast double elements',
36  dictionary               :  'dictionary elements',
37  external_byte            :  'external byte elements',
38  external_unsigned_byte   :  'external unsigned byte elements',
39  external_short           :  'external short elements',
40  external_unsigned_short  :  'external unsigned short elements',
41  external_int             :  'external int elements',
42  external_unsigned_int    :  'external unsigned int elements',
43  external_float           :  'external float elements',
44  external_double          :  'external double elements',
45  external_pixel           :  'external pixel elements'
46}
47
48function getKind(obj) {
49  if (%HasFastSmiElements(obj)) return elements_kind.fast_smi_only;
50  if (%HasFastObjectElements(obj)) return elements_kind.fast;
51  if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
52  if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
53}
54
55function isHoley(obj) {
56  if (%HasFastHoleyElements(obj)) return true;
57  return false;
58}
59
60function assertKind(expected, obj, name_opt) {
61  assertEquals(expected, getKind(obj), name_opt);
62}
63
64// Test: If a call site goes megamorphic, it retains the ability to
65// use allocation site feedback (if FLAG_allocation_site_pretenuring
66// is on).
67(function() {
68  function bar(t, len) {
69    return new t(len);
70  }
71
72  a = bar(Array, 10);
73  a[0] = 3.5;
74  b = bar(Array, 1);
75  assertKind(elements_kind.fast_double, b);
76  c = bar(Object, 3);
77  b = bar(Array, 10);
78  // TODO(mvstanton): re-enable when FLAG_allocation_site_pretenuring
79  // is on in the build.
80  // assertKind(elements_kind.fast_double, b);
81})();
82
83
84// Test: ensure that crankshafted array constructor sites are deopted
85// if another function is used.
86(function() {
87  function bar0(t) {
88    return new t();
89  }
90  a = bar0(Array);
91  a[0] = 3.5;
92  b = bar0(Array);
93  assertKind(elements_kind.fast_double, b);
94    %OptimizeFunctionOnNextCall(bar0);
95  b = bar0(Array);
96  assertKind(elements_kind.fast_double, b);
97  assertOptimized(bar0);
98  // bar0 should deopt
99  b = bar0(Object);
100  assertUnoptimized(bar0)
101  // When it's re-optimized, we should call through the full stub
102  bar0(Array);
103    %OptimizeFunctionOnNextCall(bar0);
104  b = bar0(Array);
105  // This only makes sense to test if we allow crankshafting
106  if (4 != %GetOptimizationStatus(bar0)) {
107    // We also lost our ability to record kind feedback, as the site
108    // is megamorphic now.
109    assertKind(elements_kind.fast_smi_only, b);
110    assertOptimized(bar0);
111    b[0] = 3.5;
112    c = bar0(Array);
113    assertKind(elements_kind.fast_smi_only, c);
114  }
115})();
116
117
118// Test: Ensure that inlined array calls in crankshaft learn from deopts
119// based on the move to a dictionary for the array.
120(function() {
121  function bar(len) {
122    return new Array(len);
123  }
124  a = bar(10);
125  a[0] = "a string";
126  a = bar(10);
127  assertKind(elements_kind.fast, a);
128    %OptimizeFunctionOnNextCall(bar);
129  a = bar(10);
130  assertKind(elements_kind.fast, a);
131  assertOptimized(bar);
132  bar(100000);
133  assertOptimized(bar);
134
135  // If the argument isn't a smi, things should still work.
136  a = bar("oops");
137  assertOptimized(bar);
138  assertKind(elements_kind.fast, a);
139
140  function barn(one, two, three) {
141    return new Array(one, two, three);
142  }
143
144  barn(1, 2, 3);
145  barn(1, 2, 3);
146    %OptimizeFunctionOnNextCall(barn);
147  barn(1, 2, 3);
148  assertOptimized(barn);
149  a = barn(1, "oops", 3);
150  assertOptimized(barn);
151})();
152
153
154// Test: When a method with array constructor is crankshafted, the type
155// feedback for elements kind is baked in. Verify that transitions don't
156// change it anymore
157(function() {
158  function bar() {
159    return new Array();
160  }
161  a = bar();
162  bar();
163    %OptimizeFunctionOnNextCall(bar);
164  b = bar();
165  // This only makes sense to test if we allow crankshafting
166  if (4 != %GetOptimizationStatus(bar)) {
167    assertOptimized(bar);
168      %DebugPrint(3);
169    b[0] = 3.5;
170    c = bar();
171    assertKind(elements_kind.fast_smi_only, c);
172    assertOptimized(bar);
173  }
174})();
175
176
177// Test: create arrays in two contexts, verifying that the correct
178// map for Array in that context will be used.
179(function() {
180  function bar() { return new Array(); }
181  bar();
182  bar();
183    %OptimizeFunctionOnNextCall(bar);
184  a = bar();
185  assertTrue(a instanceof Array);
186
187  var contextB = Realm.create();
188  Realm.eval(contextB, "function bar2() { return new Array(); };");
189  Realm.eval(contextB, "bar2(); bar2();");
190  Realm.eval(contextB, "%OptimizeFunctionOnNextCall(bar2);");
191  Realm.eval(contextB, "bar2();");
192  assertFalse(Realm.eval(contextB, "bar2();") instanceof Array);
193  assertTrue(Realm.eval(contextB, "bar2() instanceof Array"));
194})();
195
196// Test: create array with packed feedback, then optimize function, which
197// should deal with arguments that create holey arrays.
198(function() {
199  function bar(len) { return new Array(len); }
200  bar(0);
201  bar(0);
202    %OptimizeFunctionOnNextCall(bar);
203  a = bar(0);
204  assertOptimized(bar);
205  assertFalse(isHoley(a));
206  a = bar(1);  // ouch!
207  assertOptimized(bar);
208  assertTrue(isHoley(a));
209  a = bar(100);
210  assertTrue(isHoley(a));
211  a = bar(0);
212  assertOptimized(bar);
213  // Crankshafted functions don't use mementos, so feedback still
214  // indicates a packed array is desired. (unless --nocrankshaft is in use).
215  if (4 != %GetOptimizationStatus(bar)) {
216    assertFalse(isHoley(a));
217  }
218})();
219
220// Test: Make sure that crankshaft continues with feedback for large arrays.
221(function() {
222  function bar(len) { return new Array(len); }
223  var size = 100001;
224  // Perform a gc, because we are allocating a very large array and if a gc
225  // happens during the allocation we could lose our memento.
226  gc();
227  bar(size)[0] = 'string';
228  var res = bar(size);
229  assertKind(elements_kind.fast, bar(size));
230    %OptimizeFunctionOnNextCall(bar);
231  assertKind(elements_kind.fast, bar(size));
232  // But there is a limit, based on the size of the old generation, currently
233  // 22937600, but double it to prevent the test being too brittle.
234  var large_size = 22937600 * 2;
235  assertKind(elements_kind.dictionary, bar(large_size));
236})();
237