Added source info to TryCatches. Reorganized exception messaging

somewhat and folded stack traces into message.  Use of this in the
shell will follow in a separate changelist.



git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@235 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 23d23817
......@@ -553,7 +553,7 @@ class EXPORT Script {
class EXPORT Message {
public:
Local<String> Get();
Local<Value> GetSourceLine();
Local<String> GetSourceLine();
// TODO(1241256): Rewrite (or remove) this method. We don't want to
// deal with ownership of the returned string and we want to use
......@@ -566,8 +566,41 @@ class EXPORT Message {
// bindings.
Handle<Value> GetSourceData();
/**
* Returns the number, 1-based, of the line where the error occurred.
*/
int GetLineNumber();
/**
* Returns the index within the script of the first character where
* the error occurred.
*/
int GetStartPosition();
/**
* Returns the index within the script of the last character where
* the error occurred.
*/
int GetEndPosition();
/**
* Returns the index within the line of the first character where
* the error occurred.
*/
int GetStartColumn();
/**
* Returns the index within the line of the last character where
* the error occurred.
*/
int GetEndColumn();
/**
* Returns a string stack trace if trace_exceptions is enabled and
* one is available.
*/
Local<String> GetStackTrace();
// TODO(1245381): Print to a string instead of on a FILE.
static void PrintCurrentStackTrace(FILE* out);
};
......@@ -1911,6 +1944,15 @@ class EXPORT TryCatch {
*/
Local<Value> Exception();
/**
* Returns the message associated with this exception. If there is
* no message associated an empty handle is returned.
*
* The returned handle is valid until this TryCatch block has been
* destroyed.
*/
Local<v8::Message> Message();
/**
* Clears any exceptions that may have been caught by this try/catch block.
* After this method has been called, HasCaught() will return false.
......@@ -1935,6 +1977,7 @@ class EXPORT TryCatch {
public:
TryCatch* next_;
void* exception_;
void* message_;
bool is_verbose_;
};
......
......@@ -1081,6 +1081,7 @@ Local<Value> Script::Run() {
v8::TryCatch::TryCatch()
: next_(i::Top::try_catch_handler()),
exception_(i::Heap::the_hole_value()),
message_(i::Smi::FromInt(0)),
is_verbose_(false) {
i::Top::RegisterTryCatchHandler(this);
}
......@@ -1107,8 +1108,19 @@ v8::Local<Value> v8::TryCatch::Exception() {
}
v8::Local<v8::Message> v8::TryCatch::Message() {
if (HasCaught() && message_ != i::Smi::FromInt(0)) {
i::Object* message = reinterpret_cast<i::Object*>(message_);
return v8::Utils::MessageToLocal(i::Handle<i::Object>(message));
} else {
return v8::Local<v8::Message>();
}
}
void v8::TryCatch::Reset() {
exception_ = i::Heap::the_hole_value();
message_ = i::Smi::FromInt(0);
}
......@@ -1196,15 +1208,80 @@ int Message::GetLineNumber() {
}
Local<Value> Message::GetSourceLine() {
ON_BAILOUT("v8::Message::GetSourceLine()", return Local<Value>());
int Message::GetStartPosition() {
if (IsDeadCheck("v8::Message::GetStartPosition()")) return 0;
HandleScope scope;
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
return static_cast<int>(GetProperty(data_obj, "startPos")->Number());
}
int Message::GetEndPosition() {
if (IsDeadCheck("v8::Message::GetEndPosition()")) return 0;
HandleScope scope;
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
return static_cast<int>(GetProperty(data_obj, "endPos")->Number());
}
int Message::GetStartColumn() {
if (IsDeadCheck("v8::Message::GetStartColumn()")) return 0;
HandleScope scope;
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
EXCEPTION_PREAMBLE();
i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
"GetPositionInLine",
data_obj,
&has_pending_exception);
EXCEPTION_BAILOUT_CHECK(0);
return static_cast<int>(start_col_obj->Number());
}
int Message::GetEndColumn() {
if (IsDeadCheck("v8::Message::GetEndColumn()")) return 0;
HandleScope scope;
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
EXCEPTION_PREAMBLE();
i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
"GetPositionInLine",
data_obj,
&has_pending_exception);
EXCEPTION_BAILOUT_CHECK(0);
int start = static_cast<int>(GetProperty(data_obj, "startPos")->Number());
int end = static_cast<int>(GetProperty(data_obj, "endPos")->Number());
return static_cast<int>(start_col_obj->Number()) + (end - start);
}
v8::Local<v8::String> Message::GetStackTrace() {
if (IsDeadCheck("v8::Message::GetStackTrace()"))
return v8::Local<v8::String>();
HandleScope scope;
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
i::Handle<i::Object> trace = GetProperty(data_obj, "stackTrace");
if (trace->IsString()) {
return scope.Close(Utils::ToLocal(i::Handle<i::String>::cast(trace)));
} else {
return Local<String>();
}
}
Local<String> Message::GetSourceLine() {
ON_BAILOUT("v8::Message::GetSourceLine()", return Local<String>());
HandleScope scope;
EXCEPTION_PREAMBLE();
i::Handle<i::Object> result = CallV8HeapFunction("GetSourceLine",
Utils::OpenHandle(this),
&has_pending_exception);
EXCEPTION_BAILOUT_CHECK(Local<v8::Value>());
return scope.Close(Utils::ToLocal(result));
EXCEPTION_BAILOUT_CHECK(Local<v8::String>());
if (result->IsString()) {
return scope.Close(Utils::ToLocal(i::Handle<i::String>::cast(result)));
} else {
return Local<String>();
}
}
......
......@@ -537,8 +537,10 @@ bool Debug::CompileDebuggerScript(int index) {
// Check for caught exceptions.
if (caught_exception) {
MessageHandler::ReportMessage("error_loading_debugger", NULL,
HandleVector<Object>(&result, 1));
Handle<Object> message = MessageHandler::MakeMessageObject(
"error_loading_debugger", NULL, HandleVector<Object>(&result, 1),
Handle<String>());
MessageHandler::ReportMessage(NULL, message);
return false;
}
......
......@@ -60,8 +60,11 @@ void MessageHandler::ReportMessage(const char* msg) {
}
void MessageHandler::ReportMessage(const char* type, MessageLocation* loc,
Vector< Handle<Object> > args) {
Handle<Object> MessageHandler::MakeMessageObject(
const char* type,
MessageLocation* loc,
Vector< Handle<Object> > args,
Handle<String> stack_trace) {
// Build error message object
HandleScope scope;
Handle<Object> type_str = Factory::LookupAsciiSymbol(type);
......@@ -82,12 +85,16 @@ void MessageHandler::ReportMessage(const char* type, MessageLocation* loc,
}
Handle<Object> start_handle(Smi::FromInt(start));
Handle<Object> end_handle(Smi::FromInt(end));
const int argc = 5;
Handle<Object> stack_trace_val = stack_trace.is_null()
? Factory::undefined_value()
: Handle<Object>::cast(stack_trace);
const int argc = 6;
Object** argv[argc] = { type_str.location(),
array.location(),
start_handle.location(),
end_handle.location(),
script.location() };
script.location(),
stack_trace_val.location() };
bool caught_exception = false;
Handle<Object> message =
......@@ -97,8 +104,13 @@ void MessageHandler::ReportMessage(const char* type, MessageLocation* loc,
// skip doing the callback. This usually only happens in case of
// stack overflow exceptions being thrown by the parser when the
// stack is almost full.
if (caught_exception) return;
if (caught_exception) return Handle<Object>();
return message.EscapeFrom(&scope);
}
void MessageHandler::ReportMessage(MessageLocation* loc,
Handle<Object> message) {
v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
v8::NeanderArray global_listeners(Factory::message_listeners());
......
......@@ -70,6 +70,7 @@ class MessageLocation {
: script_(script),
start_pos_(start_pos),
end_pos_(end_pos) { }
MessageLocation() : start_pos_(-1), end_pos_(-1) { }
Handle<Script> script() const { return script_; }
int start_pos() const { return start_pos_; }
......@@ -89,10 +90,14 @@ class MessageHandler {
// Report a message (w/o JS heap allocation).
static void ReportMessage(const char* msg);
// Report a formatted message (needs JS allocation).
static void ReportMessage(const char* type,
// Returns a message object for the API to use.
static Handle<Object> MakeMessageObject(const char* type,
MessageLocation* loc,
Vector< Handle<Object> > args);
Vector< Handle<Object> > args,
Handle<String> stack_trace);
// Report a formatted message (needs JS allocation).
static void ReportMessage(MessageLocation* loc, Handle<Object> message);
static void DefaultMessageReport(const MessageLocation* loc,
Handle<Object> message_obj);
......
......@@ -555,17 +555,18 @@ function GetPositionInLine(message) {
};
function ErrorMessage(type, args, startPos, endPos, script) {
function ErrorMessage(type, args, startPos, endPos, script, stackTrace) {
this.startPos = startPos;
this.endPos = endPos;
this.type = type;
this.args = args;
this.script = script;
this.stackTrace = stackTrace;
};
function MakeMessage(type, args, startPos, endPos, script) {
return new ErrorMessage(type, args, startPos, endPos, script);
function MakeMessage(type, args, startPos, endPos, script, stackTrace) {
return new ErrorMessage(type, args, startPos, endPos, script, stackTrace);
};
......
......@@ -79,6 +79,7 @@ void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
block != NULL;
block = block->next_) {
VISIT(reinterpret_cast<Object*&>(block->exception_));
VISIT(reinterpret_cast<Object*&>(block->message_));
}
// Iterate over pointers on native execution stack.
......@@ -671,13 +672,8 @@ void Top::PrintCurrentStackTrace(FILE* out) {
}
void Top::ReportUncaughtException(Handle<Object> exception,
MessageLocation* location,
Handle<String> stack_trace) {
MessageLocation computed_location(empty_script(), -1, -1);
if (location == NULL) {
location = &computed_location;
void Top::ComputeLocation(MessageLocation* target) {
*target = MessageLocation(empty_script(), -1, -1);
StackTraceFrameIterator it;
if (!it.done()) {
JavaScriptFrame* frame = it.frame();
......@@ -688,22 +684,23 @@ void Top::ReportUncaughtException(Handle<Object> exception,
int pos = frame->FindCode()->SourcePosition(frame->pc());
// Compute the location from the function and the reloc info.
Handle<Script> casted_script(Script::cast(script));
computed_location = MessageLocation(casted_script, pos, pos + 1);
}
*target = MessageLocation(casted_script, pos, pos + 1);
}
}
}
// Report the uncaught exception.
MessageHandler::ReportMessage("uncaught_exception",
location,
HandleVector<Object>(&exception, 1));
// Optionally, report the stack trace separately.
if (!stack_trace.is_null()) {
MessageHandler::ReportMessage("stack_trace",
void Top::ReportUncaughtException(Handle<Object> exception,
MessageLocation* location,
Handle<String> stack_trace) {
Handle<Object> message =
MessageHandler::MakeMessageObject("uncaught_exception",
location,
HandleVector<String>(&stack_trace, 1));
}
HandleVector<Object>(&exception, 1),
stack_trace);
// Report the uncaught exception.
MessageHandler::ReportMessage(location, message);
}
......@@ -771,12 +768,30 @@ void Top::DoThrow(Object* exception,
ShouldReportException(&is_caught_externally);
if (is_rethrow) report_exception = false;
Handle<Object> message_obj;
MessageLocation potential_computed_location;
if (is_caught_externally || report_exception) {
if (location == NULL) {
// If no location was specified we use a computed one instead
ComputeLocation(&potential_computed_location);
location = &potential_computed_location;
}
Handle<String> stack_trace;
if (FLAG_trace_exception) stack_trace = StackTrace();
message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
location, HandleVector<Object>(&exception_handle, 1), stack_trace);
}
// If the exception is caught externally, we store it in the
// try/catch handler. The C code can find it later and process it if
// necessary.
if (is_caught_externally) {
thread_local_.try_catch_handler_->exception_ =
reinterpret_cast<void*>(*exception_handle);
if (!message_obj.is_null()) {
thread_local_.try_catch_handler_->message_ =
reinterpret_cast<void*>(*message_obj);
}
}
// Notify debugger of exception.
......@@ -786,9 +801,7 @@ void Top::DoThrow(Object* exception,
if (message != NULL) {
MessageHandler::ReportMessage(message);
} else {
Handle<String> stack_trace;
if (FLAG_trace_exception) stack_trace = StackTrace();
ReportUncaughtException(exception_handle, location, stack_trace);
MessageHandler::ReportMessage(location, message_obj);
}
}
thread_local_.external_caught_exception_ = is_caught_externally;
......
......@@ -226,6 +226,10 @@ class Top {
MessageLocation* location,
Handle<String> stack_trace);
// Attempts to compute the current source location, storing the
// result in the target out parameter.
static void ComputeLocation(MessageLocation* target);
// Override command line flag.
static void TraceException(bool flag);
......
......@@ -4843,3 +4843,40 @@ THREADED_TEST(Regress54) {
v8::Handle<v8::Object> result = templ->NewInstance();
CHECK_EQ(1, result->InternalFieldCount());
}
THREADED_TEST(TryCatchSourceInfo) {
v8::HandleScope scope;
LocalContext context;
v8::Handle<v8::String> source = v8::String::New(
"function Foo() {\n"
" return Bar();\n"
"}\n"
"\n"
"function Bar() {\n"
" return Baz();\n"
"}\n"
"\n"
"function Baz() {\n"
" throw 'nirk';\n"
"}\n"
"\n"
"Foo();\n");
v8::Handle<v8::Script> script =
v8::Script::Compile(source, v8::String::New("test.js"));
v8::TryCatch try_catch;
v8::Handle<v8::Value> result = script->Run();
CHECK(result.IsEmpty());
CHECK(try_catch.HasCaught());
v8::Handle<v8::Message> message = try_catch.Message();
CHECK(!message.IsEmpty());
CHECK_EQ(10, message->GetLineNumber());
CHECK_EQ(91, message->GetStartPosition());
CHECK_EQ(92, message->GetEndPosition());
CHECK_EQ(2, message->GetStartColumn());
CHECK_EQ(3, message->GetEndColumn());
v8::String::AsciiValue line(message->GetSourceLine());
CHECK_EQ(" throw 'nirk';", *line);
v8::String::AsciiValue name(message->GetScriptResourceName());
CHECK_EQ("test.js", *name);
}
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