keropoの備忘録

しらべたことをメモるブログ

v8 engineのサンプルプログラム

せっかく、v8をコンパイルしたので、サンプルプログラムをオフィシャルサイト等々を参考に作成してみた。
APIの仕様だったり、クラスのメンバー関数の構造が変わったらしく、ネットでよく見かけるサンプルプログラムではコンパイルが通らなかった。
一応、試行錯誤しながら、動くものが完成した。
サンプルとしては、v8にオリジナルの関数とクラスを組み込むサンプルになります。

/*
 * v8 javascript engine simple sample program.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <v8.h>

using namespace v8;

class ShellArrayBufferAllocator : public 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 TObject
{
private:
    int ident;

public:
    explicit TObject(int value = 0)
    :ident(value)
    {
    }

    int GetIdent() const { return ident; }
    
    Persistent<Object> *holder;
};

class TObjectIF
{
private:
    static TObject* GetThis(const Local<Object> handle)
    {
        void *This = Local<External>::Cast(handle->GetInternalField(0))->Value();
        return static_cast<TObject*>(This);
    }

    static void New(const FunctionCallbackInfo<Value>  &args)
    {
        TObject *p = NULL;

        if (args.Length() > 0)
        {
            p = new TObject(args[0]->Int32Value());
        } else {
            p = new TObject();
        }

        Local<Object> thisObject = args.This();
        thisObject->SetInternalField(0, External::New(args.GetIsolate(), p));

        Persistent<Object> *holder = new Persistent<Object>(args.GetIsolate(), thisObject);
        holder->SetWeak<TObject>(p, TObjectIF::Dispose);

        p->holder = holder;
    }

    static void Dispose(const WeakCallbackData<Object, TObject> &data)
    {
        TObject *p = data.GetParameter();
        Persistent<Object> *holder = p->holder;

        //release instance.
        holder->Reset();
        if (p != NULL) { delete p; }
    }

    static void GetIdent(const FunctionCallbackInfo<Value> &args)
    {
        TObject *p = GetThis(args.This());

        args.GetReturnValue().Set(p->GetIdent());
    }

public:
    static void InitializeTemplate(Isolate *isolate, Handle<ObjectTemplate> global)
    {
        Local<FunctionTemplate> clazz = FunctionTemplate::New(isolate, TObjectIF::New);
        clazz->SetClassName(String::NewFromUtf8(isolate, "TObject"));

        Local<ObjectTemplate> instTemplate = clazz->InstanceTemplate();
        instTemplate->SetInternalFieldCount(1);

        Local<ObjectTemplate> protoTemplate = clazz->PrototypeTemplate();

        protoTemplate->Set(
            String::NewFromUtf8(isolate, "getIdent"), 
            FunctionTemplate::New(isolate, TObjectIF::GetIdent));

        global->Set(String::NewFromUtf8(isolate, "TObject"), clazz);
    }
};

void Print(const FunctionCallbackInfo<Value> &args)
{
    HandleScope handle_scope(args.GetIsolate());
    for (int i = 0; i < args.Length(); i++)
    {
        String::Utf8Value str(args[i]);
        printf("%s", *str);
    }
    printf("\n");

    args.GetReturnValue().Set(0);
}

Handle<Context> InitBuildinFunction(Isolate *isolate)
{
    Handle<ObjectTemplate> global = ObjectTemplate::New(isolate);

    global->Set(String::NewFromUtf8(isolate, "print"), FunctionTemplate::New(isolate, Print));

    TObjectIF::InitializeTemplate(isolate, global);

    return Context::New(isolate, NULL, global);
}

int main(int argc, char **argv)
{
    V8::InitializeICU();
    V8::SetFlagsFromCommandLine(&argc, argv, true);

    ShellArrayBufferAllocator array_buffer_allocator;
    V8::SetArrayBufferAllocator(&array_buffer_allocator);

    Isolate *isolate = Isolate::New();
    Isolate::Scope isolate_scope(isolate);

    HandleScope handle_scope(isolate);

    Handle<Context> context = InitBuildinFunction(isolate);

    Context::Scope context_scope(context);

    Handle<String> source = String::NewFromUtf8(isolate, "var p = new TObject(10); print(p.getIdent());");

    Handle<Script> script = Script::Compile(source);

    Handle<Value> result = script->Run();

    String::Utf8Value utf8(result);
    printf("%s", *utf8);

    V8::Dispose();

    return 0;
}