Revision: 5043
Author: [email protected]
Date: Mon Jul 12 06:17:27 2010
Log: Allow to capture stack trace for uncaught exceptions
Review URL: http://codereview.chromium.org/2961003
http://code.google.com/p/v8/source/detail?r=5043
Modified:
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/debug.cc
/branches/bleeding_edge/src/messages.cc
/branches/bleeding_edge/src/messages.h
/branches/bleeding_edge/src/messages.js
/branches/bleeding_edge/src/top.cc
/branches/bleeding_edge/src/top.h
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/include/v8.h Fri Jul 2 00:39:42 2010
+++ /branches/bleeding_edge/include/v8.h Mon Jul 12 06:17:27 2010
@@ -693,6 +693,13 @@
*/
Handle<Value> GetScriptData() const;
+ /**
+ * Exception stack trace. By default stack traces are not captured for
+ * uncaught exceptions. SetCaptureStackTraceForUncaughtExceptions allows
+ * to change this option.
+ */
+ Handle<StackTrace> GetStackTrace() const;
+
/**
* Returns the number, 1-based, of the line where the error occurred.
*/
@@ -2458,6 +2465,15 @@
*/
static void RemoveMessageListeners(MessageCallback that);
+ /**
+ * Tells V8 to capture current stack trace when uncaught exception occurs
+ * and report it to the message listeners. The option is off by default.
+ */
+ static void SetCaptureStackTraceForUncaughtExceptions(
+ bool capture,
+ int frame_limit = 10,
+ StackTrace::StackTraceOptions options = StackTrace::kOverview);
+
/**
* Sets V8 flags from a string.
*/
=======================================
--- /branches/bleeding_edge/src/api.cc Thu Jun 24 06:56:35 2010
+++ /branches/bleeding_edge/src/api.cc Mon Jul 12 06:17:27 2010
@@ -1436,6 +1436,22 @@
i::Handle<i::Object> data(i::Script::cast(script->value())->data());
return scope.Close(Utils::ToLocal(data));
}
+
+
+v8::Handle<v8::StackTrace> Message::GetStackTrace() const {
+ if (IsDeadCheck("v8::Message::GetStackTrace()")) {
+ return Local<v8::StackTrace>();
+ }
+ ENTER_V8;
+ HandleScope scope;
+ i::Handle<i::JSObject> obj =
+ i::Handle<i::JSObject>::cast(Utils::OpenHandle(this));
+ i::Handle<i::Object> stackFramesObj = GetProperty(obj, "stackFrames");
+ if (!stackFramesObj->IsJSArray()) return v8::Handle<v8::StackTrace>();
+ i::Handle<i::JSArray> stackTrace =
+ i::Handle<i::JSArray>::cast(stackFramesObj);
+ return scope.Close(Utils::StackTraceToLocal(stackTrace));
+}
static i::Handle<i::Object> CallV8HeapFunction(const char* name,
@@ -1583,7 +1599,9 @@
StackTraceOptions options) {
if (IsDeadCheck("v8::StackTrace::CurrentStackTrace()"))
Local<StackTrace>();
ENTER_V8;
- return i::Top::CaptureCurrentStackTrace(frame_limit, options);
+ i::Handle<i::JSArray> stackTrace =
+ i::Top::CaptureCurrentStackTrace(frame_limit, options);
+ return Utils::StackTraceToLocal(stackTrace);
}
@@ -3780,6 +3798,17 @@
}
}
}
+
+
+void V8::SetCaptureStackTraceForUncaughtExceptions(
+ bool capture,
+ int frame_limit,
+ StackTrace::StackTraceOptions options) {
+ i::Top::SetCaptureStackTraceForUncaughtExceptions(
+ capture,
+ frame_limit,
+ options);
+}
void V8::SetCounterFunction(CounterLookupCallback callback) {
=======================================
--- /branches/bleeding_edge/src/debug.cc Tue Jul 6 05:10:49 2010
+++ /branches/bleeding_edge/src/debug.cc Mon Jul 12 06:17:27 2010
@@ -759,7 +759,7 @@
if (caught_exception) {
Handle<Object> message = MessageHandler::MakeMessageObject(
"error_loading_debugger", NULL, Vector<Handle<Object> >::empty(),
- Handle<String>());
+ Handle<String>(), Handle<JSArray>());
MessageHandler::ReportMessage(NULL, message);
return false;
}
=======================================
--- /branches/bleeding_edge/src/messages.cc Mon Mar 8 22:38:33 2010
+++ /branches/bleeding_edge/src/messages.cc Mon Jul 12 06:17:27 2010
@@ -66,7 +66,8 @@
const char* type,
MessageLocation* loc,
Vector< Handle<Object> > args,
- Handle<String> stack_trace) {
+ Handle<String> stack_trace,
+ Handle<JSArray> stack_frames) {
// Build error message object
v8::HandleScope scope; // Instantiate a closeable HandleScope for
EscapeFrom.
Handle<Object> type_str = Factory::LookupAsciiSymbol(type);
@@ -90,13 +91,17 @@
Handle<Object> stack_trace_val = stack_trace.is_null()
? Factory::undefined_value()
: Handle<Object>::cast(stack_trace);
- const int argc = 6;
+ Handle<Object> stack_frames_val = stack_frames.is_null()
+ ? Factory::undefined_value()
+ : Handle<Object>::cast(stack_frames);
+ const int argc = 7;
Object** argv[argc] = { type_str.location(),
array.location(),
start_handle.location(),
end_handle.location(),
script.location(),
- stack_trace_val.location() };
+ stack_trace_val.location(),
+ stack_frames_val.location() };
// Setup a catch handler to catch exceptions in creating the message.
This
// handler is non-verbose to avoid calling MakeMessage recursively in
case of
=======================================
--- /branches/bleeding_edge/src/messages.h Mon May 25 03:05:56 2009
+++ /branches/bleeding_edge/src/messages.h Mon Jul 12 06:17:27 2010
@@ -96,7 +96,8 @@
static Handle<Object> MakeMessageObject(const char* type,
MessageLocation* loc,
Vector< Handle<Object> > args,
- Handle<String> stack_trace);
+ Handle<String> stack_trace,
+ Handle<JSArray> stack_frames);
// Report a formatted message (needs JS allocation).
static void ReportMessage(MessageLocation* loc, Handle<Object> message);
=======================================
--- /branches/bleeding_edge/src/messages.js Wed Jul 7 03:28:22 2010
+++ /branches/bleeding_edge/src/messages.js Mon Jul 12 06:17:27 2010
@@ -601,18 +601,22 @@
}
-function ErrorMessage(type, args, startPos, endPos, script, stackTrace) {
+function ErrorMessage(type, args, startPos, endPos, script, stackTrace,
+ stackFrames) {
this.startPos = startPos;
this.endPos = endPos;
this.type = type;
this.args = args;
this.script = script;
this.stackTrace = stackTrace;
+ this.stackFrames = stackFrames;
}
-function MakeMessage(type, args, startPos, endPos, script, stackTrace) {
- return new ErrorMessage(type, args, startPos, endPos, script,
stackTrace);
+function MakeMessage(type, args, startPos, endPos, script, stackTrace,
+ stackFrames) {
+ return new ErrorMessage(type, args, startPos, endPos, script, stackTrace,
+ stackFrames);
}
=======================================
--- /branches/bleeding_edge/src/top.cc Tue May 25 02:18:08 2010
+++ /branches/bleeding_edge/src/top.cc Mon Jul 12 06:17:27 2010
@@ -44,6 +44,11 @@
NoAllocationStringAllocator* preallocated_message_space = NULL;
+bool capture_stack_trace_for_uncaught_exceptions = false;
+int stack_trace_for_uncaught_exceptions_frame_limit = 0;
+StackTrace::StackTraceOptions stack_trace_for_uncaught_exceptions_options =
+ StackTrace::kOverview;
+
Address top_addresses[] = {
#define C(name) reinterpret_cast<Address>(Top::name()),
TOP_ADDRESS_LIST(C)
@@ -365,9 +370,8 @@
}
-Local<StackTrace> Top::CaptureCurrentStackTrace(
+Handle<JSArray> Top::CaptureCurrentStackTrace(
int frame_limit, StackTrace::StackTraceOptions options) {
- v8::HandleScope scope;
// Ensure no negative values.
int limit = Max(frame_limit, 0);
Handle<JSArray> stack_trace = Factory::NewJSArray(frame_limit);
@@ -443,7 +447,7 @@
}
stack_trace->set_length(Smi::FromInt(frames_seen));
- return scope.Close(Utils::StackTraceToLocal(stack_trace));
+ return stack_trace;
}
@@ -681,10 +685,7 @@
// TODO(1240995): To avoid having to call JavaScript code to compute
// the message for stack overflow exceptions which is very likely to
// double fault with another stack overflow exception, we use a
- // precomputed message. This is somewhat problematic in that it
- // doesn't use ReportUncaughtException to determine the location
- // from where the exception occurred. It should probably be
- // reworked.
+ // precomputed message.
DoThrow(*exception, NULL, kStackOverflowMessage);
return Failure::Exception();
}
@@ -776,25 +777,6 @@
}
}
}
-
-
-void Top::ReportUncaughtException(Handle<Object> exception,
- MessageLocation* location,
- Handle<String> stack_trace) {
- Handle<Object> message;
- if (!Bootstrapper::IsActive()) {
- // It's not safe to try to make message objects while the bootstrapper
- // is active since the infrastructure may not have been properly
- // initialized.
- message =
- MessageHandler::MakeMessageObject("uncaught_exception",
- location,
- HandleVector<Object>(&exception,
1),
- stack_trace);
- }
- // Report the uncaught exception.
- MessageHandler::ReportMessage(location, message);
-}
bool Top::ShouldReturnException(bool* is_caught_externally,
@@ -869,8 +851,15 @@
// may not have been properly initialized.
Handle<String> stack_trace;
if (FLAG_trace_exception) stack_trace = StackTraceString();
+ Handle<JSArray> stack_trace_object;
+ if (report_exception && capture_stack_trace_for_uncaught_exceptions)
{
+ stack_trace_object = Top::CaptureCurrentStackTrace(
+ stack_trace_for_uncaught_exceptions_frame_limit,
+ stack_trace_for_uncaught_exceptions_options);
+ }
message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
- location, HandleVector<Object>(&exception_handle, 1),
stack_trace);
+ location, HandleVector<Object>(&exception_handle, 1),
stack_trace,
+ stack_trace_object);
}
}
@@ -995,6 +984,16 @@
clear_pending_exception();
return true;
}
+
+
+void Top::SetCaptureStackTraceForUncaughtExceptions(
+ bool capture,
+ int frame_limit,
+ StackTrace::StackTraceOptions options) {
+ capture_stack_trace_for_uncaught_exceptions = capture;
+ stack_trace_for_uncaught_exceptions_frame_limit = frame_limit;
+ stack_trace_for_uncaught_exceptions_options = options;
+}
bool Top::is_out_of_memory() {
=======================================
--- /branches/bleeding_edge/src/top.h Thu May 6 00:32:44 2010
+++ /branches/bleeding_edge/src/top.h Mon Jul 12 06:17:27 2010
@@ -226,6 +226,11 @@
(thread_local_.catcher_ != NULL) &&
(try_catch_handler() == thread_local_.catcher_);
}
+
+ static void SetCaptureStackTraceForUncaughtExceptions(
+ bool capture,
+ int frame_limit,
+ StackTrace::StackTraceOptions options);
// Tells whether the current context has experienced an out of memory
// exception.
@@ -266,7 +271,7 @@
static void PrintStack(StringStream* accumulator);
static void PrintStack();
static Handle<String> StackTraceString();
- static Local<StackTrace> CaptureCurrentStackTrace(
+ static Handle<JSArray> CaptureCurrentStackTrace(
int frame_limit,
StackTrace::StackTraceOptions options);
@@ -302,9 +307,6 @@
const char* message);
static bool ShouldReturnException(bool* is_caught_externally,
bool catchable_by_javascript);
- static void ReportUncaughtException(Handle<Object> exception,
- MessageLocation* location,
- Handle<String> stack_trace);
// Attempts to compute the current source location, storing the
// result in the target out parameter.
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Wed Jul 7 04:31:33 2010
+++ /branches/bleeding_edge/test/cctest/test-api.cc Mon Jul 12 06:17:27 2010
@@ -10348,6 +10348,40 @@
ASSERT(!detailed_result.IsEmpty());
ASSERT(detailed_result->IsObject());
}
+
+
+static void StackTraceForUncaughtExceptionListener(
+ v8::Handle<v8::Message> message,
+ v8::Handle<Value>) {
+ v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
+ CHECK_EQ(2, stack_trace->GetFrameCount());
+ checkStackFrame("origin", "foo", 2, 3, false, false,
+ stack_trace->GetFrame(0));
+ checkStackFrame("origin", "bar", 5, 3, false, false,
+ stack_trace->GetFrame(1));
+}
+
+TEST(CaptureStackTraceForUncaughtException) {
+ report_count = 0;
+ v8::HandleScope scope;
+ LocalContext env;
+ v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
+ v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
+
+ Script::Compile(v8_str("function foo() {\n"
+ " throw 1;\n"
+ "};\n"
+ "function bar() {\n"
+ " foo();\n"
+ "};"),
+ v8_str("origin"))->Run();
+ v8::Local<v8::Object> global = env->Global();
+ Local<Value> trouble = global->Get(v8_str("bar"));
+ CHECK(trouble->IsFunction());
+ Function::Cast(*trouble)->Call(global, 0, NULL);
+ v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+ v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
+}
// Test that idle notification can be handled and eventually returns true.
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev