こんだけ期間が開くと API がガラッと変わって,昔やってた AviUtl のプラグイン DLL に V8 を組み込む手法なんかも変えないといけなかったので,再び調べてみた.
サンプルとかでよく見る V8 の実行の流れは以下のようになっていて,
あるクラス::ある関数(){
Isolate 作成
Isolate スコープの中 {
Handle スコープの中 {
Context 作成
Cotext スコープの中 {
JavaScript 初期化 (スクリプトコンパイル等)
// ↑ここまで初期化処理
// ↓ここから繰り返しの処理
JavaScript 実行
}
}
}
}
AviUtl のプラグイン DLL では,初期化処理と JavaScript 実行処理は関数を分けて,それぞれの関数処理が終わるごとに AviUtl に制御を返さないといけない.かと言って単純にそれらを分けてしまうと,初期化関数を抜けた時に Handle スコープを抜ける = Context も破棄されるため,別関数で JavaScript 実行することができない.なので以下のようにする.
あるクラス::Compile(){
Isolate 作成→メンバ変数に保存
Isolate スコープの中 {
Handle スコープの中 {
Context 作成→メンバ変数に保存
Cotext スコープの中 {
JavaScript 初期化 (スクリプトコンパイル等)
}
}
}
}
あるクラス::Run(){
メンバ変数に保存した Isolate スコープの中 {
Handle スコープの中 {
メンバ変数に保存した Cotext スコープの中 {
JavaScript 実行
}
}
}
}
要は Isolate と Context はメンバ変数に保存してやれば良い.ただし Context::New は Local<> なので (そのままでは Handle スコープを抜けると破棄されるため) Persistent<> に変換してやる必要がある.(そして Run() 内でメンバ変数の Context を参照するときは,また Local<> に変換する.)Context 内のグローバルオブジェクトとか,HandleScope を抜けるとどうなるか心配だったが,この方法なら破棄されないみたい.
というわけで hello.cc をちょっと改造して上記のことを実現したソースは以下のとおり.Compile メソッドで生成した JavaScript function の hoge() を,Run メソッドで呼ぶことができている.昔やってた,HandleScope を new で生成するというやばい方法は使わなくて済んだ.
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
using namespace v8;
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
virtual void* Allocate(size_t length) {
void* data = AllocateUninitialized(length);
return data == NULL ? data : memset(data, 0, length);
}
virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
virtual void Free(void* data, size_t) { free(data); }
};
class CScript {
Platform* m_Platform;
ArrayBufferAllocator m_Allocator;
Isolate::CreateParams m_CreateParams;
Isolate* m_Isolate;
v8::Persistent<v8::Context> *m_Context;
public:
CScript( char *path ){
// Initialize V8.
V8::InitializeICU();
V8::InitializeExternalStartupData( "." );
m_Platform = platform::CreateDefaultPlatform();
V8::InitializePlatform(m_Platform);
V8::Initialize();
m_CreateParams.array_buffer_allocator = &m_Allocator;
}
~CScript(){
m_Isolate->Dispose();
V8::Dispose();
V8::ShutdownPlatform();
delete m_Platform;
}
void Compile( void ){
// Create a new Isolate and make it the current one.
m_Isolate = Isolate::New(m_CreateParams);
{
Isolate::Scope isolate_scope(m_Isolate);
// Create a stack-allocated handle scope.
HandleScope handle_scope(m_Isolate);
// Create a new context.
Local<Context> context = Context::New(m_Isolate);
m_Context = new Persistent<v8::Context>( m_Isolate, context );
// 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(m_Isolate, "function hoge(){ return 'hoge!!!'; }",
NewStringType::kNormal).ToLocalChecked();
// Compile the source code.
Local<Script> script = Script::Compile(context, source).ToLocalChecked();
Local<Value> result = script->Run(context).ToLocalChecked();
}
}
void Run( void ){
Isolate::Scope isolate_scope(m_Isolate);
// Create a stack-allocated handle scope.
HandleScope handle_scope(m_Isolate);
// Create a new context.
Local<Context> context = Local<Context>::New( m_Isolate, *m_Context);
// Enter the context for compiling and running the hello world script.
Context::Scope context_scope(context);
Local<Function> hFunction = Local<Function>::Cast( context->Global()->Get( String::NewFromUtf8( m_Isolate, "hoge" )));
if( hFunction->IsUndefined()){
int a=0;
}
Local<Value> result = hFunction->Call( context->Global(), 0, NULL);
// Run the script to get the result.
// Convert the result to an UTF8 string and print it.
String::Utf8Value utf8(result);
printf("%s\n", *utf8);
}
};
int main(int argc, char* argv[]) {
CScript *scr = new CScript( argv[ 0 ]);
scr->Compile();
scr->Run();
delete scr;
return 0;
}
0 件のコメント:
コメントを投稿