Revision: 9605
Author:   [email protected]
Date:     Thu Oct 13 03:53:31 2011
Log:      Elements kind conversion in generated code (ia32).

BUG=
TEST=

Review URL: http://codereview.chromium.org/8241003
http://code.google.com/p/v8/source/detail?r=9605

Added:
 /branches/bleeding_edge/test/mjsunit/elements-kind.js
 /branches/bleeding_edge/test/mjsunit/elements-transition.js
Deleted:
 /branches/bleeding_edge/test/mjsunit/element-kind.js
Modified:
 /branches/bleeding_edge/src/code-stubs.cc
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/ic.cc

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/elements-kind.js Thu Oct 13 03:53:31 2011
@@ -0,0 +1,274 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc
+
+// Test element kind of objects.
+// Since --smi-only-arrays affects builtins, its default setting at compile
+// time sticks if built with snapshot.  If --smi-only-arrays is deactivated
+// by default, only a no-snapshot build actually has smi-only arrays enabled
+// in this test case.  Depending on whether smi-only arrays are actually
+// enabled, this test takes the appropriate code path to check smi-only arrays.
+
+support_smi_only_arrays = %HasFastSmiOnlyElements([]);
+
+if (support_smi_only_arrays) {
+  print("Tests include smi-only arrays.");
+} else {
+  print("Tests do NOT include smi-only arrays.");
+}
+
+var elements_kind = {
+  fast_smi_only            :  'fast smi only elements',
+  fast                     :  'fast elements',
+  fast_double              :  'fast double elements',
+  dictionary               :  'dictionary elements',
+  external_byte            :  'external byte elements',
+  external_unsigned_byte   :  'external unsigned byte elements',
+  external_short           :  'external short elements',
+  external_unsigned_short  :  'external unsigned short elements',
+  external_int             :  'external int elements',
+  external_unsigned_int    :  'external unsigned int elements',
+  external_float           :  'external float elements',
+  external_double          :  'external double elements',
+  external_pixel           :  'external pixel elements'
+}
+
+function getKind(obj) {
+  if (%HasFastSmiOnlyElements(obj)) return elements_kind.fast_smi_only;
+  if (%HasFastElements(obj)) return elements_kind.fast;
+  if (%HasFastDoubleElements(obj)) return elements_kind.fast_double;
+  if (%HasDictionaryElements(obj)) return elements_kind.dictionary;
+  // Every external kind is also an external array.
+  assertTrue(%HasExternalArrayElements(obj));
+  if (%HasExternalByteElements(obj)) {
+    return elements_kind.external_byte;
+  }
+  if (%HasExternalUnsignedByteElements(obj)) {
+    return elements_kind.external_unsigned_byte;
+  }
+  if (%HasExternalShortElements(obj)) {
+    return elements_kind.external_short;
+  }
+  if (%HasExternalUnsignedShortElements(obj)) {
+    return elements_kind.external_unsigned_short;
+  }
+  if (%HasExternalIntElements(obj)) {
+    return elements_kind.external_int;
+  }
+  if (%HasExternalUnsignedIntElements(obj)) {
+    return elements_kind.external_unsigned_int;
+  }
+  if (%HasExternalFloatElements(obj)) {
+    return elements_kind.external_float;
+  }
+  if (%HasExternalDoubleElements(obj)) {
+    return elements_kind.external_double;
+  }
+  if (%HasExternalPixelElements(obj)) {
+    return elements_kind.external_pixel;
+  }
+}
+
+function assertKind(expected, obj, name_opt) {
+  if (!support_smi_only_arrays &&
+      expected == elements_kind.fast_smi_only) {
+    expected = elements_kind.fast;
+  }
+  assertEquals(expected, getKind(obj), name_opt);
+}
+
+var me = {};
+assertKind(elements_kind.fast, me);
+me.dance = 0xD15C0;
+me.drink = 0xC0C0A;
+assertKind(elements_kind.fast, me);
+
+var too = [1,2,3];
+assertKind(elements_kind.fast_smi_only, too);
+too.dance = 0xD15C0;
+too.drink = 0xC0C0A;
+assertKind(elements_kind.fast_smi_only, too);
+
+// Make sure the element kind transitions from smionly when a non-smi is stored.
+var you = new Array();
+assertKind(elements_kind.fast_smi_only, you);
+for (var i = 0; i < 1337; i++) {
+  var val = i;
+  if (i == 1336) {
+    assertKind(elements_kind.fast_smi_only, you);
+    val = new Object();
+  }
+  you[i] = val;
+}
+assertKind(elements_kind.fast, you);
+
+assertKind(elements_kind.dictionary, new Array(0xDECAF));
+
+var fast_double_array = new Array(0xDECAF);
+for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2;
+assertKind(elements_kind.fast_double, fast_double_array);
+
+assertKind(elements_kind.external_byte,           new Int8Array(9001));
+assertKind(elements_kind.external_unsigned_byte,  new Uint8Array(007));
+assertKind(elements_kind.external_short,          new Int16Array(666));
+assertKind(elements_kind.external_unsigned_short, new Uint16Array(42));
+assertKind(elements_kind.external_int,            new Int32Array(0xF));
+assertKind(elements_kind.external_unsigned_int,   new Uint32Array(23));
+assertKind(elements_kind.external_float,          new Float32Array(7));
+assertKind(elements_kind.external_double,         new Float64Array(0));
+assertKind(elements_kind.external_pixel,          new PixelArray(512));
+
+// Crankshaft support for smi-only array elements.
+function monomorphic(array) {
+  for (var i = 0; i < 3; i++) {
+    array[i] = i + 10;
+  }
+  assertKind(elements_kind.fast_smi_only, array);
+  for (var i = 0; i < 3; i++) {
+    var a = array[i];
+    assertEquals(i + 10, a);
+  }
+}
+var smi_only = [1, 2, 3];
+for (var i = 0; i < 3; i++) monomorphic(smi_only);
+%OptimizeFunctionOnNextCall(monomorphic);
+monomorphic(smi_only);
+function polymorphic(array, expected_kind) {
+  array[1] = 42;
+  assertKind(expected_kind, array);
+  var a = array[1];
+  assertEquals(42, a);
+}
+var smis = [1, 2, 3];
+var strings = [0, 0, 0]; strings[0] = "one";
+var doubles = [0, 0, 0]; doubles[0] = 1.5;
+assertKind(support_smi_only_arrays
+               ? elements_kind.fast_double
+               : elements_kind.fast,
+           doubles);
+for (var i = 0; i < 3; i++) {
+  polymorphic(smis, elements_kind.fast_smi_only);
+}
+for (var i = 0; i < 3; i++) {
+  polymorphic(strings, elements_kind.fast);
+}
+for (var i = 0; i < 3; i++) {
+  polymorphic(doubles, i == 0 && support_smi_only_arrays
+                           ? elements_kind.fast_double
+                           : elements_kind.fast);
+}
+
+/* Element transitions have not been implemented in crankshaft yet.
+%OptimizeFunctionOnNextCall(polymorphic);
+polymorphic(smis, elements_kind.fast_smi_only);
+polymorphic(strings, elements_kind.fast);
+polymorphic(doubles, elements_kind.fast);
+
+// Crankshaft support for smi-only elements in dynamic array literals.
+function get(foo) { return foo; }  // Used to generate dynamic values.
+
+function crankshaft_test() {
+  var a = [get(1), get(2), get(3)];
+  assertKind(elements_kind.fast_smi_only, a);
+  var b = [get(1), get(2), get("three")];
+  assertKind(elements_kind.fast, b);
+  var c = [get(1), get(2), get(3.5)];
+  // The full code generator doesn't support conversion to fast_double
+  // yet. Crankshaft does, but only with --smi-only-arrays support.
+  if ((%GetOptimizationStatus(crankshaft_test) & 1) &&
+      support_smi_only_arrays) {
+    assertKind(elements_kind.fast_double, c);
+  } else {
+    assertKind(elements_kind.fast, c);
+  }
+}
+for (var i = 0; i < 3; i++) {
+  crankshaft_test();
+}
+%OptimizeFunctionOnNextCall(crankshaft_test);
+crankshaft_test();
+*/
+
+// Elements_kind transitions for arrays.
+
+// A map can have three different elements_kind transitions: SMI->DOUBLE,
+// DOUBLE->OBJECT, and SMI->OBJECT. No matter in which order these three are
+// created, they must always end up with the same FAST map.
+
+// This test is meaningless without FAST_SMI_ONLY_ELEMENTS.
+if (support_smi_only_arrays) {
+  // Preparation: create one pair of identical objects for each case.
+  var a = [1, 2, 3];
+  var b = [1, 2, 3];
+  assertTrue(%HaveSameMap(a, b));
+  assertKind(elements_kind.fast_smi_only, a);
+  var c = [1, 2, 3];
+  c["case2"] = true;
+  var d = [1, 2, 3];
+  d["case2"] = true;
+  assertTrue(%HaveSameMap(c, d));
+  assertFalse(%HaveSameMap(a, c));
+  assertKind(elements_kind.fast_smi_only, c);
+  var e = [1, 2, 3];
+  e["case3"] = true;
+  var f = [1, 2, 3];
+  f["case3"] = true;
+  assertTrue(%HaveSameMap(e, f));
+  assertFalse(%HaveSameMap(a, e));
+  assertFalse(%HaveSameMap(c, e));
+  assertKind(elements_kind.fast_smi_only, e);
+  // Case 1: SMI->DOUBLE, DOUBLE->OBJECT, SMI->OBJECT.
+  a[0] = 1.5;
+  assertKind(elements_kind.fast_double, a);
+  a[0] = "foo";
+  assertKind(elements_kind.fast, a);
+  b[0] = "bar";
+  assertTrue(%HaveSameMap(a, b));
+  // Case 2: SMI->DOUBLE, SMI->OBJECT, DOUBLE->OBJECT.
+  c[0] = 1.5;
+  assertKind(elements_kind.fast_double, c);
+  assertFalse(%HaveSameMap(c, d));
+  d[0] = "foo";
+  assertKind(elements_kind.fast, d);
+  assertFalse(%HaveSameMap(c, d));
+  c[0] = "bar";
+  assertTrue(%HaveSameMap(c, d));
+  // Case 3: SMI->OBJECT, SMI->DOUBLE, DOUBLE->OBJECT.
+  e[0] = "foo";
+  assertKind(elements_kind.fast, e);
+  assertFalse(%HaveSameMap(e, f));
+  f[0] = 1.5;
+  assertKind(elements_kind.fast_double, f);
+  assertFalse(%HaveSameMap(e, f));
+  f[0] = "bar";
+  assertKind(elements_kind.fast, f);
+  assertTrue(%HaveSameMap(e, f));
+}
+
+// Throw away type information in the ICs for next stress run.
+gc();
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/elements-transition.js Thu Oct 13 03:53:31 2011
@@ -0,0 +1,85 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax --smi-only-arrays
+
+support_smi_only_arrays = %HasFastSmiOnlyElements([]);
+
+if (support_smi_only_arrays) {
+  function test(test_double, test_object, set, length) {
+ // We apply the same operations to two identical arrays. The first array + // triggers an IC miss, upon which the conversion stub is generated, but the
+    // actual conversion is done in runtime.  The second array, arriving at
+ // the previously patched IC, is then converted using the conversion stub.
+    var array_1 = new Array(length);
+    var array_2 = new Array(length);
+
+    assertTrue(%HasFastSmiOnlyElements(array_1));
+    assertTrue(%HasFastSmiOnlyElements(array_2));
+    for (var i = 0; i < length; i++) {
+      if (i == length - 8 && test_double) {
+        set(array_1, i, 0.5);
+        set(array_2, i, 0.5);
+        assertTrue(%HasFastDoubleElements(array_1));
+        assertTrue(%HasFastDoubleElements(array_2));
+      } else if (i == length - 5 && test_object) {
+        set(array_1, i, 'object');
+        set(array_2, i, 'object');
+        assertTrue(%HasFastElements(array_1));
+        assertTrue(%HasFastElements(array_2));
+      } else {
+        set(array_1, i, 2*i+1);
+        set(array_2, i, 2*i+1);
+      }
+    }
+
+    for (var i = 0; i < length; i++) {
+      if (i == length - 8 && test_double) {
+        assertEquals(0.5, array_1[i]);
+        assertEquals(0.5, array_2[i]);
+      } else if (i == length - 5 && test_object) {
+        assertEquals('object', array_1[i]);
+        assertEquals('object', array_2[i]);
+      } else {
+        assertEquals(2*i+1, array_1[i]);
+        assertEquals(2*i+1, array_2[i]);
+      }
+    }
+  }
+
+  test(false, false, function(a,i,v){ a[i] = v; }, 100);
+  test(true,  false, function(a,i,v){ a[i] = v; }, 100);
+  test(false, true,  function(a,i,v){ a[i] = v; }, 100);
+  test(true,  true,  function(a,i,v){ a[i] = v; }, 100);
+
+  test(false, false, function(a,i,v){ a[i] = v; }, 10000);
+  test(true,  false, function(a,i,v){ a[i] = v; }, 10000);
+  test(false, true,  function(a,i,v){ a[i] = v; }, 10000);
+  test(true,  true,  function(a,i,v){ a[i] = v; }, 10000);
+} else {
+  print("Test skipped because smi only arrays are not supported.");
+}
=======================================
--- /branches/bleeding_edge/test/mjsunit/element-kind.js Tue Oct 11 03:02:42 2011
+++ /dev/null
@@ -1,261 +0,0 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-//       notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-//       copyright notice, this list of conditions and the following
-//       disclaimer in the documentation and/or other materials provided
-//       with the distribution.
-//     * Neither the name of Google Inc. nor the names of its
-//       contributors may be used to endorse or promote products derived
-//       from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Flags: --allow-natives-syntax --smi-only-arrays
-// Test element kind of objects.
-// Since --smi-only-arrays affects builtins, its default setting at compile
-// time sticks if built with snapshot.  If --smi-only-arrays is deactivated
-// by default, only a no-snapshot build actually has smi-only arrays enabled
-// in this test case.  Depending on whether smi-only arrays are actually
-// enabled, this test takes the appropriate code path to check smi-only arrays.
-
-
-support_smi_only_arrays = %HasFastSmiOnlyElements([]);
-
-if (support_smi_only_arrays) {
-  print("Tests include smi-only arrays.");
-} else {
-  print("Tests do NOT include smi-only arrays.");
-}
-
-var element_kind = {
-  fast_smi_only_elements            :  0,
-  fast_elements                     :  1,
-  fast_double_elements              :  2,
-  dictionary_elements               :  3,
-  external_byte_elements            :  4,
-  external_unsigned_byte_elements   :  5,
-  external_short_elements           :  6,
-  external_unsigned_short_elements  :  7,
-  external_int_elements             :  8,
-  external_unsigned_int_elements    :  9,
-  external_float_elements           : 10,
-  external_double_elements          : 11,
-  external_pixel_elements           : 12
-}
-
-// We expect an object to only be of one element kind.
-function assertKind(expected, obj) {
-  if (support_smi_only_arrays) {
-    assertEquals(expected == element_kind.fast_smi_only_elements,
-                 %HasFastSmiOnlyElements(obj));
-    assertEquals(expected == element_kind.fast_elements,
-                 %HasFastElements(obj));
-  } else {
-    assertEquals(expected == element_kind.fast_elements ||
-                 expected == element_kind.fast_smi_only_elements,
-                 %HasFastElements(obj));
-  }
-  assertEquals(expected == element_kind.fast_double_elements,
-               %HasFastDoubleElements(obj));
-  assertEquals(expected == element_kind.dictionary_elements,
-               %HasDictionaryElements(obj));
-  assertEquals(expected == element_kind.external_byte_elements,
-               %HasExternalByteElements(obj));
-  assertEquals(expected == element_kind.external_unsigned_byte_elements,
-               %HasExternalUnsignedByteElements(obj));
-  assertEquals(expected == element_kind.external_short_elements,
-               %HasExternalShortElements(obj));
-  assertEquals(expected == element_kind.external_unsigned_short_elements,
-               %HasExternalUnsignedShortElements(obj));
-  assertEquals(expected == element_kind.external_int_elements,
-               %HasExternalIntElements(obj));
-  assertEquals(expected == element_kind.external_unsigned_int_elements,
-               %HasExternalUnsignedIntElements(obj));
-  assertEquals(expected == element_kind.external_float_elements,
-               %HasExternalFloatElements(obj));
-  assertEquals(expected == element_kind.external_double_elements,
-               %HasExternalDoubleElements(obj));
-  assertEquals(expected == element_kind.external_pixel_elements,
-               %HasExternalPixelElements(obj));
-  // every external kind is also an external array
-  assertEquals(expected >= element_kind.external_byte_elements,
-               %HasExternalArrayElements(obj));
-}
-
-var me = {};
-assertKind(element_kind.fast_elements, me);
-me.dance = 0xD15C0;
-me.drink = 0xC0C0A;
-assertKind(element_kind.fast_elements, me);
-
-var too = [1,2,3];
-assertKind(element_kind.fast_smi_only_elements, too);
-too.dance = 0xD15C0;
-too.drink = 0xC0C0A;
-assertKind(element_kind.fast_smi_only_elements, too);
-
-// Make sure the element kind transitions from smionly when a non-smi is stored.
-var you = new Array();
-assertKind(element_kind.fast_smi_only_elements, you);
-for (var i = 0; i < 1337; i++) {
-  var val = i;
-  if (i == 1336) {
-    assertKind(element_kind.fast_smi_only_elements, you);
-    val = new Object();
-  }
-  you[i] = val;
-}
-assertKind(element_kind.fast_elements, you);
-
-assertKind(element_kind.dictionary_elements, new Array(0xDECAF));
-
-var fast_double_array = new Array(0xDECAF);
-for (var i = 0; i < 0xDECAF; i++) fast_double_array[i] = i / 2;
-assertKind(element_kind.fast_double_elements, fast_double_array);
-
-assertKind(element_kind.external_byte_elements, new Int8Array(9001)); -assertKind(element_kind.external_unsigned_byte_elements, new Uint8Array(007)); -assertKind(element_kind.external_short_elements, new Int16Array(666)); -assertKind(element_kind.external_unsigned_short_elements, new Uint16Array(42)); -assertKind(element_kind.external_int_elements, new Int32Array(0xF)); -assertKind(element_kind.external_unsigned_int_elements, new Uint32Array(23)); -assertKind(element_kind.external_float_elements, new Float32Array(7)); -assertKind(element_kind.external_double_elements, new Float64Array(0)); -assertKind(element_kind.external_pixel_elements, new PixelArray(512));
-
-// Crankshaft support for smi-only array elements.
-function monomorphic(array) {
-  for (var i = 0; i < 3; i++) {
-    array[i] = i + 10;
-  }
-  assertKind(element_kind.fast_smi_only_elements, array);
-  for (var i = 0; i < 3; i++) {
-    var a = array[i];
-    assertEquals(i + 10, a);
-  }
-}
-var smi_only = [1, 2, 3];
-for (var i = 0; i < 3; i++) monomorphic(smi_only);
-%OptimizeFunctionOnNextCall(monomorphic);
-monomorphic(smi_only);
-function polymorphic(array, expected_kind) {
-  array[1] = 42;
-  assertKind(expected_kind, array);
-  var a = array[1];
-  assertEquals(42, a);
-}
-var smis = [1, 2, 3];
-var strings = ["one", "two", "three"];
-var doubles = [0, 0, 0]; doubles[0] = 1.5; doubles[1] = 2.5; doubles[2] = 3.5;
-assertKind(support_smi_only_arrays
-               ? element_kind.fast_double_elements
-               : element_kind.fast_elements,
-           doubles);
-for (var i = 0; i < 3; i++) {
-  polymorphic(smis, element_kind.fast_smi_only_elements);
-  polymorphic(strings, element_kind.fast_elements);
-  polymorphic(doubles, support_smi_only_arrays
-                           ? element_kind.fast_double_elements
-                           : element_kind.fast_elements);
-}
-%OptimizeFunctionOnNextCall(polymorphic);
-polymorphic(smis, element_kind.fast_smi_only_elements);
-polymorphic(strings, element_kind.fast_elements);
-polymorphic(doubles, support_smi_only_arrays
-    ? element_kind.fast_double_elements
-    : element_kind.fast_elements);
-
-// Crankshaft support for smi-only elements in dynamic array literals.
-function get(foo) { return foo; }  // Used to generate dynamic values.
-
-function crankshaft_test() {
-  var a = [get(1), get(2), get(3)];
-  assertKind(element_kind.fast_smi_only_elements, a);
-  var b = [get(1), get(2), get("three")];
-  assertKind(element_kind.fast_elements, b);
-  var c = [get(1), get(2), get(3.5)];
- // The full code generator doesn't support conversion to fast_double_elements
-  // yet. Crankshaft does, but only with --smi-only-arrays support.
-  if ((%GetOptimizationStatus(crankshaft_test) & 1) &&
-      support_smi_only_arrays) {
-    assertKind(element_kind.fast_double_elements, c);
-  } else {
-    assertKind(element_kind.fast_elements, c);
-  }
-}
-for (var i = 0; i < 3; i++) {
-  crankshaft_test();
-}
-%OptimizeFunctionOnNextCall(crankshaft_test);
-crankshaft_test();
-
-// Elements_kind transitions for arrays.
-
-// A map can have three different elements_kind transitions: SMI->DOUBLE,
-// DOUBLE->OBJECT, and SMI->OBJECT. No matter in which order these three are
-// created, they must always end up with the same FAST map.
-
-// This test is meaningless without FAST_SMI_ONLY_ELEMENTS.
-if (support_smi_only_arrays) {
-  // Preparation: create one pair of identical objects for each case.
-  var a = [1, 2, 3];
-  var b = [1, 2, 3];
-  assertTrue(%HaveSameMap(a, b));
-  assertKind(element_kind.fast_smi_only_elements, a);
-  var c = [1, 2, 3];
-  c["case2"] = true;
-  var d = [1, 2, 3];
-  d["case2"] = true;
-  assertTrue(%HaveSameMap(c, d));
-  assertFalse(%HaveSameMap(a, c));
-  assertKind(element_kind.fast_smi_only_elements, c);
-  var e = [1, 2, 3];
-  e["case3"] = true;
-  var f = [1, 2, 3];
-  f["case3"] = true;
-  assertTrue(%HaveSameMap(e, f));
-  assertFalse(%HaveSameMap(a, e));
-  assertFalse(%HaveSameMap(c, e));
-  assertKind(element_kind.fast_smi_only_elements, e);
-  // Case 1: SMI->DOUBLE, DOUBLE->OBJECT, SMI->OBJECT.
-  a[0] = 1.5;
-  assertKind(element_kind.fast_double_elements, a);
-  a[0] = "foo";
-  assertKind(element_kind.fast_elements, a);
-  b[0] = "bar";
-  assertTrue(%HaveSameMap(a, b));
-  // Case 2: SMI->DOUBLE, SMI->OBJECT, DOUBLE->OBJECT.
-  c[0] = 1.5;
-  assertKind(element_kind.fast_double_elements, c);
-  assertFalse(%HaveSameMap(c, d));
-  d[0] = "foo";
-  assertKind(element_kind.fast_elements, d);
-  assertFalse(%HaveSameMap(c, d));
-  c[0] = "bar";
-  assertTrue(%HaveSameMap(c, d));
-  // Case 3: SMI->OBJECT, SMI->DOUBLE, DOUBLE->OBJECT.
-  e[0] = "foo";
-  assertKind(element_kind.fast_elements, e);
-  assertFalse(%HaveSameMap(e, f));
-  f[0] = 1.5;
-  assertKind(element_kind.fast_double_elements, f);
-  assertFalse(%HaveSameMap(e, f));
-  f[0] = "bar";
-  assertKind(element_kind.fast_elements, f);
-  assertTrue(%HaveSameMap(e, f));
-}
=======================================
--- /branches/bleeding_edge/src/code-stubs.cc   Mon Oct  3 04:13:20 2011
+++ /branches/bleeding_edge/src/code-stubs.cc   Thu Oct 13 03:53:31 2011
@@ -415,4 +415,28 @@
 }


+void FastElementsConversionStub::Generate(MacroAssembler* masm) {
+#if defined(V8_TARGET_ARCH_IA32)
+  if (to_ == FAST_ELEMENTS) {
+    if (from_ == FAST_SMI_ONLY_ELEMENTS) {
+      GenerateSmiOnlyToObject(masm);
+    } else if (from_ == FAST_DOUBLE_ELEMENTS) {
+      GenerateDoubleToObject(masm, strict_mode_);
+    } else {
+      UNREACHABLE();
+    }
+    KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
+                                                     is_jsarray_,
+                                                     FAST_ELEMENTS);
+ } else if (from_ == FAST_SMI_ONLY_ELEMENTS && to_ == FAST_DOUBLE_ELEMENTS) {
+    GenerateSmiOnlyToDouble(masm, strict_mode_);
+ KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm, is_jsarray_);
+  } else {
+    UNREACHABLE();
+  }
+#else
+  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
+#endif  // V8_TARGET_ARCH_IA32
+}
+
 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Thu Oct  6 08:59:02 2011
+++ /branches/bleeding_edge/src/code-stubs.h    Thu Oct 13 03:53:31 2011
@@ -69,7 +69,8 @@
   V(KeyedLoadElement)                    \
   V(KeyedStoreElement)                   \
   V(DebuggerStatement)                   \
-  V(StringDictionaryLookup)
+  V(StringDictionaryLookup)              \
+  V(FastElementsConversion)

 // List of code stubs only used on ARM platforms.
 #ifdef V8_TARGET_ARCH_ARM
@@ -1025,6 +1026,47 @@
   Types types_;
 };

+
+class FastElementsConversionStub : public CodeStub {
+ public:
+  FastElementsConversionStub(ElementsKind from,
+                             ElementsKind to,
+                             bool is_jsarray,
+                             StrictModeFlag strict_mode)
+      : from_(from),
+        to_(to),
+        is_jsarray_(is_jsarray),
+        strict_mode_(strict_mode) {}
+
+ private:
+  class FromBits:       public BitField<ElementsKind,    0, 8> {};
+  class ToBits:         public BitField<ElementsKind,    8, 8> {};
+  class IsJSArrayBits:  public BitField<bool,           16, 8> {};
+  class StrictModeBits: public BitField<StrictModeFlag, 24, 8> {};
+
+  Major MajorKey() { return FastElementsConversion; }
+  int MinorKey() {
+    return FromBits::encode(from_) |
+        ToBits::encode(to_) |
+        IsJSArrayBits::encode(is_jsarray_) |
+        StrictModeBits::encode(strict_mode_);
+  }
+
+  void Generate(MacroAssembler* masm);
+  static void GenerateSmiOnlyToObject(MacroAssembler* masm);
+  static void GenerateSmiOnlyToDouble(MacroAssembler* masm,
+                                      StrictModeFlag strict_mode);
+  static void GenerateDoubleToObject(MacroAssembler* masm,
+                                     StrictModeFlag strict_mode);
+
+  ElementsKind from_;
+  ElementsKind to_;
+  bool is_jsarray_;
+  StrictModeFlag strict_mode_;
+
+  DISALLOW_COPY_AND_ASSIGN(FastElementsConversionStub);
+};
+
 } }  // namespace v8::internal

 #endif  // V8_CODE_STUBS_H_
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Tue Oct 11 02:28:06 2011 +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Thu Oct 13 03:53:31 2011
@@ -34,6 +34,7 @@
 #include "isolate.h"
 #include "jsregexp.h"
 #include "regexp-macro-assembler.h"
+#include "stub-cache.h"

 namespace v8 {
 namespace internal {
@@ -6749,6 +6750,13 @@
   { ebx, edx, ecx, EMIT_REMEMBERED_SET},
   // KeyedStoreStubCompiler::GenerateStoreFastElement.
   { edi, edx, ecx, EMIT_REMEMBERED_SET},
+  // FastElementConversionStub::GenerateSmiOnlyToObject
+  // and FastElementsConversionStub::GenerateSmiOnlyToDouble
+  // and FastElementsConversionStub::GenerateDoubleToObject
+  { edx, ebx, edi, EMIT_REMEMBERED_SET},
+  // FastElementConversionStub::GenerateDoubleToObject
+  { eax, edx, esi, EMIT_REMEMBERED_SET},
+  { edx, eax, edi, EMIT_REMEMBERED_SET},
   // Null termination.
   { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET}
 };
@@ -6992,6 +7000,255 @@
 }


+void FastElementsConversionStub::GenerateSmiOnlyToObject(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ebx    : target map
+  //  -- ecx    : key
+  //  -- edx    : receiver
+  //  -- esp[0] : return address
+  // -----------------------------------
+  // Set transitioned map.
+  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
+  __ RecordWriteField(edx,
+                      HeapObject::kMapOffset,
+                      ebx,
+                      edi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+}
+
+
+void FastElementsConversionStub::GenerateSmiOnlyToDouble(
+    MacroAssembler* masm, StrictModeFlag strict_mode) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ebx    : target map
+  //  -- ecx    : key
+  //  -- edx    : receiver
+  //  -- esp[0] : return address
+  // -----------------------------------
+  Label loop, entry, convert_hole, gc_required;
+  __ push(eax);
+  __ push(ebx);
+
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+  __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
+
+  // Allocate new FixedDoubleArray.
+  // edx: receiver
+  // edi: length of source FixedArray (smi-tagged)
+  __ lea(esi, Operand(edi, times_4, FixedDoubleArray::kHeaderSize));
+  __ AllocateInNewSpace(esi, eax, ebx, no_reg, &gc_required, TAG_OBJECT);
+
+  // eax: destination FixedDoubleArray
+  // edi: number of elements
+  // edx: receiver
+  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
+         Immediate(masm->isolate()->factory()->fixed_double_array_map()));
+  __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
+  __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
+  // Replace receiver's backing store with newly created FixedDoubleArray.
+  __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
+  __ mov(ebx, eax);
+  __ RecordWriteField(edx,
+                      JSObject::kElementsOffset,
+                      ebx,
+                      edi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+
+  __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
+  // Convert and copy elements
+  // esi: source FixedArray
+  // edi: number of elements to convert/copy
+  ExternalReference canonical_the_hole_nan_reference =
+      ExternalReference::address_of_the_hole_nan();
+  XMMRegister the_hole_nan = xmm1;
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope use_sse2(SSE2);
+    __ movdbl(the_hole_nan,
+              Operand::StaticVariable(canonical_the_hole_nan_reference));
+  }
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ sub(edi, Immediate(Smi::FromInt(1)));
+  __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
+  // ebx: current element from source
+  // edi: index of current element
+  __ JumpIfNotSmi(ebx, &convert_hole);
+
+  // Normal smi, convert it to double and store.
+  __ SmiUntag(ebx);
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope fscope(SSE2);
+    __ cvtsi2sd(xmm0, ebx);
+ __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
+              xmm0);
+  } else {
+    __ push(ebx);
+    __ fild_s(Operand(esp, 0));
+    __ pop(ebx);
+ __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
+  }
+  __ jmp(&entry);
+
+  // Found hole, store hole_nan_as_double instead.
+  __ bind(&convert_hole);
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope use_sse2(SSE2);
+ __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
+              the_hole_nan);
+  } else {
+    __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
+ __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
+  }
+
+  __ bind(&entry);
+  __ test(edi, edi);
+  __ j(not_zero, &loop);
+
+  Label done;
+  __ pop(ebx);
+  __ pop(eax);
+  // eax: value
+  // ebx: target map
+  // Set transitioned map.
+  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
+  __ RecordWriteField(edx,
+                      HeapObject::kMapOffset,
+                      ebx,
+                      edi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  // Restore esi.
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  __ jmp(&done, Label::kNear);
+
+  __ bind(&gc_required);
+  // Restore registers before jumping into runtime.
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  __ pop(ebx);
+  __ pop(eax);
+  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+  __ bind(&done);
+}
+
+
+void FastElementsConversionStub::GenerateDoubleToObject(
+    MacroAssembler* masm, StrictModeFlag strict_mode) {
+  // ----------- S t a t e -------------
+  //  -- eax    : value
+  //  -- ebx    : target map
+  //  -- ecx    : key
+  //  -- edx    : receiver
+  //  -- esp[0] : return address
+  // -----------------------------------
+  Label loop, entry, convert_hole, gc_required;
+  __ push(eax);
+  __ push(edx);
+  __ push(ebx);
+
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+  __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
+
+  // Allocate new FixedArray.
+  // ebx: length of source FixedDoubleArray (smi-tagged)
+  __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
+  __ AllocateInNewSpace(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
+
+  // eax: destination FixedArray
+  // ebx: number of elements
+  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
+         Immediate(masm->isolate()->factory()->fixed_array_map()));
+  __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
+  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+
+  // Box doubles into heap numbers.
+  // edi: source FixedDoubleArray
+  // eax: destination FixedArray
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ sub(ebx, Immediate(Smi::FromInt(1)));
+  // ebx: index of current element (smi-tagged)
+ uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); + __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
+  __ j(equal, &convert_hole);
+
+  // Non-hole double, copy value into a heap number.
+  __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
+  // edx: new heap number
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope fscope(SSE2);
+    __ movdbl(xmm0,
+ FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
+    __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
+  } else {
+ __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
+    __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
+    __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
+ __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
+  }
+  __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
+  __ mov(esi, ebx);
+  __ RecordWriteArray(eax,
+                      edx,
+                      esi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  __ jmp(&entry);
+
+  // Replace the-hole nan with the-hole pointer.
+  __ bind(&convert_hole);
+  __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
+         masm->isolate()->factory()->the_hole_value());
+
+  __ bind(&entry);
+  __ test(ebx, ebx);
+  __ j(not_zero, &loop);
+
+  __ pop(ebx);
+  __ pop(edx);
+  // ebx: target map
+  // edx: receiver
+  // Set transitioned map.
+  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
+  __ RecordWriteField(edx,
+                      HeapObject::kMapOffset,
+                      ebx,
+                      edi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+ // Replace receiver's backing store with newly created and filled FixedArray.
+  __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
+  __ RecordWriteField(edx,
+                      JSObject::kElementsOffset,
+                      eax,
+                      edi,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+
+  // Restore registers.
+  Label done;
+  __ pop(eax);
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  __ jmp(&done, Label::kNear);
+
+  __ bind(&gc_required);
+  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  __ pop(ebx);
+  __ pop(edx);
+  __ pop(eax);
+  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+  __ bind(&done);
+}
+
 #undef __

 } }  // namespace v8::internal
=======================================
--- /branches/bleeding_edge/src/ic.cc   Tue Oct 11 09:02:45 2011
+++ /branches/bleeding_edge/src/ic.cc   Thu Oct 13 03:53:31 2011
@@ -1593,7 +1593,7 @@
         RelocInfo* info = it.rinfo();
         Object* object = info->target_object();
         ASSERT(object->IsMap());
-        result->Add(Map::cast(object));
+        AddOneReceiverMapIfMissing(result, Map::cast(object));
       }
     }
   }
@@ -1781,12 +1781,6 @@
 MaybeObject* KeyedStoreIC::ComputePolymorphicStub(
     MapList* receiver_maps,
     StrictModeFlag strict_mode) {
-  // TODO(yangguo): <remove>
-  Code* generic_stub = (strict_mode == kStrictMode)
- ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict)
-      : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic);
-  // </remove>
-
   // Collect MONOMORPHIC stubs for all target_receiver_maps.
   CodeList handler_ics(receiver_maps->length());
   MapList transitioned_maps(receiver_maps->length());
@@ -1795,15 +1789,11 @@
     MaybeObject* maybe_cached_stub = NULL;
Map* transitioned_map = GetTransitionedMap(receiver_map, receiver_maps);
     if (transitioned_map != NULL) {
-      // TODO(yangguo): Enable this code!
-      // maybe_cached_stub = FastElementsConversionStub(
-      //     receiver_map->elements_kind(),  // original elements_kind
-      //     transitioned_map->elements_kind(),
- // receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array
-      //     strict_mode_).TryGetCode();
-      // TODO(yangguo): <remove>
-      maybe_cached_stub = generic_stub;
-      // </remove>
+      maybe_cached_stub = FastElementsConversionStub(
+          receiver_map->elements_kind(),  // original elements_kind
+          transitioned_map->elements_kind(),
+          receiver_map->instance_type() == JS_ARRAY_TYPE,  // is_js_array
+          strict_mode).TryGetCode();
     } else {
       maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
           receiver_map, strict_mode);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to