Add more bailouts for Array.slice over arguments.
authorantonm@chromium.org <antonm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 11 Jan 2011 11:23:40 +0000 (11:23 +0000)
committerantonm@chromium.org <antonm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 11 Jan 2011 11:23:40 +0000 (11:23 +0000)
Unfortunately, arguments is pretty much the normal JS object.  For now
I am adding more sanity checks (in hope that typically arguments
list is rather short.)  However it probably requires more systematic
treatment, for example, we could optimistically copy elements until
we meet first hole and in this case resort to JS builtin.

Review URL: http://codereview.chromium.org/6062006

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6256 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/builtins.cc
test/mjsunit/array-slice.js

index 0c76f6944f86684b31e360d5fe1d2f6d40ba8b78..a659c461c01e1bd68a4ef220962bbe027c02d07c 100644 (file)
@@ -636,15 +636,20 @@ BUILTIN(ArraySlice) {
       return CallJsBuiltin("ArraySlice", args);
     }
     elms = FixedArray::cast(JSObject::cast(receiver)->elements());
-    len = elms->length();
-#ifdef DEBUG
-    // Arguments object by construction should have no holes, check it.
-    if (FLAG_enable_slow_asserts) {
-      for (int i = 0; i < len; i++) {
-        ASSERT(elms->get(i) != Heap::the_hole_value());
+    Object* len_obj = JSObject::cast(receiver)
+        ->InObjectPropertyAt(Heap::arguments_length_index);
+    if (!len_obj->IsSmi()) {
+      return CallJsBuiltin("ArraySlice", args);
+    }
+    len = Smi::cast(len_obj)->value();
+    if (len > elms->length()) {
+      return CallJsBuiltin("ArraySlice", args);
+    }
+    for (int i = 0; i < len; i++) {
+      if (elms->get(i) == Heap::the_hole_value()) {
+        return CallJsBuiltin("ArraySlice", args);
       }
     }
-#endif
   }
   ASSERT(len >= 0);
   int n_arguments = args.length() - 1;
index 50b5b273064d731523414c03d6d1cd9609e687dd..5ae31dc5278ec4c90a4166f91030874c8c06663c 100644 (file)
   func(['a', 1, undefined], 'a', 1, undefined);
   func(['a', 1, undefined, void(0)], 'a', 1, undefined, void(0));
 })();
+
+// Check slicing on arguments object when missing arguments get assigined.
+(function() {
+  function func(x, y) {
+    assertEquals(1, arguments.length);
+    assertEquals(undefined, y);
+    y = 239;
+    assertEquals(1, arguments.length);  // arguments length is the same.
+    assertEquals([x], Array.prototype.slice.call(arguments, 0));
+  }
+
+  func('a');
+})();
+
+// Check slicing on arguments object when length property has been set.
+(function() {
+  function func(x, y) {
+    assertEquals(1, arguments.length);
+    arguments.length = 7;
+    assertEquals([x,,,,,,,], Array.prototype.slice.call(arguments, 0));
+  }
+
+  func('a');
+})();
+
+// Check slicing on arguments object when length property has been set to
+// some strange value.
+(function() {
+  function func(x, y) {
+    assertEquals(1, arguments.length);
+    arguments.length = 'foobar';
+    assertEquals([], Array.prototype.slice.call(arguments, 0));
+  }
+
+  func('a');
+})();
+
+// Check slicing on arguments object when extra argument has been added
+// via indexed assignment.
+(function() {
+  function func(x, y) {
+    assertEquals(1, arguments.length);
+    arguments[3] = 239;
+    assertEquals([x], Array.prototype.slice.call(arguments, 0));
+  }
+
+  func('a');
+})();
+
+// Check slicing on arguments object when argument has been deleted by index.
+(function() {
+  function func(x, y, z) {
+    assertEquals(3, arguments.length);
+    delete arguments[1];
+    assertEquals([x,,z], Array.prototype.slice.call(arguments, 0));
+  }
+
+  func('a', 'b', 'c');
+})();