google v8使用示例

概念解释

Handle
V8里使用Handle类型来托管 JavaScript对象,与C++的std::shared_pointer类似,Handle类型间的赋值均是直接传递对象引用,但不同的是,V8使用自己的GC来管理对象生命周期,而不是智能指针常用的引用计数。如果一个v8对象没有任何Handle与之相关联(不再被访问),那么这个对象很快就会被垃圾回收器回收掉。
Handle有两种类型,Local Handle和Persistent Handle,类型分别是Local : Handle和Persistent : Handle,前者和Handle没有区别,生存周期都在scope内。而后者的生命周期脱离scope,你需要手动调用Persistent::Dispose结束其生命周期。也就是说Local Handle相当于在C++在栈上分配对象,而Persistent Handle相当于C++在堆上分配对象。

Isolate
Isolate表示一个独立的v8引擎实例,每个实例维护不同的状态。一个Isolate中的对象不能在其他Isolate中使用。当v8被初始化的时候,一个默认isolate被默认创建。开发者可以通过创建额外的Isolate在多线程环境下并行使用。一个Isolate任意时间只允许一个线程在其中运行,可以使用Locker和Unlocker来进行多个线程对一个Isolate的同步。

Context
V8允许不同的JavaScript代码运行在完全不同的环境下,其运行环境称为Context。不同的Context下拥有自己的全局对象(PersistentHandle),运行代码时必须指定所在的Context。最典型的例子就是Chrome的标签,每个标签都拥有自己的Context。
Context拥有自己的全局代理对象(global proxy object),每个Context下的全局对象都是这个全局代理对象的属性。通过Context::Global ()可以得到这个全局代理对象。新建Context时你可以手动指定它的全局代理对象,这样每个Context都会自动拥有一些全局对象,比如DOM。
Context也是一种scope,通过Context::Enter ()和Context::Exit ()来进入、退出,或者使用类似于HandleScope的Context::Scope来隐式进入。

External
v8::External,它的作用是把C++的对象包装成Javascript中的变量。External::New接受一个C++对象的指针作为初始化参数,然后返回一个包含这个指针的Handle对象供v8引擎使用。在使用这个Handle对象时可以通过External::Value函数来得到C++对象的指针。

Template
Template是介于Javascript和C++变量间的中间层,你首先由C++对象生成一个Template,然后再由Template生成Javascript函数的对象。你可以事先在Template中准备好一些预备属性,然后生成的Javascript对象都将具备这些属性。

FunctionTemplate
你可以使用FunctionTemplate::New ()生成一个空函数,然后用FunctionTemplate::SetCallHandler ()将其和C++函数绑定,或者直接靠FunctionTemplate::New (InvocationCallback callback)来用C++函数初始化一个FunctionTemplate。
用来生成FunctionTemplate的C++函数必须满足InvocationCallback的条件,即函数签名必须如下:
typedef Handle (*InvocationCallback)(const Arguments& args);
如果是简单给js脚本使用,创建并设置完FunctionTemplate就可以了;但是如果在c++中使用FunctionTemplate或者是需要为Function设置一些属性字段的话,需要从FunctionTemplate通过GetFunction()来创建一个Function。
此后,你可以使用FunctionTemplate::GetFunction()来获取对应的v8::Function。但是一个FunctionTemplate只能生成一个Function,FunctionTemplate::GetFunction()返回的都是同一个实体。这是因为Javascript里显式声明的全局函数只有一个实例。
Javascript常用new Function ();的形式来创建对象,而C++中,Function::NewInstance可以返回一个函数的Instance。你可以使用Function::NewInstance返回一个函数对象,等同于Javascript中的var tmp = new func;。

ObjectTemplate
ObjectTemplate的目的就是根据包装起来的C++对象生成v8::Object。接口与Template也大致相当,通过ObjectTemplate::New返回新的ObjectTemplate,通过ObjectTemplate::NewInstance。ObjectTemplate提供了一种Internal Field,也就是内部储存空间,我们可以通过External类型把C++对象储存在ObjectTemplate中。
建立了ObjectTemplate后,我们可以通过ObjectTemplate::SetInternalFieldCount设定内部储存多少个内部变量。然后通过ObjectTemplate::NewInstance建立新的Object,再在v8::Object中通过SetInternalField来对内部变量进行操作。
Accessors的实现原理就是为Object绑定一个C++对象,并为其在全局代理对象中设置一个名字,当JavaScript按指定的名字访问Object的时候,调用Getter和Setter函数来访问C++对象数据。

如果需要在Function中创建一个Function,处理一个C++对象。首先需要将这个C++对象使用SetInnerField封转到一个Object中;其次在FunctionTemplate::New的时候,将Object作为data参数传入New函数,这样在创建的Function中就可以通过args.Data()获取到之前的Object了(Value类型的,使用ToObject转成Object类型),然后通过GetPointerFromInnerField就可以获得之前的C++对象了。

示例代码

#include <string>
#include <cstring>

#include <sys/time.h>

#include <v8.h>

using namespace v8;

#ifndef THREAD_NUM
#define THREAD_NUM 4
#endif

#ifndef DEF_CALLS
#define DEF_CALLS 100000
#endif

#ifdef NO_LOG

#define CDEBUG_LOG(format, args...) 
#define CTRACE_LOG(format, args...) 
#define CWARNING_LOG(format, args...) 
#define CFATAL_LOG(format, args...) 

#else

#define CDEBUG_LOG(format, args...) \
    do{\
         char tmpstr[65536];\
         snprintf(tmpstr,65535,format,##args);\
         printf("[thread:%u] %s\n", pthread_self(), tmpstr); \
    }while(0)
#define CTRACE_LOG(format, args...) \
    do{\
         char tmpstr[65536];\
         snprintf(tmpstr,65535,format,##args);\
         printf("[thread:%u] %s\n", pthread_self(), tmpstr); \
    }while(0)
#define CWARNING_LOG(format, args...) \
    do{\
         char tmpstr[65536];\
         snprintf(tmpstr,65535,format,##args);\
         printf("[thread:%u] %s\n", pthread_self(), tmpstr); \
    }while(0)
#define CFATAL_LOG(format, args...) \
    do{\
         char tmpstr[65536];\
         snprintf(tmpstr,65535,format,##args);\
         printf("[thread:%u] %s\n", pthread_self(), tmpstr); \
    }while(0)

#endif

static Handle<Value> IntGetter(Local<String>name, const AccessorInfo &info)
{
    String::Utf8Value utf8_value_name(name);
    std::string key(*utf8_value_name);
    const char * strKey = key.c_str();

    if(strcmp(strKey, "c"))
    {
        return Int32::New(3);
    }
    else if(strcmp(strKey, "d"))
    {
        return Int32::New(4);
    }

    return Int32::New(1);
}

static Handle<Value> NamedGetter(Local<String>name, const AccessorInfo &info)
{
    String::Utf8Value utf8_value_name(name);
    std::string key(*utf8_value_name);
    const char * strKey = key.c_str();

    if(strcmp(strKey, "f1"))
    {
        return Int32::New(5);
    }
    else if(strcmp(strKey, "f2"))
    {
        return Int32::New(6);
    }

    return Int32::New(1);
}

static Handle<Value> IndexedGetter(uint32_t index, const AccessorInfo &info)
{
    if(index==1)
        return Int32::New(7);
    else if(index==2)
        return Int32::New(8);

    return Int32::New(1);
}

static Handle<Value> Sum(const Arguments &args)
{
    if(args.Length()!=2)
        return Undefined();
    if(args[0]->IsInt32() && args[1]->IsInt32())
        return Int32::New(args[0]->Int32Value()+args[1]->Int32Value());
    else
        return Undefined();
}

void *v8_func_op(void *)
{
    int count = 0;
    struct timeval tvStart;
    struct timeval tvEnd;
    // Create a stack-allocated handle scope.
    HandleScope handle_scope;

    // Create a ObjectTemplate
    Handle<ObjectTemplate> global = ObjectTemplate::New();
    //Function Set before Context::New
    global->Set(String::New("Sum"), FunctionTemplate::New(Sum));

    Persistent<Context> context = Context::New(NULL, global);
    // Create a new context.
    //Persistent<Context> context = Context::New();
    Context::Scope context_scope(context);

    //Sum(1,2);
    //*
    (void) gettimeofday(&tvStart, NULL);
    for(int i=0; i<DEF_CALLS; i++)
    {
        // Create a stack-allocated handle scope.
        HandleScope handle_subscope;

        const char *JS_STR = "Sum(1,1)";
        Handle<String> source = String::New( JS_STR );
        Handle<Script> script = Script::Compile(source);

        // Run the script to get the result.
        TryCatch trycatch;
        Handle<Value> result = script->Run();
        if(result.IsEmpty())
        {
            Handle<Value> exception = trycatch.Exception();
            String::AsciiValue exception_str(exception);
            printf("Exception: %s\n", *exception_str);
        }
        else
        {
            if(result->IsInt32())
            {
                CDEBUG_LOG("JS RET: %d", result->Int32Value());
            }
            else
            {
                CDEBUG_LOG("JS FAILED");
            }
        }
    }
    (void) gettimeofday(&tvEnd, NULL);
    fprintf(stdout, "[thread:%u] %u calls - timespan : %lu us\n", pthread_self(), DEF_CALLS, (tvEnd.tv_sec-tvStart.tv_sec)*1000000+(tvEnd.tv_usec-tvStart.tv_usec));
    usleep(2000);
    //*/

    //1+1==2
    //*
    (void) gettimeofday(&tvStart, NULL);
    for(int i=0; i<DEF_CALLS; i++)
    {
        // Create a stack-allocated handle scope.
        HandleScope handle_subscope;

        const char *JS_STR = "1+1==2";
        Handle<String> source = String::New( JS_STR );
        Handle<Script> script = Script::Compile(source);

        // Run the script to get the result.
        TryCatch trycatch;
        Handle<Value> result = script->Run();
        if(result.IsEmpty())
        {
            Handle<Value> exception = trycatch.Exception();
            String::AsciiValue exception_str(exception);
            printf("Exception: %s\n", *exception_str);
        }
        else
        {
            if(result->IsBoolean())
            {
                if(result->BooleanValue())
                {
                    CDEBUG_LOG("JS RET: TRUE");
                }
                else
                {
                    CDEBUG_LOG("JS RET: FALSE");
                }
            }
            else
            {
                CDEBUG_LOG("JS FAILED");
            }
        }
    }
    (void) gettimeofday(&tvEnd, NULL);
    fprintf(stdout, "[thread:%u] %u calls - timespan : %lu us\n", pthread_self(), DEF_CALLS, (tvEnd.tv_sec-tvStart.tv_sec)*1000000+(tvEnd.tv_usec-tvStart.tv_usec));
    usleep(2000);
    //*/

    //static set: a+b
    //*
    context->Global()->Set(String::New("a"), Int32::New(1));
    context->Global()->Set(String::New("b"), Int32::New(2));

    (void) gettimeofday(&tvStart, NULL);
    for(int i=0; i<DEF_CALLS; i++)
    {
        // Create a stack-allocated handle scope.
        HandleScope handle_subscope;

        const char *JS_STR = "a+b";
        Handle<String> source = String::New( JS_STR );
        Handle<Script> script = Script::Compile(source);

        // Run the script to get the result.
        TryCatch trycatch;
        Handle<Value> result = script->Run();
        if(result.IsEmpty())
        {
            Handle<Value> exception = trycatch.Exception();
            String::AsciiValue exception_str(exception);
            printf("Exception: %s\n", *exception_str);
        }
        else
        {
            if(result->IsInt32())
            {
                CDEBUG_LOG("JS RET: %d", result->Int32Value());
            }
            else
            {
                CDEBUG_LOG("JS FAILED");
            }
        }
    }
    (void) gettimeofday(&tvEnd, NULL);
    fprintf(stdout, "[thread:%u] %u calls - timespan : %lu us\n", pthread_self(), DEF_CALLS, (tvEnd.tv_sec-tvStart.tv_sec)*1000000+(tvEnd.tv_usec-tvStart.tv_usec));
    usleep(2000);
    //*/

    //static accessor: c+d
    //*
    context->Global()->SetAccessor(String::New("c"), IntGetter);
    context->Global()->SetAccessor(String::New("d"), IntGetter);

    (void) gettimeofday(&tvStart, NULL);
    for(int i=0; i<DEF_CALLS; i++)
    {
        // Create a stack-allocated handle scope.
        HandleScope handle_subscope;

        const char *JS_STR = "c+d";
        Handle<String> source = String::New( JS_STR );
        Handle<Script> script = Script::Compile(source);

        // Run the script to get the result.
        TryCatch trycatch;
        Handle<Value> result = script->Run();
        if(result.IsEmpty())
        {
            Handle<Value> exception = trycatch.Exception();
            String::AsciiValue exception_str(exception);
            printf("Exception: %s\n", *exception_str);
        }
        else
        {
            if(result->IsInt32())
            {
                CDEBUG_LOG("JS RET: %d", result->Int32Value());
            }
            else
            {
                CDEBUG_LOG("JS FAILED");
            }
        }
    }
    (void) gettimeofday(&tvEnd, NULL);
    fprintf(stdout, "[thread:%u] %u calls - timespan : %lu us\n", pthread_self(), DEF_CALLS, (tvEnd.tv_sec-tvStart.tv_sec)*1000000+(tvEnd.tv_usec-tvStart.tv_usec));
    usleep(2000);
    //*/

    //named property: e.f1+e.f2
    //*
    Handle<ObjectTemplate> named = ObjectTemplate::New();
    named->SetNamedPropertyHandler(NamedGetter, NULL);
    context->Global()->Set(String::New("e"), named->NewInstance());

    (void) gettimeofday(&tvStart, NULL);
    for(int i=0; i<DEF_CALLS; i++)
    {
        // Create a stack-allocated handle scope.
        HandleScope handle_subscope;

        const char *JS_STR = "e.f1+e.f2";
        Handle<String> source = String::New( JS_STR );
        Handle<Script> script = Script::Compile(source);

        // Run the script to get the result.
        TryCatch trycatch;
        Handle<Value> result = script->Run();
        if(result.IsEmpty())
        {
            Handle<Value> exception = trycatch.Exception();
            String::AsciiValue exception_str(exception);
            printf("Exception: %s\n", *exception_str);
        }
        else
        {
            if(result->IsInt32())
            {
                CDEBUG_LOG("JS RET: %d", result->Int32Value());
            }
            else
            {
                CDEBUG_LOG("JS FAILED");
            }
        }
    }
    (void) gettimeofday(&tvEnd, NULL);
    fprintf(stdout, "[thread:%u] %u calls - timespan : %lu us\n", pthread_self(), DEF_CALLS, (tvEnd.tv_sec-tvStart.tv_sec)*1000000+(tvEnd.tv_usec-tvStart.tv_usec));
    usleep(2000);
    //*/

    //indexed property: f[1]+f[2]
    //*
    Handle<ObjectTemplate> indexed = ObjectTemplate::New();
    indexed->SetIndexedPropertyHandler(IndexedGetter, NULL);
    context->Global()->Set(String::New("f"), indexed->NewInstance());

    (void) gettimeofday(&tvStart, NULL);
    for(int i=0; i<DEF_CALLS; i++)
    {
        // Create a stack-allocated handle scope.
        HandleScope handle_subscope;

        const char *JS_STR = "f[1]+f[2]";
        Handle<String> source = String::New( JS_STR );
        Handle<Script> script = Script::Compile(source);

        // Run the script to get the result.
        TryCatch trycatch;
        Handle<Value> result = script->Run();
        if(result.IsEmpty())
        {
            Handle<Value> exception = trycatch.Exception();
            String::AsciiValue exception_str(exception);
            printf("Exception: %s\n", *exception_str);
        }
        else
        {
            if(result->IsInt32())
            {
                CDEBUG_LOG("JS RET: %d", result->Int32Value());
            }
            else
            {
                CDEBUG_LOG("JS FAILED");
            }
        }
    }
    (void) gettimeofday(&tvEnd, NULL);
    fprintf(stdout, "[thread:%u] %u calls - timespan : %lu us\n", pthread_self(), DEF_CALLS, (tvEnd.tv_sec-tvStart.tv_sec)*1000000+(tvEnd.tv_usec-tvStart.tv_usec));
    usleep(2000);
    //*/

    //Should Call GC
    V8::IdleNotification();
    V8::LowMemoryNotification();
    V8::ContextDisposedNotification();

    //Heap Statis
    {
        HeapStatistics hs;
        V8::GetHeapStatistics(&hs);
        fprintf(stderr, "[thread:%u] "
                "total_heap_size:%u "
                "total_heap_size_executable:%u "
                "used_heap_size:%u "
                "heap_size_limit:%u\n",
                pthread_self(),
                hs.total_heap_size(),
                hs.total_heap_size_executable(),
                hs.used_heap_size(),
                hs.heap_size_limit());
    }

    // Dispose the persistent context.
    context.Dispose();
    context.Clear();

    //return 0;
    return NULL;
}

void * v8_func(void *)
{
    //One thread have an isolate
    v8::Isolate* isolate = v8::Isolate::New();
    {
        Locker locker(isolate);
        v8::Isolate::Scope iscope(isolate);

        //*
        {
            ResourceConstraints rc;
            rc.set_max_young_space_size(2048); //KB
            rc.set_max_old_space_size(10); //MB
            rc.set_max_executable_size(10); //MB
            rc.set_stack_limit(reinterpret_cast<uint32_t*>((char*)&rc- 1024 * 400));

            SetResourceConstraints(&rc);
        }
        //*/

        v8_func_op(NULL);
    }

    isolate->Dispose();

    return NULL;
}

int main(int argc, char *argv[])
{
#define MAX_THREAD_NUM 120
    pthread_t pid[MAX_THREAD_NUM] = {0};
    void * res = NULL;
    int thread_num = THREAD_NUM;

    V8::SetFlagsFromCommandLine(&argc, argv, true); 

    for(int i=0; i<thread_num; i++)
        pthread_create(&pid[i], NULL, v8_func, NULL);

    for(int i=0; i<thread_num; i++)
        pthread_join(pid[i], &res);

    return 0;
}

本文转载自:http://blog.chinaunix.net/uid-20357359-id-2690542.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值