summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deps/v8/ChangeLog16
-rw-r--r--deps/v8/include/v8.h63
-rw-r--r--deps/v8/src/api.cc45
-rw-r--r--deps/v8/src/arm/codegen-arm.cc64
-rw-r--r--deps/v8/src/codegen.h7
-rw-r--r--deps/v8/src/execution.cc20
-rw-r--r--deps/v8/src/execution.h11
-rw-r--r--deps/v8/src/global-handles.cc36
-rw-r--r--deps/v8/src/heap.cc19
-rw-r--r--deps/v8/src/heap.h26
-rw-r--r--deps/v8/src/ia32/codegen-ia32.cc54
-rw-r--r--deps/v8/src/mark-compact.cc3
-rw-r--r--deps/v8/src/mark-compact.h10
-rw-r--r--deps/v8/src/messages.cc6
-rw-r--r--deps/v8/src/objects-debug.cc3
-rw-r--r--deps/v8/src/objects-inl.h1
-rw-r--r--deps/v8/src/scanner.cc3
-rw-r--r--deps/v8/src/scanner.h4
-rw-r--r--deps/v8/src/spaces.cc4
-rw-r--r--deps/v8/src/third_party/dtoa/dtoa.c2
-rw-r--r--deps/v8/src/top.cc61
-rw-r--r--deps/v8/src/top.h12
-rw-r--r--deps/v8/src/v8.cc1
-rw-r--r--deps/v8/src/v8threads.cc21
-rw-r--r--deps/v8/src/v8threads.h9
-rw-r--r--deps/v8/src/version.cc2
-rw-r--r--deps/v8/src/x64/codegen-x64.cc64
-rw-r--r--deps/v8/test/cctest/SConscript1
-rw-r--r--deps/v8/test/cctest/test-api.cc78
-rw-r--r--deps/v8/test/cctest/test-thread-termination.cc195
-rw-r--r--deps/v8/test/cctest/test-threads.cc2
-rw-r--r--deps/v8/test/mozilla/mozilla.status6
-rw-r--r--deps/v8/tools/gyp/v8.gyp22
33 files changed, 726 insertions, 145 deletions
diff --git a/deps/v8/ChangeLog b/deps/v8/ChangeLog
index c59661d36..ff39f04e3 100644
--- a/deps/v8/ChangeLog
+++ b/deps/v8/ChangeLog
@@ -1,3 +1,19 @@
+2009-08-21: Version 1.3.6
+
+ Add support for forceful termination of JavaScript execution.
+
+ Add low memory notification to the API. The embedding host can signal
+ a low memory situation to V8.
+
+ Changed the handling of global handles (persistent handles in the API
+ sense) to avoid issues regarding allocation of new global handles
+ during weak handle callbacks.
+
+ Changed the growth policy of the young space.
+
+ Fixed a GC issue introduced in version 1.3.5.
+
+
2009-08-19: Version 1.3.5
Optimize initialization of some arrays in the builtins.
diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h
index a0cc4ea8b..c7cc3154a 100644
--- a/deps/v8/include/v8.h
+++ b/deps/v8/include/v8.h
@@ -2223,6 +2223,47 @@ class V8EXPORT V8 {
*/
static int GetLogLines(int from_pos, char* dest_buf, int max_size);
+ /**
+ * Retrieve the V8 thread id of the calling thread.
+ *
+ * The thread id for a thread should only be retrieved after the V8
+ * lock has been acquired with a Locker object with that thread.
+ */
+ static int GetCurrentThreadId();
+
+ /**
+ * Forcefully terminate execution of a JavaScript thread. This can
+ * be used to terminate long-running scripts.
+ *
+ * TerminateExecution should only be called when then V8 lock has
+ * been acquired with a Locker object. Therefore, in order to be
+ * able to terminate long-running threads, preemption must be
+ * enabled to allow the user of TerminateExecution to acquire the
+ * lock.
+ *
+ * The termination is achieved by throwing an exception that is
+ * uncatchable by JavaScript exception handlers. Termination
+ * exceptions act as if they were caught by a C++ TryCatch exception
+ * handlers. If forceful termination is used, any C++ TryCatch
+ * exception handler that catches an exception should check if that
+ * exception is a termination exception and immediately return if
+ * that is the case. Returning immediately in that case will
+ * continue the propagation of the termination exception if needed.
+ *
+ * The thread id passed to TerminateExecution must have been
+ * obtained by calling GetCurrentThreadId on the thread in question.
+ *
+ * \param thread_id The thread id of the thread to terminate.
+ */
+ static void TerminateExecution(int thread_id);
+
+ /**
+ * Forcefully terminate the current thread of JavaScript execution.
+ *
+ * This method can be used by any thread even if that thread has not
+ * acquired the V8 lock with a Locker object.
+ */
+ static void TerminateExecution();
/**
* Releases any resources used by v8 and stops any utility threads
@@ -2243,6 +2284,12 @@ class V8EXPORT V8 {
*/
static void IdleNotification(bool is_high_priority);
+ /**
+ * Optional notification that the system is running low on memory.
+ * V8 uses these notifications to attempt to free memory.
+ */
+ static void LowMemoryNotification();
+
private:
V8();
@@ -2282,6 +2329,21 @@ class V8EXPORT TryCatch {
bool HasCaught() const;
/**
+ * For certain types of exceptions, it makes no sense to continue
+ * execution.
+ *
+ * Currently, the only type of exception that can be caught by a
+ * TryCatch handler and for which it does not make sense to continue
+ * is termination exception. Such exceptions are thrown when the
+ * TerminateExecution methods are called to terminate a long-running
+ * script.
+ *
+ * If CanContinue returns false, the correct action is to perform
+ * any C++ cleanup needed and then return.
+ */
+ bool CanContinue() const;
+
+ /**
* Returns the exception caught by this try/catch block. If no exception has
* been caught an empty handle is returned.
*
@@ -2337,6 +2399,7 @@ class V8EXPORT TryCatch {
void* exception_;
void* message_;
bool is_verbose_;
+ bool can_continue_;
bool capture_message_;
void* js_handler_;
};
diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc
index 88cf2bcde..7d97fc658 100644
--- a/deps/v8/src/api.cc
+++ b/deps/v8/src/api.cc
@@ -75,7 +75,7 @@ namespace v8 {
i::V8::FatalProcessOutOfMemory(NULL); \
} \
bool call_depth_is_zero = thread_local.CallDepthIsZero(); \
- i::Top::optional_reschedule_exception(call_depth_is_zero); \
+ i::Top::OptionalRescheduleException(call_depth_is_zero, false); \
return value; \
} \
} while (false)
@@ -1208,6 +1208,11 @@ bool v8::TryCatch::HasCaught() const {
}
+bool v8::TryCatch::CanContinue() const {
+ return can_continue_;
+}
+
+
v8::Local<Value> v8::TryCatch::Exception() const {
if (HasCaught()) {
// Check for out of memory exception.
@@ -2599,10 +2604,18 @@ bool v8::V8::Dispose() {
}
-void v8::V8::IdleNotification(bool is_high_priority) {
+void v8::V8::IdleNotification(bool is_high_priority) {
i::V8::IdleNotification(is_high_priority);
}
+
+void v8::V8::LowMemoryNotification() {
+#if defined(ANDROID)
+ i::Heap::CollectAllGarbage(true);
+#endif
+}
+
+
const char* v8::V8::GetVersion() {
static v8::internal::EmbeddedVector<char, 128> buffer;
v8::internal::Version::GetString(buffer);
@@ -3354,6 +3367,34 @@ int V8::GetLogLines(int from_pos, char* dest_buf, int max_size) {
return 0;
}
+
+int V8::GetCurrentThreadId() {
+ API_ENTRY_CHECK("V8::GetCurrentThreadId()");
+ EnsureInitialized("V8::GetCurrentThreadId()");
+ return i::Top::thread_id();
+}
+
+
+void V8::TerminateExecution(int thread_id) {
+ if (!i::V8::IsRunning()) return;
+ API_ENTRY_CHECK("V8::GetCurrentThreadId()");
+ // If the thread_id identifies the current thread just terminate
+ // execution right away. Otherwise, ask the thread manager to
+ // terminate the thread with the given id if any.
+ if (thread_id == i::Top::thread_id()) {
+ i::StackGuard::TerminateExecution();
+ } else {
+ i::ThreadManager::TerminateExecution(thread_id);
+ }
+}
+
+
+void V8::TerminateExecution() {
+ if (!i::V8::IsRunning()) return;
+ i::StackGuard::TerminateExecution();
+}
+
+
String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) {
EnsureInitialized("v8::String::Utf8Value::Utf8Value()");
if (obj.IsEmpty()) {
diff --git a/deps/v8/src/arm/codegen-arm.cc b/deps/v8/src/arm/codegen-arm.cc
index 40b0ac816..71ffaa241 100644
--- a/deps/v8/src/arm/codegen-arm.cc
+++ b/deps/v8/src/arm/codegen-arm.cc
@@ -5701,7 +5701,8 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
}
-void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
+void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
+ UncatchableExceptionType type) {
// Adjust this code if not the case.
ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
@@ -5725,20 +5726,22 @@ void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
// Set the top handler address to next handler past the current ENTRY handler.
ASSERT(StackHandlerConstants::kNextOffset == 0);
- __ pop(r0);
- __ str(r0, MemOperand(r3));
-
- // Set external caught exception to false.
- ExternalReference external_caught(Top::k_external_caught_exception_address);
- __ mov(r0, Operand(false));
- __ mov(r2, Operand(external_caught));
- __ str(r0, MemOperand(r2));
+ __ pop(r2);
+ __ str(r2, MemOperand(r3));
- // Set pending exception and r0 to out of memory exception.
- Failure* out_of_memory = Failure::OutOfMemoryException();
- __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
- __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
- __ str(r0, MemOperand(r2));
+ if (type == OUT_OF_MEMORY) {
+ // Set external caught exception to false.
+ ExternalReference external_caught(Top::k_external_caught_exception_address);
+ __ mov(r0, Operand(false));
+ __ mov(r2, Operand(external_caught));
+ __ str(r0, MemOperand(r2));
+
+ // Set pending exception and r0 to out of memory exception.
+ Failure* out_of_memory = Failure::OutOfMemoryException();
+ __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
+ __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
+ __ str(r0, MemOperand(r2));
+ }
// Stack layout at this point. See also StackHandlerConstants.
// sp -> state (ENTRY)
@@ -5768,6 +5771,7 @@ void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
void CEntryStub::GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
+ Label* throw_termination_exception,
Label* throw_out_of_memory_exception,
StackFrame::Type frame_type,
bool do_gc,
@@ -5838,10 +5842,10 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
__ b(eq, &retry);
- Label continue_exception;
- // If the returned failure is EXCEPTION then promote Top::pending_exception().
- __ cmp(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
- __ b(ne, &continue_exception);
+ // Special handling of out of memory exceptions.
+ Failure* out_of_memory = Failure::OutOfMemoryException();
+ __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
+ __ b(eq, throw_out_of_memory_exception);
// Retrieve the pending exception and clear the variable.
__ mov(ip, Operand(ExternalReference::the_hole_value_location()));
@@ -5850,11 +5854,10 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ ldr(r0, MemOperand(ip));
__ str(r3, MemOperand(ip));
- __ bind(&continue_exception);
- // Special handling of out of memory exception.
- Failure* out_of_memory = Failure::OutOfMemoryException();
- __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
- __ b(eq, throw_out_of_memory_exception);
+ // Special handling of termination exceptions which are uncatchable
+ // by javascript code.
+ __ cmp(r0, Operand(Factory::termination_exception()));
+ __ b(eq, throw_termination_exception);
// Handle normal exception.
__ jmp(throw_normal_exception);
@@ -5887,11 +5890,14 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
// r5: pointer to builtin function (C callee-saved)
// r6: pointer to first argument (C callee-saved)
- Label throw_out_of_memory_exception;
Label throw_normal_exception;
+ Label throw_termination_exception;
+ Label throw_out_of_memory_exception;
// Call into the runtime system.
- GenerateCore(masm, &throw_normal_exception,
+ GenerateCore(masm,
+ &throw_normal_exception,
+ &throw_termination_exception,
&throw_out_of_memory_exception,
frame_type,
false,
@@ -5900,6 +5906,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
// Do space-specific GC and retry runtime call.
GenerateCore(masm,
&throw_normal_exception,
+ &throw_termination_exception,
&throw_out_of_memory_exception,
frame_type,
true,
@@ -5910,14 +5917,17 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
__ mov(r0, Operand(reinterpret_cast<int32_t>(failure)));
GenerateCore(masm,
&throw_normal_exception,
+ &throw_termination_exception,
&throw_out_of_memory_exception,
frame_type,
true,
true);
__ bind(&throw_out_of_memory_exception);
- GenerateThrowOutOfMemory(masm);
- // control flow for generated will not return.
+ GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
+
+ __ bind(&throw_termination_exception);
+ GenerateThrowUncatchable(masm, TERMINATION);
__ bind(&throw_normal_exception);
GenerateThrowTOS(masm);
diff --git a/deps/v8/src/codegen.h b/deps/v8/src/codegen.h
index 243d87ca6..d6967b7af 100644
--- a/deps/v8/src/codegen.h
+++ b/deps/v8/src/codegen.h
@@ -70,6 +70,9 @@
// Mode to overwrite BinaryExpression values.
enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT };
+// Types of uncatchable exceptions.
+enum UncatchableExceptionType { OUT_OF_MEMORY, TERMINATION };
+
#if V8_TARGET_ARCH_IA32
#include "ia32/codegen-ia32.h"
@@ -291,12 +294,14 @@ class CEntryStub : public CodeStub {
void GenerateBody(MacroAssembler* masm, bool is_debug_break);
void GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
+ Label* throw_termination_exception,
Label* throw_out_of_memory_exception,
StackFrame::Type frame_type,
bool do_gc,
bool always_allocate_scope);
void GenerateThrowTOS(MacroAssembler* masm);
- void GenerateThrowOutOfMemory(MacroAssembler* masm);
+ void GenerateThrowUncatchable(MacroAssembler* masm,
+ UncatchableExceptionType type);
private:
Major MajorKey() { return CEntry; }
diff --git a/deps/v8/src/execution.cc b/deps/v8/src/execution.cc
index 9080f5eaa..0ad55bd55 100644
--- a/deps/v8/src/execution.cc
+++ b/deps/v8/src/execution.cc
@@ -156,7 +156,8 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func,
ASSERT(catcher.HasCaught());
ASSERT(Top::has_pending_exception());
ASSERT(Top::external_caught_exception());
- Top::optional_reschedule_exception(true);
+ bool is_bottom_call = HandleScopeImplementer::instance()->CallDepthIsZero();
+ Top::OptionalRescheduleException(is_bottom_call, true);
result = v8::Utils::OpenHandle(*catcher.Exception());
}
@@ -328,6 +329,19 @@ void StackGuard::Preempt() {
}
+bool StackGuard::IsTerminateExecution() {
+ ExecutionAccess access;
+ return thread_local_.interrupt_flags_ & TERMINATE;
+}
+
+
+void StackGuard::TerminateExecution() {
+ ExecutionAccess access;
+ thread_local_.interrupt_flags_ |= TERMINATE;
+ set_limits(kInterruptLimit, access);
+}
+
+
#ifdef ENABLE_DEBUGGER_SUPPORT
bool StackGuard::IsDebugBreak() {
ExecutionAccess access;
@@ -638,6 +652,10 @@ Object* Execution::HandleStackGuardInterrupt() {
}
#endif
if (StackGuard::IsPreempted()) RuntimePreempt();
+ if (StackGuard::IsTerminateExecution()) {
+ StackGuard::Continue(TERMINATE);
+ return Top::TerminateExecution();
+ }
if (StackGuard::IsInterrupted()) {
// interrupt
StackGuard::Continue(INTERRUPT);
diff --git a/deps/v8/src/execution.h b/deps/v8/src/execution.h
index fba696e72..456cbe74d 100644
--- a/deps/v8/src/execution.h
+++ b/deps/v8/src/execution.h
@@ -37,7 +37,8 @@ enum InterruptFlag {
INTERRUPT = 1 << 0,
DEBUGBREAK = 1 << 1,
DEBUGCOMMAND = 1 << 2,
- PREEMPT = 1 << 3
+ PREEMPT = 1 << 3,
+ TERMINATE = 1 << 4
};
class Execution : public AllStatic {
@@ -164,13 +165,15 @@ class StackGuard BASE_EMBEDDED {
static void Preempt();
static bool IsInterrupted();
static void Interrupt();
- static void Continue(InterruptFlag after_what);
+ static bool IsTerminateExecution();
+ static void TerminateExecution();
#ifdef ENABLE_DEBUGGER_SUPPORT
- static void DebugBreak();
- static void DebugCommand();
static bool IsDebugBreak();
+ static void DebugBreak();
static bool IsDebugCommand();
+ static void DebugCommand();
#endif
+ static void Continue(InterruptFlag after_what);
private:
// You should hold the ExecutionAccess lock when calling this method.
diff --git a/deps/v8/src/global-handles.cc b/deps/v8/src/global-handles.cc
index ed4e262e6..e51c4aadf 100644
--- a/deps/v8/src/global-handles.cc
+++ b/deps/v8/src/global-handles.cc
@@ -144,8 +144,8 @@ class GlobalHandles::Node : public Malloced {
// Returns the callback for this weak handle.
WeakReferenceCallback callback() { return callback_; }
- void PostGarbageCollectionProcessing() {
- if (state_ != Node::PENDING) return;
+ bool PostGarbageCollectionProcessing() {
+ if (state_ != Node::PENDING) return false;
LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
void* par = parameter();
state_ = NEAR_DEATH;
@@ -153,14 +153,19 @@ class GlobalHandles::Node : public Malloced {
// The callback function is resolved as late as possible to preserve old
// behavior.
WeakReferenceCallback func = callback();
- if (func != NULL) {
- v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
- {
- // Leaving V8.
- VMState state(EXTERNAL);
- func(object, par);
- }
+ if (func == NULL) return false;
+
+ v8::Persistent<v8::Object> object = ToApi<v8::Object>(handle());
+ {
+ // Forbid reuse of destroyed nodes as they might be already deallocated.
+ // It's fine though to reuse nodes that were destroyed in weak callback
+ // as those cannot be deallocated until we are back from the callback.
+ set_first_free(NULL);
+ // Leaving V8.
+ VMState state(EXTERNAL);
+ func(object, par);
}
+ return true;
}
// Place the handle address first to avoid offset computation.
@@ -271,15 +276,26 @@ void GlobalHandles::IdentifyWeakHandles(WeakSlotCallback f) {
}
+int post_gc_processing_count = 0;
+
void GlobalHandles::PostGarbageCollectionProcessing() {
// Process weak global handle callbacks. This must be done after the
// GC is completely done, because the callbacks may invoke arbitrary
// API functions.
// At the same time deallocate all DESTROYED nodes
ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
+ const int initial_post_gc_processing_count = ++post_gc_processing_count;
Node** p = &head_;
while (*p != NULL) {
- (*p)->PostGarbageCollectionProcessing();
+ if ((*p)->PostGarbageCollectionProcessing()) {
+ if (initial_post_gc_processing_count != post_gc_processing_count) {
+ // Weak callback triggered another GC and another round of
+ // PostGarbageCollection processing. The current node might
+ // have been deleted in that round, so we need to bail out (or
+ // restart the processing).
+ break;
+ }
+ }
if ((*p)->state_ == Node::DESTROYED) {
// Delete the link.
Node* node = *p;
diff --git a/deps/v8/src/heap.cc b/deps/v8/src/heap.cc
index 7d6e442b8..ad25f93ef 100644
--- a/deps/v8/src/heap.cc
+++ b/deps/v8/src/heap.cc
@@ -73,7 +73,7 @@ int Heap::amount_of_external_allocated_memory_at_last_global_gc_ = 0;
int Heap::semispace_size_ = 512*KB;
int Heap::old_generation_size_ = 128*MB;
int Heap::initial_semispace_size_ = 128*KB;
-#elseif defined(V8_TARGET_ARCH_X64)
+#elif defined(V8_TARGET_ARCH_X64)
int Heap::semispace_size_ = 8*MB;
int Heap::old_generation_size_ = 1*GB;
int Heap::initial_semispace_size_ = 1*MB;
@@ -315,11 +315,13 @@ void Heap::GarbageCollectionEpilogue() {
}
-void Heap::CollectAllGarbage() {
+void Heap::CollectAllGarbage(bool force_compaction) {
// Since we are ignoring the return value, the exact choice of space does
// not matter, so long as we do not specify NEW_SPACE, which would not
// cause a full GC.
+ MarkCompactCollector::SetForceCompaction(force_compaction);
CollectGarbage(0, OLD_POINTER_SPACE);
+ MarkCompactCollector::SetForceCompaction(false);
}
@@ -485,7 +487,10 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
void Heap::PostGarbageCollectionProcessing() {
// Process weak handles post gc.
- GlobalHandles::PostGarbageCollectionProcessing();
+ {
+ DisableAssertNoAllocation allow_allocation;
+ GlobalHandles::PostGarbageCollectionProcessing();
+ }
// Update flat string readers.
FlatStringReader::PostGarbageCollectionProcessing();
}
@@ -1412,6 +1417,9 @@ bool Heap::CreateInitialObjects() {
if (obj->IsFailure()) return false;
set_no_interceptor_result_sentinel(obj);
+ obj = CreateOddball(oddball_map(), "termination_exception", Smi::FromInt(-3));
+ if (obj->IsFailure()) return false;
+ set_termination_exception(obj);
// Allocate the empty string.
obj = AllocateRawAsciiString(0, TENURED);
@@ -2084,8 +2092,9 @@ Object* Heap::AllocateInitialMap(JSFunction* fun) {
if (count > in_object_properties) {
count = in_object_properties;
}
- DescriptorArray* descriptors = *Factory::NewDescriptorArray(count);
- if (descriptors->IsFailure()) return descriptors;
+ Object* descriptors_obj = DescriptorArray::Allocate(count);
+ if (descriptors_obj->IsFailure()) return descriptors_obj;
+ DescriptorArray* descriptors = DescriptorArray::cast(descriptors_obj);
for (int i = 0; i < count; i++) {
String* name = fun->shared()->GetThisPropertyAssignmentName(i);
ASSERT(name->IsSymbol());
diff --git a/deps/v8/src/heap.h b/deps/v8/src/heap.h
index ec1e21af5..ac6f5be51 100644
--- a/deps/v8/src/heap.h
+++ b/deps/v8/src/heap.h
@@ -111,6 +111,7 @@ namespace internal {
V(Object, nan_value, NanValue) \
V(Object, undefined_value, UndefinedValue) \
V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \
+ V(Object, termination_exception, TerminationException) \
V(Object, minus_zero_value, MinusZeroValue) \
V(Object, null_value, NullValue) \
V(Object, true_value, TrueValue) \
@@ -626,8 +627,9 @@ class Heap : public AllStatic {
// Returns whether required_space bytes are available after the collection.
static bool CollectGarbage(int required_space, AllocationSpace space);
- // Performs a full garbage collection.
- static void CollectAllGarbage();
+ // Performs a full garbage collection. Force compaction if the
+ // parameter is true.
+ static void CollectAllGarbage(bool force_compaction = false);
// Performs a full garbage collection if a context has been disposed
// since the last time the check was performed.
@@ -1386,6 +1388,20 @@ class AssertNoAllocation {
bool old_state_;
};
+class DisableAssertNoAllocation {
+ public:
+ DisableAssertNoAllocation() {
+ old_state_ = Heap::allow_allocation(true);
+ }
+
+ ~DisableAssertNoAllocation() {
+ Heap::allow_allocation(old_state_);
+ }
+
+ private:
+ bool old_state_;
+};
+
#else // ndef DEBUG
class AssertNoAllocation {
@@ -1394,6 +1410,12 @@ class AssertNoAllocation {
~AssertNoAllocation() { }
};
+class DisableAssertNoAllocation {
+ public:
+ DisableAssertNoAllocation() { }
+ ~DisableAssertNoAllocation() { }
+};
+
#endif
#ifdef ENABLE_LOGGING_AND_PROFILING
diff --git a/deps/v8/src/ia32/codegen-ia32.cc b/deps/v8/src/ia32/codegen-ia32.cc
index b8b3db64b..bf1f81b13 100644
--- a/deps/v8/src/ia32/codegen-ia32.cc
+++ b/deps/v8/src/ia32/codegen-ia32.cc
@@ -7505,6 +7505,7 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
void CEntryStub::GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
+ Label* throw_termination_exception,
Label* throw_out_of_memory_exception,
StackFrame::Type frame_type,
bool do_gc,
@@ -7568,10 +7569,9 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
__ j(zero, &retry, taken);
- Label continue_exception;
- // If the returned failure is EXCEPTION then promote Top::pending_exception().
- __ cmp(eax, reinterpret_cast<int32_t>(Failure::Exception()));
- __ j(not_equal, &continue_exception);
+ // Special handling of out of memory exceptions.
+ __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
+ __ j(equal, throw_out_of_memory_exception);
// Retrieve the pending exception and clear the variable.
ExternalReference pending_exception_address(Top::k_pending_exception_address);
@@ -7580,10 +7580,10 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
Operand::StaticVariable(ExternalReference::the_hole_value_location()));
__ mov(Operand::StaticVariable(pending_exception_address), edx);
- __ bind(&continue_exception);
- // Special handling of out of memory exception.
- __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
- __ j(equal, throw_out_of_memory_exception);
+ // Special handling of termination exceptions which are uncatchable
+ // by javascript code.
+ __ cmp(eax, Factory::termination_exception());
+ __ j(equal, throw_termination_exception);
// Handle normal exception.
__ jmp(throw_normal_exception);
@@ -7593,7 +7593,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
}
-void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
+void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
+ UncatchableExceptionType type) {
// Adjust this code if not the case.
ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
@@ -7618,17 +7619,19 @@ void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
ASSERT(StackHandlerConstants::kNextOffset == 0);
__ pop(Operand::StaticVariable(handler_address));
- // Set external caught exception to false.
- ExternalReference external_caught(Top::k_external_caught_exception_address);
- __ mov(eax, false);
- __ mov(Operand::StaticVariable(external_caught), eax);
+ if (type == OUT_OF_MEMORY) {
+ // Set external caught exception to false.
+ ExternalReference external_caught(Top::k_external_caught_exception_address);
+ __ mov(eax, false);
+ __ mov(Operand::StaticVariable(external_caught), eax);
- // Set pending exception and eax to out of memory exception.
- ExternalReference pending_exception(Top::k_pending_exception_address);
- __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
- __ mov(Operand::StaticVariable(pending_exception), eax);
+ // Set pending exception and eax to out of memory exception.
+ ExternalReference pending_exception(Top::k_pending_exception_address);
+ __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException()));
+ __ mov(Operand::StaticVariable(pending_exception), eax);
+ }
- // Clear the context pointer;
+ // Clear the context pointer.
__ xor_(esi, Operand(esi));
// Restore fp from handler and discard handler state.
@@ -7667,11 +7670,14 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
// edi: number of arguments including receiver (C callee-saved)
// esi: argv pointer (C callee-saved)
- Label throw_out_of_memory_exception;
Label throw_normal_exception;
+ Label throw_termination_exception;
+ Label throw_out_of_memory_exception;
// Call into the runtime system.
- GenerateCore(masm, &throw_normal_exception,
+ GenerateCore(masm,
+ &throw_normal_exception,
+ &throw_termination_exception,
&throw_out_of_memory_exception,
frame_type,
false,
@@ -7680,6 +7686,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
// Do space-specific GC and retry runtime call.
GenerateCore(masm,
&throw_normal_exception,
+ &throw_termination_exception,
&throw_out_of_memory_exception,
frame_type,
true,
@@ -7690,14 +7697,17 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
__ mov(eax, Immediate(reinterpret_cast<int32_t>(failure)));
GenerateCore(masm,
&throw_normal_exception,
+ &throw_termination_exception,
&throw_out_of_memory_exception,
frame_type,
true,
true);
__ bind(&throw_out_of_memory_exception);
- GenerateThrowOutOfMemory(masm);
- // control flow for generated will not return.
+ GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
+
+ __ bind(&throw_termination_exception);
+ GenerateThrowUncatchable(masm, TERMINATION);
__ bind(&throw_normal_exception);
GenerateThrowTOS(masm);
diff --git a/deps/v8/src/mark-compact.cc b/deps/v8/src/mark-compact.cc
index 6e823b3d9..10e81ac6a 100644
--- a/deps/v8/src/mark-compact.cc
+++ b/deps/v8/src/mark-compact.cc
@@ -39,6 +39,7 @@ namespace internal {
// -------------------------------------------------------------------------
// MarkCompactCollector
+bool MarkCompactCollector::force_compaction_ = false;
bool MarkCompactCollector::compacting_collection_ = false;
int MarkCompactCollector::previous_marked_count_ = 0;
@@ -110,7 +111,7 @@ void MarkCompactCollector::Prepare(GCTracer* tracer) {
#endif
ASSERT(!FLAG_always_compact || !FLAG_never_compact);
- compacting_collection_ = FLAG_always_compact;
+ compacting_collection_ = FLAG_always_compact || force_compaction_;
// We compact the old generation if it gets too fragmented (ie, we could
// recover an expected amount of space by reclaiming the waste and free
diff --git a/deps/v8/src/mark-compact.h b/deps/v8/src/mark-compact.h
index bd9e4a028..0bd212e0c 100644
--- a/deps/v8/src/mark-compact.h
+++ b/deps/v8/src/mark-compact.h
@@ -75,6 +75,12 @@ class MarkCompactCollector: public AllStatic {
// Type of functions to process non-live objects.
typedef void (*ProcessNonLiveFunction)(HeapObject* object);
+ // Set the global force_compaction flag, it must be called before Prepare
+ // to take effect.
+ static void SetForceCompaction(bool value) {
+ force_compaction_ = value;
+ }
+
// Prepares for GC by resetting relocation info in old and map spaces and
// choosing spaces to compact.
static void Prepare(GCTracer* tracer);
@@ -117,6 +123,10 @@ class MarkCompactCollector: public AllStatic {
// The current stage of the collector.
static CollectorState state_;
#endif
+
+ // Global flag that forces a compaction.
+ static bool force_compaction_;
+
// Global flag indicating whether spaces were compacted on the last GC.
static bool compacting_collection_;
diff --git a/deps/v8/src/messages.cc b/deps/v8/src/messages.cc
index a3fffcb50..e16b1b249 100644
--- a/deps/v8/src/messages.cc
+++ b/deps/v8/src/messages.cc
@@ -147,14 +147,12 @@ Handle<String> MessageHandler::GetMessage(Handle<Object> data) {
Handle<String> fmt_str = Factory::LookupAsciiSymbol("FormatMessage");
Handle<JSFunction> fun =
Handle<JSFunction>(
- JSFunction::cast(
- Top::builtins()->GetProperty(*fmt_str)));
+ JSFunction::cast(Top::builtins()->GetProperty(*fmt_str)));
Object** argv[1] = { data.location() };
bool caught_exception;
Handle<Object> result =
- Execution::TryCall(fun, Top::builtins(), 1, argv,
- &caught_exception);
+ Execution::TryCall(fun, Top::builtins(), 1, argv, &caught_exception);
if (caught_exception || !result->IsString()) {
return Factory::LookupAsciiSymbol("<error>");
diff --git a/deps/v8/src/objects-debug.cc b/deps/v8/src/objects-debug.cc
index e97b207ba..f71317117 100644
--- a/deps/v8/src/objects-debug.cc
+++ b/deps/v8/src/objects-debug.cc
@@ -705,7 +705,8 @@ void Oddball::OddballVerify() {
} else {
ASSERT(number->IsSmi());
int value = Smi::cast(number)->value();
- ASSERT(value == 0 || value == 1 || value == -1 || value == -2);
+ ASSERT(value == 0 || value == 1 || value == -1 ||
+ value == -2 || value == -3);
}
}
diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h
index 7b750b61e..91aae2f42 100644
--- a/deps/v8/src/objects-inl.h
+++ b/deps/v8/src/objects-inl.h
@@ -788,6 +788,7 @@ Failure* Failure::Exception() {
return Construct(EXCEPTION);
}
+
Failure* Failure::OutOfMemoryException() {
return Construct(OUT_OF_MEMORY_EXCEPTION);
}
diff --git a/deps/v8/src/scanner.cc b/deps/v8/src/scanner.cc
index 720dc3536..3dae414f9 100644
--- a/deps/v8/src/scanner.cc
+++ b/deps/v8/src/scanner.cc
@@ -183,7 +183,8 @@ uc32 TwoByteStringUTF16Buffer::Advance() {
void TwoByteStringUTF16Buffer::PushBack(uc32 ch) {
pos_--;
- ASSERT(pos_ >= 0 && raw_data_[pos_] == ch);
+ ASSERT(pos_ >= Scanner::kCharacterLookaheadBufferSize);
+ ASSERT(raw_data_[pos_ - Scanner::kCharacterLookaheadBufferSize] == ch);
}
diff --git a/deps/v8/src/scanner.h b/deps/v8/src/scanner.h
index 340da86ed..a201d0e97 100644
--- a/deps/v8/src/scanner.h
+++ b/deps/v8/src/scanner.h
@@ -212,6 +212,8 @@ class Scanner {
static unibrow::Predicate<unibrow::LineTerminator, 128> kIsLineTerminator;
static unibrow::Predicate<unibrow::WhiteSpace, 128> kIsWhiteSpace;
+ static const int kCharacterLookaheadBufferSize = 1;
+
private:
CharacterStreamUTF16Buffer char_stream_buffer_;
TwoByteStringUTF16Buffer two_byte_string_buffer_;
@@ -242,8 +244,6 @@ class Scanner {
bool has_line_terminator_before_next_;
bool is_pre_parsing_;
- static const int kCharacterLookaheadBufferSize = 1;
-
// Literal buffer support
void StartLiteral();
void AddChar(uc32 ch);
diff --git a/deps/v8/src/spaces.cc b/deps/v8/src/spaces.cc
index 9227a87f3..337f0143b 100644
--- a/deps/v8/src/spaces.cc
+++ b/deps/v8/src/spaces.cc
@@ -1079,9 +1079,9 @@ void SemiSpace::TearDown() {
bool SemiSpace::Grow() {
- // Commit 50% extra space but only up to maximum capacity.
+ // Double the semispace size but only up to maximum capacity.
int maximum_extra = maximum_capacity_ - capacity_;
- int extra = Min(RoundUp(capacity_ / 2, OS::AllocateAlignment()),
+ int extra = Min(RoundUp(capacity_, OS::AllocateAlignment()),
maximum_extra);
if (!MemoryAllocator::CommitBlock(high(), extra, executable())) {
return false;
diff --git a/deps/v8/src/third_party/dtoa/dtoa.c b/deps/v8/src/third_party/dtoa/dtoa.c
index 5caa96d16..fadc6d1e4 100644
--- a/deps/v8/src/third_party/dtoa/dtoa.c
+++ b/deps/v8/src/third_party/dtoa/dtoa.c
@@ -1535,7 +1535,7 @@ strtod
double aadj, aadj1, adj, rv, rv0;
Long L;
ULong y, z;
- Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+ Bigint *bb = NULL, *bb1, *bd = NULL, *bd0, *bs = NULL, *delta = NULL;
#ifdef SET_INEXACT
int inexact, oldinexact;
#endif
diff --git a/deps/v8/src/top.cc b/deps/v8/src/top.cc
index 96d4a01e7..550703aa1 100644
--- a/deps/v8/src/top.cc
+++ b/deps/v8/src/top.cc
@@ -98,6 +98,7 @@ void Top::InitializeThreadLocal() {
thread_local_.stack_is_cooked_ = false;
thread_local_.try_catch_handler_ = NULL;
thread_local_.context_ = NULL;
+ thread_local_.thread_id_ = ThreadManager::kInvalidId;
thread_local_.external_caught_exception_ = false;
thread_local_.failed_access_check_callback_ = NULL;
clear_pending_exception();
@@ -598,6 +599,12 @@ Failure* Top::StackOverflow() {
}
+Failure* Top::TerminateExecution() {
+ DoThrow(Heap::termination_exception(), NULL, NULL);
+ return Failure::Exception();
+}
+
+
Failure* Top::Throw(Object* exception, MessageLocation* location) {
DoThrow(exception, location, NULL);
return Failure::Exception();
@@ -694,7 +701,8 @@ void Top::ReportUncaughtException(Handle<Object> exception,
}
-bool Top::ShouldReportException(bool* is_caught_externally) {
+bool Top::ShouldReturnException(bool* is_caught_externally,
+ bool catchable_by_javascript) {
// Find the top-most try-catch handler.
StackHandler* handler =
StackHandler::FromAddress(Top::handler(Top::GetCurrentThread()));
@@ -712,7 +720,8 @@ bool Top::ShouldReportException(bool* is_caught_externally) {
//
// See comments in RegisterTryCatchHandler for details.
*is_caught_externally = try_catch != NULL &&
- (handler == NULL || handler == try_catch->js_handler_);
+ (handler == NULL || handler == try_catch->js_handler_ ||
+ !catchable_by_javascript);
if (*is_caught_externally) {
// Only report the exception if the external handler is verbose.
@@ -735,12 +744,17 @@ void Top::DoThrow(Object* exception,
// Determine reporting and whether the exception is caught externally.
bool is_caught_externally = false;
bool is_out_of_memory = exception == Failure::OutOfMemoryException();
- bool should_return_exception = ShouldReportException(&is_caught_externally);
- bool report_exception = !is_out_of_memory && should_return_exception;
+ bool is_termination_exception = exception == Heap::termination_exception();
+ bool catchable_by_javascript = !is_termination_exception && !is_out_of_memory;
+ bool should_return_exception =
+ ShouldReturnException(&is_caught_externally, catchable_by_javascript);
+ bool report_exception = catchable_by_javascript && should_return_exception;
#ifdef ENABLE_DEBUGGER_SUPPORT
// Notify debugger of exception.
- Debugger::OnException(exception_handle, report_exception);
+ if (catchable_by_javascript) {
+ Debugger::OnException(exception_handle, report_exception);
+ }
#endif
// Generate the message.
@@ -791,14 +805,21 @@ void Top::ReportPendingMessages() {
// the global context. Note: We have to mark the global context here
// since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
// set it.
+ bool external_caught = thread_local_.external_caught_exception_;
HandleScope scope;
if (thread_local_.pending_exception_ == Failure::OutOfMemoryException()) {
context()->mark_out_of_memory();
+ } else if (thread_local_.pending_exception_ ==
+ Heap::termination_exception()) {
+ if (external_caught) {
+ thread_local_.try_catch_handler_->can_continue_ = false;
+ thread_local_.try_catch_handler_->exception_ = Heap::null_value();
+ }
} else {
Handle<Object> exception(pending_exception());
- bool external_caught = thread_local_.external_caught_exception_;
thread_local_.external_caught_exception_ = false;
if (external_caught) {
+ thread_local_.try_catch_handler_->can_continue_ = true;
thread_local_.try_catch_handler_->exception_ =
thread_local_.pending_exception_;
if (!thread_local_.pending_message_obj_->IsTheHole()) {
@@ -834,16 +855,30 @@ void Top::TraceException(bool flag) {
}
-bool Top::optional_reschedule_exception(bool is_bottom_call) {
+bool Top::OptionalRescheduleException(bool is_bottom_call,
+ bool force_clear_catchable) {
// Allways reschedule out of memory exceptions.
if (!is_out_of_memory()) {
- // Never reschedule the exception if this is the bottom call.
- bool clear_exception = is_bottom_call;
+ bool is_termination_exception =
+ pending_exception() == Heap::termination_exception();
+
+ // Do not reschedule the exception if this is the bottom call or
+ // if we are asked to clear catchable exceptions. Termination
+ // exceptions are not catchable and are only cleared if this is
+ // the bottom call.
+ bool clear_exception = is_bottom_call ||
+ (force_clear_catchable && !is_termination_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.
- if (thread_local_.external_caught_exception_) {
+ if (is_termination_exception) {
+ thread_local_.external_caught_exception_ = false;
+ if (is_bottom_call) {
+ clear_pending_exception();
+ return false;
+ }
+ } else if (thread_local_.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_.try_catch_handler_ != NULL);
Address external_handler_address =
reinterpret_cast<Address>(thread_local_.try_catch_handler_);
diff --git a/deps/v8/src/top.h b/deps/v8/src/top.h
index 25242f7cc..d4d73c21f 100644
--- a/deps/v8/src/top.h
+++ b/deps/v8/src/top.h
@@ -46,6 +46,7 @@ class ThreadLocalTop BASE_EMBEDDED {
// The context where the current execution method is created and for variable
// lookups.
Context* context_;
+ int thread_id_;
Object* pending_exception_;
bool has_pending_message_;
const char* pending_message_;
@@ -118,6 +119,10 @@ class Top {
thread_local_.save_context_ = save;
}
+ // Access to current thread id.
+ static int thread_id() { return thread_local_.thread_id_; }
+ static void set_thread_id(int id) { thread_local_.thread_id_ = id; }
+
// Interface to pending exception.
static Object* pending_exception() {
ASSERT(has_pending_exception());
@@ -152,7 +157,8 @@ class Top {
// exceptions. If an exception was thrown and not handled by an external
// handler the exception is scheduled to be rethrown when we return to running
// JavaScript code. If an exception is scheduled true is returned.
- static bool optional_reschedule_exception(bool is_bottom_call);
+ static bool OptionalRescheduleException(bool is_bottom_call,
+ bool force_clear_catchable);
static bool* external_caught_exception_address() {
return &thread_local_.external_caught_exception_;
@@ -246,7 +252,8 @@ class Top {
static void DoThrow(Object* exception,
MessageLocation* location,
const char* message);
- static bool ShouldReportException(bool* is_caught_externally);
+ static bool ShouldReturnException(bool* is_caught_externally,
+ bool catchable_by_javascript);
static void ReportUncaughtException(Handle<Object> exception,
MessageLocation* location,
Handle<String> stack_trace);
@@ -260,6 +267,7 @@ class Top {
// Out of resource exception helpers.
static Failure* StackOverflow();
+ static Failure* TerminateExecution();
// Administration
static void Initialize();
diff --git a/deps/v8/src/v8.cc b/deps/v8/src/v8.cc
index 00e0e6e6d..faec986d3 100644
--- a/deps/v8/src/v8.cc
+++ b/deps/v8/src/v8.cc
@@ -156,6 +156,7 @@ uint32_t V8::Random() {
return (hi << 16) + (lo & 0xFFFF);
}
+
void V8::IdleNotification(bool is_high_priority) {
if (!FLAG_use_idle_notification) return;
// Ignore high priority instances of V8.
diff --git a/deps/v8/src/v8threads.cc b/deps/v8/src/v8threads.cc
index c5fc9fa7e..8e0a8be5a 100644
--- a/deps/v8/src/v8threads.cc
+++ b/deps/v8/src/v8threads.cc
@@ -151,6 +151,10 @@ bool ThreadManager::RestoreThread() {
from = RegExpStack::RestoreStack(from);
from = Bootstrapper::RestoreState(from);
Thread::SetThreadLocal(thread_state_key, NULL);
+ if (state->terminate_on_restore()) {
+ StackGuard::TerminateExecution();
+ state->set_terminate_on_restore(false);
+ }
state->set_id(kInvalidId);
state->Unlink();
state->LinkInto(ThreadState::FREE_LIST);
@@ -188,6 +192,7 @@ ThreadState* ThreadState::in_use_anchor_ = new ThreadState();
ThreadState::ThreadState() : id_(ThreadManager::kInvalidId),
+ terminate_on_restore_(false),
next_(this), previous_(this) {
}
@@ -317,7 +322,21 @@ int ThreadManager::CurrentId() {
void ThreadManager::AssignId() {
if (!Thread::HasThreadLocal(thread_id_key)) {
- Thread::SetThreadLocalInt(thread_id_key, next_id_++);
+ ASSERT(Locker::IsLocked());
+ int thread_id = next_id_++;
+ Thread::SetThreadLocalInt(thread_id_key, thread_id);
+ Top::set_thread_id(thread_id);
+ }
+}
+
+
+void ThreadManager::TerminateExecution(int thread_id) {
+ for (ThreadState* state = ThreadState::FirstInUse();
+ state != NULL;
+ state = state->Next()) {
+ if (thread_id == state->id()) {
+ state->set_terminate_on_restore(true);
+ }
}
}
diff --git a/deps/v8/src/v8threads.h b/deps/v8/src/v8threads.h
index 83f69f060..3f81f5706 100644
--- a/deps/v8/src/v8threads.h
+++ b/deps/v8/src/v8threads.h
@@ -50,6 +50,12 @@ class ThreadState {
void set_id(int id) { id_ = id; }
int id() { return id_; }
+ // Should the thread be terminated when it is restored?
+ bool terminate_on_restore() { return terminate_on_restore_; }
+ void set_terminate_on_restore(bool terminate_on_restore) {
+ terminate_on_restore_ = terminate_on_restore;
+ }
+
// Get data area for archiving a thread.
char* data() { return data_; }
private:
@@ -58,6 +64,7 @@ class ThreadState {
void AllocateSpace();
int id_;
+ bool terminate_on_restore_;
char* data_;
ThreadState* next_;
ThreadState* previous_;
@@ -88,6 +95,8 @@ class ThreadManager : public AllStatic {
static int CurrentId();
static void AssignId();
+ static void TerminateExecution(int thread_id);
+
static const int kInvalidId = -1;
private:
static void EagerlyArchiveThread();
diff --git a/deps/v8/src/version.cc b/deps/v8/src/version.cc
index 26b009c78..69b7510a6 100644
--- a/deps/v8/src/version.cc
+++ b/deps/v8/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 1
#define MINOR_VERSION 3
-#define BUILD_NUMBER 5
+#define BUILD_NUMBER 6
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false
diff --git a/deps/v8/src/x64/codegen-x64.cc b/deps/v8/src/x64/codegen-x64.cc
index 7fe6ebdb8..462b9600e 100644
--- a/deps/v8/src/x64/codegen-x64.cc
+++ b/deps/v8/src/x64/codegen-x64.cc
@@ -6747,6 +6747,7 @@ void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
void CEntryStub::GenerateCore(MacroAssembler* masm,
Label* throw_normal_exception,
+ Label* throw_termination_exception,
Label* throw_out_of_memory_exception,
StackFrame::Type frame_type,
bool do_gc,
@@ -6819,11 +6820,10 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ testl(rax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
__ j(zero, &retry);
- Label continue_exception;
- // If the returned failure is EXCEPTION then promote Top::pending_exception().
- __ movq(kScratchRegister, Failure::Exception(), RelocInfo::NONE);
+ // Special handling of out of memory exceptions.
+ __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE);
__ cmpq(rax, kScratchRegister);
- __ j(not_equal, &continue_exception);
+ __ j(equal, throw_out_of_memory_exception);
// Retrieve the pending exception and clear the variable.
ExternalReference pending_exception_address(Top::k_pending_exception_address);
@@ -6833,11 +6833,10 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
__ movq(rdx, Operand(rdx, 0));
__ movq(Operand(kScratchRegister, 0), rdx);
- __ bind(&continue_exception);
- // Special handling of out of memory exception.
- __ movq(kScratchRegister, Failure::OutOfMemoryException(), RelocInfo::NONE);
- __ cmpq(rax, kScratchRegister);
- __ j(equal, throw_out_of_memory_exception);
+ // Special handling of termination exceptions which are uncatchable
+ // by javascript code.
+ __ Cmp(rax, Factory::termination_exception());
+ __ j(equal, throw_termination_exception);
// Handle normal exception.
__ jmp(throw_normal_exception);
@@ -6847,7 +6846,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
}
-void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
+void CEntryStub::GenerateThrowUncatchable(MacroAssembler* masm,
+ UncatchableExceptionType type) {
// Fetch top stack handler.
ExternalReference handler_address(Top::k_handler_address);
__ movq(kScratchRegister, handler_address);
@@ -6857,30 +6857,32 @@ void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
Label loop, done;
__ bind(&loop);
// Load the type of the current stack handler.
- __ cmpq(Operand(rsp, StackHandlerConstants::kStateOffset),
- Immediate(StackHandler::ENTRY));
+ const int kStateOffset = StackHandlerConstants::kStateOffset;
+ __ cmpq(Operand(rsp, kStateOffset), Immediate(StackHandler::ENTRY));
__ j(equal, &done);
// Fetch the next handler in the list.
- ASSERT(StackHandlerConstants::kNextOffset == 0);
- __ pop(rsp);
+ const int kNextOffset = StackHandlerConstants::kNextOffset;
+ __ movq(rsp, Operand(rsp, kNextOffset));
__ jmp(&loop);
__ bind(&done);
// Set the top handler address to next handler past the current ENTRY handler.
- __ pop(rax);
- __ store_rax(handler_address);
+ __ movq(kScratchRegister, handler_address);
+ __ pop(Operand(kScratchRegister, 0));
- // Set external caught exception to false.
- __ movq(rax, Immediate(false));
- ExternalReference external_caught(Top::k_external_caught_exception_address);
- __ store_rax(external_caught);
+ if (type == OUT_OF_MEMORY) {
+ // Set external caught exception to false.
+ ExternalReference external_caught(Top::k_external_caught_exception_address);
+ __ movq(rax, Immediate(false));
+ __ store_rax(external_caught);
- // Set pending exception and rax to out of memory exception.
- __ movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
- ExternalReference pending_exception(Top::k_pending_exception_address);
- __ store_rax(pending_exception);
+ // Set pending exception and rax to out of memory exception.
+ ExternalReference pending_exception(Top::k_pending_exception_address);
+ __ movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
+ __ store_rax(pending_exception);
+ }
- // Clear the context pointer;
+ // Clear the context pointer.
__ xor_(rsi, rsi);
// Restore registers from handler.
@@ -6956,12 +6958,14 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
// r14: number of arguments including receiver (C callee-saved).
// r15: argv pointer (C callee-saved).
- Label throw_out_of_memory_exception;
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,
frame_type,
false,
@@ -6970,6 +6974,7 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
// Do space-specific GC and retry runtime call.
GenerateCore(masm,
&throw_normal_exception,
+ &throw_termination_exception,
&throw_out_of_memory_exception,
frame_type,
true,
@@ -6980,14 +6985,17 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
__ movq(rax, failure, RelocInfo::NONE);
GenerateCore(masm,
&throw_normal_exception,
+ &throw_termination_exception,
&throw_out_of_memory_exception,
frame_type,
true,
true);
__ bind(&throw_out_of_memory_exception);
- GenerateThrowOutOfMemory(masm);
- // control flow for generated will not return.
+ GenerateThrowUncatchable(masm, OUT_OF_MEMORY);
+
+ __ bind(&throw_termination_exception);
+ GenerateThrowUncatchable(masm, TERMINATION);
__ bind(&throw_normal_exception);
GenerateThrowTOS(masm);
diff --git a/deps/v8/test/cctest/SConscript b/deps/v8/test/cctest/SConscript
index 112ecd6fa..fc4e01a42 100644
--- a/deps/v8/test/cctest/SConscript
+++ b/deps/v8/test/cctest/SConscript
@@ -56,6 +56,7 @@ SOURCES = {
'test-spaces.cc',
'test-strings.cc',
'test-threads.cc',
+ 'test-thread-termination.cc',
'test-utils.cc',
'test-version.cc'
],
diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc
index e1caba3c8..7b7e1a3be 100644
--- a/deps/v8/test/cctest/test-api.cc
+++ b/deps/v8/test/cctest/test-api.cc
@@ -2843,7 +2843,7 @@ TEST(ErrorReporting) {
static const char* js_code_causing_huge_string_flattening =
"var str = 'X';"
- "for (var i = 0; i < 29; i++) {"
+ "for (var i = 0; i < 30; i++) {"
" str = str + str;"
"}"
"str.match(/X/);";
@@ -6217,6 +6217,58 @@ TEST(DontLeakGlobalObjects) {
}
+v8::Persistent<v8::Object> some_object;
+v8::Persistent<v8::Object> bad_handle;
+
+void NewPersistentHandleCallback(v8::Persistent<v8::Value>, void*) {
+ v8::HandleScope scope;
+ bad_handle = v8::Persistent<v8::Object>::New(some_object);
+}
+
+
+THREADED_TEST(NewPersistentHandleFromWeakCallback) {
+ LocalContext context;
+
+ v8::Persistent<v8::Object> handle1, handle2;
+ {
+ v8::HandleScope scope;
+ some_object = v8::Persistent<v8::Object>::New(v8::Object::New());
+ handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
+ handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
+ }
+ // Note: order is implementation dependent alas: currently
+ // global handle nodes are processed by PostGarbageCollectionProcessing
+ // in reverse allocation order, so if second allocated handle is deleted,
+ // weak callback of the first handle would be able to 'reallocate' it.
+ handle1.MakeWeak(NULL, NewPersistentHandleCallback);
+ handle2.Dispose();
+ i::Heap::CollectAllGarbage();
+}
+
+
+v8::Persistent<v8::Object> to_be_disposed;
+
+void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) {
+ to_be_disposed.Dispose();
+ i::Heap::CollectAllGarbage();
+}
+
+
+THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
+ LocalContext context;
+
+ v8::Persistent<v8::Object> handle1, handle2;
+ {
+ v8::HandleScope scope;
+ handle1 = v8::Persistent<v8::Object>::New(v8::Object::New());
+ handle2 = v8::Persistent<v8::Object>::New(v8::Object::New());
+ }
+ handle1.MakeWeak(NULL, DisposeAndForceGcCallback);
+ to_be_disposed = handle2;
+ i::Heap::CollectAllGarbage();
+}
+
+
THREADED_TEST(CheckForCrossContextObjectLiterals) {
v8::V8::Initialize();
@@ -7121,6 +7173,30 @@ THREADED_TEST(MorphCompositeStringTest) {
}
+TEST(CompileExternalTwoByteSource) {
+ v8::HandleScope scope;
+ LocalContext context;
+
+ // This is a very short list of sources, which currently is to check for a
+ // regression caused by r2703.
+ const char* ascii_sources[] = {
+ "0.5",
+ "-0.5", // This mainly testes PushBack in the Scanner.
+ "--0.5", // This mainly testes PushBack in the Scanner.
+ NULL
+ };
+
+ // Compile the sources as external two byte strings.
+ for (int i = 0; ascii_sources[i] != NULL; i++) {
+ uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
+ UC16VectorResource uc16_resource(
+ i::Vector<const uint16_t>(two_byte_string, strlen(ascii_sources[i])));
+ v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
+ v8::Script::Compile(source);
+ }
+}
+
+
class RegExpStringModificationTest {
public:
RegExpStringModificationTest()
diff --git a/deps/v8/test/cctest/test-thread-termination.cc b/deps/v8/test/cctest/test-thread-termination.cc
new file mode 100644
index 000000000..323be1d77
--- /dev/null
+++ b/deps/v8/test/cctest/test-thread-termination.cc
@@ -0,0 +1,195 @@
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+#include "platform.h"
+#include "cctest.h"
+
+
+v8::internal::Semaphore* semaphore = NULL;
+
+
+v8::Handle<v8::Value> Signal(const v8::Arguments& args) {
+ semaphore->Signal();
+ return v8::Undefined();
+}
+
+
+v8::Handle<v8::Value> TerminateCurrentThread(const v8::Arguments& args) {
+ v8::V8::TerminateExecution();
+ return v8::Undefined();
+}
+
+
+v8::Handle<v8::Value> Fail(const v8::Arguments& args) {
+ CHECK(false);
+ return v8::Undefined();
+}
+
+
+v8::Handle<v8::Value> Loop(const v8::Arguments& args) {
+ v8::Handle<v8::String> source =
+ v8::String::New("try { doloop(); fail(); } catch(e) { fail(); }");
+ v8::Script::Compile(source)->Run();
+ return v8::Undefined();
+}
+
+
+v8::Handle<v8::Value> DoLoop(const v8::Arguments& args) {
+ v8::TryCatch try_catch;
+ v8::Script::Compile(v8::String::New("function f() {"
+ " var term = true;"
+ " try {"
+ " while(true) {"
+ " if (term) terminate();"
+ " term = false;"
+ " }"
+ " fail();"
+ " } catch(e) {"
+ " fail();"
+ " }"
+ "}"
+ "f()"))->Run();
+ CHECK(try_catch.HasCaught());
+ CHECK(try_catch.Exception()->IsNull());
+ CHECK(try_catch.Message().IsEmpty());
+ CHECK(!try_catch.CanContinue());
+ return v8::Undefined();
+}
+
+
+v8::Handle<v8::ObjectTemplate> CreateGlobalTemplate(
+ v8::InvocationCallback terminate) {
+ v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+ global->Set(v8::String::New("terminate"),
+ v8::FunctionTemplate::New(terminate));
+ global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail));
+ global->Set(v8::String::New("loop"), v8::FunctionTemplate::New(Loop));
+ global->Set(v8::String::New("doloop"), v8::FunctionTemplate::New(DoLoop));
+ return global;
+}
+
+
+// Test that a single thread of JavaScript execution can terminate
+// itself.
+TEST(TerminateOnlyV8ThreadFromThreadItself) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> global =
+ CreateGlobalTemplate(TerminateCurrentThread);
+ v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
+ v8::Context::Scope context_scope(context);
+ // Run a loop that will be infinite if thread termination does not work.
+ v8::Handle<v8::String> source =
+ v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
+ v8::Script::Compile(source)->Run();
+ // Test that we can run the code again after thread termination.
+ v8::Script::Compile(source)->Run();
+ context.Dispose();
+}
+
+
+class TerminatorThread : public v8::internal::Thread {
+ void Run() {
+ semaphore->Wait();
+ v8::V8::TerminateExecution();
+ }
+};
+
+
+// Test that a single thread of JavaScript execution can be terminated
+// from the side by another thread.
+TEST(TerminateOnlyV8ThreadFromOtherThread) {
+ semaphore = v8::internal::OS::CreateSemaphore(0);
+ TerminatorThread thread;
+ thread.Start();
+
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(Signal);
+ v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
+ v8::Context::Scope context_scope(context);
+ // Run a loop that will be infinite if thread termination does not work.
+ v8::Handle<v8::String> source =
+ v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
+ v8::Script::Compile(source)->Run();
+
+ thread.Join();
+ delete semaphore;
+ semaphore = NULL;
+ context.Dispose();
+}
+
+
+class LoopingThread : public v8::internal::Thread {
+ public:
+ void Run() {
+ v8::Locker locker;
+ v8::HandleScope scope;
+ v8_thread_id_ = v8::V8::GetCurrentThreadId();
+ v8::Handle<v8::ObjectTemplate> global = CreateGlobalTemplate(Signal);
+ v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
+ v8::Context::Scope context_scope(context);
+ // Run a loop that will be infinite if thread termination does not work.
+ v8::Handle<v8::String> source =
+ v8::String::New("try { loop(); fail(); } catch(e) { fail(); }");
+ v8::Script::Compile(source)->Run();
+ context.Dispose();
+ }
+
+ int GetV8ThreadId() { return v8_thread_id_; }
+
+ private:
+ int v8_thread_id_;
+};
+
+
+// Test that multiple threads using V8 can be terminated from another
+// thread when using Lockers and preemption.
+TEST(TerminateMultipleV8Threads) {
+ {
+ v8::Locker locker;
+ v8::V8::Initialize();
+ v8::Locker::StartPreemption(1);
+ semaphore = v8::internal::OS::CreateSemaphore(0);
+ }
+ LoopingThread thread1;
+ thread1.Start();
+ LoopingThread thread2;
+ thread2.Start();
+ // Wait until both threads have signaled the semaphore.
+ semaphore->Wait();
+ semaphore->Wait();
+ {
+ v8::Locker locker;
+ v8::V8::TerminateExecution(thread1.GetV8ThreadId());
+ v8::V8::TerminateExecution(thread2.GetV8ThreadId());
+ }
+ thread1.Join();
+ thread2.Join();
+
+ delete semaphore;
+ semaphore = NULL;
+}
diff --git a/deps/v8/test/cctest/test-threads.cc b/deps/v8/test/cctest/test-threads.cc
index c0d55f250..f70c4e8c1 100644
--- a/deps/v8/test/cctest/test-threads.cc
+++ b/deps/v8/test/cctest/test-threads.cc
@@ -50,5 +50,3 @@ TEST(Preemption) {
script->Run();
}
-
-
diff --git a/deps/v8/test/mozilla/mozilla.status b/deps/v8/test/mozilla/mozilla.status
index a1551dcdd..399c9c604 100644
--- a/deps/v8/test/mozilla/mozilla.status
+++ b/deps/v8/test/mozilla/mozilla.status
@@ -624,7 +624,6 @@ js1_5/extensions/regress-333541: FAIL_OK
js1_5/extensions/regress-335700: FAIL_OK
js1_5/extensions/regress-336409-1: FAIL_OK
js1_5/extensions/regress-336409-2: FAIL_OK
-js1_5/extensions/regress-336410-1: FAIL_OK
js1_5/extensions/regress-336410-2: FAIL_OK
js1_5/extensions/regress-341956-01: FAIL_OK
js1_5/extensions/regress-341956-02: FAIL_OK
@@ -706,6 +705,11 @@ js1_5/extensions/toLocaleFormat-02: FAIL_OK
js1_5/extensions/regress-330569: TIMEOUT
js1_5/extensions/regress-351448: TIMEOUT
js1_5/extensions/regress-342960: FAIL_OK || TIMEOUT if $mode == debug
+# In the 64-bit version, this test takes longer to run out of memory
+# than it does in the 32-bit version when attempting to generate a huge
+# error message in debug mode.
+js1_5/extensions/regress-336410-1: FAIL_OK || TIMEOUT if ($mode == debug && $arch == x64)
+
##################### DECOMPILATION TESTS #####################
diff --git a/deps/v8/tools/gyp/v8.gyp b/deps/v8/tools/gyp/v8.gyp
index b0c33318f..c57419879 100644
--- a/deps/v8/tools/gyp/v8.gyp
+++ b/deps/v8/tools/gyp/v8.gyp
@@ -97,9 +97,15 @@
],
}],
],
- 'cflags_cc': [
- '-fno-rtti',
- ],
+ }],
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'GCC_OPTIMIZATION_LEVEL': '3', # -O3
+ 'GCC_STRICT_ALIASING': 'YES', # -fstrict-aliasing. Mainline gcc
+ # enables this at -O2 and above,
+ # but Apple gcc does not unless it
+ # is specified explicitly.
+ },
}],
['OS=="win"', {
'msvs_configuration_attributes': {
@@ -128,10 +134,6 @@
],
},
},
- 'xcode_settings': {
- 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO',
- 'GCC_ENABLE_CPP_RTTI': 'NO',
- },
},
'targets': [
{
@@ -387,7 +389,7 @@
'../../src/arm/assembler-arm.cc',
'../../src/arm/assembler-arm.h',
'../../src/arm/builtins-arm.cc',
- '../../src/arm/cfg-arm.cc',
+ '../../src/arm/cfg-arm.cc',
'../../src/arm/codegen-arm.cc',
'../../src/arm/codegen-arm.h',
'../../src/arm/constants-arm.h',
@@ -418,7 +420,7 @@
'../../src/ia32/assembler-ia32.cc',
'../../src/ia32/assembler-ia32.h',
'../../src/ia32/builtins-ia32.cc',
- '../../src/ia32/cfg-ia32.cc',
+ '../../src/ia32/cfg-ia32.cc',
'../../src/ia32/codegen-ia32.cc',
'../../src/ia32/codegen-ia32.h',
'../../src/ia32/cpu-ia32.cc',
@@ -451,7 +453,7 @@
'../../src/x64/assembler-x64.cc',
'../../src/x64/assembler-x64.h',
'../../src/x64/builtins-x64.cc',
- '../../src/x64/cfg-x64.cc',
+ '../../src/x64/cfg-x64.cc',
'../../src/x64/codegen-x64.cc',
'../../src/x64/codegen-x64.h',
'../../src/x64/cpu-x64.cc',