如何运行 V8 多次求值?
How to run V8 evaluation multiple times?
也许这是个愚蠢的问题(我是 C++ 的新手,只是想将它用作 android 的库),但我不能 运行 对某些 JS 多次求值
我已经开始使用 "hello world" 教程。但是后来我想要简单的东西,重新运行 main(只需将教程代码的内容包装到函数中,然后运行它在新的空main中两次。
这是我得到的:
#
# Fatal error in ../src/isolate.cc, line 1868
# Check failed: thread_data_table_.
#
==== C stack trace ===============================
1: 0xa890b9
2: 0x6a22fc
3: 0x42694f
4: 0x405f66
5: 0x405ec7
6: __libc_start_main
7: 0x405dc9
Illegal instruction (core dumped)
这是在创建新的 isolate 之后出现的
Isolate* isolate = Isolate::New(create_params);
那么,我该怎么办?我是不是使用了错误的结构?我应该 close/delete/clear 更多吗?
从更大的角度来看,我只想做评估功能,可以多次触发,除此之外还有运行同一上下文中的多个js片段(如何拆分这个功能?)。
有什么想法吗?
更新:
好的,假设主体可以分为三个逻辑部分:
初始化
int main(int argc, char* argv[]) {
// Initialize V8.
V8::InitializeICU();
V8::InitializeExternalStartupData(argv[0]);
Platform* platform = platform::CreateDefaultPlatform();
V8::InitializePlatform(platform);
V8::Initialize();
// Create a new Isolate and make it the current one.
ArrayBufferAllocator allocator;
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &allocator;
评价
Isolate* isolate = Isolate::New(create_params);
{
Isolate::Scope isolate_scope(isolate);
// Create a stack-allocated handle scope.
HandleScope handle_scope(isolate);
// Create a new context.
Local<Context> context = Context::New(isolate);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(context);
// Create a string containing the JavaScript source code.
Local<String> source =
String::NewFromUtf8(isolate, "'Hello' + ', World!'",
NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
Local<Script> script = Script::Compile(context, source).ToLocalChecked();
// Run the script to get the result.
Local<Value> result = script->Run(context).ToLocalChecked();
// Convert the result to an UTF8 string and print it.
String::Utf8Value utf8(result);
printf("%s\n", *utf8);
}
isolate->Dispose();
和清洁
// Dispose and tear down V8.
V8::Dispose();
V8::ShutdownPlatform();
delete platform;
return 0;
现在正如我之前所说,如果我 运行 main 由 init->evaluation->clean 两次组成,那意思是init->evaluation->clean->init->evaluation->clean,则出现错误。我发现,如果我将 evaluation 部分提取到单独的函数中,我可以 运行 多次,例如作为 init->(evaluation){2}->clean
它应该如何工作?下一步是将这个 main 划分为树形独立函数,这意味着我必须具有平台静态成员?它会以某种方式导致泄漏吗?
注意: 我想从 android 运行 它,这意味着例如点击UI,通过JNI将js源传播到C,然后调用c++ V8,是否已经初始化。嗯?
首选方式是"blackbox",但如果我必须持有平台,那就这样吧。如果不重新初始化 V8,它可能也会更快,对吗?
更新 2:
好吧,拆分 评估 部分以在同一 isolate/context 中实现多个 运行 仍然存在问题.
我在使用存储的隔离和上下文创建上下文后将其拆分,但没有成功。当在第二部分尝试创建源字符串时它失败了,可能是因为使用了存储的隔离(我猜是隔离范围的东西)。
:(
我在 UPDATE1 中介绍的假设是正确的。那部分效果很好。
根据UPDATE2,我将评估部分一分为二。
首先用于初始化隔离和上下文:
mIsolate = Isolate::New(mCreate_params);
Isolate::Scope isolate_scope(mIsolate);
{
// Create a stack-allocated handle scope.
HandleScope handle_scope(mIsolate);
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(mIsolate);
// Bind the global 'print' function to the C++ Print callback.
global->Set(v8::String::NewFromUtf8(mIsolate, "print"), v8::FunctionTemplate::New(mIsolate, Print));
// Create a new context.
mContext = Context::New(mIsolate, NULL, global);
Persistent<Context, CopyablePersistentTraits<Context>> persistent(mIsolate, mContext);
mContext_persistent = persistent;
}
第二个 运行 js 在相同的上下文中:
Isolate::Scope isolate_scope(mIsolate);
{
HandleScope handle_scope(mIsolate);
mContext = Local<Context>::New(mIsolate, mContext_persistent);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(mContext);
{
// Create a string containing the JavaScript source code.
Local<String> source =
String::NewFromUtf8(mIsolate, js_source, NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
Local<Script> script = Script::Compile(mContext, source).ToLocalChecked();
TryCatch trycatch(mIsolate);
// Run the script to get the result.
v8::Local<v8::Value> result;
if(!script->Run(mContext).ToLocal(&result)){
v8::String::Utf8Value exception_str(trycatch.Exception());
dprint(*exception_str);
}else{
if(!result->IsUndefined()){
String::Utf8Value utf8(result);
dprint(*utf8);
}
}
}
}
好吧,代码在 linux 上工作得很好,但是当我在 android 上第二次尝试 运行 第一部分(创建新上下文)时,我仍然遇到一些问题:
A/art: art/runtime/thread.cc:986] pthread_getschedparam failed for DumpState: No such process
A/art: art/runtime/base/mutex.cc:485] Unexpected state_ 0 in unlock for logging lock
但我想那是另一个问题。和平
您是否多次初始化 v8?
v8::V8::Initialize()
每个进程应该调用一次此方法。
深入项目源文件"v8/src/v8.cc"
,你会发现证明
bool V8::Initialize() {
InitializeOncePerProcess();
return true;
}
也许这是个愚蠢的问题(我是 C++ 的新手,只是想将它用作 android 的库),但我不能 运行 对某些 JS 多次求值
我已经开始使用 "hello world" 教程。但是后来我想要简单的东西,重新运行 main(只需将教程代码的内容包装到函数中,然后运行它在新的空main中两次。
这是我得到的:
#
# Fatal error in ../src/isolate.cc, line 1868
# Check failed: thread_data_table_.
#
==== C stack trace ===============================
1: 0xa890b9
2: 0x6a22fc
3: 0x42694f
4: 0x405f66
5: 0x405ec7
6: __libc_start_main
7: 0x405dc9
Illegal instruction (core dumped)
这是在创建新的 isolate 之后出现的
Isolate* isolate = Isolate::New(create_params);
那么,我该怎么办?我是不是使用了错误的结构?我应该 close/delete/clear 更多吗?
从更大的角度来看,我只想做评估功能,可以多次触发,除此之外还有运行同一上下文中的多个js片段(如何拆分这个功能?)。
有什么想法吗?
更新:
好的,假设主体可以分为三个逻辑部分:
初始化
int main(int argc, char* argv[]) {
// Initialize V8.
V8::InitializeICU();
V8::InitializeExternalStartupData(argv[0]);
Platform* platform = platform::CreateDefaultPlatform();
V8::InitializePlatform(platform);
V8::Initialize();
// Create a new Isolate and make it the current one.
ArrayBufferAllocator allocator;
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = &allocator;
评价
Isolate* isolate = Isolate::New(create_params);
{
Isolate::Scope isolate_scope(isolate);
// Create a stack-allocated handle scope.
HandleScope handle_scope(isolate);
// Create a new context.
Local<Context> context = Context::New(isolate);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(context);
// Create a string containing the JavaScript source code.
Local<String> source =
String::NewFromUtf8(isolate, "'Hello' + ', World!'",
NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
Local<Script> script = Script::Compile(context, source).ToLocalChecked();
// Run the script to get the result.
Local<Value> result = script->Run(context).ToLocalChecked();
// Convert the result to an UTF8 string and print it.
String::Utf8Value utf8(result);
printf("%s\n", *utf8);
}
isolate->Dispose();
和清洁
// Dispose and tear down V8.
V8::Dispose();
V8::ShutdownPlatform();
delete platform;
return 0;
现在正如我之前所说,如果我 运行 main 由 init->evaluation->clean 两次组成,那意思是init->evaluation->clean->init->evaluation->clean,则出现错误。我发现,如果我将 evaluation 部分提取到单独的函数中,我可以 运行 多次,例如作为 init->(evaluation){2}->clean
它应该如何工作?下一步是将这个 main 划分为树形独立函数,这意味着我必须具有平台静态成员?它会以某种方式导致泄漏吗?
注意: 我想从 android 运行 它,这意味着例如点击UI,通过JNI将js源传播到C,然后调用c++ V8,是否已经初始化。嗯?
首选方式是"blackbox",但如果我必须持有平台,那就这样吧。如果不重新初始化 V8,它可能也会更快,对吗?
更新 2:
好吧,拆分 评估 部分以在同一 isolate/context 中实现多个 运行 仍然存在问题.
我在使用存储的隔离和上下文创建上下文后将其拆分,但没有成功。当在第二部分尝试创建源字符串时它失败了,可能是因为使用了存储的隔离(我猜是隔离范围的东西)。
:(
我在 UPDATE1 中介绍的假设是正确的。那部分效果很好。
根据UPDATE2,我将评估部分一分为二。
首先用于初始化隔离和上下文:
mIsolate = Isolate::New(mCreate_params);
Isolate::Scope isolate_scope(mIsolate);
{
// Create a stack-allocated handle scope.
HandleScope handle_scope(mIsolate);
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(mIsolate);
// Bind the global 'print' function to the C++ Print callback.
global->Set(v8::String::NewFromUtf8(mIsolate, "print"), v8::FunctionTemplate::New(mIsolate, Print));
// Create a new context.
mContext = Context::New(mIsolate, NULL, global);
Persistent<Context, CopyablePersistentTraits<Context>> persistent(mIsolate, mContext);
mContext_persistent = persistent;
}
第二个 运行 js 在相同的上下文中:
Isolate::Scope isolate_scope(mIsolate);
{
HandleScope handle_scope(mIsolate);
mContext = Local<Context>::New(mIsolate, mContext_persistent);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(mContext);
{
// Create a string containing the JavaScript source code.
Local<String> source =
String::NewFromUtf8(mIsolate, js_source, NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
Local<Script> script = Script::Compile(mContext, source).ToLocalChecked();
TryCatch trycatch(mIsolate);
// Run the script to get the result.
v8::Local<v8::Value> result;
if(!script->Run(mContext).ToLocal(&result)){
v8::String::Utf8Value exception_str(trycatch.Exception());
dprint(*exception_str);
}else{
if(!result->IsUndefined()){
String::Utf8Value utf8(result);
dprint(*utf8);
}
}
}
}
好吧,代码在 linux 上工作得很好,但是当我在 android 上第二次尝试 运行 第一部分(创建新上下文)时,我仍然遇到一些问题:
A/art: art/runtime/thread.cc:986] pthread_getschedparam failed for DumpState: No such process
A/art: art/runtime/base/mutex.cc:485] Unexpected state_ 0 in unlock for logging lock
但我想那是另一个问题。和平
您是否多次初始化 v8?
v8::V8::Initialize()
每个进程应该调用一次此方法。
深入项目源文件"v8/src/v8.cc"
,你会发现证明
bool V8::Initialize() {
InitializeOncePerProcess();
return true;
}