Revision: 14378
Author: [email protected]
Date: Mon Apr 22 08:01:45 2013
Log: Add methods to allow resuming execution after calling
TerminateExecution().
[email protected]
BUG=v8:2361
Review URL: https://chromiumcodereview.appspot.com/14401008
Patch from Andrew Paprocki <[email protected]>.
http://code.google.com/p/v8/source/detail?r=14378
Modified:
/branches/bleeding_edge/AUTHORS
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/execution.cc
/branches/bleeding_edge/src/execution.h
/branches/bleeding_edge/src/isolate.cc
/branches/bleeding_edge/src/isolate.h
/branches/bleeding_edge/test/cctest/test-thread-termination.cc
=======================================
--- /branches/bleeding_edge/AUTHORS Thu Mar 21 07:42:17 2013
+++ /branches/bleeding_edge/AUTHORS Mon Apr 22 08:01:45 2013
@@ -9,6 +9,7 @@
Hewlett-Packard Development Company, LP
Igalia, S.L.
Joyent, Inc.
+Bloomberg Finance L.P.
Akinori MUSHA <[email protected]>
Alexander Botero-Lowry <[email protected]>
=======================================
--- /branches/bleeding_edge/include/v8.h Tue Apr 16 09:37:04 2013
+++ /branches/bleeding_edge/include/v8.h Mon Apr 22 08:01:45 2013
@@ -3675,6 +3675,24 @@
*/
static bool IsExecutionTerminating(Isolate* isolate = NULL);
+ /**
+ * Resume execution capability in the given isolate, whose execution
+ * was previously forcefully terminated using TerminateExecution().
+ *
+ * When execution is forcefully terminated using TerminateExecution(),
+ * the isolate can not resume execution until all JavaScript frames
+ * have propagated the uncatchable exception which is generated. This
+ * method allows the program embedding the engine to handle the
+ * termination event and resume execution capability, even if
+ * JavaScript frames remain on the stack.
+ *
+ * This method can be used by any thread even if that thread has not
+ * acquired the V8 lock with a Locker object.
+ *
+ * \param isolate The isolate in which to resume execution capability.
+ */
+ static void CancelTerminateExecution(Isolate* isolate);
+
/**
* Releases any resources used by v8 and stops any utility threads
* that may be running. Note that disposing v8 is permanent, it
@@ -3785,20 +3803,29 @@
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.
+ * For certain types of exceptions, it makes no sense to continue
execution.
*
- * If CanContinue returns false, the correct action is to perform
- * any C++ cleanup needed and then return.
+ * If CanContinue returns false, the correct action is to perform any C++
+ * cleanup needed and then return. If CanContinue returns false and
+ * HasTerminated returns true, it is possible to call
+ * CancelTerminateExecution in order to continue calling into the engine.
*/
bool CanContinue() const;
+ /**
+ * Returns true if an exception has been caught due to script execution
+ * being terminated.
+ *
+ * There is no JavaScript representation of an execution termination
+ * exception. Such exceptions are thrown when the TerminateExecution
+ * methods are called to terminate a long-running script.
+ *
+ * If such an exception has been thrown, HasTerminated will return true,
+ * indicating that it is possible to call CancelTerminateExecution in
order
+ * to continue calling into the engine.
+ */
+ bool HasTerminated() const;
+
/**
* Throws the exception caught by this TryCatch in a way that avoids
* it being caught again by this same TryCatch. As with ThrowException
@@ -3874,6 +3901,7 @@
bool can_continue_ : 1;
bool capture_message_ : 1;
bool rethrow_ : 1;
+ bool has_terminated_ : 1;
friend class v8::internal::Isolate;
};
=======================================
--- /branches/bleeding_edge/src/api.cc Fri Apr 19 06:26:47 2013
+++ /branches/bleeding_edge/src/api.cc Mon Apr 22 08:01:45 2013
@@ -1909,7 +1909,8 @@
is_verbose_(false),
can_continue_(true),
capture_message_(true),
- rethrow_(false) {
+ rethrow_(false),
+ has_terminated_(false) {
isolate_->RegisterTryCatchHandler(this);
}
@@ -1937,6 +1938,11 @@
}
+bool v8::TryCatch::HasTerminated() const {
+ return has_terminated_;
+}
+
+
v8::Handle<v8::Value> v8::TryCatch::ReThrow() {
if (!HasCaught()) return v8::Local<v8::Value>();
rethrow_ = true;
@@ -6114,6 +6120,12 @@
reinterpret_cast<i::Isolate*>(isolate) : i::Isolate::Current();
return IsExecutionTerminatingCheck(i_isolate);
}
+
+
+void V8::CancelTerminateExecution(Isolate* isolate) {
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
+ i_isolate->stack_guard()->CancelTerminateExecution();
+}
Isolate* Isolate::GetCurrent() {
=======================================
--- /branches/bleeding_edge/src/execution.cc Tue Apr 16 05:30:51 2013
+++ /branches/bleeding_edge/src/execution.cc Mon Apr 22 08:01:45 2013
@@ -424,6 +424,13 @@
ExecutionAccess access(isolate_);
return (thread_local_.interrupt_flags_ & TERMINATE) != 0;
}
+
+
+void StackGuard::CancelTerminateExecution() {
+ ExecutionAccess access(isolate_);
+ Continue(TERMINATE);
+ isolate_->CancelTerminateExecution();
+}
void StackGuard::TerminateExecution() {
=======================================
--- /branches/bleeding_edge/src/execution.h Fri Apr 12 01:58:22 2013
+++ /branches/bleeding_edge/src/execution.h Mon Apr 22 08:01:45 2013
@@ -190,6 +190,7 @@
void Interrupt();
bool IsTerminateExecution();
void TerminateExecution();
+ void CancelTerminateExecution();
#ifdef ENABLE_DEBUGGER_SUPPORT
bool IsDebugBreak();
void DebugBreak();
=======================================
--- /branches/bleeding_edge/src/isolate.cc Fri Apr 19 06:26:47 2013
+++ /branches/bleeding_edge/src/isolate.cc Mon Apr 22 08:01:45 2013
@@ -1075,6 +1075,23 @@
DoThrow(heap_.termination_exception(), NULL);
return Failure::Exception();
}
+
+
+void Isolate::CancelTerminateExecution() {
+ if (try_catch_handler()) {
+ try_catch_handler()->has_terminated_ = false;
+ }
+ if (has_pending_exception() &&
+ pending_exception() == heap_.termination_exception()) {
+ thread_local_top()->external_caught_exception_ = false;
+ clear_pending_exception();
+ }
+ if (has_scheduled_exception() &&
+ scheduled_exception() == heap_.termination_exception()) {
+ thread_local_top()->external_caught_exception_ = false;
+ clear_scheduled_exception();
+ }
+}
Failure* Isolate::Throw(Object* exception, MessageLocation* location) {
@@ -1990,12 +2007,14 @@
} else if (thread_local_top_.pending_exception_ ==
heap()->termination_exception()) {
try_catch_handler()->can_continue_ = false;
+ try_catch_handler()->has_terminated_ = true;
try_catch_handler()->exception_ = heap()->null_value();
} else {
// At this point all non-object (failure) exceptions have
// been dealt with so this shouldn't fail.
ASSERT(!pending_exception()->IsFailure());
try_catch_handler()->can_continue_ = true;
+ try_catch_handler()->has_terminated_ = false;
try_catch_handler()->exception_ = pending_exception();
if (!thread_local_top_.pending_message_obj_->IsTheHole()) {
try_catch_handler()->message_ =
thread_local_top_.pending_message_obj_;
=======================================
--- /branches/bleeding_edge/src/isolate.h Wed Apr 17 00:53:12 2013
+++ /branches/bleeding_edge/src/isolate.h Mon Apr 22 08:01:45 2013
@@ -783,6 +783,7 @@
// Out of resource exception helpers.
Failure* StackOverflow();
Failure* TerminateExecution();
+ void CancelTerminateExecution();
// Administration
void Iterate(ObjectVisitor* v);
=======================================
--- /branches/bleeding_edge/test/cctest/test-thread-termination.cc Thu Mar
21 07:42:17 2013
+++ /branches/bleeding_edge/test/cctest/test-thread-termination.cc Mon Apr
22 08:01:45 2013
@@ -372,3 +372,40 @@
"f()"))->Run()->IsTrue());
context.Dispose(context->GetIsolate());
}
+
+v8::Handle<v8::Value> DoLoopCancelTerminate(const v8::Arguments& args) {
+ v8::TryCatch try_catch;
+ CHECK(!v8::V8::IsExecutionTerminating());
+ v8::Script::Compile(v8::String::New("var term = true;"
+ "while(true) {"
+ " if (term) terminate();"
+ " term = false;"
+ "}"
+ "fail();"))->Run();
+ CHECK(try_catch.HasCaught());
+ CHECK(try_catch.Exception()->IsNull());
+ CHECK(try_catch.Message().IsEmpty());
+ CHECK(!try_catch.CanContinue());
+ CHECK(v8::V8::IsExecutionTerminating());
+ CHECK(try_catch.HasTerminated());
+ v8::V8::CancelTerminateExecution(v8::Isolate::GetCurrent());
+ CHECK(!v8::V8::IsExecutionTerminating());
+ return v8::Undefined();
+}
+
+// Test that a single thread of JavaScript execution can terminate
+// itself and then resume execution.
+TEST(TerminateCancelTerminateFromThreadItself) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> global =
+ CreateGlobalTemplate(TerminateCurrentThread, DoLoopCancelTerminate);
+ v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
+ v8::Context::Scope context_scope(context);
+ CHECK(!v8::V8::IsExecutionTerminating());
+ v8::Handle<v8::String> source =
+ v8::String::New("try { doloop(); } catch(e) { fail();
} 'completed';");
+ // Check that execution completed with correct return value.
+ CHECK(v8::Script::Compile(source)->Run()->Equals(v8_str("completed")));
+ context.Dispose(context->GetIsolate());
+}
+
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.