From: ager@chromium.org Date: Thu, 4 Mar 2010 12:13:04 +0000 (+0000) Subject: Add IsExecutionTerminating api method. X-Git-Tag: upstream/4.7.83~22350 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fe3b87557704752124b6e4eb60be1a67844b9277;p=platform%2Fupstream%2Fv8.git Add IsExecutionTerminating api method. IsExecutionTerminating returns true if a termination exception is currently being propagated. C++ code should not reenter V8 when IsExecutionTerminating returns true. Review URL: http://codereview.chromium.org/668052 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4016 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/include/v8.h b/include/v8.h index 92e1bb6..238dddd 100644 --- a/include/v8.h +++ b/include/v8.h @@ -2464,6 +2464,16 @@ class V8EXPORT V8 { static void TerminateExecution(); /** + * Is V8 terminating JavaScript execution. + * + * Returns true if JavaScript execution is currently terminating + * because of a call to TerminateExecution. In that case there are + * still JavaScript frames on the stack and the termination + * exception is still active. + */ + static bool IsExecutionTerminating(); + + /** * Releases any resources used by v8 and stops any utility threads * that may be running. Note that disposing v8 is permanent, it * cannot be reinitialized. diff --git a/src/api.cc b/src/api.cc index 4d193c3..f479f5c 100644 --- a/src/api.cc +++ b/src/api.cc @@ -3615,6 +3615,15 @@ void V8::TerminateExecution() { } +bool V8::IsExecutionTerminating() { + if (!i::V8::IsRunning()) return false; + if (i::Top::has_scheduled_exception()) { + return i::Top::scheduled_exception() == i::Heap::termination_exception(); + } + return false; +} + + String::Utf8Value::Utf8Value(v8::Handle obj) { EnsureInitialized("v8::String::Utf8Value::Utf8Value()"); if (obj.IsEmpty()) { diff --git a/test/cctest/test-thread-termination.cc b/test/cctest/test-thread-termination.cc index 1e8102e..83a1e19 100644 --- a/test/cctest/test-thread-termination.cc +++ b/test/cctest/test-thread-termination.cc @@ -40,6 +40,7 @@ v8::Handle Signal(const v8::Arguments& args) { v8::Handle TerminateCurrentThread(const v8::Arguments& args) { + CHECK(!v8::V8::IsExecutionTerminating()); v8::V8::TerminateExecution(); return v8::Undefined(); } @@ -52,15 +53,19 @@ v8::Handle Fail(const v8::Arguments& args) { v8::Handle Loop(const v8::Arguments& args) { + CHECK(!v8::V8::IsExecutionTerminating()); v8::Handle source = v8::String::New("try { doloop(); fail(); } catch(e) { fail(); }"); - v8::Script::Compile(source)->Run(); + v8::Handle result = v8::Script::Compile(source)->Run(); + CHECK(result.IsEmpty()); + CHECK(v8::V8::IsExecutionTerminating()); return v8::Undefined(); } v8::Handle DoLoop(const v8::Arguments& args) { v8::TryCatch try_catch; + CHECK(!v8::V8::IsExecutionTerminating()); v8::Script::Compile(v8::String::New("function f() {" " var term = true;" " try {" @@ -78,12 +83,14 @@ v8::Handle DoLoop(const v8::Arguments& args) { CHECK(try_catch.Exception()->IsNull()); CHECK(try_catch.Message().IsEmpty()); CHECK(!try_catch.CanContinue()); + CHECK(v8::V8::IsExecutionTerminating()); return v8::Undefined(); } v8::Handle DoLoopNoCall(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();" @@ -93,6 +100,7 @@ v8::Handle DoLoopNoCall(const v8::Arguments& args) { CHECK(try_catch.Exception()->IsNull()); CHECK(try_catch.Message().IsEmpty()); CHECK(!try_catch.CanContinue()); + CHECK(v8::V8::IsExecutionTerminating()); return v8::Undefined(); } @@ -118,11 +126,13 @@ TEST(TerminateOnlyV8ThreadFromThreadItself) { CreateGlobalTemplate(TerminateCurrentThread, DoLoop); v8::Persistent context = v8::Context::New(NULL, global); v8::Context::Scope context_scope(context); + CHECK(!v8::V8::IsExecutionTerminating()); // Run a loop that will be infinite if thread termination does not work. v8::Handle 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. + CHECK(!v8::V8::IsExecutionTerminating()); v8::Script::Compile(source)->Run(); context.Dispose(); } @@ -136,10 +146,12 @@ TEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) { CreateGlobalTemplate(TerminateCurrentThread, DoLoopNoCall); v8::Persistent context = v8::Context::New(NULL, global); v8::Context::Scope context_scope(context); + CHECK(!v8::V8::IsExecutionTerminating()); // Run a loop that will be infinite if thread termination does not work. v8::Handle source = v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); v8::Script::Compile(source)->Run(); + CHECK(!v8::V8::IsExecutionTerminating()); // Test that we can run the code again after thread termination. v8::Script::Compile(source)->Run(); context.Dispose(); @@ -149,6 +161,7 @@ TEST(TerminateOnlyV8ThreadFromThreadItselfNoLoop) { class TerminatorThread : public v8::internal::Thread { void Run() { semaphore->Wait(); + CHECK(!v8::V8::IsExecutionTerminating()); v8::V8::TerminateExecution(); } }; @@ -165,6 +178,7 @@ TEST(TerminateOnlyV8ThreadFromOtherThread) { v8::Handle global = CreateGlobalTemplate(Signal, DoLoop); v8::Persistent context = v8::Context::New(NULL, global); v8::Context::Scope context_scope(context); + CHECK(!v8::V8::IsExecutionTerminating()); // Run a loop that will be infinite if thread termination does not work. v8::Handle source = v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); @@ -187,6 +201,7 @@ class LoopingThread : public v8::internal::Thread { CreateGlobalTemplate(Signal, DoLoop); v8::Persistent context = v8::Context::New(NULL, global); v8::Context::Scope context_scope(context); + CHECK(!v8::V8::IsExecutionTerminating()); // Run a loop that will be infinite if thread termination does not work. v8::Handle source = v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); @@ -235,6 +250,7 @@ int call_count = 0; v8::Handle TerminateOrReturnObject(const v8::Arguments& args) { if (++call_count == 10) { + CHECK(!v8::V8::IsExecutionTerminating()); v8::V8::TerminateExecution(); return v8::Undefined(); } @@ -246,6 +262,7 @@ v8::Handle TerminateOrReturnObject(const v8::Arguments& args) { v8::Handle LoopGetProperty(const v8::Arguments& args) { v8::TryCatch try_catch; + CHECK(!v8::V8::IsExecutionTerminating()); v8::Script::Compile(v8::String::New("function f() {" " try {" " while(true) {" @@ -261,6 +278,7 @@ v8::Handle LoopGetProperty(const v8::Arguments& args) { CHECK(try_catch.Exception()->IsNull()); CHECK(try_catch.Message().IsEmpty()); CHECK(!try_catch.CanContinue()); + CHECK(v8::V8::IsExecutionTerminating()); return v8::Undefined(); } @@ -278,12 +296,14 @@ TEST(TerminateLoadICException) { v8::Persistent context = v8::Context::New(NULL, global); v8::Context::Scope context_scope(context); + CHECK(!v8::V8::IsExecutionTerminating()); // Run a loop that will be infinite if thread termination does not work. v8::Handle source = v8::String::New("try { loop(); fail(); } catch(e) { fail(); }"); call_count = 0; v8::Script::Compile(source)->Run(); // Test that we can run the code again after thread termination. + CHECK(!v8::V8::IsExecutionTerminating()); call_count = 0; v8::Script::Compile(source)->Run(); context.Dispose();