Js解释器V8引擎嵌入的异常处理
2011年08月10日
v8引擎为Google开发的JS语言解释器有着高效易用等特点,通常它执行一个Js脚本需要经过编译和运行步骤,
由于我们的脚本程序很可能不正确,随时造成过程环节的异常,我们来解决一个异常以及错误的捕捉和处理过程,如下脚本:
test.js: 使用以下经典的V8 C++示例代码来执行脚本: #include
usingnamespace v8;
//提取js文件
v8::Handle::String> ReadFile(constchar* name)
{
FILE* file = fopen(name, "rb");
if (file == NULL) return v8::Handle::String>();
fseek(file, 0, SEEK_END);
int size = ftell(file);
rewind(file);
char* chars =newchar[size +1];
chars[size] ='\0';
for (int i =0; i ::Handle::String> result = v8::String::New(chars, size);
delete[] chars;
return result;
}
int main()
{
HandleScope handle_scope;
Handle context = Context::New();
Context::Scope context_scope(context);
constchar* fname ="test.js";
Handle source = ReadFile(fname);
//ExecuteString(source, String::New(fname), true, true);
Handle script = Script::Compile(source);
Handle result = script->Run();
String::AsciiValue ascii(result);
printf("%s\n", *ascii);
return0;
}
然后编译程序
# g++ -o test test.cpp -lv8
# ./test
:58: Uncaught ReferenceError: alert is not defined
Segmentation fault
在执行过程遇到JS语法错误时,V8很干脆地中上了进程,提醒段错误。
在这我们正常应用环境是无法使用的,需要有一种异常处理机制来收集并处理错误。
这就是v8::TryCatch ,在编译前声明,在之后的编译和执行中只要有错误的发生均可捕获。
查找了相关的V8源代码,改进后的代码实现如下(函数体),
其中source为源文件内容,name用来标记当前脚本名称(文件名),
print_result表示是否打印脚本执行结果,report_exceptions表示是否报告异常(错误): bool ExecuteString(v8::Handle::String> source,
v8::Handle::Value> name,
bool print_result,
bool report_exceptions)
{
v8::HandleScope handle_scope;
v8::TryCatch try_catch; //这里设置异常机制
v8::Handle::Script> script = v8::Script::Compile(source, name);
if (script.IsEmpty()) {
// Print errors that happened during compilation.
if (report_exceptions)
ReportException(&try_catch);
returnfalse;
} else {
v8::Handle::Value> result = script->Run();
if (result.IsEmpty()) {
assert(try_catch.HasCaught());
// Print errors that happened during execution.
if (report_exceptions)
ReportException(&try_catch);
returnfalse;
} else {
assert(!try_catch.HasCaught());
if (print_result &&!result->IsUndefined()) {
// If all went well and the result wasn't undefined then print
// the returned value.
v8::String::Utf8Value str(result);
constchar* cstr = ToCString(str);
printf("%s\n", cstr);
}
returntrue;
}
}
}
相关的异常处理函数: constchar* ToCString(const v8::String::Utf8Value& value) {
return*value ?*value : "";
}
void ReportException(v8::TryCatch* try_catch) {
v8::HandleScope handle_scope;
v8::String::Utf8Value exception(try_catch->Exception());
constchar* exception_string = ToCString(exception);
v8::Handle::Message> message = try_catch->Message();
if (message.IsEmpty()) {
// V8 didn't provide any extra information about this error; just
// print the exception.
printf("%s\n", exception_string);
} else {
// Print (filename):(line number): (message).
v8::String::Utf8Value filename(message->GetScriptResourceName());
constchar* filename_string = ToCString(filename);
int linenum = message->GetLineNumber();
printf("%s:%i: %s\n", filename_string, linenum, exception_string);
// Print line of source code.
v8::String::Utf8Value sourceline(message->GetSourceLine());
constchar* sourceline_string = ToCString(sourceline);
printf("%s\n", sourceline_string);
// Print wavy underline (GetUnderline is deprecated).
int start = message->GetStartColumn();
for (int i =0; i GetEndColumn();
for (int i = start; i ::String::Utf8Value stack_trace(try_catch->StackTrace());
if (stack_trace.length() >0) {
constchar* stack_trace_string = ToCString(stack_trace);
printf("%s\n", stack_trace_string);
}
}
}
int main(int argc, char* argv[])
{
HandleScope handle_scope;
Handle context = Context::New();
Context::Scope context_scope(context);
constchar* fname ="test.js";
Handle source = ReadFile(fname);
ExecuteString(source, String::New(fname), true, true);
return0;
}
重新编译后运行结果为:
# ./test
test.js:3: ReferenceError: alert is not defined
alert(str);
^
ReferenceError: alert is not defined
at test.js:3:1
已经可以正常报告错误。