Improved performance of Array.prototype.concat by moving the implementation to C++ (issue 123).

Fixed heap growth policy to avoid growing old space to its maximum capacity before doing a garbage collection and fixed issue that would lead to artificial out of memory situations (issue 129).

Fixed Date.prototype.toLocaleDateString to return the date in the same format as WebKit.

Added missing initialization checks to debugger API.

Added removing of unused maps during GC.


git-svn-id: http://v8.googlecode.com/svn/trunk@655 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/heap-inl.h b/src/heap-inl.h
index bfa2b65..b54ef3a 100644
--- a/src/heap-inl.h
+++ b/src/heap-inl.h
@@ -39,8 +39,12 @@
 
 
 Object* Heap::AllocateRaw(int size_in_bytes,
-                          AllocationSpace space) {
+                          AllocationSpace space,
+                          AllocationSpace retry_space) {
   ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC);
+  ASSERT(space != NEW_SPACE ||
+         retry_space == OLD_POINTER_SPACE ||
+         retry_space == OLD_DATA_SPACE);
 #ifdef DEBUG
   if (FLAG_gc_interval >= 0 &&
       !disallow_allocation_failure_ &&
@@ -50,11 +54,16 @@
   Counters::objs_since_last_full.Increment();
   Counters::objs_since_last_young.Increment();
 #endif
+  Object* result;
   if (NEW_SPACE == space) {
-    return new_space_.AllocateRaw(size_in_bytes);
+    result = new_space_.AllocateRaw(size_in_bytes);
+    if (always_allocate() && result->IsFailure()) {
+      space = retry_space;
+    } else {
+      return result;
+    }
   }
 
-  Object* result;
   if (OLD_POINTER_SPACE == space) {
     result = old_pointer_space_->AllocateRaw(size_in_bytes);
   } else if (OLD_DATA_SPACE == space) {
@@ -132,17 +141,25 @@
 
 
 OldSpace* Heap::TargetSpace(HeapObject* object) {
+  InstanceType type = object->map()->instance_type();
+  AllocationSpace space = TargetSpaceId(type);
+  return (space == OLD_POINTER_SPACE)
+      ? old_pointer_space_
+      : old_data_space_;
+}
+
+
+AllocationSpace Heap::TargetSpaceId(InstanceType type) {
   // Heap numbers and sequential strings are promoted to old data space, all
   // other object types are promoted to old pointer space.  We do not use
   // object->IsHeapNumber() and object->IsSeqString() because we already
   // know that object has the heap object tag.
-  InstanceType type = object->map()->instance_type();
   ASSERT((type != CODE_TYPE) && (type != MAP_TYPE));
   bool has_pointers =
       type != HEAP_NUMBER_TYPE &&
       (type >= FIRST_NONSTRING_TYPE ||
-       String::cast(object)->representation_tag() != kSeqStringTag);
-  return has_pointers ? old_pointer_space_ : old_data_space_;
+       (type & kStringRepresentationMask) != kSeqStringTag);
+  return has_pointers ? OLD_POINTER_SPACE : OLD_DATA_SPACE;
 }
 
 
@@ -188,74 +205,59 @@
 #define GC_GREEDY_CHECK() \
   ASSERT(!FLAG_gc_greedy || v8::internal::Heap::GarbageCollectionGreedyCheck())
 
-// Do not use the identifier __object__ in a call to this macro.
-//
-// Call the function FUNCTION_CALL.  If it fails with a RetryAfterGC
-// failure, call the garbage collector and retry the function.  If the
-// garbage collector cannot reclaim the required space or the second
-// call fails with a RetryAfterGC failure, fail with out of memory.
-// If there is any other failure, return a null handle.  If either
-// call succeeds, return a handle to the functions return value.
-//
-// Note that this macro always returns or raises a fatal error.
-#define CALL_HEAP_FUNCTION(FUNCTION_CALL, TYPE)                              \
-  do {                                                                       \
-    GC_GREEDY_CHECK();                                                       \
-    Object* __object__ = FUNCTION_CALL;                                      \
-    if (__object__->IsFailure()) {                                           \
-      if (__object__->IsRetryAfterGC()) {                                    \
-        if (!Heap::CollectGarbage(                                           \
-                Failure::cast(__object__)->requested(),                      \
-                Failure::cast(__object__)->allocation_space())) {            \
-          /* TODO(1181417): Fix this. */                                     \
-          v8::internal::V8::FatalProcessOutOfMemory("CALL_HEAP_FUNCTION");   \
-        }                                                                    \
-        __object__ = FUNCTION_CALL;                                          \
-        if (__object__->IsFailure()) {                                       \
-          if (__object__->IsRetryAfterGC()) {                                \
-            /* TODO(1181417): Fix this. */                                   \
-            v8::internal::V8::FatalProcessOutOfMemory("CALL_HEAP_FUNCTION"); \
-          }                                                                  \
-          return Handle<TYPE>();                                             \
-        }                                                                    \
-      } else {                                                               \
-        if (__object__->IsOutOfMemoryFailure()) {                            \
-          v8::internal::V8::FatalProcessOutOfMemory("CALL_HEAP_FUNCTION");   \
-        }                                                                    \
-        return Handle<TYPE>();                                               \
-      }                                                                      \
-    }                                                                        \
-    return Handle<TYPE>(TYPE::cast(__object__));                             \
+
+// Calls the FUNCTION_CALL function and retries it up to three times
+// to guarantee that any allocations performed during the call will
+// succeed if there's enough memory.
+
+// Warning: Do not use the identifiers __object__ or __scope__ in a
+// call to this macro.
+
+#define CALL_AND_RETRY(FUNCTION_CALL, RETURN_VALUE, RETURN_EMPTY)         \
+  do {                                                                    \
+    GC_GREEDY_CHECK();                                                    \
+    Object* __object__ = FUNCTION_CALL;                                   \
+    if (!__object__->IsFailure()) return RETURN_VALUE;                    \
+    if (__object__->IsOutOfMemoryFailure()) {                             \
+      v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_0");      \
+    }                                                                     \
+    if (!__object__->IsRetryAfterGC()) return RETURN_EMPTY;               \
+    if (!Heap::CollectGarbage(                                            \
+            Failure::cast(__object__)->requested(),                       \
+            Failure::cast(__object__)->allocation_space())) {             \
+      v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_1");      \
+      return RETURN_EMPTY;                                                \
+    }                                                                     \
+    __object__ = FUNCTION_CALL;                                           \
+    if (!__object__->IsFailure()) return RETURN_VALUE;                    \
+    if (__object__->IsOutOfMemoryFailure()) {                             \
+      v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_2");      \
+    }                                                                     \
+    if (!__object__->IsRetryAfterGC()) return RETURN_EMPTY;               \
+    Counters::gc_last_resort_from_handles.Increment();                    \
+    Heap::CollectAllGarbage();                                            \
+    {                                                                     \
+      AlwaysAllocateScope __scope__;                                      \
+      __object__ = FUNCTION_CALL;                                         \
+    }                                                                     \
+    if (!__object__->IsFailure()) return RETURN_VALUE;                    \
+    if (__object__->IsOutOfMemoryFailure()) {                             \
+      /* TODO(1181417): Fix this. */                                      \
+      v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_3");      \
+    }                                                                     \
+    ASSERT(!__object__->IsRetryAfterGC());                                \
+    return RETURN_EMPTY;                                                  \
   } while (false)
 
 
-// Don't use the following names: __object__, __failure__.
-#define CALL_HEAP_FUNCTION_VOID(FUNCTION_CALL)                      \
-  GC_GREEDY_CHECK();                                                \
-  Object* __object__ = FUNCTION_CALL;                               \
-  if (__object__->IsFailure()) {                                    \
-    if (__object__->IsRetryAfterGC()) {                             \
-      Failure* __failure__ = Failure::cast(__object__);             \
-      if (!Heap::CollectGarbage(__failure__->requested(),           \
-                                __failure__->allocation_space())) { \
-         /* TODO(1181417): Fix this. */                             \
-         V8::FatalProcessOutOfMemory("Handles");                    \
-      }                                                             \
-      __object__ = FUNCTION_CALL;                                   \
-      if (__object__->IsFailure()) {                                \
-        if (__object__->IsRetryAfterGC()) {                         \
-           /* TODO(1181417): Fix this. */                           \
-           V8::FatalProcessOutOfMemory("Handles");                  \
-        }                                                           \
-        return;                                                     \
-      }                                                             \
-    } else {                                                        \
-      if (__object__->IsOutOfMemoryFailure()) {                     \
-         V8::FatalProcessOutOfMemory("Handles");                    \
-      }                                                             \
-      UNREACHABLE();                                                \
-    }                                                               \
-  }
+#define CALL_HEAP_FUNCTION(FUNCTION_CALL, TYPE)         \
+  CALL_AND_RETRY(FUNCTION_CALL,                         \
+                 Handle<TYPE>(TYPE::cast(__object__)),  \
+                 Handle<TYPE>())
+
+
+#define CALL_HEAP_FUNCTION_VOID(FUNCTION_CALL) \
+  CALL_AND_RETRY(FUNCTION_CALL, , )
 
 
 #ifdef DEBUG