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.



git-svn-id: http://v8.googlecode.com/svn/trunk@2739 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/api.cc b/src/api.cc
index 88cf2bcd..7d97fc6 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -75,7 +75,7 @@
           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::CanContinue() const {
+  return can_continue_;
+}
+
+
 v8::Local<Value> v8::TryCatch::Exception() const {
   if (HasCaught()) {
     // Check for out of memory exception.
@@ -2599,10 +2604,18 @@
 }
 
 
-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 @@
   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/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 40b0ac8..71ffaa2 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -5701,7 +5701,8 @@
 }
 
 
-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 @@
 
   // Set the top handler address to next handler past the current ENTRY handler.
   ASSERT(StackHandlerConstants::kNextOffset == 0);
-  __ pop(r0);
-  __ str(r0, MemOperand(r3));
+  __ pop(r2);
+  __ str(r2, 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));
+  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));
+    // 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::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 @@
   __ 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 @@
   __ 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 @@
   // 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 @@
   // 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 @@
   __ 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/src/codegen.h b/src/codegen.h
index 243d87c..d6967b7 100644
--- a/src/codegen.h
+++ b/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 @@
   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/src/execution.cc b/src/execution.cc
index 9080f5e..0ad55bd 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -156,7 +156,8 @@
     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 @@
 }
 
 
+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 @@
   }
 #endif
   if (StackGuard::IsPreempted()) RuntimePreempt();
+  if (StackGuard::IsTerminateExecution()) {
+    StackGuard::Continue(TERMINATE);
+    return Top::TerminateExecution();
+  }
   if (StackGuard::IsInterrupted()) {
     // interrupt
     StackGuard::Continue(INTERRUPT);
diff --git a/src/execution.h b/src/execution.h
index fba696e..456cbe7 100644
--- a/src/execution.h
+++ b/src/execution.h
@@ -37,7 +37,8 @@
   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 @@
   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/src/global-handles.cc b/src/global-handles.cc
index ed4e262..e51c4aa 100644
--- a/src/global-handles.cc
+++ b/src/global-handles.cc
@@ -144,8 +144,8 @@
   // 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 @@
     // 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 @@
 }
 
 
+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/src/heap.cc b/src/heap.cc
index 7d6e442..ad25f93 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -73,7 +73,7 @@
 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::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::PostGarbageCollectionProcessing() {
   // Process weak handles post gc.
-  GlobalHandles::PostGarbageCollectionProcessing();
+  {
+    DisableAssertNoAllocation allow_allocation;
+    GlobalHandles::PostGarbageCollectionProcessing();
+  }
   // Update flat string readers.
   FlatStringReader::PostGarbageCollectionProcessing();
 }
@@ -1412,6 +1417,9 @@
   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 @@
     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/src/heap.h b/src/heap.h
index ec1e21a..ac6f5be 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -111,6 +111,7 @@
   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 @@
   // 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 @@
   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 @@
   ~AssertNoAllocation() { }
 };
 
+class DisableAssertNoAllocation {
+ public:
+  DisableAssertNoAllocation() { }
+  ~DisableAssertNoAllocation() { }
+};
+
 #endif
 
 #ifdef ENABLE_LOGGING_AND_PROFILING
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index b8b3db6..bf1f81b 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -7505,6 +7505,7 @@
 
 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 @@
   __ 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 @@
          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::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 @@
   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 @@
   // 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 @@
   // 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 @@
   __ 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/src/mark-compact.cc b/src/mark-compact.cc
index 6e823b3..10e81ac 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -39,6 +39,7 @@
 // -------------------------------------------------------------------------
 // MarkCompactCollector
 
+bool MarkCompactCollector::force_compaction_ = false;
 bool MarkCompactCollector::compacting_collection_ = false;
 
 int MarkCompactCollector::previous_marked_count_ = 0;
@@ -110,7 +111,7 @@
 #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/src/mark-compact.h b/src/mark-compact.h
index bd9e4a0..0bd212e 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -75,6 +75,12 @@
   // 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 @@
   // 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/src/messages.cc b/src/messages.cc
index a3fffcb..e16b1b2 100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -147,14 +147,12 @@
   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/src/objects-debug.cc b/src/objects-debug.cc
index e97b207..f713171 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -705,7 +705,8 @@
   } 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/src/objects-inl.h b/src/objects-inl.h
index 7b750b6..91aae2f 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -788,6 +788,7 @@
   return Construct(EXCEPTION);
 }
 
+
 Failure* Failure::OutOfMemoryException() {
   return Construct(OUT_OF_MEMORY_EXCEPTION);
 }
diff --git a/src/scanner.cc b/src/scanner.cc
index 720dc35..3dae414 100644
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -183,7 +183,8 @@
 
 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/src/scanner.h b/src/scanner.h
index 340da86..a201d0e 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -212,6 +212,8 @@
   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 @@
   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/src/spaces.cc b/src/spaces.cc
index 9227a87..337f014 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -1079,9 +1079,9 @@
 
 
 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/src/third_party/dtoa/dtoa.c b/src/third_party/dtoa/dtoa.c
index 5caa96d..fadc6d1 100644
--- a/src/third_party/dtoa/dtoa.c
+++ b/src/third_party/dtoa/dtoa.c
@@ -1535,7 +1535,7 @@
 	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/src/top.cc b/src/top.cc
index 96d4a01..550703a 100644
--- a/src/top.cc
+++ b/src/top.cc
@@ -98,6 +98,7 @@
   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::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 @@
 }
 
 
-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 @@
   //
   // 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 @@
   // 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 @@
   // 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 @@
 }
 
 
-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();
 
-    // 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_) {
+    // 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 (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/src/top.h b/src/top.h
index 25242f7..d4d73c2 100644
--- a/src/top.h
+++ b/src/top.h
@@ -46,6 +46,7 @@
   // 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 @@
     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 @@
   // 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 @@
   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 @@
 
   // Out of resource exception helpers.
   static Failure* StackOverflow();
+  static Failure* TerminateExecution();
 
   // Administration
   static void Initialize();
diff --git a/src/v8.cc b/src/v8.cc
index 00e0e6e..faec986 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -156,6 +156,7 @@
   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/src/v8threads.cc b/src/v8threads.cc
index c5fc9fa..8e0a8be 100644
--- a/src/v8threads.cc
+++ b/src/v8threads.cc
@@ -151,6 +151,10 @@
   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() : id_(ThreadManager::kInvalidId),
+                             terminate_on_restore_(false),
                              next_(this), previous_(this) {
 }
 
@@ -317,7 +322,21 @@
 
 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/src/v8threads.h b/src/v8threads.h
index 83f69f0..3f81f57 100644
--- a/src/v8threads.h
+++ b/src/v8threads.h
@@ -50,6 +50,12 @@
   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 @@
   void AllocateSpace();
 
   int id_;
+  bool terminate_on_restore_;
   char* data_;
   ThreadState* next_;
   ThreadState* previous_;
@@ -88,6 +95,8 @@
   static int CurrentId();
   static void AssignId();
 
+  static void TerminateExecution(int thread_id);
+
   static const int kInvalidId = -1;
  private:
   static void EagerlyArchiveThread();
diff --git a/src/version.cc b/src/version.cc
index 26b009c..69b7510 100644
--- a/src/version.cc
+++ b/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/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 7fe6ebd..462b960 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -6747,6 +6747,7 @@
 
 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 @@
   __ 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 @@
   __ 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::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 @@
   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 @@
   // 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 @@
   // 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 @@
   __ 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);