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