Index: src/heap-inl.h |
=================================================================== |
--- src/heap-inl.h (revision 645) |
+++ src/heap-inl.h (working copy) |
@@ -39,8 +39,12 @@ |
Object* Heap::AllocateRaw(int size_in_bytes, |
- AllocationSpace space) { |
+ AllocationSpace space, |
+ AllocationSpace retry_space) { |
Erik Corry
2008/10/30 09:08:43
This is fine for now. In the long run I think we
|
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,13 @@ |
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()) return result; |
Mads Ager (chromium)
2008/10/30 08:48:14
Normally, I like these bail-outs instead of if-els
|
+ space = retry_space; |
} |
- Object* result; |
if (OLD_POINTER_SPACE == space) { |
result = old_pointer_space_->AllocateRaw(size_in_bytes); |
} else if (OLD_DATA_SPACE == space) { |
@@ -132,17 +138,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,76 +202,60 @@ |
#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 |
Erik Corry
2008/10/30 09:08:43
I don't really feel we need this warning, but if w
|
+// 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"); \ |
Erik Corry
2008/10/30 09:08:43
Is there a subtle fall-through here? Comment need
|
+ } \ |
+ 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"); \ |
+ } \ |
+ __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 |
inline bool Heap::allow_allocation(bool new_state) { |