Reviewers: ulan,
Message:
This is to make the message listener be able to access the error object
that is
causing the thrown exception.
Even though this does not change the API syntax, it changes its semantics,
as
described in v8.h. We would be using the data argument for the preset value
if
available, or the pending exception if former is not.
Alternatives that may be cleaner are:
- Changes to the API syntax, adding one more argument to MessageCallback to
pass
the exception.
- Piggyback the Error object on the Message object by adding a new field to
the
latter.
Description:
Pass pending exception to the message listener.
BUG=
Please review this at http://codereview.chromium.org/11014017/
SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge
Affected files:
M include/v8.h
M src/messages.cc
M test/cctest/test-api.cc
Index: include/v8.h
diff --git a/include/v8.h b/include/v8.h
index
72558d09ac4a364cfea1d32b5934f1aa760eb975..ea4a63441fade79b740ab7fd81ad5d0b20eb997f
100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -3089,6 +3089,9 @@ 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.
+ *
+ * If specified, data will be passed to the message listener. Otherwise,
+ * the Error object of the pending exception will be passed.
*/
static bool AddMessageListener(MessageCallback that,
Handle<Value> data = Handle<Value>());
Index: src/messages.cc
diff --git a/src/messages.cc b/src/messages.cc
index
a0793c2dfd7376dd3a066c9e320f31e2894c2272..13df9df897bdbddbb9f0d474f0beccd8cadd7278
100644
--- a/src/messages.cc
+++ b/src/messages.cc
@@ -106,6 +106,14 @@ 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);
@@ -127,7 +135,10 @@ void MessageHandler::ReportMessage(Isolate* isolate,
Handle<Foreign> callback_obj(Foreign::cast(listener.get(0)));
v8::MessageCallback callback =
FUNCTION_CAST<v8::MessageCallback>(callback_obj->foreign_address());
- Handle<Object> callback_data(listener.get(1));
+ Object* listener_data = listener.get(1);
+ // If there is no callback data set, pass the pending exception.
+ Handle<Object> callback_data(
+ listener_data->IsUndefined() ? *exception_handle :
listener_data);
{
// Do not allow exceptions to propagate.
v8::TryCatch try_catch;
Index: test/cctest/test-api.cc
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index
067d134b18650b44a56b5ddcd2338477da7ea802..60776d80b3fe0a61dc5d642ed84d1272998f805c
100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -2441,6 +2441,55 @@ THREADED_TEST(MessageHandlerData) {
}
+static void check_message_data_1(v8::Handle<v8::Message> message,
+ v8::Handle<Value> data) {
+ CHECK(data->IsNumber());
+ CHECK_EQ(1337, data->Int32Value());
+ message_received = true;
+}
+
+
+TEST(MessageHandlerException1) {
+ message_received = false;
+ v8::HandleScope scope;
+ CHECK(!message_received);
+ v8::V8::AddMessageListener(check_message_data_1);
+ LocalContext context;
+ CompileRun("throw 1337;");
+ CHECK(message_received);
+ // clear out the message listener
+ v8::V8::RemoveMessageListeners(check_message_data_1);
+}
+
+
+static void check_message_data_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(MessageHandlerException2) {
+ message_received = false;
+ v8::HandleScope scope;
+ CHECK(!message_received);
+ v8::V8::AddMessageListener(check_message_data_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_data_2);
+}
+
+
THREADED_TEST(GetSetProperty) {
v8::HandleScope scope;
LocalContext context;
@@ -5108,7 +5157,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();
@@ -17624,4 +17672,5 @@ class ThreadInterruptTest {
THREADED_TEST(SemaphoreInterruption) {
ThreadInterruptTest().RunTest();
}
+
#endif // WIN32
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev