Revert "Remove Failure::OutOfMemory propagation and V8::IgnoreOutOfMemoryException."
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 24 Mar 2014 09:17:18 +0000 (09:17 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 24 Mar 2014 09:17:18 +0000 (09:17 +0000)
This reverts r20179.

TBR=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/201573007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20183 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

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

index ef09994..5e54267 100644 (file)
@@ -4616,6 +4616,20 @@ class V8_EXPORT V8 {
   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 @@ class V8_EXPORT Context {
    */
   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();
 
index b1d133a..1c349b5 100644 (file)
@@ -95,6 +95,11 @@ namespace v8 {
         (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                                                              \
@@ -5256,6 +5261,12 @@ Handle<Value> v8::Context::GetSecurityToken() {
 }
 
 
+bool Context::HasOutOfMemoryException() {
+  i::Handle<i::Context> env = Utils::OpenHandle(this);
+  return env->has_out_of_memory();
+}
+
+
 v8::Isolate* Context::GetIsolate() {
   i::Handle<i::Context> env = Utils::OpenHandle(this);
   return reinterpret_cast<Isolate*>(env->GetIsolate());
@@ -6214,6 +6225,11 @@ Local<Integer> v8::Integer::NewFromUnsigned(Isolate* isolate, uint32_t value) {
 }
 
 
+void V8::IgnoreOutOfMemoryException() {
+  EnterIsolateIfNeeded()->set_ignore_out_of_memory(true);
+}
+
+
 bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) {
   i::Isolate* isolate = i::Isolate::Current();
   EnsureInitializedForIsolate(isolate, "v8::V8::AddMessageListener()");
index b3df94e..5609cd0 100644 (file)
@@ -1501,9 +1501,22 @@ void CEntryStub::GenerateAheadOfTime(Isolate* 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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ 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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
 
   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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                false);
 
@@ -1681,9 +1703,30 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   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);
 
index 61b395f..f06f6bc 100644 (file)
@@ -1405,6 +1405,18 @@ void CodeStub::GenerateFPStubs(Isolate* 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() {
   // CEntryStub stores the return address on the stack before calling into
   // C++ code. In some cases, the VM accesses this address, but it is not used
@@ -1429,6 +1441,7 @@ void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
 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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ 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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
                                    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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
 
   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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   GenerateCore(masm,
                &throw_normal,
                &throw_termination,
+               &throw_out_of_memory,
                true,
                false);
 
@@ -1700,6 +1723,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   GenerateCore(masm,
                &throw_normal,
                &throw_termination,
+               &throw_out_of_memory,
                true,
                true);
 
@@ -1716,6 +1740,27 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   // 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");
index 7942c7f..7edc5d5 100644 (file)
@@ -1310,6 +1310,9 @@ void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
     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);
   native_context()->set_embedder_data(*embedder_data);
index 25328fe..3367c6d 100644 (file)
@@ -1496,6 +1496,7 @@ class CEntryStub : public PlatformCodeStub {
   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);
 
index 6ba9b3e..479a692 100644 (file)
@@ -162,6 +162,7 @@ enum BindingFlags {
   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) \
@@ -439,6 +440,12 @@ class Context: public FixedArray {
     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);
   void RemoveOptimizedFunction(JSFunction* function);
index 527df6e..1ddc69d 100644 (file)
@@ -318,7 +318,7 @@ MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
       // 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),
index 7442d17..1e0a6a8 100644 (file)
@@ -135,6 +135,11 @@ static Handle<Object> Invoke(bool is_construct,
   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 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func,
     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();
index 7e465d5..efad2fb 100644 (file)
@@ -138,7 +138,7 @@ MaybeObject* Heap::AllocateInternalizedStringImpl(
 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::AllocateOneByteInternalizedString(Vector<const uint8_t> str,
 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 @@ Isolate* Heap::isolate() {
 // 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 @@ Isolate* Heap::isolate() {
       __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* Heap::isolate() {
       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 @@ Isolate* Heap::isolate() {
   CALL_AND_RETRY(ISOLATE,                                         \
                  FUNCTION_CALL,                                   \
                  return __object__,                               \
+                 return __maybe_object__,                         \
                  return __maybe_object__)
 
 
index 6b2f8f7..0691947 100644 (file)
@@ -3871,7 +3871,8 @@ MaybeObject* Heap::AllocateExternalStringFromAscii(
     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 @@ MaybeObject* Heap::AllocateExternalStringFromTwoByte(
     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::LookupSingleCharacterStringFromCode(uint16_t code) {
 
 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 @@ MaybeObject* Heap::AllocateInternalizedStringImpl(
   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::AllocateInternalizedStringImpl<false>(
 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::AllocateRawOneByteString(int length,
 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::CopyConstantPoolArrayWithMap(ConstantPoolArray* src,
 
 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::AllocateFixedDoubleArrayWithHoles(
 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
index ce9bd21..fa67502 100644 (file)
@@ -2583,9 +2583,23 @@ void CEntryStub::GenerateAheadOfTime(Isolate* 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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ 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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
 
   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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                false);
 
@@ -2747,9 +2770,27 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   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);
 
index 2e94828..5518f00 100644 (file)
@@ -80,6 +80,10 @@ int ThreadId::GetCurrentThreadId() {
 
 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 @@ void Isolate::ReportPendingMessages() {
   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 @@ void Isolate::ReportPendingMessages() {
 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 @@ bool Isolate::OptionalRescheduleException(bool is_bottom_call) {
   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) {
+    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;
+      }
+    }
+
+    // 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.
@@ -1369,6 +1383,23 @@ void Isolate::SetCaptureStackTraceForUncaughtExceptions(
 }
 
 
+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() {
   return Handle<Context>(context()->global_object()->native_context());
 }
@@ -1820,7 +1851,9 @@ void Isolate::PropagatePendingExceptionToExternalTryCatch() {
 
   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;
index 9111a1d..1f3361c 100644 (file)
@@ -288,6 +288,9 @@ class ThreadLocalTop BASE_EMBEDDED {
   // 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 @@ class Isolate {
   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 @@ class Isolate {
       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);
@@ -1465,6 +1475,17 @@ class PostponeInterruptsScope BASE_EMBEDDED {
 };
 
 
+// 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:
   explicit CodeTracer(int isolate_id)
index 3b8e223..6d06bd9 100644 (file)
@@ -1606,9 +1606,21 @@ void CEntryStub::GenerateAheadOfTime(Isolate* 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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ 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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
 
   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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                false);
 
@@ -1790,9 +1811,30 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   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);
 
index b3f23e6..2e60a44 100644 (file)
@@ -649,6 +649,12 @@ bool MaybeObject::IsRetryAfterGC() {
 }
 
 
+bool MaybeObject::IsOutOfMemory() {
+  return HAS_FAILURE_TAG(this)
+      && Failure::cast(this)->IsOutOfMemoryException();
+}
+
+
 bool MaybeObject::IsException() {
   return this == Failure::Exception();
 }
@@ -1239,6 +1245,11 @@ bool Failure::IsInternalError() const {
 }
 
 
+bool Failure::IsOutOfMemoryException() const {
+  return type() == OUT_OF_MEMORY_EXCEPTION;
+}
+
+
 AllocationSpace Failure::allocation_space() const {
   ASSERT_EQ(RETRY_AFTER_GC, type());
   return static_cast<AllocationSpace>((value() >> kFailureTypeTagSize)
@@ -1256,6 +1267,11 @@ Failure* Failure::Exception() {
 }
 
 
+Failure* Failure::OutOfMemoryException(intptr_t value) {
+  return Construct(OUT_OF_MEMORY_EXCEPTION, value);
+}
+
+
 intptr_t Failure::value() const {
   return static_cast<intptr_t>(
       reinterpret_cast<uintptr_t>(this) >> kFailureTagSize);
index c764b33..dae3223 100644 (file)
@@ -13921,7 +13921,7 @@ MaybeObject* HashTable<Shape, Key>::Allocate(Heap* heap,
                      ? 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;
index c4d3f25..34edd0a 100644 (file)
@@ -934,6 +934,7 @@ class MaybeObject BASE_EMBEDDED {
  public:
   inline bool IsFailure();
   inline bool IsRetryAfterGC();
+  inline bool IsOutOfMemory();
   inline bool IsException();
   INLINE(bool IsTheHole());
   INLINE(bool IsUninitialized());
@@ -1727,11 +1728,15 @@ class Failure: public MaybeObject {
   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);
 
index 8b18e55..b4c34ef 100644 (file)
@@ -3913,9 +3913,7 @@ MUST_USE_RESULT static MaybeObject* StringReplaceGlobalAtomRegExpWithString(
        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;
index dc5496c..ce820b1 100644 (file)
@@ -2407,9 +2407,23 @@ void CEntryStub::GenerateAheadOfTime(Isolate* 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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
   __ 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 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
       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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
 
   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 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   GenerateCore(masm,
                &throw_normal_exception,
                &throw_termination_exception,
+               &throw_out_of_memory_exception,
                true,
                false);
 
@@ -2599,9 +2622,28 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   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);
 
index 0818f33..a159522 100644 (file)
@@ -19332,6 +19332,7 @@ TEST(IsolateDifferentContexts) {
 class InitDefaultIsolateThread : public v8::internal::Thread {
  public:
   enum TestCase {
+    IgnoreOOM,
     SetResourceConstraints,
     SetFatalHandler,
     SetCounterFunction,
@@ -19348,30 +19349,34 @@ class InitDefaultIsolateThread : public v8::internal::Thread {
     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 SetAddHistogramSampleFunction:
-        v8::V8::SetAddHistogramSampleFunction(NULL);
-        break;
+    case SetCreateHistogramFunction:
+      v8::V8::SetCreateHistogramFunction(NULL);
+      break;
+
+    case SetAddHistogramSampleFunction:
+      v8::V8::SetAddHistogramSampleFunction(NULL);
+      break;
     }
     isolate->Exit();
     isolate->Dispose();
@@ -19395,26 +19400,31 @@ static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
 
 
 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
-  InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
+  InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
 }
 
 
 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
-  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
+  InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
 }
 
 
 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
-  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
+  InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
 }
 
 
 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
-  InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
+  InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
 }
 
 
 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
+  InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
+}
+
+
+TEST(InitializeDefaultIsolateOnSecondaryThread6) {
   InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
 }
 
index 0f37c3e..8e63cb0 100644 (file)
@@ -1275,6 +1275,23 @@ TEST(RobustSubStringStub) {
 }
 
 
+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) {
   CcTest::InitializeVM();
   v8::HandleScope scope(CcTest::isolate());