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:
parent
13d59a069d
commit
d8af3528dd
@ -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)
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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",
|
||||
|
13
src/top.cc
13
src/top.cc
@ -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;
|
||||
}
|
||||
|
@ -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_;
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user