Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

FPIIM-449

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/builtins.cc b/src/builtins.cc
index b8d0b42..34b370f 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -2,20 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/v8.h"
+#include "src/builtins.h"
 
 #include "src/api.h"
+#include "src/api-natives.h"
 #include "src/arguments.h"
 #include "src/base/once.h"
 #include "src/bootstrapper.h"
-#include "src/builtins.h"
-#include "src/cpu-profiler.h"
+#include "src/dateparser-inl.h"
+#include "src/elements.h"
+#include "src/frames-inl.h"
 #include "src/gdb-jit.h"
-#include "src/heap/mark-compact.h"
-#include "src/heap-profiler.h"
 #include "src/ic/handler-compiler.h"
 #include "src/ic/ic.h"
+#include "src/isolate-inl.h"
+#include "src/messages.h"
+#include "src/profiler/cpu-profiler.h"
+#include "src/property-descriptor.h"
 #include "src/prototype.h"
+#include "src/string-builder.h"
 #include "src/vm-state-inl.h"
 
 namespace v8 {
@@ -28,7 +33,10 @@
 class BuiltinArguments : public Arguments {
  public:
   BuiltinArguments(int length, Object** arguments)
-      : Arguments(length, arguments) { }
+      : Arguments(length, arguments) {
+    // Check we have at least the receiver.
+    DCHECK_LE(1, this->length());
+  }
 
   Object*& operator[] (int index) {
     DCHECK(index < length());
@@ -40,55 +48,78 @@
     return Arguments::at<S>(index);
   }
 
+  Handle<Object> atOrUndefined(Isolate* isolate, int index) {
+    if (index >= length()) {
+      return isolate->factory()->undefined_value();
+    }
+    return at<Object>(index);
+  }
+
   Handle<Object> receiver() {
     return Arguments::at<Object>(0);
   }
 
-  Handle<JSFunction> called_function() {
-    STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
-    return Arguments::at<JSFunction>(Arguments::length() - 1);
-  }
+  Handle<JSFunction> target();
+  Handle<HeapObject> new_target();
 
   // Gets the total number of arguments including the receiver (but
   // excluding extra arguments).
-  int length() const {
-    STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
-    return Arguments::length();
-  }
-
-#ifdef DEBUG
-  void Verify() {
-    // Check we have at least the receiver.
-    DCHECK(Arguments::length() >= 1);
-  }
-#endif
+  int length() const;
 };
 
 
-// Specialize BuiltinArguments for the called function extra argument.
+// Specialize BuiltinArguments for the extra arguments.
 
 template <>
-int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
+int BuiltinArguments<BuiltinExtraArguments::kNone>::length() const {
+  return Arguments::length();
+}
+
+template <>
+int BuiltinArguments<BuiltinExtraArguments::kTarget>::length() const {
   return Arguments::length() - 1;
 }
 
-#ifdef DEBUG
 template <>
-void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
-  // Check we have at least the receiver and the called function.
-  DCHECK(Arguments::length() >= 2);
-  // Make sure cast to JSFunction succeeds.
-  called_function();
+Handle<JSFunction> BuiltinArguments<BuiltinExtraArguments::kTarget>::target() {
+  return Arguments::at<JSFunction>(Arguments::length() - 1);
 }
-#endif
+
+template <>
+int BuiltinArguments<BuiltinExtraArguments::kNewTarget>::length() const {
+  return Arguments::length() - 1;
+}
+
+template <>
+Handle<HeapObject>
+BuiltinArguments<BuiltinExtraArguments::kNewTarget>::new_target() {
+  return Arguments::at<HeapObject>(Arguments::length() - 1);
+}
+
+template <>
+int BuiltinArguments<BuiltinExtraArguments::kTargetAndNewTarget>::length()
+    const {
+  return Arguments::length() - 2;
+}
+
+template <>
+Handle<JSFunction>
+BuiltinArguments<BuiltinExtraArguments::kTargetAndNewTarget>::target() {
+  return Arguments::at<JSFunction>(Arguments::length() - 2);
+}
+
+template <>
+Handle<HeapObject>
+BuiltinArguments<BuiltinExtraArguments::kTargetAndNewTarget>::new_target() {
+  return Arguments::at<HeapObject>(Arguments::length() - 1);
+}
 
 
-#define DEF_ARG_TYPE(name, spec)                      \
-  typedef BuiltinArguments<spec> name##ArgumentsType;
+#define DEF_ARG_TYPE(name, spec) \
+  typedef BuiltinArguments<BuiltinExtraArguments::spec> name##ArgumentsType;
 BUILTIN_LIST_C(DEF_ARG_TYPE)
 #undef DEF_ARG_TYPE
 
-}  // namespace
 
 // ----------------------------------------------------------------------------
 // Support macro for defining builtins in C++.
@@ -103,119 +134,115 @@
 // In the body of the builtin function the arguments can be accessed
 // through the BuiltinArguments object args.
 
-#ifdef DEBUG
-
 #define BUILTIN(name)                                            \
   MUST_USE_RESULT static Object* Builtin_Impl_##name(            \
       name##ArgumentsType args, Isolate* isolate);               \
   MUST_USE_RESULT static Object* Builtin_##name(                 \
       int args_length, Object** args_object, Isolate* isolate) { \
     name##ArgumentsType args(args_length, args_object);          \
-    args.Verify();                                               \
     return Builtin_Impl_##name(args, isolate);                   \
   }                                                              \
   MUST_USE_RESULT static Object* Builtin_Impl_##name(            \
       name##ArgumentsType args, Isolate* isolate)
 
-#else  // For release mode.
-
-#define BUILTIN(name)                                            \
-  static Object* Builtin_impl##name(                             \
-      name##ArgumentsType args, Isolate* isolate);               \
-  static Object* Builtin_##name(                                 \
-      int args_length, Object** args_object, Isolate* isolate) { \
-    name##ArgumentsType args(args_length, args_object);          \
-    return Builtin_impl##name(args, isolate);                    \
-  }                                                              \
-  static Object* Builtin_impl##name(                             \
-      name##ArgumentsType args, Isolate* isolate)
-#endif
-
-
-#ifdef DEBUG
-static inline bool CalledAsConstructor(Isolate* isolate) {
-  // Calculate the result using a full stack frame iterator and check
-  // that the state of the stack is as we assume it to be in the
-  // code below.
-  StackFrameIterator it(isolate);
-  DCHECK(it.frame()->is_exit());
-  it.Advance();
-  StackFrame* frame = it.frame();
-  bool reference_result = frame->is_construct();
-  Address fp = Isolate::c_entry_fp(isolate->thread_local_top());
-  // Because we know fp points to an exit frame we can use the relevant
-  // part of ExitFrame::ComputeCallerState directly.
-  const int kCallerOffset = ExitFrameConstants::kCallerFPOffset;
-  Address caller_fp = Memory::Address_at(fp + kCallerOffset);
-  // This inlines the part of StackFrame::ComputeType that grabs the
-  // type of the current frame.  Note that StackFrame::ComputeType
-  // has been specialized for each architecture so if any one of them
-  // changes this code has to be changed as well.
-  const int kMarkerOffset = StandardFrameConstants::kMarkerOffset;
-  const Smi* kConstructMarker = Smi::FromInt(StackFrame::CONSTRUCT);
-  Object* marker = Memory::Object_at(caller_fp + kMarkerOffset);
-  bool result = (marker == kConstructMarker);
-  DCHECK_EQ(result, reference_result);
-  return result;
-}
-#endif
-
 
 // ----------------------------------------------------------------------------
 
-BUILTIN(Illegal) {
-  UNREACHABLE();
-  return isolate->heap()->undefined_value();  // Make compiler happy.
+
+#define CHECK_RECEIVER(Type, name, method)                                  \
+  if (!args.receiver()->Is##Type()) {                                       \
+    THROW_NEW_ERROR_RETURN_FAILURE(                                         \
+        isolate,                                                            \
+        NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,          \
+                     isolate->factory()->NewStringFromAsciiChecked(method), \
+                     args.receiver()));                                     \
+  }                                                                         \
+  Handle<Type> name = Handle<Type>::cast(args.receiver())
+
+
+inline bool ClampedToInteger(Object* object, int* out) {
+  // This is an extended version of ECMA-262 7.1.11 handling signed values
+  // Try to convert object to a number and clamp values to [kMinInt, kMaxInt]
+  if (object->IsSmi()) {
+    *out = Smi::cast(object)->value();
+    return true;
+  } else if (object->IsHeapNumber()) {
+    double value = HeapNumber::cast(object)->value();
+    if (std::isnan(value)) {
+      *out = 0;
+    } else if (value > kMaxInt) {
+      *out = kMaxInt;
+    } else if (value < kMinInt) {
+      *out = kMinInt;
+    } else {
+      *out = static_cast<int>(value);
+    }
+    return true;
+  } else if (object->IsUndefined() || object->IsNull()) {
+    *out = 0;
+    return true;
+  } else if (object->IsBoolean()) {
+    *out = object->IsTrue();
+    return true;
+  }
+  return false;
 }
 
 
-BUILTIN(EmptyFunction) {
-  return isolate->heap()->undefined_value();
+inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object,
+                                     int* out) {
+  Map* arguments_map = isolate->native_context()->sloppy_arguments_map();
+  if (object->map() != arguments_map) return false;
+  DCHECK(object->HasFastElements());
+  Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
+  if (!len_obj->IsSmi()) return false;
+  *out = Max(0, Smi::cast(len_obj)->value());
+  return *out <= object->elements()->length();
 }
 
 
-static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index,
-                               FixedDoubleArray* src, int src_index, int len) {
-  if (len == 0) return;
-  MemMove(dst->data_start() + dst_index, src->data_start() + src_index,
-          len * kDoubleSize);
-}
-
-
-static bool ArrayPrototypeHasNoElements(Heap* heap, PrototypeIterator* iter) {
+inline bool PrototypeHasNoElements(PrototypeIterator* iter) {
   DisallowHeapAllocation no_gc;
   for (; !iter->IsAtEnd(); iter->Advance()) {
     if (iter->GetCurrent()->IsJSProxy()) return false;
-    if (JSObject::cast(iter->GetCurrent())->elements() !=
-        heap->empty_fixed_array()) {
-      return false;
-    }
+    JSObject* current = iter->GetCurrent<JSObject>();
+    if (current->IsAccessCheckNeeded()) return false;
+    if (current->HasIndexedInterceptor()) return false;
+    if (current->elements()->length() != 0) return false;
   }
   return true;
 }
 
 
-static inline bool IsJSArrayFastElementMovingAllowed(Heap* heap,
-                                                     JSArray* receiver) {
+inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate,
+                                              JSArray* receiver) {
   DisallowHeapAllocation no_gc;
-  PrototypeIterator iter(heap->isolate(), receiver);
-  return ArrayPrototypeHasNoElements(heap, &iter);
+  // If the array prototype chain is intact (and free of elements), and if the
+  // receiver's prototype is the array prototype, then we are done.
+  Object* prototype = receiver->map()->prototype();
+  if (prototype->IsJSArray() &&
+      isolate->is_initial_array_prototype(JSArray::cast(prototype)) &&
+      isolate->IsFastArrayConstructorPrototypeChainIntact()) {
+    return true;
+  }
+
+  // Slow case.
+  PrototypeIterator iter(isolate, receiver);
+  return PrototypeHasNoElements(&iter);
 }
 
 
 // Returns empty handle if not applicable.
 MUST_USE_RESULT
-static inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
-    Isolate* isolate,
-    Handle<Object> receiver,
-    Arguments* args,
+inline MaybeHandle<FixedArrayBase> EnsureJSArrayWithWritableFastElements(
+    Isolate* isolate, Handle<Object> receiver, Arguments* args,
     int first_added_arg) {
   if (!receiver->IsJSArray()) return MaybeHandle<FixedArrayBase>();
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
   // If there may be elements accessors in the prototype chain, the fast path
   // cannot be used if there arguments to add to the array.
   Heap* heap = isolate->heap();
-  if (args != NULL && !IsJSArrayFastElementMovingAllowed(heap, *array)) {
+  if (args != NULL && !IsJSArrayFastElementMovingAllowed(isolate, *array)) {
     return MaybeHandle<FixedArrayBase>();
   }
   if (array->map()->is_observed()) return MaybeHandle<FixedArrayBase>();
@@ -233,6 +260,12 @@
     return MaybeHandle<FixedArrayBase>();
   }
 
+  // Adding elements to the array prototype would break code that makes sure
+  // it has no elements. Handle that elsewhere.
+  if (isolate->IsAnyInitialArrayPrototype(array)) {
+    return MaybeHandle<FixedArrayBase>();
+  }
+
   // Need to ensure that the arguments passed in args can be contained in
   // the array.
   int args_length = args->length();
@@ -243,7 +276,7 @@
   ElementsKind target_kind = origin_kind;
   {
     DisallowHeapAllocation no_gc;
-    int arg_count = args->length() - first_added_arg;
+    int arg_count = args_length - first_added_arg;
     Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
     for (int i = 0; i < arg_count; i++) {
       Object* arg = arguments[i];
@@ -265,17 +298,10 @@
 }
 
 
-MUST_USE_RESULT static Object* CallJsBuiltin(
-    Isolate* isolate,
-    const char* name,
-    BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
+MUST_USE_RESULT static Object* CallJsIntrinsic(
+    Isolate* isolate, Handle<JSFunction> function,
+    BuiltinArguments<BuiltinExtraArguments::kNone> args) {
   HandleScope handleScope(isolate);
-
-  Handle<Object> js_builtin = Object::GetProperty(
-      isolate,
-      handle(isolate->native_context()->builtins(), isolate),
-      name).ToHandleChecked();
-  Handle<JSFunction> function = Handle<JSFunction>::cast(js_builtin);
   int argc = args.length() - 1;
   ScopedVector<Handle<Object> > argv(argc);
   for (int i = 0; i < argc; ++i) {
@@ -293,6 +319,18 @@
 }
 
 
+}  // namespace
+
+
+BUILTIN(Illegal) {
+  UNREACHABLE();
+  return isolate->heap()->undefined_value();  // Make compiler happy.
+}
+
+
+BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); }
+
+
 BUILTIN(ArrayPush) {
   HandleScope scope(isolate);
   Handle<Object> receiver = args.receiver();
@@ -300,106 +338,23 @@
       EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
   Handle<FixedArrayBase> elms_obj;
   if (!maybe_elms_obj.ToHandle(&elms_obj)) {
-    return CallJsBuiltin(isolate, "ArrayPush", args);
+    return CallJsIntrinsic(isolate, isolate->array_push(), args);
   }
-
+  // Fast Elements Path
+  int push_size = args.length() - 1;
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
   int len = Smi::cast(array->length())->value();
-  int to_add = args.length() - 1;
-  if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) {
-    return CallJsBuiltin(isolate, "ArrayPush", args);
+  if (push_size == 0) {
+    return Smi::FromInt(len);
+  }
+  if (push_size > 0 &&
+      JSArray::WouldChangeReadOnlyLength(array, len + push_size)) {
+    return CallJsIntrinsic(isolate, isolate->array_push(), args);
   }
   DCHECK(!array->map()->is_observed());
-
-  ElementsKind kind = array->GetElementsKind();
-
-  if (IsFastSmiOrObjectElementsKind(kind)) {
-    Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-    if (to_add == 0) {
-      return Smi::FromInt(len);
-    }
-    // Currently fixed arrays cannot grow too big, so
-    // we should never hit this case.
-    DCHECK(to_add <= (Smi::kMaxValue - len));
-
-    int new_length = len + to_add;
-
-    if (new_length > elms->length()) {
-      // New backing storage is needed.
-      int capacity = new_length + (new_length >> 1) + 16;
-      Handle<FixedArray> new_elms =
-          isolate->factory()->NewUninitializedFixedArray(capacity);
-
-      ElementsAccessor* accessor = array->GetElementsAccessor();
-      accessor->CopyElements(
-          elms_obj, 0, kind, new_elms, 0,
-          ElementsAccessor::kCopyToEndAndInitializeToHole);
-
-      elms = new_elms;
-    }
-
-    // Add the provided values.
-    DisallowHeapAllocation no_gc;
-    WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-    for (int index = 0; index < to_add; index++) {
-      elms->set(index + len, args[index + 1], mode);
-    }
-
-    if (*elms != array->elements()) {
-      array->set_elements(*elms);
-    }
-
-    // Set the length.
-    array->set_length(Smi::FromInt(new_length));
-    return Smi::FromInt(new_length);
-  } else {
-    int elms_len = elms_obj->length();
-    if (to_add == 0) {
-      return Smi::FromInt(len);
-    }
-    // Currently fixed arrays cannot grow too big, so
-    // we should never hit this case.
-    DCHECK(to_add <= (Smi::kMaxValue - len));
-
-    int new_length = len + to_add;
-
-    Handle<FixedDoubleArray> new_elms;
-
-    if (new_length > elms_len) {
-      // New backing storage is needed.
-      int capacity = new_length + (new_length >> 1) + 16;
-      // Create new backing store; since capacity > 0, we can
-      // safely cast to FixedDoubleArray.
-      new_elms = Handle<FixedDoubleArray>::cast(
-          isolate->factory()->NewFixedDoubleArray(capacity));
-
-      ElementsAccessor* accessor = array->GetElementsAccessor();
-      accessor->CopyElements(
-          elms_obj, 0, kind, new_elms, 0,
-          ElementsAccessor::kCopyToEndAndInitializeToHole);
-
-    } else {
-      // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
-      // empty_fixed_array.
-      new_elms = Handle<FixedDoubleArray>::cast(elms_obj);
-    }
-
-    // Add the provided values.
-    DisallowHeapAllocation no_gc;
-    int index;
-    for (index = 0; index < to_add; index++) {
-      Object* arg = args[index + 1];
-      new_elms->set(index + len, arg->Number());
-    }
-
-    if (*new_elms != array->elements()) {
-      array->set_elements(*new_elms);
-    }
-
-    // Set the length.
-    array->set_length(Smi::FromInt(new_length));
-    return Smi::FromInt(new_length);
-  }
+  ElementsAccessor* accessor = array->GetElementsAccessor();
+  int new_length = accessor->Push(array, elms_obj, &args, push_size);
+  return Smi::FromInt(new_length);
 }
 
 
@@ -410,30 +365,31 @@
       EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
   Handle<FixedArrayBase> elms_obj;
   if (!maybe_elms_obj.ToHandle(&elms_obj)) {
-    return CallJsBuiltin(isolate, "ArrayPop", args);
+    return CallJsIntrinsic(isolate, isolate->array_pop(), args);
   }
 
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
   DCHECK(!array->map()->is_observed());
 
-  int len = Smi::cast(array->length())->value();
+  uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value());
   if (len == 0) return isolate->heap()->undefined_value();
 
   if (JSArray::HasReadOnlyLength(array)) {
-    return CallJsBuiltin(isolate, "ArrayPop", args);
+    return CallJsIntrinsic(isolate, isolate->array_pop(), args);
   }
 
-  ElementsAccessor* accessor = array->GetElementsAccessor();
-  int new_length = len - 1;
-  Handle<Object> element =
-      accessor->Get(array, array, new_length, elms_obj).ToHandleChecked();
-  if (element->IsTheHole()) {
-    return CallJsBuiltin(isolate, "ArrayPop", args);
+  Handle<Object> result;
+  if (IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
+    // Fast Elements Path
+    result = array->GetElementsAccessor()->Pop(array, elms_obj);
+  } else {
+    // Use Slow Lookup otherwise
+    uint32_t new_length = len - 1;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, result, Object::GetElement(isolate, array, new_length));
+    JSArray::SetLength(array, new_length);
   }
-  RETURN_FAILURE_ON_EXCEPTION(
-      isolate,
-      accessor->SetLength(array, handle(Smi::FromInt(new_length), isolate)));
-  return *element;
+  return *result;
 }
 
 
@@ -445,8 +401,8 @@
       EnsureJSArrayWithWritableFastElements(isolate, receiver, NULL, 0);
   Handle<FixedArrayBase> elms_obj;
   if (!maybe_elms_obj.ToHandle(&elms_obj) ||
-      !IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(*receiver))) {
-    return CallJsBuiltin(isolate, "ArrayShift", args);
+      !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) {
+    return CallJsIntrinsic(isolate, isolate->array_shift(), args);
   }
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
   DCHECK(!array->map()->is_observed());
@@ -455,492 +411,1003 @@
   if (len == 0) return heap->undefined_value();
 
   if (JSArray::HasReadOnlyLength(array)) {
-    return CallJsBuiltin(isolate, "ArrayShift", args);
+    return CallJsIntrinsic(isolate, isolate->array_shift(), args);
   }
 
-  // Get first element
-  ElementsAccessor* accessor = array->GetElementsAccessor();
-  Handle<Object> first =
-    accessor->Get(array, array, 0, elms_obj).ToHandleChecked();
-  if (first->IsTheHole()) {
-    return CallJsBuiltin(isolate, "ArrayShift", args);
-  }
-
-  if (heap->CanMoveObjectStart(*elms_obj)) {
-    array->set_elements(heap->LeftTrimFixedArray(*elms_obj, 1));
-  } else {
-    // Shift the elements.
-    if (elms_obj->IsFixedArray()) {
-      Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-      DisallowHeapAllocation no_gc;
-      heap->MoveElements(*elms, 0, 1, len - 1);
-      elms->set(len - 1, heap->the_hole_value());
-    } else {
-      Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj);
-      MoveDoubleElements(*elms, 0, *elms, 1, len - 1);
-      elms->set_the_hole(len - 1);
-    }
-  }
-
-  // Set the length.
-  array->set_length(Smi::FromInt(len - 1));
-
+  Handle<Object> first = array->GetElementsAccessor()->Shift(array, elms_obj);
   return *first;
 }
 
 
 BUILTIN(ArrayUnshift) {
   HandleScope scope(isolate);
-  Heap* heap = isolate->heap();
   Handle<Object> receiver = args.receiver();
   MaybeHandle<FixedArrayBase> maybe_elms_obj =
       EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1);
   Handle<FixedArrayBase> elms_obj;
   if (!maybe_elms_obj.ToHandle(&elms_obj)) {
-    return CallJsBuiltin(isolate, "ArrayUnshift", args);
+    return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
   }
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
   DCHECK(!array->map()->is_observed());
-  if (!array->HasFastSmiOrObjectElements()) {
-    return CallJsBuiltin(isolate, "ArrayUnshift", args);
-  }
-  int len = Smi::cast(array->length())->value();
   int to_add = args.length() - 1;
-  int new_length = len + to_add;
+  if (to_add == 0) {
+    return array->length();
+  }
   // Currently fixed arrays cannot grow too big, so
   // we should never hit this case.
-  DCHECK(to_add <= (Smi::kMaxValue - len));
+  DCHECK(to_add <= (Smi::kMaxValue - Smi::cast(array->length())->value()));
 
-  if (to_add > 0 && JSArray::WouldChangeReadOnlyLength(array, len + to_add)) {
-    return CallJsBuiltin(isolate, "ArrayUnshift", args);
+  if (to_add > 0 && JSArray::HasReadOnlyLength(array)) {
+    return CallJsIntrinsic(isolate, isolate->array_unshift(), args);
   }
 
-  Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-
-  if (new_length > elms->length()) {
-    // New backing storage is needed.
-    int capacity = new_length + (new_length >> 1) + 16;
-    Handle<FixedArray> new_elms =
-        isolate->factory()->NewUninitializedFixedArray(capacity);
-
-    ElementsKind kind = array->GetElementsKind();
-    ElementsAccessor* accessor = array->GetElementsAccessor();
-    accessor->CopyElements(
-        elms, 0, kind, new_elms, to_add,
-        ElementsAccessor::kCopyToEndAndInitializeToHole);
-
-    elms = new_elms;
-    array->set_elements(*elms);
-  } else {
-    DisallowHeapAllocation no_gc;
-    heap->MoveElements(*elms, to_add, 0, len);
-  }
-
-  // Add the provided values.
-  DisallowHeapAllocation no_gc;
-  WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-  for (int i = 0; i < to_add; i++) {
-    elms->set(i, args[i + 1], mode);
-  }
-
-  // Set the length.
-  array->set_length(Smi::FromInt(new_length));
+  ElementsAccessor* accessor = array->GetElementsAccessor();
+  int new_length = accessor->Unshift(array, elms_obj, &args, to_add);
   return Smi::FromInt(new_length);
 }
 
 
 BUILTIN(ArraySlice) {
   HandleScope scope(isolate);
-  Heap* heap = isolate->heap();
   Handle<Object> receiver = args.receiver();
+  Handle<JSObject> object;
+  Handle<FixedArrayBase> elms_obj;
   int len = -1;
   int relative_start = 0;
   int relative_end = 0;
-  {
+  bool is_sloppy_arguments = false;
+
+  // TODO(littledan): Look up @@species only once, not once here and
+  // again in the JS builtin. Pass the species out?
+  Handle<Object> species;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, species, Object::ArraySpeciesConstructor(isolate, receiver));
+  if (*species != isolate->context()->native_context()->array_function()) {
+    return CallJsIntrinsic(isolate, isolate->array_slice(), args);
+  }
+  if (receiver->IsJSArray()) {
     DisallowHeapAllocation no_gc;
-    if (receiver->IsJSArray()) {
-      JSArray* array = JSArray::cast(*receiver);
-      if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArraySlice", args);
-      }
-
-      if (!array->HasFastElements()) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArraySlice", args);
-      }
-
-      len = Smi::cast(array->length())->value();
-    } else {
-      // Array.slice(arguments, ...) is quite a common idiom (notably more
-      // than 50% of invocations in Web apps).  Treat it in C++ as well.
-      Map* arguments_map =
-          isolate->context()->native_context()->sloppy_arguments_map();
-
-      bool is_arguments_object_with_fast_elements =
-          receiver->IsJSObject() &&
-          JSObject::cast(*receiver)->map() == arguments_map;
-      if (!is_arguments_object_with_fast_elements) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArraySlice", args);
-      }
-      JSObject* object = JSObject::cast(*receiver);
-
-      if (!object->HasFastElements()) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArraySlice", args);
-      }
-
-      Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
-      if (!len_obj->IsSmi()) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArraySlice", args);
-      }
-      len = Smi::cast(len_obj)->value();
-      if (len > object->elements()->length()) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArraySlice", args);
-      }
+    JSArray* array = JSArray::cast(*receiver);
+    if (!array->HasFastElements() ||
+        !IsJSArrayFastElementMovingAllowed(isolate, array)) {
+      AllowHeapAllocation allow_allocation;
+      return CallJsIntrinsic(isolate, isolate->array_slice(), args);
     }
-
-    DCHECK(len >= 0);
-    int n_arguments = args.length() - 1;
-
-    // Note carefully choosen defaults---if argument is missing,
-    // it's undefined which gets converted to 0 for relative_start
-    // and to len for relative_end.
-    relative_start = 0;
-    relative_end = len;
-    if (n_arguments > 0) {
-      Object* arg1 = args[1];
-      if (arg1->IsSmi()) {
-        relative_start = Smi::cast(arg1)->value();
-      } else if (arg1->IsHeapNumber()) {
-        double start = HeapNumber::cast(arg1)->value();
-        if (start < kMinInt || start > kMaxInt) {
-          AllowHeapAllocation allow_allocation;
-          return CallJsBuiltin(isolate, "ArraySlice", args);
-        }
-        relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
-      } else if (!arg1->IsUndefined()) {
+    len = Smi::cast(array->length())->value();
+    object = Handle<JSObject>::cast(receiver);
+    elms_obj = handle(array->elements(), isolate);
+  } else if (receiver->IsJSObject() &&
+             GetSloppyArgumentsLength(isolate, Handle<JSObject>::cast(receiver),
+                                      &len)) {
+    // Array.prototype.slice(arguments, ...) is quite a common idiom
+    // (notably more than 50% of invocations in Web apps).
+    // Treat it in C++ as well.
+    is_sloppy_arguments = true;
+    object = Handle<JSObject>::cast(receiver);
+    elms_obj = handle(object->elements(), isolate);
+  } else {
+    AllowHeapAllocation allow_allocation;
+    return CallJsIntrinsic(isolate, isolate->array_slice(), args);
+  }
+  DCHECK(len >= 0);
+  int argument_count = args.length() - 1;
+  // Note carefully chosen defaults---if argument is missing,
+  // it's undefined which gets converted to 0 for relative_start
+  // and to len for relative_end.
+  relative_start = 0;
+  relative_end = len;
+  if (argument_count > 0) {
+    DisallowHeapAllocation no_gc;
+    if (!ClampedToInteger(args[1], &relative_start)) {
+      AllowHeapAllocation allow_allocation;
+      return CallJsIntrinsic(isolate, isolate->array_slice(), args);
+    }
+    if (argument_count > 1) {
+      Object* end_arg = args[2];
+      // slice handles the end_arg specially
+      if (end_arg->IsUndefined()) {
+        relative_end = len;
+      } else if (!ClampedToInteger(end_arg, &relative_end)) {
         AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArraySlice", args);
-      }
-      if (n_arguments > 1) {
-        Object* arg2 = args[2];
-        if (arg2->IsSmi()) {
-          relative_end = Smi::cast(arg2)->value();
-        } else if (arg2->IsHeapNumber()) {
-          double end = HeapNumber::cast(arg2)->value();
-          if (end < kMinInt || end > kMaxInt) {
-            AllowHeapAllocation allow_allocation;
-            return CallJsBuiltin(isolate, "ArraySlice", args);
-          }
-          relative_end = std::isnan(end) ? 0 : static_cast<int>(end);
-        } else if (!arg2->IsUndefined()) {
-          AllowHeapAllocation allow_allocation;
-          return CallJsBuiltin(isolate, "ArraySlice", args);
-        }
+        return CallJsIntrinsic(isolate, isolate->array_slice(), args);
       }
     }
   }
 
   // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6.
-  int k = (relative_start < 0) ? Max(len + relative_start, 0)
-                               : Min(relative_start, len);
+  uint32_t actual_start = (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 = (relative_end < 0) ? Max(len + relative_end, 0)
-                                 : Min(relative_end, len);
+  uint32_t actual_end =
+      (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len);
 
-  // Calculate the length of result array.
-  int result_len = Max(final - k, 0);
-
-  Handle<JSObject> object = Handle<JSObject>::cast(receiver);
-  Handle<FixedArrayBase> elms(object->elements(), isolate);
-
-  ElementsKind kind = object->GetElementsKind();
-  if (IsHoleyElementsKind(kind)) {
-    DisallowHeapAllocation no_gc;
-    bool packed = true;
-    ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
-    for (int i = k; i < final; i++) {
-      if (!accessor->HasElement(object, object, i, elms)) {
-        packed = false;
-        break;
-      }
-    }
-    if (packed) {
-      kind = GetPackedElementsKind(kind);
-    } else if (!receiver->IsJSArray()) {
-      AllowHeapAllocation allow_allocation;
-      return CallJsBuiltin(isolate, "ArraySlice", args);
-    }
+  if (actual_end <= actual_start) {
+    Handle<JSArray> result_array = isolate->factory()->NewJSArray(
+        GetPackedElementsKind(object->GetElementsKind()), 0, 0);
+    return *result_array;
   }
 
-  Handle<JSArray> result_array =
-      isolate->factory()->NewJSArray(kind, result_len, result_len);
-
-  DisallowHeapAllocation no_gc;
-  if (result_len == 0) return *result_array;
-
   ElementsAccessor* accessor = object->GetElementsAccessor();
-  accessor->CopyElements(
-      elms, k, kind, handle(result_array->elements(), isolate), 0, result_len);
+  if (is_sloppy_arguments &&
+      !accessor->IsPacked(object, elms_obj, actual_start, actual_end)) {
+    // Don't deal with arguments with holes in C++
+    AllowHeapAllocation allow_allocation;
+    return CallJsIntrinsic(isolate, isolate->array_slice(), args);
+  }
+  Handle<JSArray> result_array =
+      accessor->Slice(object, elms_obj, actual_start, actual_end);
   return *result_array;
 }
 
 
 BUILTIN(ArraySplice) {
   HandleScope scope(isolate);
-  Heap* heap = isolate->heap();
   Handle<Object> receiver = args.receiver();
   MaybeHandle<FixedArrayBase> maybe_elms_obj =
       EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
   Handle<FixedArrayBase> elms_obj;
   if (!maybe_elms_obj.ToHandle(&elms_obj)) {
-    return CallJsBuiltin(isolate, "ArraySplice", args);
+    return CallJsIntrinsic(isolate, isolate->array_splice(), args);
+  }
+  // TODO(littledan): Look up @@species only once, not once here and
+  // again in the JS builtin. Pass the species out?
+  Handle<Object> species;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, species, Object::ArraySpeciesConstructor(isolate, receiver));
+  if (*species != isolate->context()->native_context()->array_function()) {
+    return CallJsIntrinsic(isolate, isolate->array_splice(), args);
   }
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
   DCHECK(!array->map()->is_observed());
 
-  int len = Smi::cast(array->length())->value();
-
-  int n_arguments = args.length() - 1;
-
+  int argument_count = args.length() - 1;
   int relative_start = 0;
-  if (n_arguments > 0) {
+  if (argument_count > 0) {
     DisallowHeapAllocation no_gc;
-    Object* arg1 = args[1];
-    if (arg1->IsSmi()) {
-      relative_start = Smi::cast(arg1)->value();
-    } else if (arg1->IsHeapNumber()) {
-      double start = HeapNumber::cast(arg1)->value();
-      if (start < kMinInt || start > kMaxInt) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArraySplice", args);
-      }
-      relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
-    } else if (!arg1->IsUndefined()) {
+    if (!ClampedToInteger(args[1], &relative_start)) {
       AllowHeapAllocation allow_allocation;
-      return CallJsBuiltin(isolate, "ArraySplice", args);
+      return CallJsIntrinsic(isolate, isolate->array_splice(), args);
     }
   }
+  int len = Smi::cast(array->length())->value();
+  // clip relative start to [0, 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 as a request to delete all the elements from the start.
-  // And it differs from the case of undefined delete count.
-  // This does not follow ECMA-262, but we do the same for
-  // compatibility.
   int actual_delete_count;
-  if (n_arguments == 1) {
+  if (argument_count == 1) {
+    // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
+    // given as a request to delete all the elements from the start.
+    // And it differs from the case of undefined delete count.
+    // This does not follow ECMA-262, but we do the same for compatibility.
     DCHECK(len - actual_start >= 0);
     actual_delete_count = len - actual_start;
   } else {
-    int value = 0;  // ToInteger(undefined) == 0
-    if (n_arguments > 1) {
-      DisallowHeapAllocation no_gc;
-      Object* arg2 = args[2];
-      if (arg2->IsSmi()) {
-        value = Smi::cast(arg2)->value();
-      } else {
+    int delete_count = 0;
+    DisallowHeapAllocation no_gc;
+    if (argument_count > 1) {
+      if (!ClampedToInteger(args[2], &delete_count)) {
         AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArraySplice", args);
+        return CallJsIntrinsic(isolate, isolate->array_splice(), args);
       }
     }
-    actual_delete_count = Min(Max(value, 0), len - actual_start);
+    actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
   }
 
-  ElementsKind elements_kind = array->GetElementsKind();
-
-  int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
-  int new_length = len - actual_delete_count + item_count;
-
-  // For double mode we do not support changing the length.
-  if (new_length > len && IsFastDoubleElementsKind(elements_kind)) {
-    return CallJsBuiltin(isolate, "ArraySplice", args);
-  }
+  int add_count = (argument_count > 1) ? (argument_count - 2) : 0;
+  int new_length = len - actual_delete_count + add_count;
 
   if (new_length != len && JSArray::HasReadOnlyLength(array)) {
     AllowHeapAllocation allow_allocation;
-    return CallJsBuiltin(isolate, "ArraySplice", args);
+    return CallJsIntrinsic(isolate, isolate->array_splice(), args);
   }
-
-  if (new_length == 0) {
-    Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(
-        elms_obj, elements_kind, actual_delete_count);
-    array->set_elements(heap->empty_fixed_array());
-    array->set_length(Smi::FromInt(0));
-    return *result;
-  }
-
-  Handle<JSArray> result_array =
-      isolate->factory()->NewJSArray(elements_kind,
-                                     actual_delete_count,
-                                     actual_delete_count);
-
-  if (actual_delete_count > 0) {
-    DisallowHeapAllocation no_gc;
-    ElementsAccessor* accessor = array->GetElementsAccessor();
-    accessor->CopyElements(
-        elms_obj, actual_start, elements_kind,
-        handle(result_array->elements(), isolate), 0, actual_delete_count);
-  }
-
-  bool elms_changed = false;
-  if (item_count < actual_delete_count) {
-    // Shrink the array.
-    const bool trim_array = !heap->lo_space()->Contains(*elms_obj) &&
-      ((actual_start + item_count) <
-          (len - actual_delete_count - actual_start));
-    if (trim_array) {
-      const int delta = actual_delete_count - item_count;
-
-      if (elms_obj->IsFixedDoubleArray()) {
-        Handle<FixedDoubleArray> elms =
-            Handle<FixedDoubleArray>::cast(elms_obj);
-        MoveDoubleElements(*elms, delta, *elms, 0, actual_start);
-      } else {
-        Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-        DisallowHeapAllocation no_gc;
-        heap->MoveElements(*elms, delta, 0, actual_start);
-      }
-
-      if (heap->CanMoveObjectStart(*elms_obj)) {
-        // On the fast path we move the start of the object in memory.
-        elms_obj = handle(heap->LeftTrimFixedArray(*elms_obj, delta));
-      } else {
-        // This is the slow path. We are going to move the elements to the left
-        // by copying them. For trimmed values we store the hole.
-        if (elms_obj->IsFixedDoubleArray()) {
-          Handle<FixedDoubleArray> elms =
-              Handle<FixedDoubleArray>::cast(elms_obj);
-          MoveDoubleElements(*elms, 0, *elms, delta, len - delta);
-          elms->FillWithHoles(len - delta, len);
-        } else {
-          Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-          DisallowHeapAllocation no_gc;
-          heap->MoveElements(*elms, 0, delta, len - delta);
-          elms->FillWithHoles(len - delta, len);
-        }
-      }
-      elms_changed = true;
-    } else {
-      if (elms_obj->IsFixedDoubleArray()) {
-        Handle<FixedDoubleArray> elms =
-            Handle<FixedDoubleArray>::cast(elms_obj);
-        MoveDoubleElements(*elms, actual_start + item_count,
-                           *elms, actual_start + actual_delete_count,
-                           (len - actual_delete_count - actual_start));
-        elms->FillWithHoles(new_length, len);
-      } else {
-        Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-        DisallowHeapAllocation no_gc;
-        heap->MoveElements(*elms, actual_start + item_count,
-                           actual_start + actual_delete_count,
-                           (len - actual_delete_count - actual_start));
-        elms->FillWithHoles(new_length, len);
-      }
-    }
-  } else if (item_count > actual_delete_count) {
-    Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-    // Currently fixed arrays cannot grow too big, so
-    // we should never hit this case.
-    DCHECK((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;
-      Handle<FixedArray> new_elms =
-          isolate->factory()->NewUninitializedFixedArray(capacity);
-
-      DisallowHeapAllocation no_gc;
-
-      ElementsKind kind = array->GetElementsKind();
-      ElementsAccessor* accessor = array->GetElementsAccessor();
-      if (actual_start > 0) {
-        // Copy the part before actual_start as is.
-        accessor->CopyElements(
-            elms, 0, kind, new_elms, 0, actual_start);
-      }
-      accessor->CopyElements(
-          elms, actual_start + actual_delete_count, kind,
-          new_elms, actual_start + item_count,
-          ElementsAccessor::kCopyToEndAndInitializeToHole);
-
-      elms_obj = new_elms;
-      elms_changed = true;
-    } else {
-      DisallowHeapAllocation no_gc;
-      heap->MoveElements(*elms, actual_start + item_count,
-                         actual_start + actual_delete_count,
-                         (len - actual_delete_count - actual_start));
-    }
-  }
-
-  if (IsFastDoubleElementsKind(elements_kind)) {
-    Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj);
-    for (int k = actual_start; k < actual_start + item_count; k++) {
-      Object* arg = args[3 + k - actual_start];
-      if (arg->IsSmi()) {
-        elms->set(k, Smi::cast(arg)->value());
-      } else {
-        elms->set(k, HeapNumber::cast(arg)->value());
-      }
-    }
-  } else {
-    Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-    DisallowHeapAllocation 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);
-    }
-  }
-
-  if (elms_changed) {
-    array->set_elements(*elms_obj);
-  }
-  // Set the length.
-  array->set_length(Smi::FromInt(new_length));
-
+  ElementsAccessor* accessor = array->GetElementsAccessor();
+  Handle<JSArray> result_array = accessor->Splice(
+      array, elms_obj, actual_start, actual_delete_count, &args, add_count);
   return *result_array;
 }
 
 
-BUILTIN(ArrayConcat) {
-  HandleScope scope(isolate);
+// Array Concat -------------------------------------------------------------
 
-  int n_arguments = args.length();
+namespace {
+
+/**
+ * A simple visitor visits every element of Array's.
+ * The backend storage can be a fixed array for fast elements case,
+ * or a dictionary for sparse array. Since Dictionary is a subtype
+ * of FixedArray, the class can be used by both fast and slow cases.
+ * The second parameter of the constructor, fast_elements, specifies
+ * whether the storage is a FixedArray or Dictionary.
+ *
+ * An index limit is used to deal with the situation that a result array
+ * length overflows 32-bit non-negative integer.
+ */
+class ArrayConcatVisitor {
+ public:
+  ArrayConcatVisitor(Isolate* isolate, Handle<FixedArray> storage,
+                     bool fast_elements)
+      : isolate_(isolate),
+        storage_(Handle<FixedArray>::cast(
+            isolate->global_handles()->Create(*storage))),
+        index_offset_(0u),
+        bit_field_(FastElementsField::encode(fast_elements) |
+                   ExceedsLimitField::encode(false)) {}
+
+  ~ArrayConcatVisitor() { clear_storage(); }
+
+  void visit(uint32_t i, Handle<Object> elm) {
+    if (i >= JSObject::kMaxElementCount - index_offset_) {
+      set_exceeds_array_limit(true);
+      return;
+    }
+    uint32_t index = index_offset_ + i;
+
+    if (fast_elements()) {
+      if (index < static_cast<uint32_t>(storage_->length())) {
+        storage_->set(index, *elm);
+        return;
+      }
+      // Our initial estimate of length was foiled, possibly by
+      // getters on the arrays increasing the length of later arrays
+      // during iteration.
+      // This shouldn't happen in anything but pathological cases.
+      SetDictionaryMode();
+      // Fall-through to dictionary mode.
+    }
+    DCHECK(!fast_elements());
+    Handle<SeededNumberDictionary> dict(
+        SeededNumberDictionary::cast(*storage_));
+    // The object holding this backing store has just been allocated, so
+    // it cannot yet be used as a prototype.
+    Handle<SeededNumberDictionary> result =
+        SeededNumberDictionary::AtNumberPut(dict, index, elm, false);
+    if (!result.is_identical_to(dict)) {
+      // Dictionary needed to grow.
+      clear_storage();
+      set_storage(*result);
+    }
+  }
+
+  void increase_index_offset(uint32_t delta) {
+    if (JSObject::kMaxElementCount - index_offset_ < delta) {
+      index_offset_ = JSObject::kMaxElementCount;
+    } else {
+      index_offset_ += delta;
+    }
+    // If the initial length estimate was off (see special case in visit()),
+    // but the array blowing the limit didn't contain elements beyond the
+    // provided-for index range, go to dictionary mode now.
+    if (fast_elements() &&
+        index_offset_ >
+            static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
+      SetDictionaryMode();
+    }
+  }
+
+  bool exceeds_array_limit() const {
+    return ExceedsLimitField::decode(bit_field_);
+  }
+
+  Handle<JSArray> ToArray() {
+    Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
+    Handle<Object> length =
+        isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
+    Handle<Map> map = JSObject::GetElementsTransitionMap(
+        array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
+    array->set_map(*map);
+    array->set_length(*length);
+    array->set_elements(*storage_);
+    return array;
+  }
+
+ private:
+  // Convert storage to dictionary mode.
+  void SetDictionaryMode() {
+    DCHECK(fast_elements());
+    Handle<FixedArray> current_storage(*storage_);
+    Handle<SeededNumberDictionary> slow_storage(
+        SeededNumberDictionary::New(isolate_, current_storage->length()));
+    uint32_t current_length = static_cast<uint32_t>(current_storage->length());
+    for (uint32_t i = 0; i < current_length; i++) {
+      HandleScope loop_scope(isolate_);
+      Handle<Object> element(current_storage->get(i), isolate_);
+      if (!element->IsTheHole()) {
+        // The object holding this backing store has just been allocated, so
+        // it cannot yet be used as a prototype.
+        Handle<SeededNumberDictionary> new_storage =
+            SeededNumberDictionary::AtNumberPut(slow_storage, i, element,
+                                                false);
+        if (!new_storage.is_identical_to(slow_storage)) {
+          slow_storage = loop_scope.CloseAndEscape(new_storage);
+        }
+      }
+    }
+    clear_storage();
+    set_storage(*slow_storage);
+    set_fast_elements(false);
+  }
+
+  inline void clear_storage() {
+    GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
+  }
+
+  inline void set_storage(FixedArray* storage) {
+    storage_ =
+        Handle<FixedArray>::cast(isolate_->global_handles()->Create(storage));
+  }
+
+  class FastElementsField : public BitField<bool, 0, 1> {};
+  class ExceedsLimitField : public BitField<bool, 1, 1> {};
+
+  bool fast_elements() const { return FastElementsField::decode(bit_field_); }
+  void set_fast_elements(bool fast) {
+    bit_field_ = FastElementsField::update(bit_field_, fast);
+  }
+  void set_exceeds_array_limit(bool exceeds) {
+    bit_field_ = ExceedsLimitField::update(bit_field_, exceeds);
+  }
+
+  Isolate* isolate_;
+  Handle<FixedArray> storage_;  // Always a global handle.
+  // Index after last seen index. Always less than or equal to
+  // JSObject::kMaxElementCount.
+  uint32_t index_offset_;
+  uint32_t bit_field_;
+};
+
+
+uint32_t EstimateElementCount(Handle<JSArray> array) {
+  uint32_t length = static_cast<uint32_t>(array->length()->Number());
+  int element_count = 0;
+  switch (array->GetElementsKind()) {
+    case FAST_SMI_ELEMENTS:
+    case FAST_HOLEY_SMI_ELEMENTS:
+    case FAST_ELEMENTS:
+    case FAST_HOLEY_ELEMENTS: {
+      // Fast elements can't have lengths that are not representable by
+      // a 32-bit signed integer.
+      DCHECK(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
+      int fast_length = static_cast<int>(length);
+      Handle<FixedArray> elements(FixedArray::cast(array->elements()));
+      for (int i = 0; i < fast_length; i++) {
+        if (!elements->get(i)->IsTheHole()) element_count++;
+      }
+      break;
+    }
+    case FAST_DOUBLE_ELEMENTS:
+    case FAST_HOLEY_DOUBLE_ELEMENTS: {
+      // Fast elements can't have lengths that are not representable by
+      // a 32-bit signed integer.
+      DCHECK(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
+      int fast_length = static_cast<int>(length);
+      if (array->elements()->IsFixedArray()) {
+        DCHECK(FixedArray::cast(array->elements())->length() == 0);
+        break;
+      }
+      Handle<FixedDoubleArray> elements(
+          FixedDoubleArray::cast(array->elements()));
+      for (int i = 0; i < fast_length; i++) {
+        if (!elements->is_the_hole(i)) element_count++;
+      }
+      break;
+    }
+    case DICTIONARY_ELEMENTS: {
+      Handle<SeededNumberDictionary> dictionary(
+          SeededNumberDictionary::cast(array->elements()));
+      int capacity = dictionary->Capacity();
+      for (int i = 0; i < capacity; i++) {
+        Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
+        if (dictionary->IsKey(*key)) {
+          element_count++;
+        }
+      }
+      break;
+    }
+    case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+    case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
+
+      TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+      // External arrays are always dense.
+      return length;
+  }
+  // As an estimate, we assume that the prototype doesn't contain any
+  // inherited elements.
+  return element_count;
+}
+
+
+template <class ExternalArrayClass, class ElementType>
+void IterateTypedArrayElements(Isolate* isolate, Handle<JSObject> receiver,
+                               bool elements_are_ints,
+                               bool elements_are_guaranteed_smis,
+                               ArrayConcatVisitor* visitor) {
+  Handle<ExternalArrayClass> array(
+      ExternalArrayClass::cast(receiver->elements()));
+  uint32_t len = static_cast<uint32_t>(array->length());
+
+  DCHECK(visitor != NULL);
+  if (elements_are_ints) {
+    if (elements_are_guaranteed_smis) {
+      for (uint32_t j = 0; j < len; j++) {
+        HandleScope loop_scope(isolate);
+        Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
+                      isolate);
+        visitor->visit(j, e);
+      }
+    } else {
+      for (uint32_t j = 0; j < len; j++) {
+        HandleScope loop_scope(isolate);
+        int64_t val = static_cast<int64_t>(array->get_scalar(j));
+        if (Smi::IsValid(static_cast<intptr_t>(val))) {
+          Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
+          visitor->visit(j, e);
+        } else {
+          Handle<Object> e =
+              isolate->factory()->NewNumber(static_cast<ElementType>(val));
+          visitor->visit(j, e);
+        }
+      }
+    }
+  } else {
+    for (uint32_t j = 0; j < len; j++) {
+      HandleScope loop_scope(isolate);
+      Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
+      visitor->visit(j, e);
+    }
+  }
+}
+
+
+// Used for sorting indices in a List<uint32_t>.
+int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
+  uint32_t a = *ap;
+  uint32_t b = *bp;
+  return (a == b) ? 0 : (a < b) ? -1 : 1;
+}
+
+
+void CollectElementIndices(Handle<JSObject> object, uint32_t range,
+                           List<uint32_t>* indices) {
+  Isolate* isolate = object->GetIsolate();
+  ElementsKind kind = object->GetElementsKind();
+  switch (kind) {
+    case FAST_SMI_ELEMENTS:
+    case FAST_ELEMENTS:
+    case FAST_HOLEY_SMI_ELEMENTS:
+    case FAST_HOLEY_ELEMENTS: {
+      Handle<FixedArray> elements(FixedArray::cast(object->elements()));
+      uint32_t length = static_cast<uint32_t>(elements->length());
+      if (range < length) length = range;
+      for (uint32_t i = 0; i < length; i++) {
+        if (!elements->get(i)->IsTheHole()) {
+          indices->Add(i);
+        }
+      }
+      break;
+    }
+    case FAST_HOLEY_DOUBLE_ELEMENTS:
+    case FAST_DOUBLE_ELEMENTS: {
+      if (object->elements()->IsFixedArray()) {
+        DCHECK(object->elements()->length() == 0);
+        break;
+      }
+      Handle<FixedDoubleArray> elements(
+          FixedDoubleArray::cast(object->elements()));
+      uint32_t length = static_cast<uint32_t>(elements->length());
+      if (range < length) length = range;
+      for (uint32_t i = 0; i < length; i++) {
+        if (!elements->is_the_hole(i)) {
+          indices->Add(i);
+        }
+      }
+      break;
+    }
+    case DICTIONARY_ELEMENTS: {
+      Handle<SeededNumberDictionary> dict(
+          SeededNumberDictionary::cast(object->elements()));
+      uint32_t capacity = dict->Capacity();
+      for (uint32_t j = 0; j < capacity; j++) {
+        HandleScope loop_scope(isolate);
+        Handle<Object> k(dict->KeyAt(j), isolate);
+        if (dict->IsKey(*k)) {
+          DCHECK(k->IsNumber());
+          uint32_t index = static_cast<uint32_t>(k->Number());
+          if (index < range) {
+            indices->Add(index);
+          }
+        }
+      }
+      break;
+    }
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS:
+
+      TYPED_ARRAYS(TYPED_ARRAY_CASE)
+#undef TYPED_ARRAY_CASE
+      {
+        uint32_t length = static_cast<uint32_t>(
+            FixedArrayBase::cast(object->elements())->length());
+        if (range <= length) {
+          length = range;
+          // We will add all indices, so we might as well clear it first
+          // and avoid duplicates.
+          indices->Clear();
+        }
+        for (uint32_t i = 0; i < length; i++) {
+          indices->Add(i);
+        }
+        if (length == range) return;  // All indices accounted for already.
+        break;
+      }
+    case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+    case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
+      ElementsAccessor* accessor = object->GetElementsAccessor();
+      for (uint32_t i = 0; i < range; i++) {
+        if (accessor->HasElement(object, i)) {
+          indices->Add(i);
+        }
+      }
+      break;
+    }
+  }
+
+  PrototypeIterator iter(isolate, object);
+  if (!iter.IsAtEnd()) {
+    // The prototype will usually have no inherited element indices,
+    // but we have to check.
+    CollectElementIndices(PrototypeIterator::GetCurrent<JSObject>(iter), range,
+                          indices);
+  }
+}
+
+
+bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver,
+                         uint32_t length, ArrayConcatVisitor* visitor) {
+  for (uint32_t i = 0; i < length; ++i) {
+    HandleScope loop_scope(isolate);
+    Maybe<bool> maybe = JSReceiver::HasElement(receiver, i);
+    if (!maybe.IsJust()) return false;
+    if (maybe.FromJust()) {
+      Handle<Object> element_value;
+      ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, element_value,
+                                       Object::GetElement(isolate, receiver, i),
+                                       false);
+      visitor->visit(i, element_value);
+    }
+  }
+  visitor->increase_index_offset(length);
+  return true;
+}
+
+
+/**
+ * A helper function that visits "array" elements of a JSReceiver in numerical
+ * order.
+ *
+ * The visitor argument called for each existing element in the array
+ * with the element index and the element's value.
+ * Afterwards it increments the base-index of the visitor by the array
+ * length.
+ * Returns false if any access threw an exception, otherwise true.
+ */
+bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver,
+                     ArrayConcatVisitor* visitor) {
+  uint32_t length = 0;
+
+  if (receiver->IsJSArray()) {
+    Handle<JSArray> array = Handle<JSArray>::cast(receiver);
+    length = static_cast<uint32_t>(array->length()->Number());
+  } else {
+    Handle<Object> val;
+    Handle<Object> key = isolate->factory()->length_string();
+    ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+        isolate, val, Runtime::GetObjectProperty(isolate, receiver, key),
+        false);
+    ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, val,
+                                     Object::ToLength(isolate, val), false);
+    // TODO(caitp): Support larger element indexes (up to 2^53-1).
+    if (!val->ToUint32(&length)) {
+      length = 0;
+    }
+  }
+
+  if (!(receiver->IsJSArray() || receiver->IsJSTypedArray())) {
+    // For classes which are not known to be safe to access via elements alone,
+    // use the slow case.
+    return IterateElementsSlow(isolate, receiver, length, visitor);
+  }
+  Handle<JSObject> array = Handle<JSObject>::cast(receiver);
+
+  switch (array->GetElementsKind()) {
+    case FAST_SMI_ELEMENTS:
+    case FAST_ELEMENTS:
+    case FAST_HOLEY_SMI_ELEMENTS:
+    case FAST_HOLEY_ELEMENTS: {
+      // Run through the elements FixedArray and use HasElement and GetElement
+      // to check the prototype for missing elements.
+      Handle<FixedArray> elements(FixedArray::cast(array->elements()));
+      int fast_length = static_cast<int>(length);
+      DCHECK(fast_length <= elements->length());
+      for (int j = 0; j < fast_length; j++) {
+        HandleScope loop_scope(isolate);
+        Handle<Object> element_value(elements->get(j), isolate);
+        if (!element_value->IsTheHole()) {
+          visitor->visit(j, element_value);
+        } else {
+          Maybe<bool> maybe = JSReceiver::HasElement(array, j);
+          if (!maybe.IsJust()) return false;
+          if (maybe.FromJust()) {
+            // Call GetElement on array, not its prototype, or getters won't
+            // have the correct receiver.
+            ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+                isolate, element_value, Object::GetElement(isolate, array, j),
+                false);
+            visitor->visit(j, element_value);
+          }
+        }
+      }
+      break;
+    }
+    case FAST_HOLEY_DOUBLE_ELEMENTS:
+    case FAST_DOUBLE_ELEMENTS: {
+      // Empty array is FixedArray but not FixedDoubleArray.
+      if (length == 0) break;
+      // Run through the elements FixedArray and use HasElement and GetElement
+      // to check the prototype for missing elements.
+      if (array->elements()->IsFixedArray()) {
+        DCHECK(array->elements()->length() == 0);
+        break;
+      }
+      Handle<FixedDoubleArray> elements(
+          FixedDoubleArray::cast(array->elements()));
+      int fast_length = static_cast<int>(length);
+      DCHECK(fast_length <= elements->length());
+      for (int j = 0; j < fast_length; j++) {
+        HandleScope loop_scope(isolate);
+        if (!elements->is_the_hole(j)) {
+          double double_value = elements->get_scalar(j);
+          Handle<Object> element_value =
+              isolate->factory()->NewNumber(double_value);
+          visitor->visit(j, element_value);
+        } else {
+          Maybe<bool> maybe = JSReceiver::HasElement(array, j);
+          if (!maybe.IsJust()) return false;
+          if (maybe.FromJust()) {
+            // Call GetElement on array, not its prototype, or getters won't
+            // have the correct receiver.
+            Handle<Object> element_value;
+            ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+                isolate, element_value, Object::GetElement(isolate, array, j),
+                false);
+            visitor->visit(j, element_value);
+          }
+        }
+      }
+      break;
+    }
+    case DICTIONARY_ELEMENTS: {
+      // CollectElementIndices() can't be called when there's a JSProxy
+      // on the prototype chain.
+      for (PrototypeIterator iter(isolate, array); !iter.IsAtEnd();
+           iter.Advance()) {
+        if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
+          return IterateElementsSlow(isolate, array, length, visitor);
+        }
+      }
+      Handle<SeededNumberDictionary> dict(array->element_dictionary());
+      List<uint32_t> indices(dict->Capacity() / 2);
+      // Collect all indices in the object and the prototypes less
+      // than length. This might introduce duplicates in the indices list.
+      CollectElementIndices(array, length, &indices);
+      indices.Sort(&compareUInt32);
+      int j = 0;
+      int n = indices.length();
+      while (j < n) {
+        HandleScope loop_scope(isolate);
+        uint32_t index = indices[j];
+        Handle<Object> element;
+        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+            isolate, element, Object::GetElement(isolate, array, index), false);
+        visitor->visit(index, element);
+        // Skip to next different index (i.e., omit duplicates).
+        do {
+          j++;
+        } while (j < n && indices[j] == index);
+      }
+      break;
+    }
+    case UINT8_CLAMPED_ELEMENTS: {
+      Handle<FixedUint8ClampedArray> pixels(
+          FixedUint8ClampedArray::cast(array->elements()));
+      for (uint32_t j = 0; j < length; j++) {
+        Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
+        visitor->visit(j, e);
+      }
+      break;
+    }
+    case INT8_ELEMENTS: {
+      IterateTypedArrayElements<FixedInt8Array, int8_t>(isolate, array, true,
+                                                        true, visitor);
+      break;
+    }
+    case UINT8_ELEMENTS: {
+      IterateTypedArrayElements<FixedUint8Array, uint8_t>(isolate, array, true,
+                                                          true, visitor);
+      break;
+    }
+    case INT16_ELEMENTS: {
+      IterateTypedArrayElements<FixedInt16Array, int16_t>(isolate, array, true,
+                                                          true, visitor);
+      break;
+    }
+    case UINT16_ELEMENTS: {
+      IterateTypedArrayElements<FixedUint16Array, uint16_t>(
+          isolate, array, true, true, visitor);
+      break;
+    }
+    case INT32_ELEMENTS: {
+      IterateTypedArrayElements<FixedInt32Array, int32_t>(isolate, array, true,
+                                                          false, visitor);
+      break;
+    }
+    case UINT32_ELEMENTS: {
+      IterateTypedArrayElements<FixedUint32Array, uint32_t>(
+          isolate, array, true, false, visitor);
+      break;
+    }
+    case FLOAT32_ELEMENTS: {
+      IterateTypedArrayElements<FixedFloat32Array, float>(isolate, array, false,
+                                                          false, visitor);
+      break;
+    }
+    case FLOAT64_ELEMENTS: {
+      IterateTypedArrayElements<FixedFloat64Array, double>(
+          isolate, array, false, false, visitor);
+      break;
+    }
+    case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+    case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: {
+      for (uint32_t index = 0; index < length; index++) {
+        HandleScope loop_scope(isolate);
+        Handle<Object> element;
+        ASSIGN_RETURN_ON_EXCEPTION_VALUE(
+            isolate, element, Object::GetElement(isolate, array, index), false);
+        visitor->visit(index, element);
+      }
+      break;
+    }
+  }
+  visitor->increase_index_offset(length);
+  return true;
+}
+
+
+bool HasConcatSpreadableModifier(Isolate* isolate, Handle<JSArray> obj) {
+  DCHECK(isolate->IsFastArrayConstructorPrototypeChainIntact());
+  if (!FLAG_harmony_concat_spreadable) return false;
+  Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol());
+  Maybe<bool> maybe = JSReceiver::HasProperty(obj, key);
+  return maybe.FromMaybe(false);
+}
+
+
+static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) {
+  HandleScope handle_scope(isolate);
+  if (!obj->IsJSReceiver()) return Just(false);
+  if (FLAG_harmony_concat_spreadable) {
+    Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol());
+    Handle<Object> value;
+    MaybeHandle<Object> maybeValue =
+        i::Runtime::GetObjectProperty(isolate, obj, key);
+    if (!maybeValue.ToHandle(&value)) return Nothing<bool>();
+    if (!value->IsUndefined()) return Just(value->BooleanValue());
+  }
+  return Object::IsArray(obj);
+}
+
+
+Object* Slow_ArrayConcat(Arguments* args, Isolate* isolate) {
+  int argument_count = args->length();
+
+  // Pass 1: estimate the length and number of elements of the result.
+  // The actual length can be larger if any of the arguments have getters
+  // that mutate other arguments (but will otherwise be precise).
+  // The number of elements is precise if there are no inherited elements.
+
+  ElementsKind kind = FAST_SMI_ELEMENTS;
+
+  uint32_t estimate_result_length = 0;
+  uint32_t estimate_nof_elements = 0;
+  for (int i = 0; i < argument_count; i++) {
+    HandleScope loop_scope(isolate);
+    Handle<Object> obj((*args)[i], isolate);
+    uint32_t length_estimate;
+    uint32_t element_estimate;
+    if (obj->IsJSArray()) {
+      Handle<JSArray> array(Handle<JSArray>::cast(obj));
+      length_estimate = static_cast<uint32_t>(array->length()->Number());
+      if (length_estimate != 0) {
+        ElementsKind array_kind =
+            GetPackedElementsKind(array->map()->elements_kind());
+        kind = GetMoreGeneralElementsKind(kind, array_kind);
+      }
+      element_estimate = EstimateElementCount(array);
+    } else {
+      if (obj->IsHeapObject()) {
+        if (obj->IsNumber()) {
+          kind = GetMoreGeneralElementsKind(kind, FAST_DOUBLE_ELEMENTS);
+        } else {
+          kind = GetMoreGeneralElementsKind(kind, FAST_ELEMENTS);
+        }
+      }
+      length_estimate = 1;
+      element_estimate = 1;
+    }
+    // Avoid overflows by capping at kMaxElementCount.
+    if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) {
+      estimate_result_length = JSObject::kMaxElementCount;
+    } else {
+      estimate_result_length += length_estimate;
+    }
+    if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) {
+      estimate_nof_elements = JSObject::kMaxElementCount;
+    } else {
+      estimate_nof_elements += element_estimate;
+    }
+  }
+
+  // If estimated number of elements is more than half of length, a
+  // fixed array (fast case) is more time and space-efficient than a
+  // dictionary.
+  bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
+
+  if (fast_case && kind == FAST_DOUBLE_ELEMENTS) {
+    Handle<FixedArrayBase> storage =
+        isolate->factory()->NewFixedDoubleArray(estimate_result_length);
+    int j = 0;
+    bool failure = false;
+    if (estimate_result_length > 0) {
+      Handle<FixedDoubleArray> double_storage =
+          Handle<FixedDoubleArray>::cast(storage);
+      for (int i = 0; i < argument_count; i++) {
+        Handle<Object> obj((*args)[i], isolate);
+        if (obj->IsSmi()) {
+          double_storage->set(j, Smi::cast(*obj)->value());
+          j++;
+        } else if (obj->IsNumber()) {
+          double_storage->set(j, obj->Number());
+          j++;
+        } else {
+          JSArray* array = JSArray::cast(*obj);
+          uint32_t length = static_cast<uint32_t>(array->length()->Number());
+          switch (array->map()->elements_kind()) {
+            case FAST_HOLEY_DOUBLE_ELEMENTS:
+            case FAST_DOUBLE_ELEMENTS: {
+              // Empty array is FixedArray but not FixedDoubleArray.
+              if (length == 0) break;
+              FixedDoubleArray* elements =
+                  FixedDoubleArray::cast(array->elements());
+              for (uint32_t i = 0; i < length; i++) {
+                if (elements->is_the_hole(i)) {
+                  // TODO(jkummerow/verwaest): We could be a bit more clever
+                  // here: Check if there are no elements/getters on the
+                  // prototype chain, and if so, allow creation of a holey
+                  // result array.
+                  // Same thing below (holey smi case).
+                  failure = true;
+                  break;
+                }
+                double double_value = elements->get_scalar(i);
+                double_storage->set(j, double_value);
+                j++;
+              }
+              break;
+            }
+            case FAST_HOLEY_SMI_ELEMENTS:
+            case FAST_SMI_ELEMENTS: {
+              FixedArray* elements(FixedArray::cast(array->elements()));
+              for (uint32_t i = 0; i < length; i++) {
+                Object* element = elements->get(i);
+                if (element->IsTheHole()) {
+                  failure = true;
+                  break;
+                }
+                int32_t int_value = Smi::cast(element)->value();
+                double_storage->set(j, int_value);
+                j++;
+              }
+              break;
+            }
+            case FAST_HOLEY_ELEMENTS:
+            case FAST_ELEMENTS:
+            case DICTIONARY_ELEMENTS:
+              DCHECK_EQ(0u, length);
+              break;
+            default:
+              UNREACHABLE();
+          }
+        }
+        if (failure) break;
+      }
+    }
+    if (!failure) {
+      Handle<JSArray> array = isolate->factory()->NewJSArray(0);
+      Smi* length = Smi::FromInt(j);
+      Handle<Map> map;
+      map = JSObject::GetElementsTransitionMap(array, kind);
+      array->set_map(*map);
+      array->set_length(length);
+      array->set_elements(*storage);
+      return *array;
+    }
+    // In case of failure, fall through.
+  }
+
+  Handle<FixedArray> storage;
+  if (fast_case) {
+    // The backing storage array must have non-existing elements to preserve
+    // holes across concat operations.
+    storage =
+        isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
+  } else {
+    // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
+    uint32_t at_least_space_for =
+        estimate_nof_elements + (estimate_nof_elements >> 2);
+    storage = Handle<FixedArray>::cast(
+        SeededNumberDictionary::New(isolate, at_least_space_for));
+  }
+
+  ArrayConcatVisitor visitor(isolate, storage, fast_case);
+
+  for (int i = 0; i < argument_count; i++) {
+    Handle<Object> obj((*args)[i], isolate);
+    Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj);
+    MAYBE_RETURN(spreadable, isolate->heap()->exception());
+    if (spreadable.FromJust()) {
+      Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj);
+      if (!IterateElements(isolate, object, &visitor)) {
+        return isolate->heap()->exception();
+      }
+    } else {
+      visitor.visit(0, obj);
+      visitor.increase_index_offset(1);
+    }
+  }
+
+  if (visitor.exceeds_array_limit()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError(MessageTemplate::kInvalidArrayLength));
+  }
+  return *visitor.ToArray();
+}
+
+
+MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, Arguments* args) {
+  if (!isolate->IsFastArrayConstructorPrototypeChainIntact()) {
+    return MaybeHandle<JSArray>();
+  }
+  int n_arguments = args->length();
   int result_len = 0;
-  ElementsKind elements_kind = GetInitialFastElementsKind();
-  bool has_double = false;
   {
     DisallowHeapAllocation no_gc;
-    Heap* heap = isolate->heap();
-    Context* native_context = isolate->context()->native_context();
-    Object* array_proto = native_context->array_function()->prototype();
-    PrototypeIterator iter(isolate, array_proto,
-                           PrototypeIterator::START_AT_RECEIVER);
-    if (!ArrayPrototypeHasNoElements(heap, &iter)) {
-      AllowHeapAllocation allow_allocation;
-      return CallJsBuiltin(isolate, "ArrayConcatJS", args);
-    }
-
+    Object* array_proto = isolate->array_function()->prototype();
     // Iterate through all the arguments performing checks
     // and calculating total length.
-    bool is_holey = false;
     for (int i = 0; i < n_arguments; i++) {
-      Object* arg = args[i];
+      Object* arg = (*args)[i];
+      if (!arg->IsJSArray()) return MaybeHandle<JSArray>();
+      Handle<JSArray> array(JSArray::cast(arg), isolate);
+      if (!array->HasFastElements()) return MaybeHandle<JSArray>();
       PrototypeIterator iter(isolate, arg);
-      if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements() ||
-          iter.GetCurrent() != array_proto) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArrayConcatJS", args);
+      if (iter.GetCurrent() != array_proto) return MaybeHandle<JSArray>();
+      if (HasConcatSpreadableModifier(isolate, array)) {
+        return MaybeHandle<JSArray>();
       }
-      int len = Smi::cast(JSArray::cast(arg)->length())->value();
+      int len = Smi::cast(array->length())->value();
 
       // We shouldn't overflow when adding another len.
       const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
@@ -948,73 +1415,1971 @@
       USE(kHalfOfMaxInt);
       result_len += len;
       DCHECK(result_len >= 0);
-
-      if (result_len > FixedDoubleArray::kMaxLength) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "ArrayConcatJS", args);
-      }
-
-      ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
-      has_double = has_double || IsFastDoubleElementsKind(arg_kind);
-      is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
-      if (IsMoreGeneralElementsKindTransition(elements_kind, arg_kind)) {
-        elements_kind = arg_kind;
+      // Throw an Error if we overflow the FixedArray limits
+      if (FixedArray::kMaxLength < result_len) {
+        THROW_NEW_ERROR(isolate,
+                        NewRangeError(MessageTemplate::kInvalidArrayLength),
+                        JSArray);
       }
     }
-    if (is_holey) elements_kind = GetHoleyElementsKind(elements_kind);
   }
+  return ElementsAccessor::Concat(isolate, args, n_arguments);
+}
 
-  // If a double array is concatted into a fast elements array, the fast
-  // elements array needs to be initialized to contain proper holes, since
-  // boxing doubles may cause incremental marking.
-  ArrayStorageAllocationMode mode =
-      has_double && IsFastObjectElementsKind(elements_kind)
-      ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE : DONT_INITIALIZE_ARRAY_ELEMENTS;
-  Handle<JSArray> result_array =
-      isolate->factory()->NewJSArray(elements_kind,
-                                     result_len,
-                                     result_len,
-                                     mode);
-  if (result_len == 0) return *result_array;
+}  // namespace
 
-  int j = 0;
-  Handle<FixedArrayBase> storage(result_array->elements(), isolate);
-  ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
-  for (int i = 0; i < n_arguments; i++) {
-    // It is crucial to keep |array| in a raw pointer form to avoid performance
-    // degradation.
-    JSArray* array = JSArray::cast(args[i]);
-    int len = Smi::cast(array->length())->value();
-    if (len > 0) {
-      ElementsKind from_kind = array->GetElementsKind();
-      accessor->CopyElements(array, 0, from_kind, storage, j, len);
-      j += len;
+// ES6 22.1.3.1 Array.prototype.concat
+BUILTIN(ArrayConcat) {
+  HandleScope scope(isolate);
+
+  Handle<Object> receiver;
+  if (!Object::ToObject(isolate, handle(args[0], isolate))
+           .ToHandle(&receiver)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Array.prototype.concat")));
+  }
+  args[0] = *receiver;
+
+  Handle<JSArray> result_array;
+  if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
+    return *result_array;
+  }
+  if (isolate->has_pending_exception()) return isolate->heap()->exception();
+  return Slow_ArrayConcat(&args, isolate);
+}
+
+
+// ES6 22.1.2.2 Array.isArray
+BUILTIN(ArrayIsArray) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+  Handle<Object> object = args.at<Object>(1);
+  Maybe<bool> result = Object::IsArray(object);
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return *isolate->factory()->ToBoolean(result.FromJust());
+}
+
+
+// ES6 19.1.2.1 Object.assign
+BUILTIN(ObjectAssign) {
+  HandleScope scope(isolate);
+  Handle<Object> target = args.atOrUndefined(isolate, 1);
+
+  // 1. Let to be ? ToObject(target).
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target,
+                                     Execution::ToObject(isolate, target));
+  Handle<JSReceiver> to = Handle<JSReceiver>::cast(target);
+  // 2. If only one argument was passed, return to.
+  if (args.length() == 2) return *to;
+  // 3. Let sources be the List of argument values starting with the
+  //    second argument.
+  // 4. For each element nextSource of sources, in ascending index order,
+  for (int i = 2; i < args.length(); ++i) {
+    Handle<Object> next_source = args.at<Object>(i);
+    // 4a. If nextSource is undefined or null, let keys be an empty List.
+    if (next_source->IsUndefined() || next_source->IsNull()) continue;
+    // 4b. Else,
+    // 4b i. Let from be ToObject(nextSource).
+    Handle<JSReceiver> from =
+        Object::ToObject(isolate, next_source).ToHandleChecked();
+    // 4b ii. Let keys be ? from.[[OwnPropertyKeys]]().
+    Handle<FixedArray> keys;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, keys, JSReceiver::GetKeys(from, JSReceiver::OWN_ONLY,
+                                           ALL_PROPERTIES, KEEP_NUMBERS));
+    // 4c. Repeat for each element nextKey of keys in List order,
+    for (int j = 0; j < keys->length(); ++j) {
+      Handle<Object> next_key(keys->get(j), isolate);
+      // 4c i. Let desc be ? from.[[GetOwnProperty]](nextKey).
+      PropertyDescriptor desc;
+      Maybe<bool> found =
+          JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc);
+      if (found.IsNothing()) return isolate->heap()->exception();
+      // 4c ii. If desc is not undefined and desc.[[Enumerable]] is true, then
+      if (found.FromJust() && desc.enumerable()) {
+        // 4c ii 1. Let propValue be ? Get(from, nextKey).
+        Handle<Object> prop_value;
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+            isolate, prop_value,
+            Runtime::GetObjectProperty(isolate, from, next_key, STRICT));
+        // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true).
+        Handle<Object> status;
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+            isolate, status, Runtime::SetObjectProperty(isolate, to, next_key,
+                                                        prop_value, STRICT));
+      }
     }
   }
+  // 5. Return to.
+  return *to;
+}
 
-  DCHECK(j == result_len);
 
-  return *result_array;
+// ES6 section 19.1.2.2 Object.create ( O [ , Properties ] )
+BUILTIN(ObjectCreate) {
+  HandleScope scope(isolate);
+  Handle<Object> prototype = args.atOrUndefined(isolate, 1);
+  if (!prototype->IsNull() && !prototype->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype));
+  }
+
+  // Generate the map with the specified {prototype} based on the Object
+  // function's initial map from the current native context.
+  // TODO(bmeurer): Use a dedicated cache for Object.create; think about
+  // slack tracking for Object.create.
+  Handle<Map> map(isolate->native_context()->object_function()->initial_map(),
+                  isolate);
+  if (map->prototype() != *prototype) {
+    map = Map::TransitionToPrototype(map, prototype, FAST_PROTOTYPE);
+  }
+
+  // Actually allocate the object.
+  Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(map);
+
+  // Define the properties if properties was specified and is not undefined.
+  Handle<Object> properties = args.atOrUndefined(isolate, 2);
+  if (!properties->IsUndefined()) {
+    RETURN_FAILURE_ON_EXCEPTION(
+        isolate, JSReceiver::DefineProperties(isolate, object, properties));
+  }
+
+  return *object;
+}
+
+
+// ES6 section 19.1.2.5 Object.freeze ( O )
+BUILTIN(ObjectFreeze) {
+  HandleScope scope(isolate);
+  Handle<Object> object = args.atOrUndefined(isolate, 1);
+  if (object->IsJSReceiver()) {
+    MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
+                                               FROZEN, Object::THROW_ON_ERROR),
+                 isolate->heap()->exception());
+  }
+  return *object;
+}
+
+
+// ES6 section 19.1.2.11 Object.isExtensible ( O )
+BUILTIN(ObjectIsExtensible) {
+  HandleScope scope(isolate);
+  Handle<Object> object = args.atOrUndefined(isolate, 1);
+  Maybe<bool> result =
+      object->IsJSReceiver()
+          ? JSReceiver::IsExtensible(Handle<JSReceiver>::cast(object))
+          : Just(false);
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return isolate->heap()->ToBoolean(result.FromJust());
+}
+
+
+// ES6 section 19.1.2.12 Object.isFrozen ( O )
+BUILTIN(ObjectIsFrozen) {
+  HandleScope scope(isolate);
+  Handle<Object> object = args.atOrUndefined(isolate, 1);
+  Maybe<bool> result = object->IsJSReceiver()
+                           ? JSReceiver::TestIntegrityLevel(
+                                 Handle<JSReceiver>::cast(object), FROZEN)
+                           : Just(true);
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return isolate->heap()->ToBoolean(result.FromJust());
+}
+
+
+// ES6 section 19.1.2.13 Object.isSealed ( O )
+BUILTIN(ObjectIsSealed) {
+  HandleScope scope(isolate);
+  Handle<Object> object = args.atOrUndefined(isolate, 1);
+  Maybe<bool> result = object->IsJSReceiver()
+                           ? JSReceiver::TestIntegrityLevel(
+                                 Handle<JSReceiver>::cast(object), SEALED)
+                           : Just(true);
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return isolate->heap()->ToBoolean(result.FromJust());
+}
+
+
+// ES6 section 19.1.2.14 Object.keys ( O )
+BUILTIN(ObjectKeys) {
+  HandleScope scope(isolate);
+  Handle<Object> object = args.atOrUndefined(isolate, 1);
+  Handle<JSReceiver> receiver;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
+                                     Execution::ToObject(isolate, object));
+  Handle<FixedArray> keys;
+
+  int enum_length = receiver->map()->EnumLength();
+  if (enum_length != kInvalidEnumCacheSentinel &&
+      JSObject::cast(*receiver)->elements() ==
+          isolate->heap()->empty_fixed_array()) {
+    DCHECK(receiver->IsJSObject());
+    DCHECK(!JSObject::cast(*receiver)->HasNamedInterceptor());
+    DCHECK(!JSObject::cast(*receiver)->IsAccessCheckNeeded());
+    DCHECK(!HeapObject::cast(receiver->map()->prototype())
+                ->map()
+                ->is_hidden_prototype());
+    DCHECK(JSObject::cast(*receiver)->HasFastProperties());
+    if (enum_length == 0) {
+      keys = isolate->factory()->empty_fixed_array();
+    } else {
+      Handle<FixedArray> cache(
+          receiver->map()->instance_descriptors()->GetEnumCache());
+      keys = isolate->factory()->NewFixedArray(enum_length);
+      for (int i = 0; i < enum_length; i++) {
+        keys->set(i, cache->get(i));
+      }
+    }
+  } else {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, keys,
+        JSReceiver::GetKeys(receiver, JSReceiver::OWN_ONLY, ENUMERABLE_STRINGS,
+                            CONVERT_TO_STRING));
+  }
+  return *isolate->factory()->NewJSArrayWithElements(keys, FAST_ELEMENTS);
+}
+
+
+// ES6 section 19.1.2.15 Object.preventExtensions ( O )
+BUILTIN(ObjectPreventExtensions) {
+  HandleScope scope(isolate);
+  Handle<Object> object = args.atOrUndefined(isolate, 1);
+  if (object->IsJSReceiver()) {
+    MAYBE_RETURN(JSReceiver::PreventExtensions(Handle<JSReceiver>::cast(object),
+                                               Object::THROW_ON_ERROR),
+                 isolate->heap()->exception());
+  }
+  return *object;
+}
+
+
+// ES6 section 19.1.2.17 Object.seal ( O )
+BUILTIN(ObjectSeal) {
+  HandleScope scope(isolate);
+  Handle<Object> object = args.atOrUndefined(isolate, 1);
+  if (object->IsJSReceiver()) {
+    MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object),
+                                               SEALED, Object::THROW_ON_ERROR),
+                 isolate->heap()->exception());
+  }
+  return *object;
+}
+
+
+namespace {
+
+bool CodeGenerationFromStringsAllowed(Isolate* isolate,
+                                      Handle<Context> context) {
+  DCHECK(context->allow_code_gen_from_strings()->IsFalse());
+  // Check with callback if set.
+  AllowCodeGenerationFromStringsCallback callback =
+      isolate->allow_code_gen_callback();
+  if (callback == NULL) {
+    // No callback set and code generation disallowed.
+    return false;
+  } else {
+    // Callback set. Let it decide if code generation is allowed.
+    VMState<EXTERNAL> state(isolate);
+    return callback(v8::Utils::ToLocal(context));
+  }
+}
+
+
+MaybeHandle<JSFunction> CompileString(Handle<Context> context,
+                                      Handle<String> source,
+                                      ParseRestriction restriction) {
+  Isolate* const isolate = context->GetIsolate();
+  Handle<Context> native_context(context->native_context(), isolate);
+
+  // Check if native context allows code generation from
+  // strings. Throw an exception if it doesn't.
+  if (native_context->allow_code_gen_from_strings()->IsFalse() &&
+      !CodeGenerationFromStringsAllowed(isolate, native_context)) {
+    Handle<Object> error_message =
+        native_context->ErrorMessageForCodeGenerationFromStrings();
+    THROW_NEW_ERROR(isolate, NewEvalError(MessageTemplate::kCodeGenFromStrings,
+                                          error_message),
+                    JSFunction);
+  }
+
+  // Compile source string in the native context.
+  Handle<SharedFunctionInfo> outer_info(native_context->closure()->shared(),
+                                        isolate);
+  return Compiler::GetFunctionFromEval(source, outer_info, native_context,
+                                       SLOPPY, restriction,
+                                       RelocInfo::kNoPosition);
+}
+
+}  // namespace
+
+
+// ES6 section 18.2.1 eval (x)
+BUILTIN(GlobalEval) {
+  HandleScope scope(isolate);
+  Handle<Object> x = args.atOrUndefined(isolate, 1);
+  Handle<JSFunction> target = args.target();
+  Handle<JSObject> target_global_proxy(target->global_proxy(), isolate);
+  if (!x->IsString()) return *x;
+  Handle<JSFunction> function;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, function,
+      CompileString(handle(target->native_context(), isolate),
+                    Handle<String>::cast(x), NO_PARSE_RESTRICTION));
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result,
+      Execution::Call(isolate, function, target_global_proxy, 0, nullptr));
+  return *result;
+}
+
+
+// ES6 section 26.1.3 Reflect.defineProperty
+BUILTIN(ReflectDefineProperty) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(4, args.length());
+  Handle<Object> target = args.at<Object>(1);
+  Handle<Object> key = args.at<Object>(2);
+  Handle<Object> attributes = args.at<Object>(3);
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.defineProperty")));
+  }
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Object::ToName(isolate, key));
+
+  PropertyDescriptor desc;
+  if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) {
+    return isolate->heap()->exception();
+  }
+
+  Maybe<bool> result =
+      JSReceiver::DefineOwnProperty(isolate, Handle<JSReceiver>::cast(target),
+                                    name, &desc, Object::DONT_THROW);
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return *isolate->factory()->ToBoolean(result.FromJust());
+}
+
+
+// ES6 section 26.1.4 Reflect.deleteProperty
+BUILTIN(ReflectDeleteProperty) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(3, args.length());
+  Handle<Object> target = args.at<Object>(1);
+  Handle<Object> key = args.at<Object>(2);
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.deleteProperty")));
+  }
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Object::ToName(isolate, key));
+
+  Maybe<bool> result = JSReceiver::DeletePropertyOrElement(
+      Handle<JSReceiver>::cast(target), name, SLOPPY);
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return *isolate->factory()->ToBoolean(result.FromJust());
+}
+
+
+// ES6 section 26.1.6 Reflect.get
+BUILTIN(ReflectGet) {
+  HandleScope scope(isolate);
+  Handle<Object> target = args.atOrUndefined(isolate, 1);
+  Handle<Object> key = args.atOrUndefined(isolate, 2);
+  Handle<Object> receiver = args.length() > 3 ? args.at<Object>(3) : target;
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.get")));
+  }
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Object::ToName(isolate, key));
+
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, Object::GetPropertyOrElement(
+          Handle<JSReceiver>::cast(target), name, receiver));
+
+  return *result;
+}
+
+
+// ES6 section 26.1.7 Reflect.getOwnPropertyDescriptor
+BUILTIN(ReflectGetOwnPropertyDescriptor) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(3, args.length());
+  Handle<Object> target = args.at<Object>(1);
+  Handle<Object> key = args.at<Object>(2);
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.getOwnPropertyDescriptor")));
+  }
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Object::ToName(isolate, key));
+
+  PropertyDescriptor desc;
+  Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
+      isolate, Handle<JSReceiver>::cast(target), name, &desc);
+  MAYBE_RETURN(found, isolate->heap()->exception());
+  if (!found.FromJust()) return isolate->heap()->undefined_value();
+  return *desc.ToObject(isolate);
+}
+
+
+// ES6 section 26.1.8 Reflect.getPrototypeOf
+BUILTIN(ReflectGetPrototypeOf) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+  Handle<Object> target = args.at<Object>(1);
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.getPrototypeOf")));
+  }
+  Handle<Object> prototype;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, prototype,
+                                     Object::GetPrototype(isolate, target));
+  return *prototype;
+}
+
+
+// ES6 section 26.1.9 Reflect.has
+BUILTIN(ReflectHas) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(3, args.length());
+  Handle<Object> target = args.at<Object>(1);
+  Handle<Object> key = args.at<Object>(2);
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.has")));
+  }
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Object::ToName(isolate, key));
+
+  Maybe<bool> result =
+      JSReceiver::HasProperty(Handle<JSReceiver>::cast(target), name);
+  return result.IsJust() ? *isolate->factory()->ToBoolean(result.FromJust())
+                         : isolate->heap()->exception();
+}
+
+
+// ES6 section 26.1.10 Reflect.isExtensible
+BUILTIN(ReflectIsExtensible) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+  Handle<Object> target = args.at<Object>(1);
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.isExtensible")));
+  }
+
+  Maybe<bool> result =
+      JSReceiver::IsExtensible(Handle<JSReceiver>::cast(target));
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return *isolate->factory()->ToBoolean(result.FromJust());
+}
+
+
+// ES6 section 26.1.11 Reflect.ownKeys
+BUILTIN(ReflectOwnKeys) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+  Handle<Object> target = args.at<Object>(1);
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.ownKeys")));
+  }
+
+  Handle<FixedArray> keys;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, keys, JSReceiver::GetKeys(Handle<JSReceiver>::cast(target),
+                                         JSReceiver::OWN_ONLY, ALL_PROPERTIES,
+                                         CONVERT_TO_STRING));
+  return *isolate->factory()->NewJSArrayWithElements(keys);
+}
+
+
+// ES6 section 26.1.12 Reflect.preventExtensions
+BUILTIN(ReflectPreventExtensions) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+  Handle<Object> target = args.at<Object>(1);
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.preventExtensions")));
+  }
+
+  Maybe<bool> result = JSReceiver::PreventExtensions(
+      Handle<JSReceiver>::cast(target), Object::DONT_THROW);
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return *isolate->factory()->ToBoolean(result.FromJust());
+}
+
+
+// ES6 section 26.1.13 Reflect.set
+BUILTIN(ReflectSet) {
+  HandleScope scope(isolate);
+  Handle<Object> target = args.atOrUndefined(isolate, 1);
+  Handle<Object> key = args.atOrUndefined(isolate, 2);
+  Handle<Object> value = args.atOrUndefined(isolate, 3);
+  Handle<Object> receiver = args.length() > 4 ? args.at<Object>(4) : target;
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.set")));
+  }
+
+  Handle<Name> name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
+                                     Object::ToName(isolate, key));
+
+  LookupIterator it = LookupIterator::PropertyOrElement(
+      isolate, receiver, name, Handle<JSReceiver>::cast(target));
+  Maybe<bool> result = Object::SetSuperProperty(
+      &it, value, SLOPPY, Object::MAY_BE_STORE_FROM_KEYED);
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return *isolate->factory()->ToBoolean(result.FromJust());
+}
+
+
+// ES6 section 26.1.14 Reflect.setPrototypeOf
+BUILTIN(ReflectSetPrototypeOf) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(3, args.length());
+  Handle<Object> target = args.at<Object>(1);
+  Handle<Object> proto = args.at<Object>(2);
+
+  if (!target->IsJSReceiver()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kCalledOnNonObject,
+                              isolate->factory()->NewStringFromAsciiChecked(
+                                  "Reflect.setPrototypeOf")));
+  }
+
+  if (!proto->IsJSReceiver() && !proto->IsNull()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, proto));
+  }
+
+  Maybe<bool> result = JSReceiver::SetPrototype(
+      Handle<JSReceiver>::cast(target), proto, true, Object::DONT_THROW);
+  MAYBE_RETURN(result, isolate->heap()->exception());
+  return *isolate->factory()->ToBoolean(result.FromJust());
 }
 
 
 // -----------------------------------------------------------------------------
-// Generator and strict mode poison pills
+// ES6 section 20.3 Date Objects
 
 
-BUILTIN(StrictModePoisonPill) {
-  HandleScope scope(isolate);
-  THROW_NEW_ERROR_RETURN_FAILURE(
-      isolate,
-      NewTypeError("strict_poison_pill", HandleVector<Object>(NULL, 0)));
+namespace {
+
+// ES6 section 20.3.1.1 Time Values and Time Range
+const double kMinYear = -1000000.0;
+const double kMaxYear = -kMinYear;
+const double kMinMonth = -10000000.0;
+const double kMaxMonth = -kMinMonth;
+
+
+// 20.3.1.2 Day Number and Time within Day
+const double kMsPerDay = 86400000.0;
+
+
+// ES6 section 20.3.1.11 Hours, Minutes, Second, and Milliseconds
+const double kMsPerSecond = 1000.0;
+const double kMsPerMinute = 60000.0;
+const double kMsPerHour = 3600000.0;
+
+
+// ES6 section 20.3.1.14 MakeDate (day, time)
+double MakeDate(double day, double time) {
+  if (std::isfinite(day) && std::isfinite(time)) {
+    return time + day * kMsPerDay;
+  }
+  return std::numeric_limits<double>::quiet_NaN();
 }
 
 
-BUILTIN(GeneratorPoisonPill) {
+// ES6 section 20.3.1.13 MakeDay (year, month, date)
+double MakeDay(double year, double month, double date) {
+  if ((kMinYear <= year && year <= kMaxYear) &&
+      (kMinMonth <= month && month <= kMaxMonth) && std::isfinite(date)) {
+    int y = FastD2I(year);
+    int m = FastD2I(month);
+    y += m / 12;
+    m %= 12;
+    if (m < 0) {
+      m += 12;
+      y -= 1;
+    }
+    DCHECK_LE(0, m);
+    DCHECK_LT(m, 12);
+
+    // kYearDelta is an arbitrary number such that:
+    // a) kYearDelta = -1 (mod 400)
+    // b) year + kYearDelta > 0 for years in the range defined by
+    //    ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
+    //    Jan 1 1970. This is required so that we don't run into integer
+    //    division of negative numbers.
+    // c) there shouldn't be an overflow for 32-bit integers in the following
+    //    operations.
+    static const int kYearDelta = 399999;
+    static const int kBaseDay =
+        365 * (1970 + kYearDelta) + (1970 + kYearDelta) / 4 -
+        (1970 + kYearDelta) / 100 + (1970 + kYearDelta) / 400;
+    int day_from_year = 365 * (y + kYearDelta) + (y + kYearDelta) / 4 -
+                        (y + kYearDelta) / 100 + (y + kYearDelta) / 400 -
+                        kBaseDay;
+    if ((y % 4 != 0) || (y % 100 == 0 && y % 400 != 0)) {
+      static const int kDayFromMonth[] = {0,   31,  59,  90,  120, 151,
+                                          181, 212, 243, 273, 304, 334};
+      day_from_year += kDayFromMonth[m];
+    } else {
+      static const int kDayFromMonth[] = {0,   31,  60,  91,  121, 152,
+                                          182, 213, 244, 274, 305, 335};
+      day_from_year += kDayFromMonth[m];
+    }
+    return static_cast<double>(day_from_year - 1) + date;
+  }
+  return std::numeric_limits<double>::quiet_NaN();
+}
+
+
+// ES6 section 20.3.1.12 MakeTime (hour, min, sec, ms)
+double MakeTime(double hour, double min, double sec, double ms) {
+  if (std::isfinite(hour) && std::isfinite(min) && std::isfinite(sec) &&
+      std::isfinite(ms)) {
+    double const h = DoubleToInteger(hour);
+    double const m = DoubleToInteger(min);
+    double const s = DoubleToInteger(sec);
+    double const milli = DoubleToInteger(ms);
+    return h * kMsPerHour + m * kMsPerMinute + s * kMsPerSecond + milli;
+  }
+  return std::numeric_limits<double>::quiet_NaN();
+}
+
+
+// ES6 section 20.3.1.15 TimeClip (time)
+double TimeClip(double time) {
+  if (-DateCache::kMaxTimeInMs <= time && time <= DateCache::kMaxTimeInMs) {
+    return DoubleToInteger(time) + 0.0;
+  }
+  return std::numeric_limits<double>::quiet_NaN();
+}
+
+
+const char* kShortWeekDays[] = {"Sun", "Mon", "Tue", "Wed",
+                                "Thu", "Fri", "Sat"};
+const char* kShortMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                              "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+
+// ES6 section 20.3.1.16 Date Time String Format
+double ParseDateTimeString(Handle<String> str) {
+  Isolate* const isolate = str->GetIsolate();
+  str = String::Flatten(str);
+  // TODO(bmeurer): Change DateParser to not use the FixedArray.
+  Handle<FixedArray> tmp =
+      isolate->factory()->NewFixedArray(DateParser::OUTPUT_SIZE);
+  DisallowHeapAllocation no_gc;
+  String::FlatContent str_content = str->GetFlatContent();
+  bool result;
+  if (str_content.IsOneByte()) {
+    result = DateParser::Parse(str_content.ToOneByteVector(), *tmp,
+                               isolate->unicode_cache());
+  } else {
+    result = DateParser::Parse(str_content.ToUC16Vector(), *tmp,
+                               isolate->unicode_cache());
+  }
+  if (!result) return std::numeric_limits<double>::quiet_NaN();
+  double const day = MakeDay(tmp->get(0)->Number(), tmp->get(1)->Number(),
+                             tmp->get(2)->Number());
+  double const time = MakeTime(tmp->get(3)->Number(), tmp->get(4)->Number(),
+                               tmp->get(5)->Number(), tmp->get(6)->Number());
+  double date = MakeDate(day, time);
+  if (tmp->get(7)->IsNull()) {
+    if (!std::isnan(date)) {
+      date = isolate->date_cache()->ToUTC(static_cast<int64_t>(date));
+    }
+  } else {
+    date -= tmp->get(7)->Number() * 1000.0;
+  }
+  return date;
+}
+
+
+enum ToDateStringMode { kDateOnly, kTimeOnly, kDateAndTime };
+
+
+// ES6 section 20.3.4.41.1 ToDateString(tv)
+void ToDateString(double time_val, Vector<char> str, DateCache* date_cache,
+                  ToDateStringMode mode = kDateAndTime) {
+  if (std::isnan(time_val)) {
+    SNPrintF(str, "Invalid Date");
+    return;
+  }
+  int64_t time_ms = static_cast<int64_t>(time_val);
+  int64_t local_time_ms = date_cache->ToLocal(time_ms);
+  int year, month, day, weekday, hour, min, sec, ms;
+  date_cache->BreakDownTime(local_time_ms, &year, &month, &day, &weekday, &hour,
+                            &min, &sec, &ms);
+  int timezone_offset = -date_cache->TimezoneOffset(time_ms);
+  int timezone_hour = std::abs(timezone_offset) / 60;
+  int timezone_min = std::abs(timezone_offset) % 60;
+  const char* local_timezone = date_cache->LocalTimezone(time_ms);
+  switch (mode) {
+    case kDateOnly:
+      SNPrintF(str, "%s %s %02d %4d", kShortWeekDays[weekday],
+               kShortMonths[month], day, year);
+      return;
+    case kTimeOnly:
+      SNPrintF(str, "%02d:%02d:%02d GMT%c%02d%02d (%s)", hour, min, sec,
+               (timezone_offset < 0) ? '-' : '+', timezone_hour, timezone_min,
+               local_timezone);
+      return;
+    case kDateAndTime:
+      SNPrintF(str, "%s %s %02d %4d %02d:%02d:%02d GMT%c%02d%02d (%s)",
+               kShortWeekDays[weekday], kShortMonths[month], day, year, hour,
+               min, sec, (timezone_offset < 0) ? '-' : '+', timezone_hour,
+               timezone_min, local_timezone);
+      return;
+  }
+  UNREACHABLE();
+}
+
+
+Object* SetLocalDateValue(Handle<JSDate> date, double time_val) {
+  if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs &&
+      time_val <= DateCache::kMaxTimeBeforeUTCInMs) {
+    Isolate* const isolate = date->GetIsolate();
+    time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val));
+  } else {
+    time_val = std::numeric_limits<double>::quiet_NaN();
+  }
+  return *JSDate::SetValue(date, TimeClip(time_val));
+}
+
+}  // namespace
+
+
+// ES6 section 20.3.2 The Date Constructor for the [[Call]] case.
+BUILTIN(DateConstructor) {
+  HandleScope scope(isolate);
+  double const time_val = JSDate::CurrentTimeValue(isolate);
+  char buffer[128];
+  Vector<char> str(buffer, arraysize(buffer));
+  ToDateString(time_val, str, isolate->date_cache());
+  return *isolate->factory()->NewStringFromAsciiChecked(str.start());
+}
+
+
+// ES6 section 20.3.2 The Date Constructor for the [[Construct]] case.
+BUILTIN(DateConstructor_ConstructStub) {
+  HandleScope scope(isolate);
+  int const argc = args.length() - 1;
+  Handle<JSFunction> target = args.target();
+  Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
+  double time_val;
+  if (argc == 0) {
+    time_val = JSDate::CurrentTimeValue(isolate);
+  } else if (argc == 1) {
+    Handle<Object> value = args.at<Object>(1);
+    if (value->IsJSDate()) {
+      time_val = Handle<JSDate>::cast(value)->value()->Number();
+    } else {
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
+                                         Object::ToPrimitive(value));
+      if (value->IsString()) {
+        time_val = ParseDateTimeString(Handle<String>::cast(value));
+      } else {
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
+                                           Object::ToNumber(value));
+        time_val = value->Number();
+      }
+    }
+  } else {
+    Handle<Object> year_object;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object,
+                                       Object::ToNumber(args.at<Object>(1)));
+    Handle<Object> month_object;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
+                                       Object::ToNumber(args.at<Object>(2)));
+    double year = year_object->Number();
+    double month = month_object->Number();
+    double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0;
+    if (argc >= 3) {
+      Handle<Object> date_object;
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date_object,
+                                         Object::ToNumber(args.at<Object>(3)));
+      date = date_object->Number();
+      if (argc >= 4) {
+        Handle<Object> hours_object;
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+            isolate, hours_object, Object::ToNumber(args.at<Object>(4)));
+        hours = hours_object->Number();
+        if (argc >= 5) {
+          Handle<Object> minutes_object;
+          ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+              isolate, minutes_object, Object::ToNumber(args.at<Object>(5)));
+          minutes = minutes_object->Number();
+          if (argc >= 6) {
+            Handle<Object> seconds_object;
+            ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+                isolate, seconds_object, Object::ToNumber(args.at<Object>(6)));
+            seconds = seconds_object->Number();
+            if (argc >= 7) {
+              Handle<Object> ms_object;
+              ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+                  isolate, ms_object, Object::ToNumber(args.at<Object>(7)));
+              ms = ms_object->Number();
+            }
+          }
+        }
+      }
+    }
+    if (!std::isnan(year)) {
+      double const y = DoubleToInteger(year);
+      if (0.0 <= y && y <= 99) year = 1900 + y;
+    }
+    double const day = MakeDay(year, month, date);
+    double const time = MakeTime(hours, minutes, seconds, ms);
+    time_val = MakeDate(day, time);
+    if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs &&
+        time_val <= DateCache::kMaxTimeBeforeUTCInMs) {
+      time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val));
+    } else {
+      time_val = std::numeric_limits<double>::quiet_NaN();
+    }
+  }
+  Handle<JSDate> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     JSDate::New(target, new_target, time_val));
+  return *result;
+}
+
+
+// ES6 section 20.3.3.1 Date.now ( )
+BUILTIN(DateNow) {
+  HandleScope scope(isolate);
+  return *isolate->factory()->NewNumber(JSDate::CurrentTimeValue(isolate));
+}
+
+
+// ES6 section 20.3.3.2 Date.parse ( string )
+BUILTIN(DateParse) {
+  HandleScope scope(isolate);
+  Handle<String> string;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, string,
+      Object::ToString(isolate, args.atOrUndefined(isolate, 1)));
+  return *isolate->factory()->NewNumber(ParseDateTimeString(string));
+}
+
+
+// ES6 section 20.3.3.4 Date.UTC (year,month,date,hours,minutes,seconds,ms)
+BUILTIN(DateUTC) {
+  HandleScope scope(isolate);
+  int const argc = args.length() - 1;
+  double year = std::numeric_limits<double>::quiet_NaN();
+  double month = std::numeric_limits<double>::quiet_NaN();
+  double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0;
+  if (argc >= 1) {
+    Handle<Object> year_object;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object,
+                                       Object::ToNumber(args.at<Object>(1)));
+    year = year_object->Number();
+    if (argc >= 2) {
+      Handle<Object> month_object;
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
+                                         Object::ToNumber(args.at<Object>(2)));
+      month = month_object->Number();
+      if (argc >= 3) {
+        Handle<Object> date_object;
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+            isolate, date_object, Object::ToNumber(args.at<Object>(3)));
+        date = date_object->Number();
+        if (argc >= 4) {
+          Handle<Object> hours_object;
+          ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+              isolate, hours_object, Object::ToNumber(args.at<Object>(4)));
+          hours = hours_object->Number();
+          if (argc >= 5) {
+            Handle<Object> minutes_object;
+            ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+                isolate, minutes_object, Object::ToNumber(args.at<Object>(5)));
+            minutes = minutes_object->Number();
+            if (argc >= 6) {
+              Handle<Object> seconds_object;
+              ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+                  isolate, seconds_object,
+                  Object::ToNumber(args.at<Object>(6)));
+              seconds = seconds_object->Number();
+              if (argc >= 7) {
+                Handle<Object> ms_object;
+                ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+                    isolate, ms_object, Object::ToNumber(args.at<Object>(7)));
+                ms = ms_object->Number();
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+  if (!std::isnan(year)) {
+    double const y = DoubleToInteger(year);
+    if (0.0 <= y && y <= 99) year = 1900 + y;
+  }
+  double const day = MakeDay(year, month, date);
+  double const time = MakeTime(hours, minutes, seconds, ms);
+  return *isolate->factory()->NewNumber(TimeClip(MakeDate(day, time)));
+}
+
+
+// ES6 section 20.3.4.20 Date.prototype.setDate ( date )
+BUILTIN(DatePrototypeSetDate) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setDate");
+  Handle<Object> value = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value));
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
+    int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
+    int year, month, day;
+    isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
+    time_val = MakeDate(MakeDay(year, month, value->Number()), time_within_day);
+  }
+  return SetLocalDateValue(date, time_val);
+}
+
+
+// ES6 section 20.3.4.21 Date.prototype.setFullYear (year, month, date)
+BUILTIN(DatePrototypeSetFullYear) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setFullYear");
+  int const argc = args.length() - 1;
+  Handle<Object> year = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year));
+  double y = year->Number(), m = 0.0, dt = 1.0;
+  int time_within_day = 0;
+  if (!std::isnan(date->value()->Number())) {
+    int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
+    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
+    int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
+    time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
+    int year, month, day;
+    isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
+    m = month;
+    dt = day;
+  }
+  if (argc >= 2) {
+    Handle<Object> month = args.at<Object>(2);
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month));
+    m = month->Number();
+    if (argc >= 3) {
+      Handle<Object> date = args.at<Object>(3);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date));
+      dt = date->Number();
+    }
+  }
+  double time_val = MakeDate(MakeDay(y, m, dt), time_within_day);
+  return SetLocalDateValue(date, time_val);
+}
+
+
+// ES6 section 20.3.4.22 Date.prototype.setHours(hour, min, sec, ms)
+BUILTIN(DatePrototypeSetHours) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setHours");
+  int const argc = args.length() - 1;
+  Handle<Object> hour = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour, Object::ToNumber(hour));
+  double h = hour->Number();
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
+    int day = isolate->date_cache()->DaysFromTime(local_time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
+    double m = (time_within_day / (60 * 1000)) % 60;
+    double s = (time_within_day / 1000) % 60;
+    double milli = time_within_day % 1000;
+    if (argc >= 2) {
+      Handle<Object> min = args.at<Object>(2);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min));
+      m = min->Number();
+      if (argc >= 3) {
+        Handle<Object> sec = args.at<Object>(3);
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
+        s = sec->Number();
+        if (argc >= 4) {
+          Handle<Object> ms = args.at<Object>(4);
+          ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
+          milli = ms->Number();
+        }
+      }
+    }
+    time_val = MakeDate(day, MakeTime(h, m, s, milli));
+  }
+  return SetLocalDateValue(date, time_val);
+}
+
+
+// ES6 section 20.3.4.23 Date.prototype.setMilliseconds(ms)
+BUILTIN(DatePrototypeSetMilliseconds) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setMilliseconds");
+  Handle<Object> ms = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
+    int day = isolate->date_cache()->DaysFromTime(local_time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
+    int h = time_within_day / (60 * 60 * 1000);
+    int m = (time_within_day / (60 * 1000)) % 60;
+    int s = (time_within_day / 1000) % 60;
+    time_val = MakeDate(day, MakeTime(h, m, s, ms->Number()));
+  }
+  return SetLocalDateValue(date, time_val);
+}
+
+
+// ES6 section 20.3.4.24 Date.prototype.setMinutes ( min, sec, ms )
+BUILTIN(DatePrototypeSetMinutes) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setMinutes");
+  int const argc = args.length() - 1;
+  Handle<Object> min = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min));
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
+    int day = isolate->date_cache()->DaysFromTime(local_time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
+    int h = time_within_day / (60 * 60 * 1000);
+    double m = min->Number();
+    double s = (time_within_day / 1000) % 60;
+    double milli = time_within_day % 1000;
+    if (argc >= 2) {
+      Handle<Object> sec = args.at<Object>(2);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
+      s = sec->Number();
+      if (argc >= 3) {
+        Handle<Object> ms = args.at<Object>(3);
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
+        milli = ms->Number();
+      }
+    }
+    time_val = MakeDate(day, MakeTime(h, m, s, milli));
+  }
+  return SetLocalDateValue(date, time_val);
+}
+
+
+// ES6 section 20.3.4.25 Date.prototype.setMonth ( month, date )
+BUILTIN(DatePrototypeSetMonth) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setMonth");
+  int const argc = args.length() - 1;
+  Handle<Object> month = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month));
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
+    int days = isolate->date_cache()->DaysFromTime(local_time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
+    int year, unused, day;
+    isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day);
+    double m = month->Number();
+    double dt = day;
+    if (argc >= 2) {
+      Handle<Object> date = args.at<Object>(2);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date));
+      dt = date->Number();
+    }
+    time_val = MakeDate(MakeDay(year, m, dt), time_within_day);
+  }
+  return SetLocalDateValue(date, time_val);
+}
+
+
+// ES6 section 20.3.4.26 Date.prototype.setSeconds ( sec, ms )
+BUILTIN(DatePrototypeSetSeconds) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setSeconds");
+  int const argc = args.length() - 1;
+  Handle<Object> sec = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
+    int day = isolate->date_cache()->DaysFromTime(local_time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
+    int h = time_within_day / (60 * 60 * 1000);
+    double m = (time_within_day / (60 * 1000)) % 60;
+    double s = sec->Number();
+    double milli = time_within_day % 1000;
+    if (argc >= 2) {
+      Handle<Object> ms = args.at<Object>(2);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
+      milli = ms->Number();
+    }
+    time_val = MakeDate(day, MakeTime(h, m, s, milli));
+  }
+  return SetLocalDateValue(date, time_val);
+}
+
+
+// ES6 section 20.3.4.27 Date.prototype.setTime ( time )
+BUILTIN(DatePrototypeSetTime) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setTime");
+  Handle<Object> value = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value));
+  return *JSDate::SetValue(date, TimeClip(value->Number()));
+}
+
+
+// ES6 section 20.3.4.28 Date.prototype.setUTCDate ( date )
+BUILTIN(DatePrototypeSetUTCDate) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCDate");
+  Handle<Object> value = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value));
+  if (std::isnan(date->value()->Number())) return date->value();
+  int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
+  int const days = isolate->date_cache()->DaysFromTime(time_ms);
+  int const time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
+  int year, month, day;
+  isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
+  double const time_val =
+      MakeDate(MakeDay(year, month, value->Number()), time_within_day);
+  return *JSDate::SetValue(date, TimeClip(time_val));
+}
+
+
+// ES6 section 20.3.4.29 Date.prototype.setUTCFullYear (year, month, date)
+BUILTIN(DatePrototypeSetUTCFullYear) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCFullYear");
+  int const argc = args.length() - 1;
+  Handle<Object> year = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year));
+  double y = year->Number(), m = 0.0, dt = 1.0;
+  int time_within_day = 0;
+  if (!std::isnan(date->value()->Number())) {
+    int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
+    int const days = isolate->date_cache()->DaysFromTime(time_ms);
+    time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
+    int year, month, day;
+    isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
+    m = month;
+    dt = day;
+  }
+  if (argc >= 2) {
+    Handle<Object> month = args.at<Object>(2);
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month));
+    m = month->Number();
+    if (argc >= 3) {
+      Handle<Object> date = args.at<Object>(3);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date));
+      dt = date->Number();
+    }
+  }
+  double const time_val = MakeDate(MakeDay(y, m, dt), time_within_day);
+  return *JSDate::SetValue(date, TimeClip(time_val));
+}
+
+
+// ES6 section 20.3.4.30 Date.prototype.setUTCHours(hour, min, sec, ms)
+BUILTIN(DatePrototypeSetUTCHours) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCHours");
+  int const argc = args.length() - 1;
+  Handle<Object> hour = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour, Object::ToNumber(hour));
+  double h = hour->Number();
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int day = isolate->date_cache()->DaysFromTime(time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
+    double m = (time_within_day / (60 * 1000)) % 60;
+    double s = (time_within_day / 1000) % 60;
+    double milli = time_within_day % 1000;
+    if (argc >= 2) {
+      Handle<Object> min = args.at<Object>(2);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min));
+      m = min->Number();
+      if (argc >= 3) {
+        Handle<Object> sec = args.at<Object>(3);
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
+        s = sec->Number();
+        if (argc >= 4) {
+          Handle<Object> ms = args.at<Object>(4);
+          ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
+          milli = ms->Number();
+        }
+      }
+    }
+    time_val = MakeDate(day, MakeTime(h, m, s, milli));
+  }
+  return *JSDate::SetValue(date, TimeClip(time_val));
+}
+
+
+// ES6 section 20.3.4.31 Date.prototype.setUTCMilliseconds(ms)
+BUILTIN(DatePrototypeSetUTCMilliseconds) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMilliseconds");
+  Handle<Object> ms = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int day = isolate->date_cache()->DaysFromTime(time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
+    int h = time_within_day / (60 * 60 * 1000);
+    int m = (time_within_day / (60 * 1000)) % 60;
+    int s = (time_within_day / 1000) % 60;
+    time_val = MakeDate(day, MakeTime(h, m, s, ms->Number()));
+  }
+  return *JSDate::SetValue(date, TimeClip(time_val));
+}
+
+
+// ES6 section 20.3.4.32 Date.prototype.setUTCMinutes ( min, sec, ms )
+BUILTIN(DatePrototypeSetUTCMinutes) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMinutes");
+  int const argc = args.length() - 1;
+  Handle<Object> min = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min));
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int day = isolate->date_cache()->DaysFromTime(time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
+    int h = time_within_day / (60 * 60 * 1000);
+    double m = min->Number();
+    double s = (time_within_day / 1000) % 60;
+    double milli = time_within_day % 1000;
+    if (argc >= 2) {
+      Handle<Object> sec = args.at<Object>(2);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
+      s = sec->Number();
+      if (argc >= 3) {
+        Handle<Object> ms = args.at<Object>(3);
+        ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
+        milli = ms->Number();
+      }
+    }
+    time_val = MakeDate(day, MakeTime(h, m, s, milli));
+  }
+  return *JSDate::SetValue(date, TimeClip(time_val));
+}
+
+
+// ES6 section 20.3.4.31 Date.prototype.setUTCMonth ( month, date )
+BUILTIN(DatePrototypeSetUTCMonth) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMonth");
+  int const argc = args.length() - 1;
+  Handle<Object> month = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month));
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int days = isolate->date_cache()->DaysFromTime(time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
+    int year, unused, day;
+    isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day);
+    double m = month->Number();
+    double dt = day;
+    if (argc >= 2) {
+      Handle<Object> date = args.at<Object>(2);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date));
+      dt = date->Number();
+    }
+    time_val = MakeDate(MakeDay(year, m, dt), time_within_day);
+  }
+  return *JSDate::SetValue(date, TimeClip(time_val));
+}
+
+
+// ES6 section 20.3.4.34 Date.prototype.setUTCSeconds ( sec, ms )
+BUILTIN(DatePrototypeSetUTCSeconds) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCSeconds");
+  int const argc = args.length() - 1;
+  Handle<Object> sec = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
+  double time_val = date->value()->Number();
+  if (!std::isnan(time_val)) {
+    int64_t const time_ms = static_cast<int64_t>(time_val);
+    int day = isolate->date_cache()->DaysFromTime(time_ms);
+    int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
+    int h = time_within_day / (60 * 60 * 1000);
+    double m = (time_within_day / (60 * 1000)) % 60;
+    double s = sec->Number();
+    double milli = time_within_day % 1000;
+    if (argc >= 2) {
+      Handle<Object> ms = args.at<Object>(2);
+      ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
+      milli = ms->Number();
+    }
+    time_val = MakeDate(day, MakeTime(h, m, s, milli));
+  }
+  return *JSDate::SetValue(date, TimeClip(time_val));
+}
+
+
+// ES6 section 20.3.4.35 Date.prototype.toDateString ( )
+BUILTIN(DatePrototypeToDateString) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.toDateString");
+  char buffer[128];
+  Vector<char> str(buffer, arraysize(buffer));
+  ToDateString(date->value()->Number(), str, isolate->date_cache(), kDateOnly);
+  return *isolate->factory()->NewStringFromAsciiChecked(str.start());
+}
+
+
+// ES6 section 20.3.4.36 Date.prototype.toISOString ( )
+BUILTIN(DatePrototypeToISOString) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.toISOString");
+  double const time_val = date->value()->Number();
+  if (std::isnan(time_val)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
+  }
+  int64_t const time_ms = static_cast<int64_t>(time_val);
+  int year, month, day, weekday, hour, min, sec, ms;
+  isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday,
+                                       &hour, &min, &sec, &ms);
+  char buffer[128];
+  Vector<char> str(buffer, arraysize(buffer));
+  if (year >= 0 && year <= 9999) {
+    SNPrintF(str, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", year, month + 1, day,
+             hour, min, sec, ms);
+  } else if (year < 0) {
+    SNPrintF(str, "-%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", -year, month + 1, day,
+             hour, min, sec, ms);
+  } else {
+    SNPrintF(str, "+%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", year, month + 1, day,
+             hour, min, sec, ms);
+  }
+  return *isolate->factory()->NewStringFromAsciiChecked(str.start());
+}
+
+
+// ES6 section 20.3.4.41 Date.prototype.toString ( )
+BUILTIN(DatePrototypeToString) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.toString");
+  char buffer[128];
+  Vector<char> str(buffer, arraysize(buffer));
+  ToDateString(date->value()->Number(), str, isolate->date_cache());
+  return *isolate->factory()->NewStringFromAsciiChecked(str.start());
+}
+
+
+// ES6 section 20.3.4.42 Date.prototype.toTimeString ( )
+BUILTIN(DatePrototypeToTimeString) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.toTimeString");
+  char buffer[128];
+  Vector<char> str(buffer, arraysize(buffer));
+  ToDateString(date->value()->Number(), str, isolate->date_cache(), kTimeOnly);
+  return *isolate->factory()->NewStringFromAsciiChecked(str.start());
+}
+
+
+// ES6 section 20.3.4.43 Date.prototype.toUTCString ( )
+BUILTIN(DatePrototypeToUTCString) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.toUTCString");
+  double const time_val = date->value()->Number();
+  if (std::isnan(time_val)) {
+    return *isolate->factory()->NewStringFromAsciiChecked("Invalid Date");
+  }
+  char buffer[128];
+  Vector<char> str(buffer, arraysize(buffer));
+  int64_t time_ms = static_cast<int64_t>(time_val);
+  int year, month, day, weekday, hour, min, sec, ms;
+  isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday,
+                                       &hour, &min, &sec, &ms);
+  SNPrintF(str, "%s, %02d %s %4d %02d:%02d:%02d GMT", kShortWeekDays[weekday],
+           day, kShortMonths[month], year, hour, min, sec);
+  return *isolate->factory()->NewStringFromAsciiChecked(str.start());
+}
+
+
+// ES6 section 20.3.4.44 Date.prototype.valueOf ( )
+BUILTIN(DatePrototypeValueOf) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.valueOf");
+  return date->value();
+}
+
+
+// ES6 section 20.3.4.45 Date.prototype [ @@toPrimitive ] ( hint )
+BUILTIN(DatePrototypeToPrimitive) {
+  HandleScope scope(isolate);
+  DCHECK_EQ(2, args.length());
+  CHECK_RECEIVER(JSReceiver, receiver, "Date.prototype [ @@toPrimitive ]");
+  Handle<Object> hint = args.at<Object>(1);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     JSDate::ToPrimitive(receiver, hint));
+  return *result;
+}
+
+
+// ES6 section B.2.4.1 Date.prototype.getYear ( )
+BUILTIN(DatePrototypeGetYear) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.getYear");
+  double time_val = date->value()->Number();
+  if (std::isnan(time_val)) return date->value();
+  int64_t time_ms = static_cast<int64_t>(time_val);
+  int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
+  int days = isolate->date_cache()->DaysFromTime(local_time_ms);
+  int year, month, day;
+  isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
+  return Smi::FromInt(year - 1900);
+}
+
+
+// ES6 section B.2.4.2 Date.prototype.setYear ( year )
+BUILTIN(DatePrototypeSetYear) {
+  HandleScope scope(isolate);
+  CHECK_RECEIVER(JSDate, date, "Date.prototype.setYear");
+  Handle<Object> year = args.atOrUndefined(isolate, 1);
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year));
+  double m = 0.0, dt = 1.0, y = year->Number();
+  if (0.0 <= y && y <= 99.0) {
+    y = 1900.0 + DoubleToInteger(y);
+  }
+  int time_within_day = 0;
+  if (!std::isnan(date->value()->Number())) {
+    int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
+    int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
+    int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
+    time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
+    int year, month, day;
+    isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
+    m = month;
+    dt = day;
+  }
+  double time_val = MakeDate(MakeDay(y, m, dt), time_within_day);
+  return SetLocalDateValue(date, time_val);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetDate(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kDay);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetDay(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kWeekday);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetFullYear(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kYear);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetHours(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kHour);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetMilliseconds(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kMillisecond);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetMinutes(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kMinute);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetMonth(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kMonth);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetSeconds(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kSecond);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetTime(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kDateValue);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetTimezoneOffset(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kTimezoneOffset);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetUTCDate(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kDayUTC);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetUTCDay(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kWeekdayUTC);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetUTCFullYear(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kYearUTC);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetUTCHours(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kHourUTC);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetUTCMilliseconds(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kMillisecondUTC);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetUTCMinutes(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kMinuteUTC);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetUTCMonth(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kMonthUTC);
+}
+
+
+// static
+void Builtins::Generate_DatePrototypeGetUTCSeconds(MacroAssembler* masm) {
+  Generate_DatePrototype_GetField(masm, JSDate::kSecondUTC);
+}
+
+
+namespace {
+
+// ES6 section 19.2.1.1.1 CreateDynamicFunction
+MaybeHandle<JSFunction> CreateDynamicFunction(
+    Isolate* isolate,
+    BuiltinArguments<BuiltinExtraArguments::kTargetAndNewTarget> args,
+    const char* token) {
+  // Compute number of arguments, ignoring the receiver.
+  DCHECK_LE(1, args.length());
+  int const argc = args.length() - 1;
+
+  // Build the source string.
+  Handle<String> source;
+  {
+    IncrementalStringBuilder builder(isolate);
+    builder.AppendCharacter('(');
+    builder.AppendCString(token);
+    builder.AppendCharacter('(');
+    bool parenthesis_in_arg_string = false;
+    if (argc > 1) {
+      for (int i = 1; i < argc; ++i) {
+        if (i > 1) builder.AppendCharacter(',');
+        Handle<String> param;
+        ASSIGN_RETURN_ON_EXCEPTION(
+            isolate, param, Object::ToString(isolate, args.at<Object>(i)),
+            JSFunction);
+        param = String::Flatten(param);
+        builder.AppendString(param);
+        // If the formal parameters string include ) - an illegal
+        // character - it may make the combined function expression
+        // compile. We avoid this problem by checking for this early on.
+        DisallowHeapAllocation no_gc;  // Ensure vectors stay valid.
+        String::FlatContent param_content = param->GetFlatContent();
+        for (int i = 0, length = param->length(); i < length; ++i) {
+          if (param_content.Get(i) == ')') {
+            parenthesis_in_arg_string = true;
+            break;
+          }
+        }
+      }
+      // If the formal parameters include an unbalanced block comment, the
+      // function must be rejected. Since JavaScript does not allow nested
+      // comments we can include a trailing block comment to catch this.
+      builder.AppendCString("\n/**/");
+    }
+    builder.AppendCString(") {\n");
+    if (argc > 0) {
+      Handle<String> body;
+      ASSIGN_RETURN_ON_EXCEPTION(
+          isolate, body, Object::ToString(isolate, args.at<Object>(argc)),
+          JSFunction);
+      builder.AppendString(body);
+    }
+    builder.AppendCString("\n})");
+    ASSIGN_RETURN_ON_EXCEPTION(isolate, source, builder.Finish(), JSFunction);
+
+    // The SyntaxError must be thrown after all the (observable) ToString
+    // conversions are done.
+    if (parenthesis_in_arg_string) {
+      THROW_NEW_ERROR(isolate,
+                      NewSyntaxError(MessageTemplate::kParenthesisInArgString),
+                      JSFunction);
+    }
+  }
+
+  // Compile the string in the constructor and not a helper so that errors to
+  // come from here.
+  Handle<JSFunction> target = args.target();
+  Handle<JSObject> target_global_proxy(target->global_proxy(), isolate);
+  Handle<JSFunction> function;
+  {
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, function,
+        CompileString(handle(target->native_context(), isolate), source,
+                      ONLY_SINGLE_FUNCTION_LITERAL),
+        JSFunction);
+    Handle<Object> result;
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, result,
+        Execution::Call(isolate, function, target_global_proxy, 0, nullptr),
+        JSFunction);
+    function = Handle<JSFunction>::cast(result);
+    function->shared()->set_name_should_print_as_anonymous(true);
+  }
+
+  // If new.target is equal to target then the function created
+  // is already correctly setup and nothing else should be done
+  // here. But if new.target is not equal to target then we are
+  // have a Function builtin subclassing case and therefore the
+  // function has wrong initial map. To fix that we create a new
+  // function object with correct initial map.
+  Handle<Object> unchecked_new_target = args.new_target();
+  if (!unchecked_new_target->IsUndefined() &&
+      !unchecked_new_target.is_identical_to(target)) {
+    Handle<JSReceiver> new_target =
+        Handle<JSReceiver>::cast(unchecked_new_target);
+    Handle<Map> initial_map;
+    ASSIGN_RETURN_ON_EXCEPTION(
+        isolate, initial_map,
+        JSFunction::GetDerivedMap(isolate, target, new_target), JSFunction);
+
+    Handle<SharedFunctionInfo> shared_info(function->shared(), isolate);
+    Handle<Map> map = Map::AsLanguageMode(
+        initial_map, shared_info->language_mode(), shared_info->kind());
+
+    Handle<Context> context(function->context(), isolate);
+    function = isolate->factory()->NewFunctionFromSharedFunctionInfo(
+        map, shared_info, context, NOT_TENURED);
+  }
+  return function;
+}
+
+}  // namespace
+
+
+// ES6 section 19.2.1.1 Function ( p1, p2, ... , pn, body )
+BUILTIN(FunctionConstructor) {
+  HandleScope scope(isolate);
+  Handle<JSFunction> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, CreateDynamicFunction(isolate, args, "function"));
+  return *result;
+}
+
+
+// ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args )
+BUILTIN(FunctionPrototypeBind) {
+  HandleScope scope(isolate);
+  DCHECK_LE(1, args.length());
+  if (!args.receiver()->IsCallable()) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewTypeError(MessageTemplate::kFunctionBind));
+  }
+
+  // Allocate the bound function with the given {this_arg} and {args}.
+  Handle<JSReceiver> target = args.at<JSReceiver>(0);
+  Handle<Object> this_arg = isolate->factory()->undefined_value();
+  ScopedVector<Handle<Object>> argv(std::max(0, args.length() - 2));
+  if (args.length() > 1) {
+    this_arg = args.at<Object>(1);
+    for (int i = 2; i < args.length(); ++i) {
+      argv[i - 2] = args.at<Object>(i);
+    }
+  }
+  Handle<JSBoundFunction> function;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, function,
+      isolate->factory()->NewJSBoundFunction(target, this_arg, argv));
+
+  // TODO(bmeurer): Optimize the rest for the common cases where {target} is
+  // a function with some initial map or even a bound function.
+  // Setup the "length" property based on the "length" of the {target}.
+  Handle<Object> length(Smi::FromInt(0), isolate);
+  Maybe<bool> target_has_length =
+      JSReceiver::HasOwnProperty(target, isolate->factory()->length_string());
+  if (!target_has_length.IsJust()) {
+    return isolate->heap()->exception();
+  } else if (target_has_length.FromJust()) {
+    Handle<Object> target_length;
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, target_length,
+        JSReceiver::GetProperty(target, isolate->factory()->length_string()));
+    if (target_length->IsNumber()) {
+      length = isolate->factory()->NewNumber(std::max(
+          0.0, DoubleToInteger(target_length->Number()) - argv.length()));
+    }
+  }
+  function->set_length(*length);
+
+  // Setup the "name" property based on the "name" of the {target}.
+  Handle<Object> target_name;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, target_name,
+      JSReceiver::GetProperty(target, isolate->factory()->name_string()));
+  Handle<String> name;
+  if (!target_name->IsString()) {
+    name = isolate->factory()->bound__string();
+  } else {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, name, Name::ToFunctionName(Handle<String>::cast(target_name)));
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+        isolate, name, isolate->factory()->NewConsString(
+                           isolate->factory()->bound__string(), name));
+  }
+  function->set_name(*name);
+  return *function;
+}
+
+
+// ES6 section 19.2.3.5 Function.prototype.toString ( )
+BUILTIN(FunctionPrototypeToString) {
+  HandleScope scope(isolate);
+  Handle<Object> receiver = args.receiver();
+  if (receiver->IsJSBoundFunction()) {
+    return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver));
+  } else if (receiver->IsJSFunction()) {
+    return *JSFunction::ToString(Handle<JSFunction>::cast(receiver));
+  }
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewTypeError(MessageTemplate::kNotGeneric,
+                            isolate->factory()->NewStringFromAsciiChecked(
+                                "Function.prototype.toString")));
+}
+
+
+// ES6 section 25.2.1.1 GeneratorFunction (p1, p2, ... , pn, body)
+BUILTIN(GeneratorFunctionConstructor) {
+  HandleScope scope(isolate);
+  Handle<JSFunction> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, CreateDynamicFunction(isolate, args, "function*"));
+  return *result;
+}
+
+
+// ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Call]] case.
+BUILTIN(SymbolConstructor) {
+  HandleScope scope(isolate);
+  Handle<Symbol> result = isolate->factory()->NewSymbol();
+  Handle<Object> description = args.atOrUndefined(isolate, 1);
+  if (!description->IsUndefined()) {
+    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, description,
+                                       Object::ToString(isolate, description));
+    result->set_name(*description);
+  }
+  return *result;
+}
+
+
+// ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Construct]] case.
+BUILTIN(SymbolConstructor_ConstructStub) {
+  HandleScope scope(isolate);
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewTypeError(MessageTemplate::kNotConstructor,
+                            isolate->factory()->Symbol_string()));
+}
+
+
+// ES6 19.1.3.6 Object.prototype.toString
+BUILTIN(ObjectProtoToString) {
+  HandleScope scope(isolate);
+  Handle<Object> object = args.at<Object>(0);
+  Handle<String> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, result, JSObject::ObjectProtoToString(isolate, object));
+  return *result;
+}
+
+
+// ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Call]] case.
+BUILTIN(ArrayBufferConstructor) {
+  HandleScope scope(isolate);
+  Handle<JSFunction> target = args.target();
+  DCHECK(*target == target->native_context()->array_buffer_fun() ||
+         *target == target->native_context()->shared_array_buffer_fun());
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
+                            handle(target->shared()->name(), isolate)));
+}
+
+
+// ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Construct]] case.
+BUILTIN(ArrayBufferConstructor_ConstructStub) {
+  HandleScope scope(isolate);
+  Handle<JSFunction> target = args.target();
+  Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
+  Handle<Object> length = args.atOrUndefined(isolate, 1);
+  DCHECK(*target == target->native_context()->array_buffer_fun() ||
+         *target == target->native_context()->shared_array_buffer_fun());
+  Handle<Object> number_length;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_length,
+                                     Object::ToInteger(isolate, length));
+  if (number_length->Number() < 0.0) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
+  }
+  Handle<Map> initial_map;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+      isolate, initial_map,
+      JSFunction::GetDerivedMap(isolate, target, new_target));
+  size_t byte_length;
+  if (!TryNumberToSize(isolate, *number_length, &byte_length)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
+  }
+  Handle<JSArrayBuffer> result = Handle<JSArrayBuffer>::cast(
+      isolate->factory()->NewJSObjectFromMap(initial_map));
+  SharedFlag shared_flag =
+      (*target == target->native_context()->array_buffer_fun())
+          ? SharedFlag::kNotShared
+          : SharedFlag::kShared;
+  if (!JSArrayBuffer::SetupAllocatingData(result, isolate, byte_length, true,
+                                          shared_flag)) {
+    THROW_NEW_ERROR_RETURN_FAILURE(
+        isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed));
+  }
+  return *result;
+}
+
+
+// ES6 section 24.1.3.1 ArrayBuffer.isView ( arg )
+BUILTIN(ArrayBufferIsView) {
+  SealHandleScope shs(isolate);
+  DCHECK_EQ(2, args.length());
+  Object* arg = args[1];
+  return isolate->heap()->ToBoolean(arg->IsJSArrayBufferView());
+}
+
+
+// ES6 section 26.2.1.1 Proxy ( target, handler ) for the [[Call]] case.
+BUILTIN(ProxyConstructor) {
   HandleScope scope(isolate);
   THROW_NEW_ERROR_RETURN_FAILURE(
       isolate,
-      NewTypeError("generator_poison_pill", HandleVector<Object>(NULL, 0)));
+      NewTypeError(MessageTemplate::kConstructorNotFunction,
+                   isolate->factory()->NewStringFromAsciiChecked("Proxy")));
+}
+
+
+// ES6 section 26.2.1.1 Proxy ( target, handler ) for the [[Construct]] case.
+BUILTIN(ProxyConstructor_ConstructStub) {
+  HandleScope scope(isolate);
+  DCHECK(isolate->proxy_function()->IsConstructor());
+  Handle<Object> target = args.atOrUndefined(isolate, 1);
+  Handle<Object> handler = args.atOrUndefined(isolate, 2);
+  Handle<JSProxy> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     JSProxy::New(isolate, target, handler));
+  return *result;
+}
+
+
+// -----------------------------------------------------------------------------
+// Throwers for restricted function properties and strict arguments object
+// properties
+
+
+BUILTIN(RestrictedFunctionPropertiesThrower) {
+  HandleScope scope(isolate);
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewTypeError(MessageTemplate::kRestrictedFunctionProperties));
+}
+
+
+BUILTIN(RestrictedStrictArgumentsPropertiesThrower) {
+  HandleScope scope(isolate);
+  THROW_NEW_ERROR_RETURN_FAILURE(
+      isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
 }
 
 
@@ -1022,108 +3387,55 @@
 //
 
 
-// Searches the hidden prototype chain of the given object for the first
-// object that is an instance of the given type.  If no such object can
-// be found then Heap::null_value() is returned.
-static inline Object* FindHidden(Heap* heap,
-                                 Object* object,
-                                 FunctionTemplateInfo* type) {
-  for (PrototypeIterator iter(heap->isolate(), object,
-                              PrototypeIterator::START_AT_RECEIVER);
-       !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
-    if (type->IsTemplateFor(iter.GetCurrent())) {
-      return iter.GetCurrent();
-    }
-  }
-  return heap->null_value();
-}
-
-
-// Returns the holder JSObject if the function can legally be called
-// with this receiver.  Returns Heap::null_value() if the call is
-// illegal.  Any arguments that don't fit the expected type is
-// overwritten with undefined.  Note that holder and the arguments are
-// implicitly rewritten with the first object in the hidden prototype
-// chain that actually has the expected type.
-static inline Object* TypeCheck(Heap* heap,
-                                int argc,
-                                Object** argv,
-                                FunctionTemplateInfo* info) {
-  Object* recv = argv[0];
-  // API calls are only supported with JSObject receivers.
-  if (!recv->IsJSObject()) return heap->null_value();
-  Object* sig_obj = info->signature();
-  if (sig_obj->IsUndefined()) return recv;
-  SignatureInfo* sig = SignatureInfo::cast(sig_obj);
-  // If necessary, check the receiver
-  Object* recv_type = sig->receiver();
-  Object* holder = recv;
-  if (!recv_type->IsUndefined()) {
-    holder = FindHidden(heap, holder, FunctionTemplateInfo::cast(recv_type));
-    if (holder == heap->null_value()) return heap->null_value();
-  }
-  Object* args_obj = sig->args();
-  // If there is no argument signature we're done
-  if (args_obj->IsUndefined()) return holder;
-  FixedArray* args = FixedArray::cast(args_obj);
-  int length = args->length();
-  if (argc <= length) length = argc - 1;
-  for (int i = 0; i < length; i++) {
-    Object* argtype = args->get(i);
-    if (argtype->IsUndefined()) continue;
-    Object** arg = &argv[-1 - i];
-    Object* current = *arg;
-    current = FindHidden(heap, current, FunctionTemplateInfo::cast(argtype));
-    if (current == heap->null_value()) current = heap->undefined_value();
-    *arg = current;
-  }
-  return holder;
-}
-
+namespace {
 
 template <bool is_construct>
-MUST_USE_RESULT static Object* HandleApiCallHelper(
-    BuiltinArguments<NEEDS_CALLED_FUNCTION> args, Isolate* isolate) {
-  DCHECK(is_construct == CalledAsConstructor(isolate));
-  Heap* heap = isolate->heap();
-
+MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper(
+    Isolate* isolate, BuiltinArguments<BuiltinExtraArguments::kTarget> args) {
   HandleScope scope(isolate);
-  Handle<JSFunction> function = args.called_function();
-  DCHECK(function->shared()->IsApiFunction());
+  Handle<JSFunction> function = args.target();
+  DCHECK(args.receiver()->IsJSReceiver());
+  // TODO(ishell): turn this back to a DCHECK.
+  CHECK(function->shared()->IsApiFunction());
 
   Handle<FunctionTemplateInfo> fun_data(
       function->shared()->get_api_func_data(), isolate);
   if (is_construct) {
-    ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
+    ASSIGN_RETURN_ON_EXCEPTION(
         isolate, fun_data,
-        isolate->factory()->ConfigureInstance(
-            fun_data, Handle<JSObject>::cast(args.receiver())));
+        ApiNatives::ConfigureInstance(isolate, fun_data,
+                                      Handle<JSObject>::cast(args.receiver())),
+        Object);
   }
 
-  SharedFunctionInfo* shared = function->shared();
-  if (shared->strict_mode() == SLOPPY && !shared->native()) {
-    Object* recv = args[0];
-    DCHECK(!recv->IsNull());
-    if (recv->IsUndefined()) args[0] = function->global_proxy();
+  if (!is_construct && !fun_data->accept_any_receiver()) {
+    Handle<JSReceiver> receiver = args.at<JSReceiver>(0);
+    if (receiver->IsJSObject() && receiver->IsAccessCheckNeeded()) {
+      Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
+      if (!isolate->MayAccess(handle(isolate->context()), js_receiver)) {
+        isolate->ReportFailedAccessCheck(js_receiver);
+        RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+      }
+    }
   }
 
-  Object* raw_holder = TypeCheck(heap, args.length(), &args[0], *fun_data);
+  Object* raw_holder = fun_data->GetCompatibleReceiver(isolate, args[0]);
 
   if (raw_holder->IsNull()) {
     // This function cannot be called with the given receiver.  Abort!
-    THROW_NEW_ERROR_RETURN_FAILURE(
-        isolate,
-        NewTypeError("illegal_invocation", HandleVector(&function, 1)));
+    THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kIllegalInvocation),
+                    Object);
   }
 
   Object* raw_call_data = fun_data->call_code();
   if (!raw_call_data->IsUndefined()) {
+    // TODO(ishell): remove this debugging code.
+    CHECK(raw_call_data->IsCallHandlerInfo());
     CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
     Object* callback_obj = call_data->callback();
     v8::FunctionCallback callback =
         v8::ToCData<v8::FunctionCallback>(callback_obj);
     Object* data_obj = call_data->data();
-    Object* result;
 
     LOG(isolate, ApiObjectAccess("call", JSObject::cast(*args.receiver())));
     DCHECK(raw_holder->IsJSObject());
@@ -1136,29 +3448,123 @@
                                      args.length() - 1,
                                      is_construct);
 
-    v8::Handle<v8::Value> value = custom.Call(callback);
+    v8::Local<v8::Value> value = custom.Call(callback);
+    Handle<Object> result;
     if (value.IsEmpty()) {
-      result = heap->undefined_value();
+      result = isolate->factory()->undefined_value();
     } else {
-      result = *reinterpret_cast<Object**>(*value);
+      result = v8::Utils::OpenHandle(*value);
       result->VerifyApiCallResultType();
     }
 
-    RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-    if (!is_construct || result->IsJSObject()) return result;
+    RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+    if (!is_construct || result->IsJSObject()) {
+      return scope.CloseAndEscape(result);
+    }
   }
 
-  return *args.receiver();
+  return scope.CloseAndEscape(args.receiver());
 }
 
+}  // namespace
+
 
 BUILTIN(HandleApiCall) {
-  return HandleApiCallHelper<false>(args, isolate);
+  HandleScope scope(isolate);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     HandleApiCallHelper<false>(isolate, args));
+  return *result;
 }
 
 
 BUILTIN(HandleApiCallConstruct) {
-  return HandleApiCallHelper<true>(args, isolate);
+  HandleScope scope(isolate);
+  Handle<Object> result;
+  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
+                                     HandleApiCallHelper<true>(isolate, args));
+  return *result;
+}
+
+
+Handle<Code> Builtins::CallFunction(ConvertReceiverMode mode) {
+  switch (mode) {
+    case ConvertReceiverMode::kNullOrUndefined:
+      return CallFunction_ReceiverIsNullOrUndefined();
+    case ConvertReceiverMode::kNotNullOrUndefined:
+      return CallFunction_ReceiverIsNotNullOrUndefined();
+    case ConvertReceiverMode::kAny:
+      return CallFunction_ReceiverIsAny();
+  }
+  UNREACHABLE();
+  return Handle<Code>::null();
+}
+
+
+Handle<Code> Builtins::Call(ConvertReceiverMode mode) {
+  switch (mode) {
+    case ConvertReceiverMode::kNullOrUndefined:
+      return Call_ReceiverIsNullOrUndefined();
+    case ConvertReceiverMode::kNotNullOrUndefined:
+      return Call_ReceiverIsNotNullOrUndefined();
+    case ConvertReceiverMode::kAny:
+      return Call_ReceiverIsAny();
+  }
+  UNREACHABLE();
+  return Handle<Code>::null();
+}
+
+
+namespace {
+
+class RelocatableArguments
+    : public BuiltinArguments<BuiltinExtraArguments::kTarget>,
+      public Relocatable {
+ public:
+  RelocatableArguments(Isolate* isolate, int length, Object** arguments)
+      : BuiltinArguments<BuiltinExtraArguments::kTarget>(length, arguments),
+        Relocatable(isolate) {}
+
+  virtual inline void IterateInstance(ObjectVisitor* v) {
+    if (length() == 0) return;
+    v->VisitPointers(lowest_address(), highest_address() + 1);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RelocatableArguments);
+};
+
+}  // namespace
+
+
+MaybeHandle<Object> Builtins::InvokeApiFunction(Handle<JSFunction> function,
+                                                Handle<Object> receiver,
+                                                int argc,
+                                                Handle<Object> args[]) {
+  // Construct BuiltinArguments object: function, arguments reversed, receiver.
+  const int kBufferSize = 32;
+  Object* small_argv[kBufferSize];
+  Object** argv;
+  if (argc + 2 <= kBufferSize) {
+    argv = small_argv;
+  } else {
+    argv = new Object* [argc + 2];
+  }
+  argv[argc + 1] = *receiver;
+  for (int i = 0; i < argc; ++i) {
+    argv[argc - i] = *args[i];
+  }
+  argv[0] = *function;
+  MaybeHandle<Object> result;
+  {
+    auto isolate = function->GetIsolate();
+    RelocatableArguments arguments(isolate, argc + 2, &argv[argc + 1]);
+    result = HandleApiCallHelper<false>(isolate, arguments);
+  }
+  if (argv != small_argv) {
+    delete[] argv;
+  }
+  return result;
 }
 
 
@@ -1166,12 +3572,8 @@
 // API. The object can be called as either a constructor (using new) or just as
 // a function (without new).
 MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor(
-    Isolate* isolate,
-    bool is_construct_call,
-    BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
-  // Non-functions are never called as constructors. Even if this is an object
-  // called as a constructor the delegate call is not a construct call.
-  DCHECK(!CalledAsConstructor(isolate));
+    Isolate* isolate, bool is_construct_call,
+    BuiltinArguments<BuiltinExtraArguments::kNone> args) {
   Heap* heap = isolate->heap();
 
   Handle<Object> receiver = args.receiver();
@@ -1181,12 +3583,15 @@
 
   // Get the invocation callback from the function descriptor that was
   // used to create the called object.
-  DCHECK(obj->map()->has_instance_call_handler());
-  JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
-  DCHECK(constructor->shared()->IsApiFunction());
+  DCHECK(obj->map()->is_callable());
+  JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor());
+  // TODO(ishell): turn this back to a DCHECK.
+  CHECK(constructor->shared()->IsApiFunction());
   Object* handler =
       constructor->shared()->get_api_func_data()->instance_call_handler();
   DCHECK(!handler->IsUndefined());
+  // TODO(ishell): remove this debugging code.
+  CHECK(handler->IsCallHandlerInfo());
   CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
   Object* callback_obj = call_data->callback();
   v8::FunctionCallback callback =
@@ -1205,7 +3610,7 @@
                                      &args[0] - 1,
                                      args.length() - 1,
                                      is_construct_call);
-    v8::Handle<v8::Value> value = custom.Call(callback);
+    v8::Local<v8::Value> value = custom.Call(callback);
     if (value.IsEmpty()) {
       result = heap->undefined_value();
     } else {
@@ -1239,7 +3644,12 @@
 
 
 static void Generate_LoadIC_Normal(MacroAssembler* masm) {
-  LoadIC::GenerateNormal(masm);
+  LoadIC::GenerateNormal(masm, SLOPPY);
+}
+
+
+static void Generate_LoadIC_Normal_Strong(MacroAssembler* masm) {
+  LoadIC::GenerateNormal(masm, STRONG);
 }
 
 
@@ -1249,17 +3659,22 @@
 
 
 static void Generate_LoadIC_Slow(MacroAssembler* masm) {
-  LoadIC::GenerateRuntimeGetProperty(masm);
+  LoadIC::GenerateRuntimeGetProperty(masm, SLOPPY);
 }
 
 
-static void Generate_KeyedLoadIC_Initialize(MacroAssembler* masm) {
-  KeyedLoadIC::GenerateInitialize(masm);
+static void Generate_LoadIC_Slow_Strong(MacroAssembler* masm) {
+  LoadIC::GenerateRuntimeGetProperty(masm, STRONG);
 }
 
 
 static void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) {
-  KeyedLoadIC::GenerateRuntimeGetProperty(masm);
+  KeyedLoadIC::GenerateRuntimeGetProperty(masm, SLOPPY);
+}
+
+
+static void Generate_KeyedLoadIC_Slow_Strong(MacroAssembler* masm) {
+  KeyedLoadIC::GenerateRuntimeGetProperty(masm, STRONG);
 }
 
 
@@ -1268,13 +3683,13 @@
 }
 
 
-static void Generate_KeyedLoadIC_Generic(MacroAssembler* masm) {
-  KeyedLoadIC::GenerateGeneric(masm);
+static void Generate_KeyedLoadIC_Megamorphic(MacroAssembler* masm) {
+  KeyedLoadIC::GenerateMegamorphic(masm, SLOPPY);
 }
 
 
-static void Generate_KeyedLoadIC_PreMonomorphic(MacroAssembler* masm) {
-  KeyedLoadIC::GeneratePreMonomorphic(masm);
+static void Generate_KeyedLoadIC_Megamorphic_Strong(MacroAssembler* masm) {
+  KeyedLoadIC::GenerateMegamorphic(masm, STRONG);
 }
 
 
@@ -1313,16 +3728,6 @@
 }
 
 
-static void Generate_KeyedStoreIC_Generic(MacroAssembler* masm) {
-  KeyedStoreIC::GenerateGeneric(masm, SLOPPY);
-}
-
-
-static void Generate_KeyedStoreIC_Generic_Strict(MacroAssembler* masm) {
-  KeyedStoreIC::GenerateGeneric(masm, STRICT);
-}
-
-
 static void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) {
   KeyedStoreIC::GenerateMiss(masm);
 }
@@ -1348,69 +3753,15 @@
 }
 
 
-static void Generate_KeyedStoreIC_SloppyArguments(MacroAssembler* masm) {
-  KeyedStoreIC::GenerateSloppyArguments(masm);
-}
-
-
-static void Generate_CallICStub_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateCallICStubDebugBreak(masm);
-}
-
-
-static void Generate_LoadIC_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateLoadICDebugBreak(masm);
-}
-
-
-static void Generate_StoreIC_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateStoreICDebugBreak(masm);
-}
-
-
-static void Generate_KeyedLoadIC_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateKeyedLoadICDebugBreak(masm);
-}
-
-
-static void Generate_KeyedStoreIC_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateKeyedStoreICDebugBreak(masm);
-}
-
-
-static void Generate_CompareNilIC_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateCompareNilICDebugBreak(masm);
-}
-
-
 static void Generate_Return_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateReturnDebugBreak(masm);
-}
-
-
-static void Generate_CallFunctionStub_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateCallFunctionStubDebugBreak(masm);
-}
-
-
-static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateCallConstructStubDebugBreak(masm);
-}
-
-
-static void Generate_CallConstructStub_Recording_DebugBreak(
-    MacroAssembler* masm) {
-  DebugCodegen::GenerateCallConstructStubRecordDebugBreak(masm);
+  DebugCodegen::GenerateDebugBreakStub(masm,
+                                       DebugCodegen::SAVE_RESULT_REGISTER);
 }
 
 
 static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
-  DebugCodegen::GenerateSlotDebugBreak(masm);
-}
-
-
-static void Generate_PlainReturn_LiveEdit(MacroAssembler* masm) {
-  DebugCodegen::GeneratePlainReturnLiveEdit(masm);
+  DebugCodegen::GenerateDebugBreakStub(masm,
+                                       DebugCodegen::IGNORE_RESULT_REGISTER);
 }
 
 
@@ -1435,17 +3786,6 @@
 };
 #undef DEF_ENUM_C
 
-#define DEF_JS_NAME(name, ignore) #name,
-#define DEF_JS_ARGC(ignore, argc) argc,
-const char* const Builtins::javascript_names_[id_count] = {
-  BUILTINS_LIST_JS(DEF_JS_NAME)
-};
-
-int const Builtins::javascript_argc_[id_count] = {
-  BUILTINS_LIST_JS(DEF_JS_ARGC)
-};
-#undef DEF_JS_NAME
-#undef DEF_JS_ARGC
 
 struct BuiltinDesc {
   byte* generator;
@@ -1485,36 +3825,34 @@
   functions[builtin_count].s_name = NULL;
   functions[builtin_count].name = builtin_count;
   functions[builtin_count].flags = static_cast<Code::Flags>(0);
-  functions[builtin_count].extra_args = NO_EXTRA_ARGUMENTS;
+  functions[builtin_count].extra_args = BuiltinExtraArguments::kNone;
 
-#define DEF_FUNCTION_PTR_C(aname, aextra_args)                         \
-    functions->generator = FUNCTION_ADDR(Generate_Adaptor);            \
-    functions->c_code = FUNCTION_ADDR(Builtin_##aname);                \
-    functions->s_name = #aname;                                        \
-    functions->name = c_##aname;                                       \
-    functions->flags = Code::ComputeFlags(Code::BUILTIN);              \
-    functions->extra_args = aextra_args;                               \
-    ++functions;
+#define DEF_FUNCTION_PTR_C(aname, aextra_args)                \
+  functions->generator = FUNCTION_ADDR(Generate_Adaptor);     \
+  functions->c_code = FUNCTION_ADDR(Builtin_##aname);         \
+  functions->s_name = #aname;                                 \
+  functions->name = c_##aname;                                \
+  functions->flags = Code::ComputeFlags(Code::BUILTIN);       \
+  functions->extra_args = BuiltinExtraArguments::aextra_args; \
+  ++functions;
 
-#define DEF_FUNCTION_PTR_A(aname, kind, state, extra)                       \
-    functions->generator = FUNCTION_ADDR(Generate_##aname);                 \
-    functions->c_code = NULL;                                               \
-    functions->s_name = #aname;                                             \
-    functions->name = k##aname;                                             \
-    functions->flags = Code::ComputeFlags(Code::kind,                       \
-                                          state,                            \
-                                          extra);                           \
-    functions->extra_args = NO_EXTRA_ARGUMENTS;                             \
-    ++functions;
+#define DEF_FUNCTION_PTR_A(aname, kind, state, extra)              \
+  functions->generator = FUNCTION_ADDR(Generate_##aname);          \
+  functions->c_code = NULL;                                        \
+  functions->s_name = #aname;                                      \
+  functions->name = k##aname;                                      \
+  functions->flags = Code::ComputeFlags(Code::kind, state, extra); \
+  functions->extra_args = BuiltinExtraArguments::kNone;            \
+  ++functions;
 
-#define DEF_FUNCTION_PTR_H(aname, kind)                                     \
-    functions->generator = FUNCTION_ADDR(Generate_##aname);                 \
-    functions->c_code = NULL;                                               \
-    functions->s_name = #aname;                                             \
-    functions->name = k##aname;                                             \
-    functions->flags = Code::ComputeHandlerFlags(Code::kind);               \
-    functions->extra_args = NO_EXTRA_ARGUMENTS;                             \
-    ++functions;
+#define DEF_FUNCTION_PTR_H(aname, kind)                     \
+  functions->generator = FUNCTION_ADDR(Generate_##aname);   \
+  functions->c_code = NULL;                                 \
+  functions->s_name = #aname;                               \
+  functions->name = k##aname;                               \
+  functions->flags = Code::ComputeHandlerFlags(Code::kind); \
+  functions->extra_args = BuiltinExtraArguments::kNone;     \
+  ++functions;
 
   BUILTIN_LIST_C(DEF_FUNCTION_PTR_C)
   BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
@@ -1540,6 +3878,9 @@
 #ifdef DEBUG
   // We can generate a lot of debug code on Arm64.
   const size_t buffer_size = 32*KB;
+#elif V8_TARGET_ARCH_PPC64
+  // 8 KB is insufficient on PPC64 when FLAG_debug_code is on.
+  const size_t buffer_size = 10 * KB;
 #else
   const size_t buffer_size = 8*KB;
 #endif
@@ -1549,7 +3890,8 @@
   // separate code object for each one.
   for (int i = 0; i < builtin_count; i++) {
     if (create_heap_objects) {
-      MacroAssembler masm(isolate, u.buffer, sizeof u.buffer);
+      MacroAssembler masm(isolate, u.buffer, sizeof u.buffer,
+                          CodeObjectRequired::kYes);
       // Generate the code/adaptor.
       typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
       Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
@@ -1615,12 +3957,12 @@
 
 
 void Builtins::Generate_InterruptCheck(MacroAssembler* masm) {
-  masm->TailCallRuntime(Runtime::kInterrupt, 0, 1);
+  masm->TailCallRuntime(Runtime::kInterrupt);
 }
 
 
 void Builtins::Generate_StackCheck(MacroAssembler* masm) {
-  masm->TailCallRuntime(Runtime::kStackGuard, 0, 1);
+  masm->TailCallRuntime(Runtime::kStackGuard);
 }
 
 
@@ -1650,4 +3992,5 @@
 #undef DEFINE_BUILTIN_ACCESSOR_A
 
 
-} }  // namespace v8::internal
+}  // namespace internal
+}  // namespace v8