Introduce builtin for Array.shift function.
authorantonm@chromium.org <antonm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 15 Feb 2010 09:17:38 +0000 (09:17 +0000)
committerantonm@chromium.org <antonm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 15 Feb 2010 09:17:38 +0000 (09:17 +0000)
Review URL: http://codereview.chromium.org/606017

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

src/bootstrapper.cc
src/builtins.cc
src/builtins.h
test/mjsunit/array-shift.js [new file with mode: 0644]

index e88861d..045a630 100644 (file)
@@ -1473,25 +1473,27 @@ void Genesis::AddSpecialFunction(Handle<JSObject> prototype,
 void Genesis::BuildSpecialFunctionTable() {
   HandleScope scope;
   Handle<JSObject> global = Handle<JSObject>(global_context()->global());
-  // Add special versions for Array.prototype.pop and push.
+  // Add special versions for some Array.prototype functions.
   Handle<JSFunction> function =
       Handle<JSFunction>(
           JSFunction::cast(global->GetProperty(Heap::Array_symbol())));
   Handle<JSObject> visible_prototype =
       Handle<JSObject>(JSObject::cast(function->prototype()));
-  // Remember to put push and pop on the hidden prototype if it's there.
-  Handle<JSObject> push_and_pop_prototype;
+  // Remember to put those specializations on the hidden prototype if present.
+  Handle<JSObject> special_prototype;
   Handle<Object> superproto(visible_prototype->GetPrototype());
   if (superproto->IsJSObject() &&
       JSObject::cast(*superproto)->map()->is_hidden_prototype()) {
-    push_and_pop_prototype = Handle<JSObject>::cast(superproto);
+    special_prototype = Handle<JSObject>::cast(superproto);
   } else {
-    push_and_pop_prototype = visible_prototype;
+    special_prototype = visible_prototype;
   }
-  AddSpecialFunction(push_and_pop_prototype, "pop",
+  AddSpecialFunction(special_prototype, "pop",
                      Handle<Code>(Builtins::builtin(Builtins::ArrayPop)));
-  AddSpecialFunction(push_and_pop_prototype, "push",
+  AddSpecialFunction(special_prototype, "push",
                      Handle<Code>(Builtins::builtin(Builtins::ArrayPush)));
+  AddSpecialFunction(special_prototype, "shift",
+                     Handle<Code>(Builtins::builtin(Builtins::ArrayShift)));
 }
 
 
index 9c4cdac..1159a21 100644 (file)
@@ -313,6 +313,43 @@ BUILTIN(ArrayPop) {
 }
 
 
+BUILTIN(ArrayShift) {
+  JSArray* array = JSArray::cast(*args.receiver());
+  ASSERT(array->HasFastElements());
+
+  int len = Smi::cast(array->length())->value();
+  if (len == 0) return Heap::undefined_value();
+
+  // Fetch the prototype.
+  JSFunction* array_function =
+      Top::context()->global_context()->array_function();
+  JSObject* prototype = JSObject::cast(array_function->prototype());
+
+  // Get first element
+  FixedArray* elms = FixedArray::cast(array->elements());
+  Object* first = elms->get(0);
+
+  if (first->IsTheHole()) {
+    first = prototype->GetElement(0);
+  }
+
+  // Shift the elements.
+  for (int i = 0; i < len - 1; i++) {
+    Object* e = elms->get(i + 1);
+    if (e->IsTheHole() && prototype->HasElement(i + 1)) {
+      e = prototype->GetElement(i + 1);
+    }
+    elms->set(i, e);
+  }
+  elms->set(len - 1, Heap::the_hole_value());
+
+  // Set the length.
+  array->set_length(Smi::FromInt(len - 1));
+
+  return first;
+}
+
+
 // -----------------------------------------------------------------------------
 //
 
index 9df6ef8..a008285 100644 (file)
@@ -48,6 +48,7 @@ enum BuiltinExtraArguments {
                                                                     \
   V(ArrayPush, NO_EXTRA_ARGUMENTS)                                  \
   V(ArrayPop, NO_EXTRA_ARGUMENTS)                                   \
+  V(ArrayShift, NO_EXTRA_ARGUMENTS)                                 \
                                                                     \
   V(HandleApiCall, NEEDS_CALLED_FUNCTION)                           \
   V(FastHandleApiCall, NO_EXTRA_ARGUMENTS)                          \
diff --git a/test/mjsunit/array-shift.js b/test/mjsunit/array-shift.js
new file mode 100644 (file)
index 0000000..43439ab
--- /dev/null
@@ -0,0 +1,46 @@
+// Copyright 2010 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.
+
+// Check that shifting array of holes keeps it as array of holes
+(function() {
+  var array = new Array(10);
+  array.shift();
+  assertFalse(0 in array);
+})();
+
+// Now check the case with array of holes and some elements on prototype.
+(function() {
+  var array = new Array(10);
+  Array.prototype[7] = "@7";
+  assertEquals(array[0], undefined);
+  assertEquals(array[7], Array.prototype[7]);
+
+  array.shift();
+
+  assertEquals(array[0], undefined);
+  assertEquals(array[7], Array.prototype[7]);
+})();