Revision: 20183
Author:   yang...@chromium.org
Date:     Mon Mar 24 09:17:18 2014 UTC
Log: Revert "Remove Failure::OutOfMemory propagation and V8::IgnoreOutOfMemoryException."

This reverts r20179.

TBR=svenpa...@chromium.org

Review URL: https://codereview.chromium.org/201573007
http://code.google.com/p/v8/source/detail?r=20183

Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/api.cc
 /branches/bleeding_edge/src/arm/code-stubs-arm.cc
 /branches/bleeding_edge/src/arm64/code-stubs-arm64.cc
 /branches/bleeding_edge/src/bootstrapper.cc
 /branches/bleeding_edge/src/code-stubs.h
 /branches/bleeding_edge/src/contexts.h
 /branches/bleeding_edge/src/elements.cc
 /branches/bleeding_edge/src/execution.cc
 /branches/bleeding_edge/src/heap-inl.h
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
 /branches/bleeding_edge/src/isolate.cc
 /branches/bleeding_edge/src/isolate.h
 /branches/bleeding_edge/src/mips/code-stubs-mips.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc
 /branches/bleeding_edge/test/cctest/test-api.cc
 /branches/bleeding_edge/test/cctest/test-strings.cc

=======================================
--- /branches/bleeding_edge/include/v8.h        Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/include/v8.h        Mon Mar 24 09:17:18 2014 UTC
@@ -4615,6 +4615,20 @@
    */
   static void SetArrayBufferAllocator(ArrayBuffer::Allocator* allocator);

+  /**
+   * Ignore out-of-memory exceptions.
+   *
+   * V8 running out of memory is treated as a fatal error by default.
+   * This means that the fatal error handler is called and that V8 is
+   * terminated.
+   *
+   * IgnoreOutOfMemoryException can be used to not treat an
+   * out-of-memory situation as a fatal error.  This way, the contexts
+   * that did not cause the out of memory problem might be able to
+   * continue execution.
+   */
+  static void IgnoreOutOfMemoryException();
+
   /**
    * Check if V8 is dead and therefore unusable.  This is the case after
    * fatal errors such as out-of-memory situations.
@@ -5219,6 +5233,9 @@
    */
   void Exit();

+ /** Returns true if the context has experienced an out of memory situation. */
+  bool HasOutOfMemoryException();
+
   /** Returns an isolate associated with a current context. */
   v8::Isolate* GetIsolate();

=======================================
--- /branches/bleeding_edge/src/api.cc  Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/api.cc  Mon Mar 24 09:17:18 2014 UTC
@@ -95,6 +95,11 @@
(isolate)->handle_scope_implementer(); \ handle_scope_implementer->DecrementCallDepth(); \ if (has_pending_exception) { \ + if (handle_scope_implementer->CallDepthIsZero() && \ + (isolate)->is_out_of_memory()) { \ + if (!(isolate)->ignore_out_of_memory()) \ + i::V8::FatalProcessOutOfMemory(NULL); \ + } \ bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero(); \ (isolate)->OptionalRescheduleException(call_depth_is_zero); \ do_callback \
@@ -5254,6 +5259,12 @@
   i::Handle<i::Object> token_handle(security_token, isolate);
   return Utils::ToLocal(token_handle);
 }
+
+
+bool Context::HasOutOfMemoryException() {
+  i::Handle<i::Context> env = Utils::OpenHandle(this);
+  return env->has_out_of_memory();
+}


 v8::Isolate* Context::GetIsolate() {
@@ -6212,6 +6223,11 @@
i::Handle<i::Object> result = internal_isolate->factory()->NewNumber(value);
   return Utils::IntegerToLocal(result);
 }
+
+
+void V8::IgnoreOutOfMemoryException() {
+  EnterIsolateIfNeeded()->set_ignore_out_of_memory(true);
+}


 bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) {
=======================================
--- /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Mar 24 08:47:45 2014 UTC +++ /branches/bleeding_edge/src/arm/code-stubs-arm.cc Mon Mar 24 09:17:18 2014 UTC
@@ -1499,11 +1499,24 @@
   CEntryStub stub(1, kDontSaveFPRegs);
   stub.GetCode(isolate);
 }
+
+
+static void JumpIfOOM(MacroAssembler* masm,
+                      Register value,
+                      Register scratch,
+                      Label* oom_label) {
+  STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
+  STATIC_ASSERT(kFailureTag == 3);
+  __ and_(scratch, value, Operand(0xf));
+  __ cmp(scratch, Operand(0xf));
+  __ b(eq, oom_label);
+}


 void CEntryStub::GenerateCore(MacroAssembler* masm,
                               Label* throw_normal_exception,
                               Label* throw_termination_exception,
+                              Label* throw_out_of_memory_exception,
                               bool do_gc,
                               bool always_allocate) {
   // r0: result parameter for PerformGC, if any
@@ -1601,11 +1614,17 @@
   __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
   __ b(eq, &retry);

+  // Special handling of out of memory exceptions.
+  JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
+
   // Retrieve the pending exception.
   __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
                                        isolate)));
   __ ldr(r0, MemOperand(ip));

+  // See if we just retrieved an OOM exception.
+  JumpIfOOM(masm, r0, ip, throw_out_of_memory_exception);
+
   // Clear the pending exception.
   __ LoadRoot(r3, Heap::kTheHoleValueRootIndex);
   __ mov(ip, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
@@ -1660,11 +1679,13 @@

   Label throw_normal_exception;
   Label throw_termination_exception;
+  Label throw_out_of_memory_exception;

   // Call into the runtime system.
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                false,
                false);

@@ -1672,6 +1693,7 @@
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                false);

@@ -1681,9 +1703,30 @@
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                true);

+  __ bind(&throw_out_of_memory_exception);
+  // Set external caught exception to false.
+  Isolate* isolate = masm->isolate();
+ ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
+                                    isolate);
+  __ mov(r0, Operand(false, RelocInfo::NONE32));
+  __ mov(r2, Operand(external_caught));
+  __ str(r0, MemOperand(r2));
+
+  // Set pending exception and r0 to out of memory exception.
+  Label already_have_failure;
+  JumpIfOOM(masm, r0, ip, &already_have_failure);
+  Failure* out_of_memory = Failure::OutOfMemoryException(0x1);
+  __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
+  __ bind(&already_have_failure);
+  __ mov(r2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                       isolate)));
+  __ str(r0, MemOperand(r2));
+  // Fall through to the next label.
+
   __ bind(&throw_termination_exception);
   __ ThrowUncatchable(r0);

=======================================
--- /branches/bleeding_edge/src/arm64/code-stubs-arm64.cc Mon Mar 24 08:47:45 2014 UTC +++ /branches/bleeding_edge/src/arm64/code-stubs-arm64.cc Mon Mar 24 09:17:18 2014 UTC
@@ -1403,6 +1403,18 @@
   // nothing to do here.
   USE(isolate);
 }
+
+
+static void JumpIfOOM(MacroAssembler* masm,
+                      Register value,
+                      Register scratch,
+                      Label* oom_label) {
+  STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
+  STATIC_ASSERT(kFailureTag == 3);
+  __ And(scratch, value, 0xf);
+  __ Cmp(scratch, 0xf);
+  __ B(eq, oom_label);
+}


 bool CEntryStub::NeedsImmovableCode() {
@@ -1429,6 +1441,7 @@
 void CEntryStub::GenerateCore(MacroAssembler* masm,
                               Label* throw_normal,
                               Label* throw_termination,
+                              Label* throw_out_of_memory,
                               bool do_gc,
                               bool always_allocate) {
   // x0  : Result parameter for PerformGC, if do_gc is true.
@@ -1576,6 +1589,10 @@
   __ Tst(result, kFailureTypeTagMask << kFailureTagSize);
   __ B(eq, &retry);   // RETRY_AFTER_GC

+  // Special handling of out-of-memory exceptions: Pass the failure result,
+  // rather than the exception descriptor.
+  JumpIfOOM(masm, result, x10, throw_out_of_memory);
+
   // Retrieve the pending exception.
   const Register& exception = result;
   const Register& exception_address = x11;
@@ -1584,6 +1601,9 @@
                                    isolate)));
   __ Ldr(exception, MemOperand(exception_address));

+  // See if we just retrieved an OOM exception.
+  JumpIfOOM(masm, exception, x10, throw_out_of_memory);
+
   // Clear the pending exception.
   __ Mov(x10, Operand(isolate->factory()->the_hole_value()));
   __ Str(x10, MemOperand(exception_address));
@@ -1677,11 +1697,13 @@

   Label throw_normal;
   Label throw_termination;
+  Label throw_out_of_memory;

   // Call the runtime function.
   GenerateCore(masm,
                &throw_normal,
                &throw_termination,
+               &throw_out_of_memory,
                false,
                false);

@@ -1692,6 +1714,7 @@
   GenerateCore(masm,
                &throw_normal,
                &throw_termination,
+               &throw_out_of_memory,
                true,
                false);

@@ -1700,6 +1723,7 @@
   GenerateCore(masm,
                &throw_normal,
                &throw_termination,
+               &throw_out_of_memory,
                true,
                true);

@@ -1716,6 +1740,27 @@
// If we throw an exception, we can end up re-entering CEntryStub before we // pop the exit frame, so need to ensure that x21-x23 contain GC-safe values
   // here.
+  __ Bind(&throw_out_of_memory);
+  ASM_LOCATION("Throw out of memory");
+  __ Mov(argv, 0);
+  __ Mov(argc, 0);
+  __ Mov(target, 0);
+  // Set external caught exception to false.
+  Isolate* isolate = masm->isolate();
+ __ Mov(x2, Operand(ExternalReference(Isolate::kExternalCaughtExceptionAddress,
+                                       isolate)));
+  __ Str(xzr, MemOperand(x2));
+
+  // Set pending exception and x0 to out of memory exception.
+  Label already_have_failure;
+  JumpIfOOM(masm, x0, x10, &already_have_failure);
+  Failure* out_of_memory = Failure::OutOfMemoryException(0x1);
+  __ Mov(x0, Operand(reinterpret_cast<uint64_t>(out_of_memory)));
+  __ Bind(&already_have_failure);
+  __ Mov(x2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                       isolate)));
+  __ Str(x0, MemOperand(x2));
+  // Fall through to the next label.

   __ Bind(&throw_termination);
   ASM_LOCATION("Throw termination");
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/bootstrapper.cc Mon Mar 24 09:17:18 2014 UTC
@@ -1309,6 +1309,9 @@
     native_context()->set_call_as_constructor_delegate(*delegate);
     delegate->shared()->DontAdaptArguments();
   }
+
+  // Initialize the out of memory slot.
+  native_context()->set_out_of_memory(heap->false_value());

   // Initialize the embedder data slot.
   Handle<FixedArray> embedder_data = factory->NewFixedArray(3);
=======================================
--- /branches/bleeding_edge/src/code-stubs.h    Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/code-stubs.h    Mon Mar 24 09:17:18 2014 UTC
@@ -1496,6 +1496,7 @@
   void GenerateCore(MacroAssembler* masm,
                     Label* throw_normal_exception,
                     Label* throw_termination_exception,
+                    Label* throw_out_of_memory_exception,
                     bool do_gc,
                     bool always_allocate_scope);

=======================================
--- /branches/bleeding_edge/src/contexts.h      Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/contexts.h      Mon Mar 24 09:17:18 2014 UTC
@@ -162,6 +162,7 @@
   V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
V(OPAQUE_REFERENCE_FUNCTION_INDEX, JSFunction, opaque_reference_function) \ V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
+  V(OUT_OF_MEMORY_INDEX, Object, out_of_memory) \
   V(MAP_CACHE_INDEX, Object, map_cache) \
   V(EMBEDDER_DATA_INDEX, FixedArray, embedder_data) \
V(ALLOW_CODE_GEN_FROM_STRINGS_INDEX, Object, allow_code_gen_from_strings) \
@@ -438,6 +439,12 @@
     Map* map = this->map();
     return map == map->GetHeap()->global_context_map();
   }
+
+  // Tells whether the native context is marked with out of memory.
+  inline bool has_out_of_memory();
+
+  // Mark the native context with out of memory.
+  inline void mark_out_of_memory();

   // A native context holds a list of all functions with optimized code.
   void AddOptimizedFunction(JSFunction* function);
=======================================
--- /branches/bleeding_edge/src/elements.cc     Mon Mar 24 09:06:04 2014 UTC
+++ /branches/bleeding_edge/src/elements.cc     Mon Mar 24 09:17:18 2014 UTC
@@ -318,7 +318,7 @@
// that no GC is triggered, allocate HeapNumbers from old space if they
       // can't be taken from new space.
       if (!maybe_value->ToObject(&value)) {
-        ASSERT(maybe_value->IsRetryAfterGC());
+ ASSERT(maybe_value->IsRetryAfterGC() || maybe_value->IsOutOfMemory());
         Heap* heap = from->GetHeap();
         MaybeObject* maybe_value_object =
             heap->AllocateHeapNumber(from->get_scalar(i + from_start),
=======================================
--- /branches/bleeding_edge/src/execution.cc    Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/execution.cc    Mon Mar 24 09:17:18 2014 UTC
@@ -135,6 +135,11 @@
   ASSERT(*has_pending_exception == isolate->has_pending_exception());
   if (*has_pending_exception) {
     isolate->ReportPendingMessages();
+    if (isolate->pending_exception()->IsOutOfMemory()) {
+      if (!isolate->ignore_out_of_memory()) {
+        V8::FatalProcessOutOfMemory("JS", true);
+      }
+    }
 #ifdef ENABLE_DEBUGGER_SUPPORT
     // Reset stepping state when script exits with uncaught exception.
     if (isolate->debugger()->IsDebuggerActive()) {
@@ -220,6 +225,9 @@
     ASSERT(catcher.HasCaught());
     ASSERT(isolate->has_pending_exception());
     ASSERT(isolate->external_caught_exception());
+    if (isolate->is_out_of_memory() && !isolate->ignore_out_of_memory()) {
+      V8::FatalProcessOutOfMemory("OOM during Execution::TryCall");
+    }
     if (isolate->pending_exception() ==
         isolate->heap()->termination_exception()) {
       result = isolate->factory()->termination_exception();
=======================================
--- /branches/bleeding_edge/src/heap-inl.h      Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/heap-inl.h      Mon Mar 24 09:17:18 2014 UTC
@@ -138,7 +138,7 @@
MaybeObject* Heap::AllocateOneByteInternalizedString(Vector<const uint8_t> str,
                                                      uint32_t hash_field) {
   if (str.length() > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return Failure::OutOfMemoryException(0x2);
   }
   // Compute map and object size.
   Map* map = ascii_internalized_string_map();
@@ -171,7 +171,7 @@
MaybeObject* Heap::AllocateTwoByteInternalizedString(Vector<const uc16> str,
                                                      uint32_t hash_field) {
   if (str.length() > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return Failure::OutOfMemoryException(0x3);
   }
   // Compute map and object size.
   Map* map = internalized_string_map();
@@ -641,18 +641,24 @@
 // Warning: Do not use the identifiers __object__, __maybe_object__ or
 // __scope__ in a call to this macro.

-#define CALL_AND_RETRY(ISOLATE, FUNCTION_CALL, RETURN_VALUE, RETURN_EMPTY) \ +#define CALL_AND_RETRY(ISOLATE, FUNCTION_CALL, RETURN_VALUE, RETURN_EMPTY, OOM)\ do { \ GC_GREEDY_CHECK(ISOLATE); \ MaybeObject* __maybe_object__ = FUNCTION_CALL; \ Object* __object__ = NULL; \ if (__maybe_object__->ToObject(&__object__)) RETURN_VALUE; \ + if (__maybe_object__->IsOutOfMemory()) { \ + OOM; \ + } \ if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY; \ (ISOLATE)->heap()->CollectGarbage(Failure::cast(__maybe_object__)-> \ allocation_space(), \ "allocation failure"); \ __maybe_object__ = FUNCTION_CALL; \ if (__maybe_object__->ToObject(&__object__)) RETURN_VALUE; \ + if (__maybe_object__->IsOutOfMemory()) { \ + OOM; \ + } \ if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY; \ (ISOLATE)->counters()->gc_last_resort_from_handles()->Increment(); \ (ISOLATE)->heap()->CollectAllAvailableGarbage("last resort gc"); \
@@ -661,6 +667,9 @@
__maybe_object__ = FUNCTION_CALL; \ } \ if (__maybe_object__->ToObject(&__object__)) RETURN_VALUE; \ + if (__maybe_object__->IsOutOfMemory()) { \ + OOM; \ + } \ if (__maybe_object__->IsRetryAfterGC()) { \ /* TODO(1181417): Fix this. */ \ v8::internal::Heap::FatalProcessOutOfMemory("CALL_AND_RETRY_LAST", true);\
@@ -674,7 +683,8 @@
ISOLATE, \ FUNCTION_CALL, \ RETURN_VALUE, \
-      RETURN_EMPTY)
+ RETURN_EMPTY, \
+      v8::internal::Heap::FatalProcessOutOfMemory("CALL_AND_RETRY", true))

#define CALL_HEAP_FUNCTION(ISOLATE, FUNCTION_CALL, TYPE) \ CALL_AND_RETRY_OR_DIE(ISOLATE, \
@@ -691,6 +701,7 @@
   CALL_AND_RETRY(ISOLATE,                                         \
                  FUNCTION_CALL,                                   \
                  return __object__,                               \
+                 return __maybe_object__,                         \
                  return __maybe_object__)


=======================================
--- /branches/bleeding_edge/src/heap.cc Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/heap.cc Mon Mar 24 09:17:18 2014 UTC
@@ -3871,7 +3871,8 @@
     const ExternalAsciiString::Resource* resource) {
   size_t length = resource->length();
   if (length > static_cast<size_t>(String::kMaxLength)) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    isolate()->context()->mark_out_of_memory();
+    return Failure::OutOfMemoryException(0x5);
   }

   Map* map = external_ascii_string_map();
@@ -3893,7 +3894,8 @@
     const ExternalTwoByteString::Resource* resource) {
   size_t length = resource->length();
   if (length > static_cast<size_t>(String::kMaxLength)) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    isolate()->context()->mark_out_of_memory();
+    return Failure::OutOfMemoryException(0x6);
   }

   // For small strings we check whether the resource contains only
@@ -3944,7 +3946,7 @@

 MaybeObject* Heap::AllocateByteArray(int length, PretenureFlag pretenure) {
   if (length < 0 || length > ByteArray::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true);
+    return Failure::OutOfMemoryException(0x7);
   }
   int size = ByteArray::SizeFor(length);
   AllocationSpace space = SelectSpace(size, OLD_DATA_SPACE, pretenure);
@@ -4979,7 +4981,7 @@
   Map* map;

   if (chars > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return Failure::OutOfMemoryException(0x9);
   }
   if (is_one_byte) {
     map = ascii_internalized_string_map();
@@ -5027,7 +5029,7 @@
 MaybeObject* Heap::AllocateRawOneByteString(int length,
                                             PretenureFlag pretenure) {
   if (length < 0 || length > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return Failure::OutOfMemoryException(0xb);
   }
   int size = SeqOneByteString::SizeFor(length);
   ASSERT(size <= SeqOneByteString::kMaxSize);
@@ -5051,7 +5053,7 @@
 MaybeObject* Heap::AllocateRawTwoByteString(int length,
                                             PretenureFlag pretenure) {
   if (length < 0 || length > String::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
+    return Failure::OutOfMemoryException(0xc);
   }
   int size = SeqTwoByteString::SizeFor(length);
   ASSERT(size <= SeqTwoByteString::kMaxSize);
@@ -5199,7 +5201,7 @@

MaybeObject* Heap::AllocateRawFixedArray(int length, PretenureFlag pretenure) {
   if (length < 0 || length > FixedArray::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true);
+    return Failure::OutOfMemoryException(0xe);
   }
   int size = FixedArray::SizeFor(length);
   AllocationSpace space = SelectSpace(size, OLD_POINTER_SPACE, pretenure);
@@ -5311,7 +5313,7 @@
 MaybeObject* Heap::AllocateRawFixedDoubleArray(int length,
                                                PretenureFlag pretenure) {
   if (length < 0 || length > FixedDoubleArray::kMaxLength) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid array length", true);
+    return Failure::OutOfMemoryException(0xf);
   }
   int size = FixedDoubleArray::SizeFor(length);
 #ifndef V8_HOST_ARCH_64_BIT
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Mar 24 08:47:45 2014 UTC +++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Mar 24 09:17:18 2014 UTC
@@ -2581,11 +2581,25 @@
   CEntryStub stub(1, kDontSaveFPRegs);
   stub.GetCode(isolate);
 }
+
+
+static void JumpIfOOM(MacroAssembler* masm,
+                      Register value,
+                      Register scratch,
+                      Label* oom_label) {
+  __ mov(scratch, value);
+  STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
+  STATIC_ASSERT(kFailureTag == 3);
+  __ and_(scratch, 0xf);
+  __ cmp(scratch, 0xf);
+  __ j(equal, oom_label);
+}


 void CEntryStub::GenerateCore(MacroAssembler* masm,
                               Label* throw_normal_exception,
                               Label* throw_termination_exception,
+                              Label* throw_out_of_memory_exception,
                               bool do_gc,
                               bool always_allocate_scope) {
   // eax: result parameter for PerformGC, if any
@@ -2680,9 +2694,15 @@
__ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
   __ j(zero, &retry, Label::kNear);

+  // Special handling of out of memory exceptions.
+  JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
+
   // Retrieve the pending exception.
   __ mov(eax, Operand::StaticVariable(pending_exception_address));

+  // See if we just retrieved an OOM exception.
+  JumpIfOOM(masm, eax, ecx, throw_out_of_memory_exception);
+
   // Clear the pending exception.
   __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value()));
   __ mov(Operand::StaticVariable(pending_exception_address), edx);
@@ -2726,11 +2746,13 @@

   Label throw_normal_exception;
   Label throw_termination_exception;
+  Label throw_out_of_memory_exception;

   // Call into the runtime system.
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                false,
                false);

@@ -2738,6 +2760,7 @@
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                false);

@@ -2747,9 +2770,27 @@
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                true);

+  __ bind(&throw_out_of_memory_exception);
+  // Set external caught exception to false.
+  Isolate* isolate = masm->isolate();
+ ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
+                                    isolate);
+  __ mov(Operand::StaticVariable(external_caught), Immediate(false));
+
+  // Set pending exception and eax to out of memory exception.
+  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
+                                      isolate);
+  Label already_have_failure;
+  JumpIfOOM(masm, eax, ecx, &already_have_failure);
+ __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException(0x1)));
+  __ bind(&already_have_failure);
+  __ mov(Operand::StaticVariable(pending_exception), eax);
+  // Fall through to the next label.
+
   __ bind(&throw_termination_exception);
   __ ThrowUncatchable(eax);

=======================================
--- /branches/bleeding_edge/src/isolate.cc      Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/isolate.cc      Mon Mar 24 09:17:18 2014 UTC
@@ -80,6 +80,10 @@

 ThreadLocalTop::ThreadLocalTop() {
   InitializeInternal();
+  // This flag may be set using v8::V8::IgnoreOutOfMemoryException()
+  // before an isolate is initialized. The initialize methods below do
+  // not touch it to preserve its value.
+  ignore_out_of_memory_ = false;
 }


@@ -1269,8 +1273,14 @@
   ASSERT(has_pending_exception());
   PropagatePendingExceptionToExternalTryCatch();

+  // If the pending exception is OutOfMemoryException set out_of_memory in
+  // the native context.  Note: We have to mark the native context here
+  // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
+  // set it.
   HandleScope scope(this);
-  if (thread_local_top_.pending_exception_ ==
+  if (thread_local_top_.pending_exception_->IsOutOfMemory()) {
+    context()->mark_out_of_memory();
+  } else if (thread_local_top_.pending_exception_ ==
              heap()->termination_exception()) {
     // Do nothing: if needed, the exception has been already propagated to
     // v8::TryCatch.
@@ -1301,7 +1311,8 @@
 MessageLocation Isolate::GetMessageLocation() {
   ASSERT(has_pending_exception());

- if (thread_local_top_.pending_exception_ != heap()->termination_exception() &&
+  if (!thread_local_top_.pending_exception_->IsOutOfMemory() &&
+ thread_local_top_.pending_exception_ != heap()->termination_exception() &&
       thread_local_top_.has_pending_message_ &&
       !thread_local_top_.pending_message_obj_->IsTheHole() &&
       !thread_local_top_.pending_message_obj_->IsTheHole()) {
@@ -1320,36 +1331,39 @@
   ASSERT(has_pending_exception());
   PropagatePendingExceptionToExternalTryCatch();

-  bool is_termination_exception =
-      pending_exception() == heap_.termination_exception();
+  // Always reschedule out of memory exceptions.
+  if (!is_out_of_memory()) {
+    bool is_termination_exception =
+        pending_exception() == heap_.termination_exception();

-  // Do not reschedule the exception if this is the bottom call.
-  bool clear_exception = is_bottom_call;
+    // Do not reschedule the exception if this is the bottom call.
+    bool clear_exception = is_bottom_call;
+
+    if (is_termination_exception) {
+      if (is_bottom_call) {
+        thread_local_top()->external_caught_exception_ = false;
+        clear_pending_exception();
+        return false;
+      }
+    } else if (thread_local_top()->external_caught_exception_) {
+      // If the exception is externally caught, clear it if there are no
+      // JavaScript frames on the way to the C++ frame that has the
+      // external handler.
+      ASSERT(thread_local_top()->try_catch_handler_address() != NULL);
+      Address external_handler_address =
+          thread_local_top()->try_catch_handler_address();
+      JavaScriptFrameIterator it(this);
+      if (it.done() || (it.frame()->sp() > external_handler_address)) {
+        clear_exception = true;
+      }
+    }

-  if (is_termination_exception) {
-    if (is_bottom_call) {
+    // Clear the exception if needed.
+    if (clear_exception) {
       thread_local_top()->external_caught_exception_ = false;
       clear_pending_exception();
       return false;
     }
-  } else if (thread_local_top()->external_caught_exception_) {
-    // If the exception is externally caught, clear it if there are no
-    // JavaScript frames on the way to the C++ frame that has the
-    // external handler.
-    ASSERT(thread_local_top()->try_catch_handler_address() != NULL);
-    Address external_handler_address =
-        thread_local_top()->try_catch_handler_address();
-    JavaScriptFrameIterator it(this);
-    if (it.done() || (it.frame()->sp() > external_handler_address)) {
-      clear_exception = true;
-    }
-  }
-
-  // Clear the exception if needed.
-  if (clear_exception) {
-    thread_local_top()->external_caught_exception_ = false;
-    clear_pending_exception();
-    return false;
   }

   // Reschedule the exception.
@@ -1367,6 +1381,23 @@
   stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit;
   stack_trace_for_uncaught_exceptions_options_ = options;
 }
+
+
+bool Isolate::is_out_of_memory() {
+  if (has_pending_exception()) {
+    MaybeObject* e = pending_exception();
+    if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
+      return true;
+    }
+  }
+  if (has_scheduled_exception()) {
+    MaybeObject* e = scheduled_exception();
+    if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
+      return true;
+    }
+  }
+  return false;
+}


 Handle<Context> Isolate::native_context() {
@@ -1820,7 +1851,9 @@

   if (!external_caught) return;

-  if (thread_local_top_.pending_exception_ ==
+  if (thread_local_top_.pending_exception_->IsOutOfMemory()) {
+    // Do not propagate OOM exception: we should kill VM asap.
+  } else if (thread_local_top_.pending_exception_ ==
              heap()->termination_exception()) {
     try_catch_handler()->can_continue_ = false;
     try_catch_handler()->has_terminated_ = true;
=======================================
--- /branches/bleeding_edge/src/isolate.h       Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/isolate.h       Mon Mar 24 09:17:18 2014 UTC
@@ -288,6 +288,9 @@
   // Head of the list of live LookupResults.
   LookupResult* top_lookup_result_;

+  // Whether out of memory exceptions should be ignored.
+  bool ignore_out_of_memory_;
+
  private:
   void InitializeInternal();

@@ -638,7 +641,8 @@
   bool IsExternallyCaught();

   bool is_catchable_by_javascript(MaybeObject* exception) {
-    return exception != heap()->termination_exception();
+    return (!exception->IsOutOfMemory()) &&
+        (exception != heap()->termination_exception());
   }

   // Serializer.
@@ -717,6 +721,12 @@
       int frame_limit,
       StackTrace::StackTraceOptions options);

+  // Tells whether the current context has experienced an out of memory
+  // exception.
+  bool is_out_of_memory();
+
+  THREAD_LOCAL_TOP_ACCESSOR(bool,  ignore_out_of_memory)
+
   void PrintCurrentStackTrace(FILE* out);
   void PrintStack(StringStream* accumulator);
   void PrintStack(FILE* out);
@@ -1464,6 +1474,17 @@
   Isolate* isolate_;
 };

+
+// Tells whether the native context is marked with out of memory.
+inline bool Context::has_out_of_memory() {
+  return native_context()->out_of_memory()->IsTrue();
+}
+
+
+// Mark the native context with out of memory.
+inline void Context::mark_out_of_memory() {
+  native_context()->set_out_of_memory(GetIsolate()->heap()->true_value());
+}

 class CodeTracer V8_FINAL : public Malloced {
  public:
=======================================
--- /branches/bleeding_edge/src/mips/code-stubs-mips.cc Mon Mar 24 08:47:45 2014 UTC +++ /branches/bleeding_edge/src/mips/code-stubs-mips.cc Mon Mar 24 09:17:18 2014 UTC
@@ -1604,11 +1604,23 @@
   CEntryStub stub(1, kDontSaveFPRegs);
   stub.GetCode(isolate);
 }
+
+
+static void JumpIfOOM(MacroAssembler* masm,
+                      Register value,
+                      Register scratch,
+                      Label* oom_label) {
+  STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
+  STATIC_ASSERT(kFailureTag == 3);
+  __ andi(scratch, value, 0xf);
+  __ Branch(oom_label, eq, scratch, Operand(0xf));
+}


 void CEntryStub::GenerateCore(MacroAssembler* masm,
                               Label* throw_normal_exception,
                               Label* throw_termination_exception,
+                              Label* throw_out_of_memory_exception,
                               bool do_gc,
                               bool always_allocate) {
   // v0: result parameter for PerformGC, if any
@@ -1711,11 +1723,17 @@
   __ andi(t0, v0, ((1 << kFailureTypeTagSize) - 1) << kFailureTagSize);
   __ Branch(&retry, eq, t0, Operand(zero_reg));

+  // Special handling of out of memory exceptions.
+  JumpIfOOM(masm, v0, t0, throw_out_of_memory_exception);
+
   // Retrieve the pending exception.
   __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
                                       isolate)));
   __ lw(v0, MemOperand(t0));

+  // See if we just retrieved an OOM exception.
+  JumpIfOOM(masm, v0, t0, throw_out_of_memory_exception);
+
   // Clear the pending exception.
   __ li(a3, Operand(isolate->factory()->the_hole_value()));
   __ li(t0, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
@@ -1769,11 +1787,13 @@

   Label throw_normal_exception;
   Label throw_termination_exception;
+  Label throw_out_of_memory_exception;

   // Call into the runtime system.
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                false,
                false);

@@ -1781,6 +1801,7 @@
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                false);

@@ -1790,9 +1811,30 @@
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                true);

+  __ bind(&throw_out_of_memory_exception);
+  // Set external caught exception to false.
+  Isolate* isolate = masm->isolate();
+ ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
+                                    isolate);
+  __ li(a0, Operand(false, RelocInfo::NONE32));
+  __ li(a2, Operand(external_caught));
+  __ sw(a0, MemOperand(a2));
+
+  // Set pending exception and v0 to out of memory exception.
+  Label already_have_failure;
+  JumpIfOOM(masm, v0, t0, &already_have_failure);
+  Failure* out_of_memory = Failure::OutOfMemoryException(0x1);
+  __ li(v0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
+  __ bind(&already_have_failure);
+  __ li(a2, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                      isolate)));
+  __ sw(v0, MemOperand(a2));
+  // Fall through to the next label.
+
   __ bind(&throw_termination_exception);
   __ ThrowUncatchable(v0);

=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/objects-inl.h   Mon Mar 24 09:17:18 2014 UTC
@@ -647,6 +647,12 @@
   return HAS_FAILURE_TAG(this)
     && Failure::cast(this)->type() == Failure::RETRY_AFTER_GC;
 }
+
+
+bool MaybeObject::IsOutOfMemory() {
+  return HAS_FAILURE_TAG(this)
+      && Failure::cast(this)->IsOutOfMemoryException();
+}


 bool MaybeObject::IsException() {
@@ -1237,6 +1243,11 @@
 bool Failure::IsInternalError() const {
   return type() == INTERNAL_ERROR;
 }
+
+
+bool Failure::IsOutOfMemoryException() const {
+  return type() == OUT_OF_MEMORY_EXCEPTION;
+}


 AllocationSpace Failure::allocation_space() const {
@@ -1254,6 +1265,11 @@
 Failure* Failure::Exception() {
   return Construct(EXCEPTION);
 }
+
+
+Failure* Failure::OutOfMemoryException(intptr_t value) {
+  return Construct(OUT_OF_MEMORY_EXCEPTION, value);
+}


 intptr_t Failure::value() const {
=======================================
--- /branches/bleeding_edge/src/objects.cc      Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc      Mon Mar 24 09:17:18 2014 UTC
@@ -13921,7 +13921,7 @@
                      ? at_least_space_for
                      : ComputeCapacity(at_least_space_for);
   if (capacity > HashTable::kMaxCapacity) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
+    return Failure::OutOfMemoryException(0x10);
   }

   Object* obj;
=======================================
--- /branches/bleeding_edge/src/objects.h       Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/objects.h       Mon Mar 24 09:17:18 2014 UTC
@@ -934,6 +934,7 @@
  public:
   inline bool IsFailure();
   inline bool IsRetryAfterGC();
+  inline bool IsOutOfMemory();
   inline bool IsException();
   INLINE(bool IsTheHole());
   INLINE(bool IsUninitialized());
@@ -1727,11 +1728,15 @@
   inline AllocationSpace allocation_space() const;

   inline bool IsInternalError() const;
+  inline bool IsOutOfMemoryException() const;

   static inline Failure* RetryAfterGC(AllocationSpace space);
   static inline Failure* RetryAfterGC();  // NEW_SPACE
   static inline Failure* Exception();
   static inline Failure* InternalError();
+  // TODO(jkummerow): The value is temporary instrumentation. Remove it
+  // when it has served its purpose.
+  static inline Failure* OutOfMemoryException(intptr_t value);
   // Casting.
   static inline Failure* cast(MaybeObject* object);

=======================================
--- /branches/bleeding_edge/src/runtime.cc      Mon Mar 24 08:47:45 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc      Mon Mar 24 09:17:18 2014 UTC
@@ -3913,9 +3913,7 @@
        static_cast<int64_t>(pattern_len)) *
       static_cast<int64_t>(matches) +
       static_cast<int64_t>(subject_len);
-  if (result_len_64 > INT_MAX) {
- v8::internal::Heap::FatalProcessOutOfMemory("invalid string length", true);
-  }
+  if (result_len_64 > INT_MAX) return Failure::OutOfMemoryException(0x11);
   int result_len = static_cast<int>(result_len_64);

   int subject_pos = 0;
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Mar 24 08:47:45 2014 UTC +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Mar 24 09:17:18 2014 UTC
@@ -2405,11 +2405,25 @@
   CEntryStub save_doubles(1, kSaveFPRegs);
   save_doubles.GetCode(isolate);
 }
+
+
+static void JumpIfOOM(MacroAssembler* masm,
+                      Register value,
+                      Register scratch,
+                      Label* oom_label) {
+  __ movp(scratch, value);
+  STATIC_ASSERT(Failure::OUT_OF_MEMORY_EXCEPTION == 3);
+  STATIC_ASSERT(kFailureTag == 3);
+  __ and_(scratch, Immediate(0xf));
+  __ cmpq(scratch, Immediate(0xf));
+  __ j(equal, oom_label);
+}


 void CEntryStub::GenerateCore(MacroAssembler* masm,
                               Label* throw_normal_exception,
                               Label* throw_termination_exception,
+                              Label* throw_out_of_memory_exception,
                               bool do_gc,
                               bool always_allocate_scope) {
   // rax: result parameter for PerformGC, if any.
@@ -2516,6 +2530,9 @@
__ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
   __ j(zero, &retry, Label::kNear);

+  // Special handling of out of memory exceptions.
+  JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception);
+
   // Retrieve the pending exception.
   ExternalReference pending_exception_address(
       Isolate::kPendingExceptionAddress, masm->isolate());
@@ -2523,6 +2540,9 @@
       masm->ExternalOperand(pending_exception_address);
   __ movp(rax, pending_exception_operand);

+  // See if we just retrieved an OOM exception.
+  JumpIfOOM(masm, rax, kScratchRegister, throw_out_of_memory_exception);
+
   // Clear the pending exception.
   pending_exception_operand =
       masm->ExternalOperand(pending_exception_address);
@@ -2578,11 +2598,13 @@

   Label throw_normal_exception;
   Label throw_termination_exception;
+  Label throw_out_of_memory_exception;

   // Call into the runtime system.
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                false,
                false);

@@ -2590,6 +2612,7 @@
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                false);

@@ -2599,9 +2622,28 @@
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                true);

+  __ bind(&throw_out_of_memory_exception);
+  // Set external caught exception to false.
+  Isolate* isolate = masm->isolate();
+ ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress,
+                                    isolate);
+  __ Set(rax, static_cast<int64_t>(false));
+  __ Store(external_caught, rax);
+
+  // Set pending exception and rax to out of memory exception.
+  ExternalReference pending_exception(Isolate::kPendingExceptionAddress,
+                                      isolate);
+  Label already_have_failure;
+  JumpIfOOM(masm, rax, kScratchRegister, &already_have_failure);
+ __ Move(rax, Failure::OutOfMemoryException(0x1), Assembler::RelocInfoNone());
+  __ bind(&already_have_failure);
+  __ Store(pending_exception, rax);
+  // Fall through to the next label.
+
   __ bind(&throw_termination_exception);
   __ ThrowUncatchable(rax);

=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Mon Mar 24 08:47:45 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-api.cc Mon Mar 24 09:17:18 2014 UTC
@@ -19332,6 +19332,7 @@
 class InitDefaultIsolateThread : public v8::internal::Thread {
  public:
   enum TestCase {
+    IgnoreOOM,
     SetResourceConstraints,
     SetFatalHandler,
     SetCounterFunction,
@@ -19348,30 +19349,34 @@
     v8::Isolate* isolate = v8::Isolate::New();
     isolate->Enter();
     switch (testCase_) {
-      case SetResourceConstraints: {
-        static const int K = 1024;
-        v8::ResourceConstraints constraints;
-        constraints.set_max_young_space_size(256 * K);
-        constraints.set_max_old_space_size(4 * K * K);
-        v8::SetResourceConstraints(CcTest::isolate(), &constraints);
-        break;
-      }
+    case IgnoreOOM:
+      v8::V8::IgnoreOutOfMemoryException();
+      break;

-      case SetFatalHandler:
-        v8::V8::SetFatalErrorHandler(NULL);
-        break;
+    case SetResourceConstraints: {
+      static const int K = 1024;
+      v8::ResourceConstraints constraints;
+      constraints.set_max_young_space_size(256 * K);
+      constraints.set_max_old_space_size(4 * K * K);
+      v8::SetResourceConstraints(CcTest::isolate(), &constraints);
+      break;
+    }

-      case SetCounterFunction:
-        v8::V8::SetCounterFunction(NULL);
-        break;
+    case SetFatalHandler:
+      v8::V8::SetFatalErrorHandler(NULL);
+      break;

-      case SetCreateHistogramFunction:
-        v8::V8::SetCreateHistogramFunction(NULL);
-        break;
+    case SetCounterFunction:
+      v8::V8::SetCounterFunction(NULL);
+      break;
+
+    case SetCreateHistogramFunction:
+      v8::V8::SetCreateHistogramFunction(NULL);
+      break;

-      case SetAddHistogramSampleFunction:
-        v8::V8::SetAddHistogramSampleFunction(NULL);
-        break;
+    case SetAddHistogramSampleFunction:
+      v8::V8::SetAddHistogramSampleFunction(NULL);
+      break;
     }
     isolate->Exit();
     isolate->Dispose();
@@ -19395,26 +19400,31 @@


 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
+  InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
+}
+
+
+TEST(InitializeDefaultIsolateOnSecondaryThread2) {
   InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
 }


-TEST(InitializeDefaultIsolateOnSecondaryThread2) {
+TEST(InitializeDefaultIsolateOnSecondaryThread3) {
   InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
 }


-TEST(InitializeDefaultIsolateOnSecondaryThread3) {
+TEST(InitializeDefaultIsolateOnSecondaryThread4) {
   InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
 }


-TEST(InitializeDefaultIsolateOnSecondaryThread4) {
+TEST(InitializeDefaultIsolateOnSecondaryThread5) {
InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
 }


-TEST(InitializeDefaultIsolateOnSecondaryThread5) {
+TEST(InitializeDefaultIsolateOnSecondaryThread6) {
InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
 }

=======================================
--- /branches/bleeding_edge/test/cctest/test-strings.cc Mon Mar 24 08:47:45 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-strings.cc Mon Mar 24 09:17:18 2014 UTC
@@ -1273,6 +1273,23 @@
   CompileRun("var slice = long.slice(1, 15);");
   CheckException("%_SubString(slice, 0, 17);");
 }
+
+
+TEST(RegExpOverflow) {
+  // Result string has the length 2^32, causing a 32-bit integer overflow.
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  v8::V8::IgnoreOutOfMemoryException();
+  v8::Local<v8::Value> result = CompileRun(
+      "var a = 'a';                     "
+      "for (var i = 0; i < 16; i++) {   "
+      "  a += a;                        "
+      "}                                "
+      "a.replace(/a/g, a);              ");
+  CHECK(result.IsEmpty());
+  CHECK(context->HasOutOfMemoryException());
+}


 TEST(StringReplaceAtomTwoByteResult) {

--
--
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to v8-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to