Index: src/factory.cc |
diff --git a/src/factory.cc b/src/factory.cc |
index 12d7f5750e3909c37d680b33052e5e38a343c72c..d6dd38d963d6dfeff29c20fe56ff14ca2344ed94 100644 |
--- a/src/factory.cc |
+++ b/src/factory.cc |
@@ -15,6 +15,44 @@ namespace v8 { |
namespace internal { |
+// 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__, __maybe_object__, |
+// __allocation__ or __scope__ in a call to this macro. |
+ |
+#define RETURN_OBJECT_UNLESS_RETRY(ISOLATE, TYPE) \ |
+ if (__allocation__.To(&__object__)) { \ |
+ DCHECK(__object__ != (ISOLATE)->heap()->exception()); \ |
+ return Handle<TYPE>(TYPE::cast(__object__), ISOLATE); \ |
+ } |
+ |
+#define CALL_HEAP_FUNCTION(ISOLATE, FUNCTION_CALL, TYPE) \ |
+ do { \ |
+ AllocationResult __allocation__ = FUNCTION_CALL; \ |
+ Object* __object__ = NULL; \ |
+ RETURN_OBJECT_UNLESS_RETRY(ISOLATE, TYPE) \ |
+ /* Two GCs before panicking. In newspace will almost always succeed. */ \ |
+ for (int __i__ = 0; __i__ < 2; __i__++) { \ |
+ (ISOLATE)->heap()->CollectGarbage(__allocation__.RetrySpace(), \ |
+ "allocation failure"); \ |
+ __allocation__ = FUNCTION_CALL; \ |
+ RETURN_OBJECT_UNLESS_RETRY(ISOLATE, TYPE) \ |
+ } \ |
+ (ISOLATE)->counters()->gc_last_resort_from_handles()->Increment(); \ |
+ (ISOLATE)->heap()->CollectAllAvailableGarbage("last resort gc"); \ |
+ { \ |
+ AlwaysAllocateScope __scope__(ISOLATE); \ |
+ __allocation__ = FUNCTION_CALL; \ |
+ } \ |
+ RETURN_OBJECT_UNLESS_RETRY(ISOLATE, TYPE) \ |
+ /* TODO(1181417): Fix this. */ \ |
+ v8::internal::Heap::FatalProcessOutOfMemory("CALL_AND_RETRY_LAST", true); \ |
+ return Handle<TYPE>(); \ |
+ } while (false) |
+ |
+ |
template<typename T> |
Handle<T> Factory::New(Handle<Map> map, AllocationSpace space) { |
CALL_HEAP_FUNCTION( |