Merge V8 3.9 at 3.9.24.9

http://v8.googlecode.com/svn/branches/3.9@11260

Bug: 5688872
Change-Id: Iddd944e82189d92df3fc427dc5f0d3f1b2f0c6c8
diff --git a/src/builtins.cc b/src/builtins.cc
index 90a8d3e..0f493e6 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -33,6 +33,7 @@
 #include "builtins.h"
 #include "gdb-jit.h"
 #include "ic-inl.h"
+#include "heap-profiler.h"
 #include "mark-compact.h"
 #include "vm-state-inl.h"
 
@@ -193,13 +194,21 @@
   JSArray* array;
   if (CalledAsConstructor(isolate)) {
     array = JSArray::cast((*args)[0]);
+    // Initialize elements and length in case later allocations fail so that the
+    // array object is initialized in a valid state.
+    array->set_length(Smi::FromInt(0));
+    array->set_elements(heap->empty_fixed_array());
+    if (!FLAG_smi_only_arrays) {
+      Context* global_context = isolate->context()->global_context();
+      if (array->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS &&
+          !global_context->object_js_array_map()->IsUndefined()) {
+        array->set_map(Map::cast(global_context->object_js_array_map()));
+      }
+    }
   } else {
     // Allocate the JS Array
-    Object* obj;
-    { MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
-      if (!maybe_obj->ToObject(&obj)) return maybe_obj;
-    }
-    array = JSArray::cast(obj);
+    MaybeObject* maybe_obj = heap->AllocateJSObject(constructor);
+    if (!maybe_obj->To(&array)) return maybe_obj;
   }
 
   // Optimize the case where there is one argument and the argument is a
@@ -209,12 +218,13 @@
     if (obj->IsSmi()) {
       int len = Smi::cast(obj)->value();
       if (len >= 0 && len < JSObject::kInitialMaxFastElementArray) {
-        Object* obj;
+        Object* fixed_array;
         { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(len);
-          if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+          if (!maybe_obj->ToObject(&fixed_array)) return maybe_obj;
         }
-        MaybeObject* maybe_obj = array->SetContent(FixedArray::cast(obj));
-        if (maybe_obj->IsFailure()) return maybe_obj;
+        // We do not use SetContent to skip the unnecessary elements type check.
+        array->set_elements(FixedArray::cast(fixed_array));
+        array->set_length(Smi::cast(obj));
         return array;
       }
     }
@@ -301,50 +311,6 @@
 }
 
 
-MUST_USE_RESULT static MaybeObject* AllocateJSArray(Heap* heap) {
-  JSFunction* array_function =
-      heap->isolate()->context()->global_context()->array_function();
-  Object* result;
-  { MaybeObject* maybe_result = heap->AllocateJSObject(array_function);
-    if (!maybe_result->ToObject(&result)) return maybe_result;
-  }
-  return result;
-}
-
-
-MUST_USE_RESULT static MaybeObject* AllocateEmptyJSArray(Heap* heap) {
-  Object* result;
-  { MaybeObject* maybe_result = AllocateJSArray(heap);
-    if (!maybe_result->ToObject(&result)) return maybe_result;
-  }
-  JSArray* result_array = JSArray::cast(result);
-  result_array->set_length(Smi::FromInt(0));
-  result_array->set_elements(heap->empty_fixed_array());
-  return result_array;
-}
-
-
-static void CopyElements(Heap* heap,
-                         AssertNoAllocation* no_gc,
-                         FixedArray* dst,
-                         int dst_index,
-                         FixedArray* src,
-                         int src_index,
-                         int len) {
-  ASSERT(dst != src);  // Use MoveElements instead.
-  ASSERT(dst->map() != HEAP->fixed_cow_array_map());
-  ASSERT(len > 0);
-  CopyWords(dst->data_start() + dst_index,
-            src->data_start() + src_index,
-            len);
-  WriteBarrierMode mode = dst->GetWriteBarrierMode(*no_gc);
-  if (mode == UPDATE_WRITE_BARRIER) {
-    heap->RecordWrites(dst->address(), dst->OffsetOfElementAt(dst_index), len);
-  }
-  heap->incremental_marking()->RecordWrites(dst);
-}
-
-
 static void MoveElements(Heap* heap,
                          AssertNoAllocation* no_gc,
                          FixedArray* dst,
@@ -352,6 +318,7 @@
                          FixedArray* src,
                          int src_index,
                          int len) {
+  if (len == 0) return;
   ASSERT(dst->map() != HEAP->fixed_cow_array_map());
   memmove(dst->data_start() + dst_index,
           src->data_start() + src_index,
@@ -414,6 +381,8 @@
     MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
   }
 
+  HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(),
+                                     elms->address() + size_delta));
   return FixedArray::cast(HeapObject::FromAddress(
       elms->address() + to_trim * kPointerSize));
 }
@@ -542,10 +511,8 @@
     }
     FixedArray* new_elms = FixedArray::cast(obj);
 
-    AssertNoAllocation no_gc;
-    if (len > 0) {
-      CopyElements(heap, &no_gc, new_elms, 0, elms, 0, len);
-    }
+    CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
+                               new_elms, FAST_ELEMENTS, 0, len);
     FillWithHoles(heap, new_elms, new_length, capacity);
 
     elms = new_elms;
@@ -680,10 +647,8 @@
       if (!maybe_obj->ToObject(&obj)) return maybe_obj;
     }
     FixedArray* new_elms = FixedArray::cast(obj);
-    AssertNoAllocation no_gc;
-    if (len > 0) {
-      CopyElements(heap, &no_gc, new_elms, to_add, elms, 0, len);
-    }
+    CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
+                               new_elms, FAST_ELEMENTS, to_add, len);
     FillWithHoles(heap, new_elms, new_length, capacity);
     elms = new_elms;
     array->set_elements(elms);
@@ -781,45 +746,22 @@
   int final = (relative_end < 0) ? Max(len + relative_end, 0)
                                  : Min(relative_end, len);
 
-  // Calculate the length of result array.
-  int result_len = final - k;
-  if (result_len <= 0) {
-    return AllocateEmptyJSArray(heap);
-  }
-
-  Object* result;
-  { MaybeObject* maybe_result = AllocateJSArray(heap);
-    if (!maybe_result->ToObject(&result)) return maybe_result;
-  }
-  JSArray* result_array = JSArray::cast(result);
-
-  { MaybeObject* maybe_result =
-        heap->AllocateUninitializedFixedArray(result_len);
-    if (!maybe_result->ToObject(&result)) return maybe_result;
-  }
-  FixedArray* result_elms = FixedArray::cast(result);
-
-  MaybeObject* maybe_object =
-      result_array->EnsureCanContainElements(result_elms,
-                                             DONT_ALLOW_DOUBLE_ELEMENTS);
-  if (maybe_object->IsFailure()) return maybe_object;
-
-  AssertNoAllocation no_gc;
-  CopyElements(heap, &no_gc, result_elms, 0, elms, k, result_len);
-
-  // Set elements.
-  result_array->set_elements(result_elms);
-
-  // Set the length.
-  result_array->set_length(Smi::FromInt(result_len));
-
-  // Set the ElementsKind.
   ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
-  if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(),
-                                          elements_kind)) {
-    MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind);
-    if (maybe->IsFailure()) return maybe;
-  }
+
+  // Calculate the length of result array.
+  int result_len = Max(final - k, 0);
+
+  MaybeObject* maybe_array =
+      heap->AllocateJSArrayAndStorage(elements_kind,
+                                      result_len,
+                                      result_len);
+  JSArray* result_array;
+  if (!maybe_array->To(&result_array)) return maybe_array;
+
+  CopyObjectToObjectElements(elms, FAST_ELEMENTS, k,
+                             FixedArray::cast(result_array->elements()),
+                             FAST_ELEMENTS, 0, result_len);
+
   return result_array;
 }
 
@@ -880,47 +822,19 @@
   }
 
   JSArray* result_array = NULL;
-  if (actual_delete_count == 0) {
-    Object* result;
-    { MaybeObject* maybe_result = AllocateEmptyJSArray(heap);
-      if (!maybe_result->ToObject(&result)) return maybe_result;
-    }
-    result_array = JSArray::cast(result);
-  } else {
-    // Allocate result array.
-    Object* result;
-    { MaybeObject* maybe_result = AllocateJSArray(heap);
-      if (!maybe_result->ToObject(&result)) return maybe_result;
-    }
-    result_array = JSArray::cast(result);
+  ElementsKind elements_kind =
+      JSObject::cast(receiver)->GetElementsKind();
+  MaybeObject* maybe_array =
+      heap->AllocateJSArrayAndStorage(elements_kind,
+                                      actual_delete_count,
+                                      actual_delete_count);
+  if (!maybe_array->To(&result_array)) return maybe_array;
 
-    { MaybeObject* maybe_result =
-          heap->AllocateUninitializedFixedArray(actual_delete_count);
-      if (!maybe_result->ToObject(&result)) return maybe_result;
-    }
-    FixedArray* result_elms = FixedArray::cast(result);
-
-    AssertNoAllocation no_gc;
+  {
     // Fill newly created array.
-    CopyElements(heap,
-                 &no_gc,
-                 result_elms, 0,
-                 elms, actual_start,
-                 actual_delete_count);
-
-    // Set elements.
-    result_array->set_elements(result_elms);
-
-    // Set the length.
-    result_array->set_length(Smi::FromInt(actual_delete_count));
-
-    // Set the ElementsKind.
-    ElementsKind elements_kind = array->GetElementsKind();
-    if (IsMoreGeneralElementsKindTransition(result_array->GetElementsKind(),
-                                            elements_kind)) {
-      MaybeObject* maybe = result_array->TransitionElementsKind(elements_kind);
-      if (maybe->IsFailure()) return maybe;
-    }
+    CopyObjectToObjectElements(elms, FAST_ELEMENTS, actual_start,
+                               FixedArray::cast(result_array->elements()),
+                               FAST_ELEMENTS, 0, actual_delete_count);
   }
 
   int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
@@ -935,7 +849,7 @@
     if (trim_array) {
       const int delta = actual_delete_count - item_count;
 
-      if (actual_start > 0) {
+      {
         AssertNoAllocation no_gc;
         MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
       }
@@ -967,18 +881,17 @@
       }
       FixedArray* new_elms = FixedArray::cast(obj);
 
-      AssertNoAllocation no_gc;
-      // Copy the part before actual_start as is.
-      if (actual_start > 0) {
-        CopyElements(heap, &no_gc, new_elms, 0, elms, 0, actual_start);
+      {
+        // Copy the part before actual_start as is.
+        CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
+                                   new_elms, FAST_ELEMENTS, 0, actual_start);
+        const int to_copy = len - actual_delete_count - actual_start;
+        CopyObjectToObjectElements(elms, FAST_ELEMENTS,
+                                   actual_start + actual_delete_count,
+                                   new_elms, FAST_ELEMENTS,
+                                   actual_start + item_count, to_copy);
       }
-      const int to_copy = len - actual_delete_count - actual_start;
-      if (to_copy > 0) {
-        CopyElements(heap, &no_gc,
-                     new_elms, actual_start + item_count,
-                     elms, actual_start + actual_delete_count,
-                     to_copy);
-      }
+
       FillWithHoles(heap, new_elms, new_length, capacity);
 
       elms = new_elms;
@@ -1022,6 +935,7 @@
   // and calculating total length.
   int n_arguments = args.length();
   int result_len = 0;
+  ElementsKind elements_kind = FAST_SMI_ONLY_ELEMENTS;
   for (int i = 0; i < n_arguments; i++) {
     Object* arg = args[i];
     if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastTypeElements()
@@ -1041,54 +955,35 @@
     if (result_len > FixedArray::kMaxLength) {
       return CallJsBuiltin(isolate, "ArrayConcat", args);
     }
-  }
 
-  if (result_len == 0) {
-    return AllocateEmptyJSArray(heap);
+    if (!JSArray::cast(arg)->HasFastSmiOnlyElements()) {
+      elements_kind = FAST_ELEMENTS;
+    }
   }
 
   // Allocate result.
-  Object* result;
-  { MaybeObject* maybe_result = AllocateJSArray(heap);
-    if (!maybe_result->ToObject(&result)) return maybe_result;
-  }
-  JSArray* result_array = JSArray::cast(result);
-
-  { MaybeObject* maybe_result =
-        heap->AllocateUninitializedFixedArray(result_len);
-    if (!maybe_result->ToObject(&result)) return maybe_result;
-  }
-  FixedArray* result_elms = FixedArray::cast(result);
-
-  // Ensure element type transitions happen before copying elements in.
-  if (result_array->HasFastSmiOnlyElements()) {
-    for (int i = 0; i < n_arguments; i++) {
-      JSArray* array = JSArray::cast(args[i]);
-      if (!array->HasFastSmiOnlyElements()) {
-        result_array->EnsureCanContainHeapObjectElements();
-        break;
-      }
-    }
-  }
+  JSArray* result_array;
+  MaybeObject* maybe_array =
+      heap->AllocateJSArrayAndStorage(elements_kind,
+                                      result_len,
+                                      result_len);
+  if (!maybe_array->To(&result_array)) return maybe_array;
+  if (result_len == 0) return result_array;
 
   // Copy data.
-  AssertNoAllocation no_gc;
   int start_pos = 0;
+  FixedArray* result_elms(FixedArray::cast(result_array->elements()));
   for (int i = 0; i < n_arguments; i++) {
     JSArray* array = JSArray::cast(args[i]);
     int len = Smi::cast(array->length())->value();
-    if (len > 0) {
-      FixedArray* elms = FixedArray::cast(array->elements());
-      CopyElements(heap, &no_gc, result_elms, start_pos, elms, 0, len);
-      start_pos += len;
-    }
+    FixedArray* elms = FixedArray::cast(array->elements());
+    CopyObjectToObjectElements(elms, FAST_ELEMENTS, 0,
+                               result_elms, FAST_ELEMENTS,
+                               start_pos, len);
+    start_pos += len;
   }
   ASSERT(start_pos == result_len);
 
-  // Set the length and elements.
-  result_array->set_length(Smi::FromInt(result_len));
-  result_array->set_elements(result_elms);
-
   return result_array;
 }
 
@@ -1592,11 +1487,6 @@
 }
 
 
-static void Generate_ConstructCall_DebugBreak(MacroAssembler* masm) {
-  Debug::GenerateConstructCallDebugBreak(masm);
-}
-
-
 static void Generate_Return_DebugBreak(MacroAssembler* masm) {
   Debug::GenerateReturnDebugBreak(masm);
 }
@@ -1607,6 +1497,23 @@
 }
 
 
+static void Generate_CallFunctionStub_Recording_DebugBreak(
+    MacroAssembler* masm) {
+  Debug::GenerateCallFunctionStubRecordDebugBreak(masm);
+}
+
+
+static void Generate_CallConstructStub_DebugBreak(MacroAssembler* masm) {
+  Debug::GenerateCallConstructStubDebugBreak(masm);
+}
+
+
+static void Generate_CallConstructStub_Recording_DebugBreak(
+    MacroAssembler* masm) {
+  Debug::GenerateCallConstructStubRecordDebugBreak(masm);
+}
+
+
 static void Generate_Slot_DebugBreak(MacroAssembler* masm) {
   Debug::GenerateSlotDebugBreak(masm);
 }
@@ -1660,30 +1567,30 @@
   BuiltinExtraArguments extra_args;
 };
 
+#define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }
+
 class BuiltinFunctionTable {
  public:
-  BuiltinFunctionTable() {
-    Builtins::InitBuiltinFunctionTable();
+  BuiltinDesc* functions() {
+    CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
+    return functions_;
   }
 
-  static const BuiltinDesc* functions() { return functions_; }
-
- private:
-  static BuiltinDesc functions_[Builtins::builtin_count + 1];
+  OnceType once_;
+  BuiltinDesc functions_[Builtins::builtin_count + 1];
 
   friend class Builtins;
 };
 
-BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1];
-
-static const BuiltinFunctionTable builtin_function_table_init;
+static BuiltinFunctionTable builtin_function_table =
+    BUILTIN_FUNCTION_TABLE_INIT;
 
 // Define array of pointers to generators and C builtin functions.
 // We do this in a sort of roundabout way so that we can do the initialization
 // within the lexical scope of Builtins:: and within a context where
 // Code::Flags names a non-abstract type.
 void Builtins::InitBuiltinFunctionTable() {
-  BuiltinDesc* functions = BuiltinFunctionTable::functions_;
+  BuiltinDesc* functions = builtin_function_table.functions_;
   functions[builtin_count].generator = NULL;
   functions[builtin_count].c_code = NULL;
   functions[builtin_count].s_name = NULL;
@@ -1727,7 +1634,7 @@
   // Create a scope for the handles in the builtins.
   HandleScope scope(isolate);
 
-  const BuiltinDesc* functions = BuiltinFunctionTable::functions();
+  const BuiltinDesc* functions = builtin_function_table.functions();
 
   // For now we generate builtin adaptor code into a stack-allocated
   // buffer, before copying it into individual code objects. Be careful