Fix the handling of termination exceptions thrown when creating error

objects in the runtime system.
Review URL: http://codereview.chromium.org/179062

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2796 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
ager@chromium.org 2009-09-01 13:55:45 +00:00
parent 13d59a069d
commit d8af3528dd
7 changed files with 76 additions and 20 deletions

View File

@ -75,7 +75,7 @@ namespace v8 {
i::V8::FatalProcessOutOfMemory(NULL); \
} \
bool call_depth_is_zero = thread_local.CallDepthIsZero(); \
i::Top::OptionalRescheduleException(call_depth_is_zero, false); \
i::Top::OptionalRescheduleException(call_depth_is_zero); \
return value; \
} \
} while (false)

View File

@ -661,7 +661,7 @@ bool Debug::CompileDebuggerScript(int index) {
// Check for caught exceptions.
if (caught_exception) {
Handle<Object> message = MessageHandler::MakeMessageObject(
"error_loading_debugger", NULL, HandleVector<Object>(&result, 1),
"error_loading_debugger", NULL, Vector<Handle<Object> >::empty(),
Handle<String>());
MessageHandler::ReportMessage(NULL, message);
return false;
@ -2001,9 +2001,7 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event,
event_listener_data_.location() };
Handle<Object> result = Execution::TryCall(fun, Top::global(),
argc, argv, &caught_exception);
if (caught_exception) {
// Silently ignore exceptions from debug event listeners.
}
// Silently ignore exceptions from debug event listeners.
}
}
}

View File

@ -156,9 +156,12 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func,
ASSERT(catcher.HasCaught());
ASSERT(Top::has_pending_exception());
ASSERT(Top::external_caught_exception());
bool is_bottom_call = HandleScopeImplementer::instance()->CallDepthIsZero();
Top::OptionalRescheduleException(is_bottom_call, true);
result = v8::Utils::OpenHandle(*catcher.Exception());
if (Top::pending_exception() == Heap::termination_exception()) {
result = Factory::termination_exception();
} else {
result = v8::Utils::OpenHandle(*catcher.Exception());
}
Top::OptionalRescheduleException(true);
}
ASSERT(!Top::has_pending_exception());

View File

@ -163,7 +163,7 @@ function FormatMessage(message) {
illegal_break: "Illegal break statement",
illegal_continue: "Illegal continue statement",
illegal_return: "Illegal return statement",
error_loading_debugger: "Error loading debugger %0",
error_loading_debugger: "Error loading debugger",
no_input_to_regexp: "No input to %0",
result_not_primitive: "Result of %0 must be a primitive, was %1",
invalid_json: "String '%0' is not valid JSON",

View File

@ -855,23 +855,18 @@ void Top::TraceException(bool flag) {
}
bool Top::OptionalRescheduleException(bool is_bottom_call,
bool force_clear_catchable) {
bool Top::OptionalRescheduleException(bool is_bottom_call) {
// Allways reschedule out of memory exceptions.
if (!is_out_of_memory()) {
bool is_termination_exception =
pending_exception() == Heap::termination_exception();
// Do not reschedule the exception if this is the bottom call 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);
// Do not reschedule the exception if this is the bottom call.
bool clear_exception = is_bottom_call;
if (is_termination_exception) {
thread_local_.external_caught_exception_ = false;
if (is_bottom_call) {
thread_local_.external_caught_exception_ = false;
clear_pending_exception();
return false;
}

View File

@ -157,8 +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 OptionalRescheduleException(bool is_bottom_call,
bool force_clear_catchable);
static bool OptionalRescheduleException(bool is_bottom_call);
static bool* external_caught_exception_address() {
return &thread_local_.external_caught_exception_;

View File

@ -193,3 +193,63 @@ TEST(TerminateMultipleV8Threads) {
delete semaphore;
semaphore = NULL;
}
int call_count = 0;
v8::Handle<v8::Value> TerminateOrReturnObject(const v8::Arguments& args) {
if (++call_count == 10) {
v8::V8::TerminateExecution();
return v8::Undefined();
}
v8::Local<v8::Object> result = v8::Object::New();
result->Set(v8::String::New("x"), v8::Integer::New(42));
return result;
}
v8::Handle<v8::Value> LoopGetProperty(const v8::Arguments& args) {
v8::TryCatch try_catch;
v8::Script::Compile(v8::String::New("function f() {"
" try {"
" while(true) {"
" terminate_or_return_object().x;"
" }"
" 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();
}
// Test that we correctly handle termination exceptions if they are
// triggered by the creation of error objects in connection with ICs.
TEST(TerminateLoadICException) {
v8::HandleScope scope;
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
global->Set(v8::String::New("terminate_or_return_object"),
v8::FunctionTemplate::New(TerminateOrReturnObject));
global->Set(v8::String::New("fail"), v8::FunctionTemplate::New(Fail));
global->Set(v8::String::New("loop"),
v8::FunctionTemplate::New(LoopGetProperty));
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(); }");
call_count = 0;
v8::Script::Compile(source)->Run();
// Test that we can run the code again after thread termination.
call_count = 0;
v8::Script::Compile(source)->Run();
context.Dispose();
}