Update V8 to r4588

We're using WebKit r58033, as used by
http://src.chromium.org/svn/releases/5.0.387.0/DEPS
This requires http://v8.googlecode.com/svn/trunk@4465 but this version has a
crashing bug for ARM. Instead we use http://v8.googlecode.com/svn/trunk@4588,
which is used by http://src.chromium.org/svn/releases/6.0.399.0/DEPS

Note that a trivial bug fix was required in arm/codegen-arm.cc. This is guarded
with ANDROID. See http://code.google.com/p/v8/issues/detail?id=703

Change-Id: I459647a8286c4f8c7405f0c5581ecbf051a6f1e8
diff --git a/src/builtins.cc b/src/builtins.cc
index ee98769..e6cbd94 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -242,9 +242,165 @@
 }
 
 
+static Object* AllocateJSArray() {
+  JSFunction* array_function =
+      Top::context()->global_context()->array_function();
+  Object* result = Heap::AllocateJSObject(array_function);
+  if (result->IsFailure()) return result;
+  return result;
+}
+
+
+static Object* AllocateEmptyJSArray() {
+  Object* result = AllocateJSArray();
+  if (result->IsFailure()) return result;
+  JSArray* result_array = JSArray::cast(result);
+  result_array->set_length(Smi::FromInt(0));
+  result_array->set_elements(Heap::empty_fixed_array());
+  return result_array;
+}
+
+
+static void CopyElements(AssertNoAllocation* no_gc,
+                         FixedArray* dst,
+                         int dst_index,
+                         FixedArray* src,
+                         int src_index,
+                         int len) {
+  ASSERT(dst != src);  // Use MoveElements instead.
+  ASSERT(len > 0);
+  CopyWords(dst->data_start() + dst_index,
+            src->data_start() + src_index,
+            len);
+  WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
+  if (mode == UPDATE_WRITE_BARRIER) {
+    Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
+  }
+}
+
+
+static void MoveElements(AssertNoAllocation* no_gc,
+                         FixedArray* dst,
+                         int dst_index,
+                         FixedArray* src,
+                         int src_index,
+                         int len) {
+  memmove(dst->data_start() + dst_index,
+          src->data_start() + src_index,
+          len * kPointerSize);
+  WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
+  if (mode == UPDATE_WRITE_BARRIER) {
+    Heap::RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
+  }
+}
+
+
+static void FillWithHoles(FixedArray* dst, int from, int to) {
+  MemsetPointer(dst->data_start() + from, Heap::the_hole_value(), to - from);
+}
+
+
+static FixedArray* LeftTrimFixedArray(FixedArray* elms, int to_trim) {
+  // For now this trick is only applied to fixed arrays in new space.
+  // In large object space the object's start must coincide with chunk
+  // and thus the trick is just not applicable.
+  // In old space we do not use this trick to avoid dealing with
+  // remembered sets.
+  ASSERT(Heap::new_space()->Contains(elms));
+
+  STATIC_ASSERT(FixedArray::kMapOffset == 0);
+  STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
+  STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
+
+  Object** former_start = HeapObject::RawField(elms, 0);
+
+  const int len = elms->length();
+
+  // Technically in new space this write might be omitted (except for
+  // debug mode which iterates through the heap), but to play safer
+  // we still do it.
+  Heap::CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
+
+  former_start[to_trim] = Heap::fixed_array_map();
+  former_start[to_trim + 1] = reinterpret_cast<Object*>(len - to_trim);
+
+  ASSERT_EQ(elms->address() + to_trim * kPointerSize,
+            (elms + to_trim * kPointerSize)->address());
+  return elms + to_trim * kPointerSize;
+}
+
+
+static bool ArrayPrototypeHasNoElements() {
+  // This method depends on non writability of Object and Array prototype
+  // fields.
+  Context* global_context = Top::context()->global_context();
+  // Array.prototype
+  JSObject* proto =
+      JSObject::cast(global_context->array_function()->prototype());
+  if (proto->elements() != Heap::empty_fixed_array()) return false;
+  // Hidden prototype
+  proto = JSObject::cast(proto->GetPrototype());
+  ASSERT(proto->elements() == Heap::empty_fixed_array());
+  // Object.prototype
+  proto = JSObject::cast(proto->GetPrototype());
+  if (proto != global_context->initial_object_prototype()) return false;
+  if (proto->elements() != Heap::empty_fixed_array()) return false;
+  ASSERT(proto->GetPrototype()->IsNull());
+  return true;
+}
+
+
+static bool IsJSArrayWithFastElements(Object* receiver,
+                                      FixedArray** elements) {
+  if (!receiver->IsJSArray()) {
+    return false;
+  }
+
+  JSArray* array = JSArray::cast(receiver);
+
+  HeapObject* elms = HeapObject::cast(array->elements());
+  if (elms->map() != Heap::fixed_array_map()) {
+    return false;
+  }
+
+  *elements = FixedArray::cast(elms);
+  return true;
+}
+
+
+static Object* CallJsBuiltin(const char* name,
+                             BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
+  HandleScope handleScope;
+
+  Handle<Object> js_builtin =
+      GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
+                  name);
+  ASSERT(js_builtin->IsJSFunction());
+  Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
+  Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
+  int n_args = args.length() - 1;
+  for (int i = 0; i < n_args; i++) {
+    argv[i] = args.at<Object>(i + 1).location();
+  }
+  bool pending_exception = false;
+  Handle<Object> result = Execution::Call(function,
+                                          args.receiver(),
+                                          n_args,
+                                          argv.start(),
+                                          &pending_exception);
+  argv.Dispose();
+  if (pending_exception) return Failure::Exception();
+  return *result;
+}
+
+
 BUILTIN(ArrayPush) {
-  JSArray* array = JSArray::cast(*args.receiver());
-  ASSERT(array->HasFastElements());
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)) {
+    return CallJsBuiltin("ArrayPush", args);
+  }
+  JSArray* array = JSArray::cast(receiver);
 
   int len = Smi::cast(array->length())->value();
   int to_add = args.length() - 1;
@@ -256,27 +412,27 @@
   ASSERT(to_add <= (Smi::kMaxValue - len));
 
   int new_length = len + to_add;
-  FixedArray* elms = FixedArray::cast(array->elements());
 
   if (new_length > elms->length()) {
     // New backing storage is needed.
     int capacity = new_length + (new_length >> 1) + 16;
-    Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+    Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
     if (obj->IsFailure()) return obj;
+    FixedArray* new_elms = FixedArray::cast(obj);
 
     AssertNoAllocation no_gc;
-    FixedArray* new_elms = FixedArray::cast(obj);
-    WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
-    // Fill out the new array with old elements.
-    for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
+    if (len > 0) {
+      CopyElements(&no_gc, new_elms, 0, elms, 0, len);
+    }
+    FillWithHoles(new_elms, new_length, capacity);
+
     elms = new_elms;
     array->set_elements(elms);
   }
 
+  // Add the provided values.
   AssertNoAllocation no_gc;
   WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-
-  // Add the provided values.
   for (int index = 0; index < to_add; index++) {
     elms->set(index + len, args[index + 1], mode);
   }
@@ -288,15 +444,17 @@
 
 
 BUILTIN(ArrayPop) {
-  JSArray* array = JSArray::cast(*args.receiver());
-  ASSERT(array->HasFastElements());
-  Object* undefined = Heap::undefined_value();
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)) {
+    return CallJsBuiltin("ArrayPop", args);
+  }
+  JSArray* array = JSArray::cast(receiver);
 
   int len = Smi::cast(array->length())->value();
-  if (len == 0) return undefined;
+  if (len == 0) return Heap::undefined_value();
 
   // Get top element
-  FixedArray* elms = FixedArray::cast(array->elements());
   Object* top = elms->get(len - 1);
 
   // Set the length.
@@ -318,42 +476,35 @@
 }
 
 
-static Object* GetElementToMove(uint32_t index,
-                                FixedArray* elms,
-                                JSObject* prototype) {
-  Object* e = elms->get(index);
-  if (e->IsTheHole() && prototype->HasElement(index)) {
-    e = prototype->GetElement(index);
-  }
-  return e;
-}
-
-
 BUILTIN(ArrayShift) {
-  JSArray* array = JSArray::cast(*args.receiver());
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)
+      || !ArrayPrototypeHasNoElements()) {
+    return CallJsBuiltin("ArrayShift", args);
+  }
+  JSArray* array = JSArray::cast(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());
-
-  FixedArray* elms = FixedArray::cast(array->elements());
-
   // Get first element
   Object* first = elms->get(0);
   if (first->IsTheHole()) {
-    first = prototype->GetElement(0);
+    first = Heap::undefined_value();
   }
 
-  // Shift the elements.
-  for (int i = 0; i < len - 1; i++) {
-    elms->set(i, GetElementToMove(i + 1, elms, prototype));
+  if (Heap::new_space()->Contains(elms)) {
+    // As elms still in the same space they used to be (new space),
+    // there is no need to update remembered set.
+    array->set_elements(LeftTrimFixedArray(elms, 1), SKIP_WRITE_BARRIER);
+  } else {
+    // Shift the elements.
+    AssertNoAllocation no_gc;
+    MoveElements(&no_gc, elms, 0, elms, 1, len - 1);
+    elms->set(len - 1, Heap::the_hole_value());
   }
-  elms->set(len - 1, Heap::the_hole_value());
 
   // Set the length.
   array->set_length(Smi::FromInt(len - 1));
@@ -363,54 +514,40 @@
 
 
 BUILTIN(ArrayUnshift) {
-  JSArray* array = JSArray::cast(*args.receiver());
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)
+      || !ArrayPrototypeHasNoElements()) {
+    return CallJsBuiltin("ArrayUnshift", args);
+  }
+  JSArray* array = JSArray::cast(receiver);
   ASSERT(array->HasFastElements());
 
   int len = Smi::cast(array->length())->value();
   int to_add = args.length() - 1;
-  // Note that we cannot quit early if to_add == 0 as
-  // values should be lifted from prototype into
-  // the array.
-
   int new_length = len + to_add;
   // Currently fixed arrays cannot grow too big, so
   // we should never hit this case.
   ASSERT(to_add <= (Smi::kMaxValue - len));
 
-  FixedArray* elms = FixedArray::cast(array->elements());
-
-  // Fetch the prototype.
-  JSFunction* array_function =
-      Top::context()->global_context()->array_function();
-  JSObject* prototype = JSObject::cast(array_function->prototype());
-
   if (new_length > elms->length()) {
     // New backing storage is needed.
     int capacity = new_length + (new_length >> 1) + 16;
-    Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+    Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
     if (obj->IsFailure()) return obj;
+    FixedArray* new_elms = FixedArray::cast(obj);
 
     AssertNoAllocation no_gc;
-    FixedArray* new_elms = FixedArray::cast(obj);
-    WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
-    // Fill out the new array with old elements.
-    for (int i = 0; i < len; i++)
-      new_elms->set(to_add + i,
-                    GetElementToMove(i, elms, prototype),
-                    mode);
+    if (len > 0) {
+      CopyElements(&no_gc, new_elms, to_add, elms, 0, len);
+    }
+    FillWithHoles(new_elms, new_length, capacity);
 
     elms = new_elms;
     array->set_elements(elms);
   } else {
     AssertNoAllocation no_gc;
-    WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-
-    // Move elements to the right
-    for (int i = 0; i < len; i++) {
-      elms->set(new_length - i - 1,
-                GetElementToMove(len - i - 1, elms, prototype),
-                mode);
-    }
+    MoveElements(&no_gc, elms, to_add, elms, 0, len);
   }
 
   // Add the provided values.
@@ -426,33 +563,14 @@
 }
 
 
-static Object* CallJsBuiltin(const char* name,
-                             BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
-  HandleScope handleScope;
-
-  Handle<Object> js_builtin =
-      GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
-                  name);
-  ASSERT(js_builtin->IsJSFunction());
-  Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
-  Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
-  int n_args = args.length() - 1;
-  for (int i = 0; i < n_args; i++) {
-    argv[i] = &args[i + 1];
-  }
-  bool pending_exception = false;
-  Handle<Object> result = Execution::Call(function,
-                                          args.receiver(),
-                                          n_args,
-                                          argv.start(),
-                                          &pending_exception);
-  if (pending_exception) return Failure::Exception();
-  return *result;
-}
-
-
 BUILTIN(ArraySlice) {
-  JSArray* array = JSArray::cast(*args.receiver());
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)
+      || !ArrayPrototypeHasNoElements()) {
+    return CallJsBuiltin("ArraySlice", args);
+  }
+  JSArray* array = JSArray::cast(receiver);
   ASSERT(array->HasFastElements());
 
   int len = Smi::cast(array->length())->value();
@@ -460,21 +578,21 @@
   int n_arguments = args.length() - 1;
 
   // Note carefully choosen defaults---if argument is missing,
-  // it's undefined which gets converted to 0 for relativeStart
-  // and to len for relativeEnd.
-  int relativeStart = 0;
-  int relativeEnd = len;
+  // it's undefined which gets converted to 0 for relative_start
+  // and to len for relative_end.
+  int relative_start = 0;
+  int relative_end = len;
   if (n_arguments > 0) {
     Object* arg1 = args[1];
     if (arg1->IsSmi()) {
-      relativeStart = Smi::cast(arg1)->value();
+      relative_start = Smi::cast(arg1)->value();
     } else if (!arg1->IsUndefined()) {
       return CallJsBuiltin("ArraySlice", args);
     }
     if (n_arguments > 1) {
       Object* arg2 = args[2];
       if (arg2->IsSmi()) {
-        relativeEnd = Smi::cast(arg2)->value();
+        relative_end = Smi::cast(arg2)->value();
       } else if (!arg2->IsUndefined()) {
         return CallJsBuiltin("ArraySlice", args);
       }
@@ -482,43 +600,29 @@
   }
 
   // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
-  int k = (relativeStart < 0) ? Max(len + relativeStart, 0)
-                              : Min(relativeStart, len);
+  int k = (relative_start < 0) ? Max(len + relative_start, 0)
+                               : Min(relative_start, len);
 
   // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8.
-  int final = (relativeEnd < 0) ? Max(len + relativeEnd, 0)
-                                : Min(relativeEnd, len);
+  int final = (relative_end < 0) ? Max(len + relative_end, 0)
+                                 : Min(relative_end, len);
 
   // Calculate the length of result array.
   int result_len = final - k;
-  if (result_len < 0) {
-    result_len = 0;
+  if (result_len <= 0) {
+    return AllocateEmptyJSArray();
   }
 
-  JSFunction* array_function =
-      Top::context()->global_context()->array_function();
-  Object* result = Heap::AllocateJSObject(array_function);
+  Object* result = AllocateJSArray();
   if (result->IsFailure()) return result;
   JSArray* result_array = JSArray::cast(result);
 
-  result = Heap::AllocateFixedArrayWithHoles(result_len);
+  result = Heap::AllocateUninitializedFixedArray(result_len);
   if (result->IsFailure()) return result;
   FixedArray* result_elms = FixedArray::cast(result);
 
-  FixedArray* elms = FixedArray::cast(array->elements());
-
-  // Fetch the prototype.
-  JSObject* prototype = JSObject::cast(array_function->prototype());
-
   AssertNoAllocation no_gc;
-  WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc);
-
-  // Fill newly created array.
-  for (int i = 0; i < result_len; i++) {
-    result_elms->set(i,
-                     GetElementToMove(k + i, elms, prototype),
-                     mode);
-  }
+  CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
 
   // Set elements.
   result_array->set_elements(result_elms);
@@ -530,7 +634,13 @@
 
 
 BUILTIN(ArraySplice) {
-  JSArray* array = JSArray::cast(*args.receiver());
+  Object* receiver = *args.receiver();
+  FixedArray* elms = NULL;
+  if (!IsJSArrayWithFastElements(receiver, &elms)
+      || !ArrayPrototypeHasNoElements()) {
+    return CallJsBuiltin("ArraySplice", args);
+  }
+  JSArray* array = JSArray::cast(receiver);
   ASSERT(array->HasFastElements());
 
   int len = Smi::cast(array->length())->value();
@@ -546,118 +656,129 @@
     return Heap::undefined_value();
   }
 
-  int relativeStart = 0;
+  int relative_start = 0;
   Object* arg1 = args[1];
   if (arg1->IsSmi()) {
-    relativeStart = Smi::cast(arg1)->value();
+    relative_start = Smi::cast(arg1)->value();
   } else if (!arg1->IsUndefined()) {
     return CallJsBuiltin("ArraySplice", args);
   }
-  int actualStart = (relativeStart < 0) ? Max(len + relativeStart, 0)
-                                        : Min(relativeStart, len);
+  int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
+                                          : Min(relative_start, len);
 
   // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
   // given differently from when an undefined delete count is given.
   // This does not follow ECMA-262, but we do the same for
   // compatibility.
-  int deleteCount = len;
+  int delete_count = len;
   if (n_arguments > 1) {
     Object* arg2 = args[2];
     if (arg2->IsSmi()) {
-      deleteCount = Smi::cast(arg2)->value();
+      delete_count = Smi::cast(arg2)->value();
     } else {
       return CallJsBuiltin("ArraySplice", args);
     }
   }
-  int actualDeleteCount = Min(Max(deleteCount, 0), len - actualStart);
+  int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
 
-  JSFunction* array_function =
-      Top::context()->global_context()->array_function();
+  JSArray* result_array = NULL;
+  if (actual_delete_count == 0) {
+    Object* result = AllocateEmptyJSArray();
+    if (result->IsFailure()) return result;
+    result_array = JSArray::cast(result);
+  } else {
+    // Allocate result array.
+    Object* result = AllocateJSArray();
+    if (result->IsFailure()) return result;
+    result_array = JSArray::cast(result);
 
-  // Allocate result array.
-  Object* result = Heap::AllocateJSObject(array_function);
-  if (result->IsFailure()) return result;
-  JSArray* result_array = JSArray::cast(result);
+    result = Heap::AllocateUninitializedFixedArray(actual_delete_count);
+    if (result->IsFailure()) return result;
+    FixedArray* result_elms = FixedArray::cast(result);
 
-  result = Heap::AllocateFixedArrayWithHoles(actualDeleteCount);
-  if (result->IsFailure()) return result;
-  FixedArray* result_elms = FixedArray::cast(result);
+    AssertNoAllocation no_gc;
+    // Fill newly created array.
+    CopyElements(&no_gc,
+                 result_elms, 0,
+                 elms, actual_start,
+                 actual_delete_count);
 
-  FixedArray* elms = FixedArray::cast(array->elements());
+    // Set elements.
+    result_array->set_elements(result_elms);
 
-  // Fetch the prototype.
-  JSObject* prototype = JSObject::cast(array_function->prototype());
-
-  AssertNoAllocation no_gc;
-  WriteBarrierMode mode = result_elms->GetWriteBarrierMode(no_gc);
-
-  // Fill newly created array.
-  for (int k = 0; k < actualDeleteCount; k++) {
-    result_elms->set(k,
-                     GetElementToMove(actualStart + k, elms, prototype),
-                     mode);
+    // Set the length.
+    result_array->set_length(Smi::FromInt(actual_delete_count));
   }
 
-  // Set elements.
-  result_array->set_elements(result_elms);
+  int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
 
-  // Set the length.
-  result_array->set_length(Smi::FromInt(actualDeleteCount));
+  int new_length = len - actual_delete_count + item_count;
 
-  int itemCount = (n_arguments > 1) ? (n_arguments - 2) : 0;
-
-  int new_length = len - actualDeleteCount + itemCount;
-
-  mode = elms->GetWriteBarrierMode(no_gc);
-  if (itemCount < actualDeleteCount) {
+  if (item_count < actual_delete_count) {
     // Shrink the array.
-    for (int k = actualStart; k < (len - actualDeleteCount); k++) {
-      elms->set(k + itemCount,
-                GetElementToMove(k + actualDeleteCount, elms, prototype),
-                mode);
-    }
+    const bool trim_array = Heap::new_space()->Contains(elms) &&
+      ((actual_start + item_count) <
+          (len - actual_delete_count - actual_start));
+    if (trim_array) {
+      const int delta = actual_delete_count - item_count;
 
-    for (int k = len; k > new_length; k--) {
-      elms->set(k - 1, Heap::the_hole_value());
+      if (actual_start > 0) {
+        Object** start = elms->data_start();
+        memmove(start + delta, start, actual_start * kPointerSize);
+      }
+
+      elms = LeftTrimFixedArray(elms, delta);
+      array->set_elements(elms, SKIP_WRITE_BARRIER);
+    } else {
+      AssertNoAllocation no_gc;
+      MoveElements(&no_gc,
+                   elms, actual_start + item_count,
+                   elms, actual_start + actual_delete_count,
+                   (len - actual_delete_count - actual_start));
+      FillWithHoles(elms, new_length, len);
     }
-  } else if (itemCount > actualDeleteCount) {
+  } else if (item_count > actual_delete_count) {
     // Currently fixed arrays cannot grow too big, so
     // we should never hit this case.
-    ASSERT((itemCount - actualDeleteCount) <= (Smi::kMaxValue - len));
-
-    FixedArray* source_elms = elms;
+    ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
 
     // Check if array need to grow.
     if (new_length > elms->length()) {
       // New backing storage is needed.
       int capacity = new_length + (new_length >> 1) + 16;
-      Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
+      Object* obj = Heap::AllocateUninitializedFixedArray(capacity);
       if (obj->IsFailure()) return obj;
-
       FixedArray* new_elms = FixedArray::cast(obj);
-      mode = new_elms->GetWriteBarrierMode(no_gc);
 
-      // Copy the part before actualStart as is.
-      for (int k = 0; k < actualStart; k++) {
-        new_elms->set(k, elms->get(k), mode);
+      AssertNoAllocation no_gc;
+      // Copy the part before actual_start as is.
+      if (actual_start > 0) {
+        CopyElements(&no_gc, new_elms, 0, elms, 0, actual_start);
       }
+      const int to_copy = len - actual_delete_count - actual_start;
+      if (to_copy > 0) {
+        CopyElements(&no_gc,
+                     new_elms, actual_start + item_count,
+                     elms, actual_start + actual_delete_count,
+                     to_copy);
+      }
+      FillWithHoles(new_elms, new_length, capacity);
 
-      source_elms = elms;
       elms = new_elms;
       array->set_elements(elms);
-    }
-
-    for (int k = len - actualDeleteCount; k > actualStart; k--) {
-      elms->set(k + itemCount - 1,
-                GetElementToMove(k + actualDeleteCount - 1,
-                                 source_elms,
-                                 prototype),
-                mode);
+    } else {
+      AssertNoAllocation no_gc;
+      MoveElements(&no_gc,
+                   elms, actual_start + item_count,
+                   elms, actual_start + actual_delete_count,
+                   (len - actual_delete_count - actual_start));
     }
   }
 
-  for (int k = actualStart; k < actualStart + itemCount; k++) {
-    elms->set(k, args[3 + k - actualStart], mode);
+  AssertNoAllocation no_gc;
+  WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+  for (int k = actual_start; k < actual_start + item_count; k++) {
+    elms->set(k, args[3 + k - actual_start], mode);
   }
 
   // Set the length.
@@ -667,6 +788,70 @@
 }
 
 
+BUILTIN(ArrayConcat) {
+  if (!ArrayPrototypeHasNoElements()) {
+    return CallJsBuiltin("ArrayConcat", args);
+  }
+
+  // Iterate through all the arguments performing checks
+  // and calculating total length.
+  int n_arguments = args.length();
+  int result_len = 0;
+  for (int i = 0; i < n_arguments; i++) {
+    Object* arg = args[i];
+    if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()) {
+      return CallJsBuiltin("ArrayConcat", args);
+    }
+
+    int len = Smi::cast(JSArray::cast(arg)->length())->value();
+
+    // We shouldn't overflow when adding another len.
+    const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
+    STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
+    USE(kHalfOfMaxInt);
+    result_len += len;
+    ASSERT(result_len >= 0);
+
+    if (result_len > FixedArray::kMaxLength) {
+      return CallJsBuiltin("ArrayConcat", args);
+    }
+  }
+
+  if (result_len == 0) {
+    return AllocateEmptyJSArray();
+  }
+
+  // Allocate result.
+  Object* result = AllocateJSArray();
+  if (result->IsFailure()) return result;
+  JSArray* result_array = JSArray::cast(result);
+
+  result = Heap::AllocateUninitializedFixedArray(result_len);
+  if (result->IsFailure()) return result;
+  FixedArray* result_elms = FixedArray::cast(result);
+
+  // Copy data.
+  AssertNoAllocation no_gc;
+  int start_pos = 0;
+  for (int i = 0; i < n_arguments; i++) {
+    JSArray* array = JSArray::cast(args[i]);
+    int len = Smi::cast(array->length())->value();
+    if (len > 0) {
+      FixedArray* elms = FixedArray::cast(array->elements());
+      CopyElements(&no_gc, result_elms, start_pos, elms, 0, len);
+      start_pos += len;
+    }
+  }
+  ASSERT(start_pos == result_len);
+
+  // Set the length and elements.
+  result_array->set_length(Smi::FromInt(result_len));
+  result_array->set_elements(result_elms);
+
+  return result_array;
+}
+
+
 // -----------------------------------------------------------------------------
 //
 
@@ -726,20 +911,19 @@
 
   HandleScope scope;
   Handle<JSFunction> function = args.called_function();
+  ASSERT(function->shared()->IsApiFunction());
 
+  FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
   if (is_construct) {
-    Handle<FunctionTemplateInfo> desc =
-        Handle<FunctionTemplateInfo>(
-            FunctionTemplateInfo::cast(function->shared()->function_data()));
+    Handle<FunctionTemplateInfo> desc(fun_data);
     bool pending_exception = false;
     Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
                                &pending_exception);
     ASSERT(Top::has_pending_exception() == pending_exception);
     if (pending_exception) return Failure::Exception();
+    fun_data = *desc;
   }
 
-  FunctionTemplateInfo* fun_data =
-      FunctionTemplateInfo::cast(function->shared()->function_data());
   Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
 
   if (raw_holder->IsNull()) {
@@ -810,8 +994,8 @@
 
 static void VerifyTypeCheck(Handle<JSObject> object,
                             Handle<JSFunction> function) {
-  FunctionTemplateInfo* info =
-      FunctionTemplateInfo::cast(function->shared()->function_data());
+  ASSERT(function->shared()->IsApiFunction());
+  FunctionTemplateInfo* info = function->shared()->get_api_func_data();
   if (info->signature()->IsUndefined()) return;
   SignatureInfo* signature = SignatureInfo::cast(info->signature());
   Object* receiver_type = signature->receiver();
@@ -895,9 +1079,9 @@
   // used to create the called object.
   ASSERT(obj->map()->has_instance_call_handler());
   JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
-  Object* template_info = constructor->shared()->function_data();
+  ASSERT(constructor->shared()->IsApiFunction());
   Object* handler =
-      FunctionTemplateInfo::cast(template_info)->instance_call_handler();
+      constructor->shared()->get_api_func_data()->instance_call_handler();
   ASSERT(!handler->IsUndefined());
   CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
   Object* callback_obj = call_data->callback();
@@ -1079,6 +1263,11 @@
 }
 
 
+static void Generate_StoreIC_ArrayLength(MacroAssembler* masm) {
+  StoreIC::GenerateArrayLength(masm);
+}
+
+
 static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
   KeyedStoreIC::GenerateGeneric(masm);
 }
@@ -1166,6 +1355,14 @@
 static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
   Debug::GenerateStubNoRegistersDebugBreak(masm);
 }
+
+static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
+  Debug::GeneratePlainReturnLiveEdit(masm);
+}
+
+static void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) {
+  Debug::GenerateFrameDropperLiveEdit(masm);
+}
 #endif
 
 Object* Builtins::builtins_[builtin_count] = { NULL, };
@@ -1267,8 +1464,8 @@
         }
       }
       // Log the event and add the code to the builtins array.
-      LOG(CodeCreateEvent(Logger::BUILTIN_TAG,
-                          Code::cast(code), functions[i].s_name));
+      PROFILE(CodeCreateEvent(Logger::BUILTIN_TAG,
+                              Code::cast(code), functions[i].s_name));
       builtins_[i] = code;
 #ifdef ENABLE_DISASSEMBLER
       if (FLAG_print_builtin_code) {