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); ...@@ -2658,7 +2658,7 @@ bool V8EXPORT SetResourceConstraints(ResourceConstraints* constraints);
typedef void (*FatalErrorCallback)(const char* location, const char* message); 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 { ...@@ -3101,8 +3101,7 @@ class V8EXPORT V8 {
* The same message listener can be added more than once and in that * The same message listener can be added more than once and in that
* case it will be called more than once for each message. * case it will be called more than once for each message.
*/ */
static bool AddMessageListener(MessageCallback that, static bool AddMessageListener(MessageCallback that);
Handle<Value> data = Handle<Value>());
/** /**
* Remove all message listeners from the specified callback function. * Remove all message listeners from the specified callback function.
......
...@@ -5255,19 +5255,14 @@ void V8::IgnoreOutOfMemoryException() { ...@@ -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(); i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::V8::AddMessageListener()"); EnsureInitializedForIsolate(isolate, "v8::V8::AddMessageListener()");
ON_BAILOUT(isolate, "v8::V8::AddMessageListener()", return false); ON_BAILOUT(isolate, "v8::V8::AddMessageListener()", return false);
ENTER_V8(isolate); ENTER_V8(isolate);
i::HandleScope scope(isolate); i::HandleScope scope(isolate);
NeanderArray listeners(isolate->factory()->message_listeners()); NeanderArray listeners(isolate->factory()->message_listeners());
NeanderObject obj(2); listeners.add(isolate->factory()->NewForeign(FUNCTION_ADDR(that)));
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());
return true; return true;
} }
...@@ -5282,8 +5277,7 @@ void V8::RemoveMessageListeners(MessageCallback that) { ...@@ -5282,8 +5277,7 @@ void V8::RemoveMessageListeners(MessageCallback that) {
for (int i = 0; i < listeners.length(); i++) { for (int i = 0; i < listeners.length(); i++) {
if (listeners.get(i)->IsUndefined()) continue; // skip deleted ones 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(listeners.get(i)));
i::Handle<i::Foreign> callback_obj(i::Foreign::cast(listener.get(0)));
if (callback_obj->foreign_address() == FUNCTION_ADDR(that)) { if (callback_obj->foreign_address() == FUNCTION_ADDR(that)) {
listeners.set(i, isolate->heap()->undefined_value()); listeners.set(i, isolate->heap()->undefined_value());
} }
......
...@@ -106,11 +106,20 @@ void MessageHandler::ReportMessage(Isolate* isolate, ...@@ -106,11 +106,20 @@ void MessageHandler::ReportMessage(Isolate* isolate,
// We are calling into embedder's code which can throw exceptions. // 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 // Thus we need to save current exception state, reset it to the clean one
// and ignore scheduled exceptions callbacks can throw. // 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::ExceptionScope exception_scope(isolate);
isolate->clear_pending_exception(); isolate->clear_pending_exception();
isolate->set_external_caught_exception(false); isolate->set_external_caught_exception(false);
v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message); 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()); v8::NeanderArray global_listeners(FACTORY->message_listeners());
int global_length = global_listeners.length(); int global_length = global_listeners.length();
...@@ -123,15 +132,13 @@ void MessageHandler::ReportMessage(Isolate* isolate, ...@@ -123,15 +132,13 @@ void MessageHandler::ReportMessage(Isolate* isolate,
for (int i = 0; i < global_length; i++) { for (int i = 0; i < global_length; i++) {
HandleScope scope; HandleScope scope;
if (global_listeners.get(i)->IsUndefined()) continue; if (global_listeners.get(i)->IsUndefined()) continue;
v8::NeanderObject listener(JSObject::cast(global_listeners.get(i))); Handle<Foreign> callback_obj(Foreign::cast(global_listeners.get(i)));
Handle<Foreign> callback_obj(Foreign::cast(listener.get(0)));
v8::MessageCallback callback = v8::MessageCallback callback =
FUNCTION_CAST<v8::MessageCallback>(callback_obj->foreign_address()); FUNCTION_CAST<v8::MessageCallback>(callback_obj->foreign_address());
Handle<Object> callback_data(listener.get(1));
{ {
// Do not allow exceptions to propagate. // Do not allow exceptions to propagate.
v8::TryCatch try_catch; 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()) { if (isolate->has_scheduled_exception()) {
isolate->clear_scheduled_exception(); isolate->clear_scheduled_exception();
......
...@@ -2414,20 +2414,19 @@ THREADED_TEST(ScriptException) { ...@@ -2414,20 +2414,19 @@ THREADED_TEST(ScriptException) {
bool message_received; 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) { v8::Handle<Value> data) {
CHECK_EQ(5.76, data->NumberValue());
CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
CHECK_EQ(7.56, message->GetScriptData()->NumberValue()); CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
message_received = true; message_received = true;
} }
THREADED_TEST(MessageHandlerData) { THREADED_TEST(MessageHandler0) {
message_received = false; message_received = false;
v8::HandleScope scope; v8::HandleScope scope;
CHECK(!message_received); CHECK(!message_received);
v8::V8::AddMessageListener(check_message, v8_num(5.76)); v8::V8::AddMessageListener(check_message_0);
LocalContext context; LocalContext context;
v8::ScriptOrigin origin = v8::ScriptOrigin origin =
v8::ScriptOrigin(v8_str("6.75")); v8::ScriptOrigin(v8_str("6.75"));
...@@ -2437,7 +2436,56 @@ THREADED_TEST(MessageHandlerData) { ...@@ -2437,7 +2436,56 @@ THREADED_TEST(MessageHandlerData) {
script->Run(); script->Run();
CHECK(message_received); CHECK(message_received);
// clear out the message listener // 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) { ...@@ -3078,7 +3126,7 @@ TEST(APIThrowMessageOverwrittenToString) {
"Number.prototype.toString = function() { return 'Whoops'; };" "Number.prototype.toString = function() { return 'Whoops'; };"
"ReferenceError.prototype.toString = Object.prototype.toString;"); "ReferenceError.prototype.toString = Object.prototype.toString;");
CompileRun("asdf;"); CompileRun("asdf;");
v8::V8::RemoveMessageListeners(check_message); v8::V8::RemoveMessageListeners(check_reference_error_message);
} }
...@@ -3125,7 +3173,7 @@ TEST(APIThrowMessage) { ...@@ -3125,7 +3173,7 @@ TEST(APIThrowMessage) {
LocalContext context(0, templ); LocalContext context(0, templ);
CompileRun("ThrowFromC();"); CompileRun("ThrowFromC();");
CHECK(message_received); CHECK(message_received);
v8::V8::RemoveMessageListeners(check_message); v8::V8::RemoveMessageListeners(receive_message);
} }
...@@ -3143,7 +3191,7 @@ TEST(APIThrowMessageAndVerboseTryCatch) { ...@@ -3143,7 +3191,7 @@ TEST(APIThrowMessageAndVerboseTryCatch) {
CHECK(try_catch.HasCaught()); CHECK(try_catch.HasCaught());
CHECK(result.IsEmpty()); CHECK(result.IsEmpty());
CHECK(message_received); CHECK(message_received);
v8::V8::RemoveMessageListeners(check_message); v8::V8::RemoveMessageListeners(receive_message);
} }
...@@ -5108,7 +5156,6 @@ TEST(RegexpOutOfMemory) { ...@@ -5108,7 +5156,6 @@ TEST(RegexpOutOfMemory) {
static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message, static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
v8::Handle<Value> data) { v8::Handle<Value> data) {
CHECK_EQ(v8::Undefined(), data);
CHECK(message->GetScriptResourceName()->IsUndefined()); CHECK(message->GetScriptResourceName()->IsUndefined());
CHECK_EQ(v8::Undefined(), message->GetScriptResourceName()); CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
message->GetLineNumber(); 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