如何多次运行V8评估?

时间:2016-05-23 12:52:47

标签: javascript android c++ v8

也许这是一个愚蠢的问题(我是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::New(create_params);

嗯,我该怎么办?我使用错误的构造吗?我应该关闭/删除/清除更多内容吗?

在更大的视图中我只想做评估函数,可以多次触发,除此之外还在同一个上下文中运行多个js snipets(如何拆分这个函数?)。

有什么想法吗?

更新

好的,我们可以说主要部分可分为三个逻辑部分:

初始化

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-&gt;评估 - &gt;清理 两次,那就意味着 init-&gt ;评估 - &gt; clean-&gt; init-&gt;评估 - &gt;清理 ,然后发生错误。我已经想到,如果我将 评估 部分提取到单独的函数中,我可以多次运行它,例如as init-&gt;(评估){2} - &gt;清理

这是怎么回事?下一步是把这个主要分成树分开的功能,这意味着我必须有平台的静态成员?它会以某种方式导致泄漏吗?

注意:我想从Android运行它,这意味着,例如单击UI,通过JNI将js源传播到C,然后调用已初始化或未初始化的c ++ V8。 HM?

首选方式是拥有“blackbox”,但如果我必须拥有平台,那就这样吧。没有重新初始化V8,它也可能更快,对吗?

更新2:

那么,在分析 评估 部分以在同一个隔离/上下文中实现多次运行时仍然存在问题。

我在创建了存储隔离和上下文的上下文之后将其拆分了,但没有运气。当在第二部分中尝试创建源字符串时,它会失败,可能是因为使用了存储的隔离(我猜的是具有隔离范围的东西)。

:(

2 个答案:

答案 0 :(得分:1)

我在 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

但这是我猜的另一个问题。和平。

答案 1 :(得分:1)

您是否多次初始化v8?

v8::V8::Initialize()每个进程都应调用一次此方法。

深入到项目源文件"v8/src/v8.cc",你会发现证明

bool V8::Initialize() {
  InitializeOncePerProcess();
  return true;
}