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.