Commit 5fa8f2f4 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Pass pending exception to the message listener.

BUG=

Review URL: https://chromiumcodereview.appspot.com/11014017

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12768 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6dc35811
......@@ -2658,7 +2658,7 @@ bool V8EXPORT SetResourceConstraints(ResourceConstraints* constraints);
typedef void (*FatalErrorCallback)(const char* location, const char* message);
typedef void (*MessageCallback)(Handle<Message> message, Handle<Value> data);
typedef void (*MessageCallback)(Handle<Message> message, Handle<Value> error);
/**
......@@ -3101,8 +3101,7 @@ class V8EXPORT V8 {
* The same message listener can be added more than once and in that
* case it will be called more than once for each message.
*/
static bool AddMessageListener(MessageCallback that,
Handle<Value> data = Handle<Value>());
static bool AddMessageListener(MessageCallback that);
/**
* Remove all message listeners from the specified callback function.
......
......@@ -5255,19 +5255,14 @@ void V8::IgnoreOutOfMemoryException() {
}
bool V8::AddMessageListener(MessageCallback that, Handle<Value> data) {
bool V8::AddMessageListener(MessageCallback that) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::V8::AddMessageListener()");
ON_BAILOUT(isolate, "v8::V8::AddMessageListener()", return false);
ENTER_V8(isolate);
i::HandleScope scope(isolate);
NeanderArray listeners(isolate->factory()->message_listeners());
NeanderObject obj(2);
obj.set(0, *isolate->factory()->NewForeign(FUNCTION_ADDR(that)));
obj.set(1, data.IsEmpty() ?
isolate->heap()->undefined_value() :
*Utils::OpenHandle(*data));
listeners.add(obj.value());
listeners.add(isolate->factory()->NewForeign(FUNCTION_ADDR(that)));
return true;
}
......@@ -5282,8 +5277,7 @@ void V8::RemoveMessageListeners(MessageCallback that) {
for (int i = 0; i < listeners.length(); i++) {
if (listeners.get(i)->IsUndefined()) continue; // skip deleted ones
NeanderObject listener(i::JSObject::cast(listeners.get(i)));
i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listener.get(0)));
i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listeners.get(i)));
if (callback_obj->foreign_address() == FUNCTION_ADDR(that)) {
listeners.set(i, isolate->heap()->undefined_value());
}
......
......@@ -106,11 +106,20 @@ void MessageHandler::ReportMessage(Isolate* isolate,
// We are calling into embedder's code which can throw exceptions.
// Thus we need to save current exception state, reset it to the clean one
// and ignore scheduled exceptions callbacks can throw.
// We pass the exception object into the message handler callback though.
Object* exception_object = isolate->heap()->undefined_value();
if (isolate->has_pending_exception()) {
isolate->pending_exception()->ToObject(&exception_object);
}
Handle<Object> exception_handle(exception_object);
Isolate::ExceptionScope exception_scope(isolate);
isolate->clear_pending_exception();
isolate->set_external_caught_exception(false);
v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
v8::Local<v8::Value> api_exception_obj = v8::Utils::ToLocal(exception_handle);
v8::NeanderArray global_listeners(FACTORY->message_listeners());
int global_length = global_listeners.length();
......@@ -123,15 +132,13 @@ void MessageHandler::ReportMessage(Isolate* isolate,
for (int i = 0; i < global_length; i++) {
HandleScope scope;
if (global_listeners.get(i)->IsUndefined()) continue;
v8::NeanderObject listener(JSObject::cast(global_listeners.get(i)));
Handle<Foreign> callback_obj(Foreign::cast(listener.get(0)));
Handle<Foreign> callback_obj(Foreign::cast(global_listeners.get(i)));
v8::MessageCallback callback =
FUNCTION_CAST<v8::MessageCallback>(callback_obj->foreign_address());
Handle<Object> callback_data(listener.get(1));
{
// Do not allow exceptions to propagate.
v8::TryCatch try_catch;
callback(api_message_obj, v8::Utils::ToLocal(callback_data));
callback(api_message_obj, api_exception_obj);
}
if (isolate->has_scheduled_exception()) {
isolate->clear_scheduled_exception();
......
......@@ -2414,20 +2414,19 @@ THREADED_TEST(ScriptException) {
bool message_received;
static void check_message(v8::Handle<v8::Message> message,
static void check_message_0(v8::Handle<v8::Message> message,
v8::Handle<Value> data) {
CHECK_EQ(5.76, data->NumberValue());
CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
message_received = true;
}
THREADED_TEST(MessageHandlerData) {
THREADED_TEST(MessageHandler0) {
message_received = false;
v8::HandleScope scope;
CHECK(!message_received);
v8::V8::AddMessageListener(check_message, v8_num(5.76));
v8::V8::AddMessageListener(check_message_0);
LocalContext context;
v8::ScriptOrigin origin =
v8::ScriptOrigin(v8_str("6.75"));
......@@ -2437,7 +2436,56 @@ THREADED_TEST(MessageHandlerData) {
script->Run();
CHECK(message_received);
// clear out the message listener
v8::V8::RemoveMessageListeners(check_message);
v8::V8::RemoveMessageListeners(check_message_0);
}
static void check_message_1(v8::Handle<v8::Message> message,
v8::Handle<Value> data) {
CHECK(data->IsNumber());
CHECK_EQ(1337, data->Int32Value());
message_received = true;
}
TEST(MessageHandler1) {
message_received = false;
v8::HandleScope scope;
CHECK(!message_received);
v8::V8::AddMessageListener(check_message_1);
LocalContext context;
CompileRun("throw 1337;");
CHECK(message_received);
// clear out the message listener
v8::V8::RemoveMessageListeners(check_message_1);
}
static void check_message_2(v8::Handle<v8::Message> message,
v8::Handle<Value> data) {
LocalContext context;
CHECK(data->IsObject());
v8::Local<v8::Value> hidden_property =
v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
CHECK(v8_str("hidden value")->Equals(hidden_property));
message_received = true;
}
TEST(MessageHandler2) {
message_received = false;
v8::HandleScope scope;
CHECK(!message_received);
v8::V8::AddMessageListener(check_message_2);
LocalContext context;
v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
v8_str("hidden value"));
context->Global()->Set(v8_str("error"), error);
CompileRun("throw error;");
CHECK(message_received);
// clear out the message listener
v8::V8::RemoveMessageListeners(check_message_2);
}
......@@ -3078,7 +3126,7 @@ TEST(APIThrowMessageOverwrittenToString) {
"Number.prototype.toString = function() { return 'Whoops'; };"
"ReferenceError.prototype.toString = Object.prototype.toString;");
CompileRun("asdf;");
v8::V8::RemoveMessageListeners(check_message);
v8::V8::RemoveMessageListeners(check_reference_error_message);
}
......@@ -3125,7 +3173,7 @@ TEST(APIThrowMessage) {
LocalContext context(0, templ);
CompileRun("ThrowFromC();");
CHECK(message_received);
v8::V8::RemoveMessageListeners(check_message);
v8::V8::RemoveMessageListeners(receive_message);
}
......@@ -3143,7 +3191,7 @@ TEST(APIThrowMessageAndVerboseTryCatch) {
CHECK(try_catch.HasCaught());
CHECK(result.IsEmpty());
CHECK(message_received);
v8::V8::RemoveMessageListeners(check_message);
v8::V8::RemoveMessageListeners(receive_message);
}
......@@ -5108,7 +5156,6 @@ TEST(RegexpOutOfMemory) {
static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
v8::Handle<Value> data) {
CHECK_EQ(v8::Undefined(), data);
CHECK(message->GetScriptResourceName()->IsUndefined());
CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
message->GetLineNumber();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment