首页 > 解决方案 > 嵌入式 V8 上下文和脚本编译崩溃

问题描述

召集 V8 专家。我将 V8 嵌入到我的一个项目中,并且在模块化我的代码时遇到了问题。最简单的例子是编译并运行一个打印“Hello World!”的小脚本。来自 C++ 函数。工作版本如下:

void testV8(const v8::FunctionCallbackInfo<v8::Value>& args) {
    printf("Hello World!\n");
}

void working() {
    v8::Isolate* isolate = nullptr;
    std::string code = "testV8();";

    {
        // Basic initialization
        std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
        v8::V8::InitializePlatform(platform.get());
        v8::V8::Initialize();
        v8::Isolate::CreateParams initOptions;
        initOptions.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
        isolate = v8::Isolate::New(initOptions);
        isolate->Enter();

        // Create context
        v8::HandleScope handleScope(isolate);
        auto global = v8::ObjectTemplate::New(isolate);
        v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);

        // Enter context
        v8::Context::Scope contextScope(context);

        // Bind function
        v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(isolate, &testV8);
        auto name = v8::String::NewFromUtf8(isolate, "testV8").ToLocalChecked();
        context->Global()->Set(context, name, ft->GetFunction(context).ToLocalChecked());

        // Run script
        auto execCode = v8::String::NewFromUtf8(isolate, code.c_str()).ToLocalChecked();
        v8::Local<v8::Script> script;
        if (v8::Script::Compile(context, execCode).ToLocal(&script)) {
            v8::Local<v8::Value> result;
            script->Run(context).ToLocal(&result);
        }
    }
}

当我尝试将代码拆分为可管理的范围时(模仿我想稍后构建的包装类),我在脚本编译时遇到了崩溃:

void testV8(const v8::FunctionCallbackInfo<v8::Value>& args) {
    printf("Hello World!\n");
}

void failing() {
    v8::Isolate* isolate = nullptr;
    std::string code = "testV8();";
    v8::Persistent<v8::Context> persistentContext;

    {
        // Basic initialization
        std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
        v8::V8::InitializePlatform(platform.get());
        v8::V8::Initialize();
        v8::Isolate::CreateParams initOptions;
        initOptions.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
        isolate = v8::Isolate::New(initOptions);
        isolate->Enter();

        // Create context
        v8::HandleScope handleScope(isolate);
        auto global = v8::ObjectTemplate::New(isolate);
        v8::Local<v8::Context> context = v8::Context::New(isolate, nullptr, global);

        // Save context
        persistentContext.Reset(isolate, context);
    }

    {
        // Rebuild scopes and enter context
        v8::Locker locker(isolate);
        v8::HandleScope handleScope(isolate);
        v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, persistentContext);
        v8::Context::Scope contextScope(context);

        // Bind function
        v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(isolate, &testV8);
        auto name = v8::String::NewFromUtf8(isolate, "testV8").ToLocalChecked();
        context->Global()->Set(context, name, ft->GetFunction(context).ToLocalChecked());
    }

    {
        // Rebuild scopes and enter context
        v8::Locker locker(isolate);
        v8::HandleScope handleScope(isolate);
        v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate, persistentContext);
        v8::Context::Scope contextScope(context);

        // Run script
        auto execCode = v8::String::NewFromUtf8(isolate, code.c_str()).ToLocalChecked();
        v8::Local<v8::Script> script;
        if (v8::Script::Compile(context, execCode).ToLocal(&script)) {
            v8::Local<v8::Value> result;
            script->Run(context).ToLocal(&result);
        }
    }
}

基于 xCode 构建并在 Macbook 上运行此代码。我不知道我是否做错了什么,或者上下文是否存在错误。在线研究使我相信,以这种方式使用持久上下文可以很好地在作用域之间保持相同的上下文。这里出了什么问题?

标签: javascriptc++v8embedded-v8

解决方案


问题是一旦范围结束,平台的 unique_ptr 就会被破坏。将其移动到父范围可以修复它。


推荐阅读