V8 javascript引擎初步体验

v8 引擎,不必多说,大名鼎鼎,迄今最快的js引擎。

这么好的东西,如果尽在浏览器中使用,太浪费了,也希望用到其他地方,比如一些客户端开发中。

闲言少讲,这就开始

下载源码

去官方网站:https://code.google.com/p/v8/

我喜欢用git,所以从这里下载

git clone git://github.com/v8/v8.git v8 && cd v8

编译

我为android平台编译的,折腾了好久,记录一些重点。你首先要看这个:http://code.google.com/p/v8/wiki/BuildingWithGYP

其实关键是

make dependencies

这需要花很长时间(呃,没办法,国内网速不给力,我下载了好几次)。。。

然后,在android上编译(其他平台?so easy,看文档), 你可以先看看D8OnAndroid (是android平台的一个js命令行吧,不明觉厉)的编译,不过没什么用处。

我自己的编译方法,是用交叉编译的

Cross-compiling

Similar to building with Clang, you can also use a cross-compiler. Just export your toolchain (CXX/LINK environment variables should be enough) and compile. For example:

export CXX=/path/to/cross-compile-g++
export LINK=/path/to/cross-compile-g++
make arm.release

(编译等待中.....)

完了之后,你就可以使用了。

在android上使用

首先,创建一个工程(怎么创建?这个。。。还是自己找吧),一个Activity工程就行,然后在工程目录下创建一个jni目录。

具体怎么使用ndk,我就不说,自己找吧,我说重点的:

1. 拷贝头文件和库文件

为了方便,我把头文件和库文件放在jni下的include和lib下。头文件直接从v8/include文件夹下拷贝就可以,库文件比较麻烦一些,必须拷贝这些:


libicudata.a  libicui18n.a  libicuuc.a  libv8.a  libv8_snapshot.a

你可以从v8/out目录下查找(用find吧,反正记不住具体在什么位置了) 少了编译时就会报找不到符合的错误(说多了都是泪啊)

2. 注意Android.mk的写法

在写Android.mk的时候,必须注意:

1. 库的引用顺序很重要,顺序错了,一样找不到符号

2. 要用stl,

Android.mk和Application.mk(STL需要的)的代码如下,给大家和参考,省得走弯路

Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_CFLAGS += -I$(LOCAL_PATH)/include
LOCAL_LDFLAGS +=     $(LOCAL_PATH)/lib/libv8.a     $(LOCAL_PATH)/lib/libv8_snapshot.a     $(LOCAL_PATH)/lib/libicui18n.a     $(LOCAL_PATH)/lib/libicuuc.a     $(LOCAL_PATH)/lib/libicudata.a     /<path>/android-ndk-r9d//sources/cxx-stl/stlport/libs/armeabi/libstlport_static.a

LOCAL_MODULE := jswrapper
LOCAL_LDLIBS := -llog

LOCAL_SRC_FILES :=     registers.cpp     JavaScriptContextWrap.cpp     javautils.cpp     JsJavaClassProxy.cpp     javawrap.cpp

#sample.cpp sample-jni.cpp
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true

LOCAL_WHOLE_STATIC_LIBRARIES += android_support

include $(BUILD_SHARED_LIBRARY)

$(call import-module, android/support)

(我很笨啊,stl不全路径链接就找不到,呃,难道上天又一次中意我,要给我磨练吗......)

记得lib的顺序和stl噢。。。

Application.mk

APP_CFLAGS += -fexceptions
APP_CFLAGS += -frtti
APP_STL := stlport_static
#gnustl_static

编译用ndk-build就好了。

代码编写

至于jni部分的代码,我就不写了,不懂的baidu和google,你懂的。

头文件?用一个 "v8.h"就好了。

1. 初始化

v8::V8::InitializeICU();

(完了?是的,就这么简单)

2. 创建Isolate和Context

    isolate_ = v8::Isolate::New();
    isolate_->Enter();
    v8::HandleScope handle_scope(isolate_);

    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
    
    //create Log object
    v8::Handle<v8::ObjectTemplate> log = v8::ObjectTemplate::New(isolate_);
    log->Set(v8::String::NewFromUtf8(isolate_, "e"),
            v8::FunctionTemplate::New(isolate_, js_func_log_e));
    log->Set(v8::String::NewFromUtf8(isolate_, "i"),
            v8::FunctionTemplate::New(isolate_, js_func_log_i));
    log->Set(v8::String::NewFromUtf8(isolate_, "v"),
            v8::FunctionTemplate::New(isolate_, js_func_log_v));
    log->Set(v8::String::NewFromUtf8(isolate_, "d"),
            v8::FunctionTemplate::New(isolate_, js_func_log_d));
    global->Set(v8::String::NewFromUtf8(isolate_, "Log"), log);

    //TODO others
    global->Set(v8::String::NewFromUtf8(isolate_, "import_java_class"),
            v8::FunctionTemplate::New(isolate_, js_func_import_java_class));
    
    
    context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));

内容有点多哈。别着急,听我慢慢道来。

首先,创建一个v8::Isolate, 用v8::Isolate::New()。 isolate是什么东东?这个嘛,其实我也不太清楚,大概类似一个虚拟机,所有的javascript对象都在这个isolate上,不太的isolate老死不相往来。

然后需要调用一下isolate_->Enter(),当然要销毁时,调用一下isolate_->Leave()。

对了,v8是c++的,成员方法首字母都是大写的。

第二,我们可以创建一个ObjectTemplate了。ObjectTemplate望文生义,是对象的模版,怎么说呢,对应到C++和java里面,你可以认为是静态类,有一堆静态方法。

各位请先看最后一句:v8::Context::New(isolate_, NULL, global)。这句话注册一个全局的模版,也就是说,如果我在global中注册一个print函数,那么可以直接在js中这样写:

print ("Hi, I\'m from native");

我们的例子里面,是注册了一个Log的子ObjectTempl,Log又包含e, i,  v, d几个方法,其实就是对应的android.util.Log.e, i, v, d。

注册方法是调用Set,C++函数指针需要用

v8::FunctionTemplate::New

来包装。这些知道就行了,不必深究(其实我也不懂)

还有一点必须说明:上面的代码实际上是一个类的一部分,这里有两个成员变量:

    v8::Persistent<v8::Context> context_;
    v8::Isolate* isolate_;

isolate直接使用指针,而Context必须用Persistent,这是一个可以持久保持对象的指针(防止被v8当垃圾回收了),使用方法是用 Rest:

    context_.Reset(isolate_, v8::Context::New(isolate_, NULL, global));

3. 定义一个函数

凡事先看代码:(我用js_func_log_x来实现js_func_log_i等函数的公共部分)

void js_func_log_x(int level, const v8::FunctionCallbackInfo<v8::Value>& args) {
    if (args.Length() == 0) {
        return ;
    }

    //get tag
    char szTag[1024] = "";
    {
        v8::HandleScope handle_scope(args.GetIsolate());
        v8::String::Utf8Value str(args[0]);
        const char* cstr = ToCString(str);

        strcpy(szTag, cstr);
    }

    char szLog[1024*8] = "";

    bool first = true;
    int len = 0;
    for (int i = 1; i < args.Length(); i++)
    {
        v8::HandleScope handle_scope(args.GetIsolate());
        if (first) {
            first = false;
        } else {
            len += sprintf(szLog + len, " ");
        }
        v8::String::Utf8Value str(args[i]);
        const char* cstr = ToCString(str);
        len += sprintf(szLog + len, "%s", cstr);
    }

    __android_log_print(level, szTag, "%s", szLog);
}

args 包含了参数和运行时。在每次取参数处理参数时,必须调用

        v8::HandleScope handle_scope(args.GetIsolate());

(why?I don‘t known 。。。。)

从Value中取字符串,则需要用ToCString,他也很简单:

static const char* ToCString(const v8::String::Utf8Value& value) {
  return *value ? *value : "<string conversion failed>";
}

正经的给v8使用的函数是这样的:

void js_func_log_i(const v8::FunctionCallbackInfo<v8::Value>& args) {
    js_func_log_x(ANDROID_LOG_INFO, args);
}

void js_func_log_v(const v8::FunctionCallbackInfo<v8::Value>& args) {
    js_func_log_x(ANDROID_LOG_VERBOSE, args);
}

void js_func_log_d(const v8::FunctionCallbackInfo<v8::Value>& args) {
    js_func_log_x(ANDROID_LOG_DEBUG, args);
}

void js_func_log_e(const v8::FunctionCallbackInfo<v8::Value>& args) {
    js_func_log_x(ANDROID_LOG_ERROR, args);
}

好了,初体验到此结束

一些重要的知识点

1. 关联一个对象到Isolate上

Isolate可以有多个,如果有一个对象关联到Isolate,该如何从Isolate找到该对象呢?

使用Isolate的GetData/SetData

比如

JavaWrapper* JavaWrapper::fromIsolate(Isolate* isolate) {
    if (isolate == NULL) {
        return NULL;
    }

    void *data = isolate->GetData(ISOLATE_SLOT_JAVA_WRAPPER);

    JavaWrapper* javawrap = reinterpret_cast<JavaWrapper*>(data);

    return javawrap && javawrap->isolate_ == isolate ? javawrap : NULL;

}

JavaWrapper::JavaWrapper(Isolate* isolate)
:isolate_(isolate)
{
    isolate_->SetData(ISOLATE_SLOT_JAVA_WRAPPER, (void*)this);
}

2. 怎样从v8::Value中得到其他类型的参数

v8::Value是个复合对象,我们可以这样做:

    for (int i = 0; i < count; i++) {
        HandleScope handle_scope(args.GetIsolate());
        Local<Value> v = args[i];

        if (v->IsUndefined() || v->IsNull()) {
            types[i] = JsJavaClassProxy::NullClass();
            values[i] = JsJavaClassProxy::NullObject();
            LOGV(" arg(%d) is null\n", i);
        } else if (v->IsTrue() || v->IsFalse()) {
            types[i] = JsJavaClassProxy::BooleanClass();
            jboolean jv = (jboolean)(v->IsTrue() ? true : false);
            values[i] = jreflect::ValueOf(env, jv);
            LOGV(" arg(%d) is boolean:%d", i, jv);
        } else if (v->IsString()) {
            types[i] = JsJavaClassProxy::StringClass();
            String::Utf8Value str(v);
            const char* cstr = ToCString(str);
            values[i] = env->NewStringUTF(cstr);
            LOGV(" arg(%d) is String:%s", i, cstr);
        } else if (v->IsBoolean()) {
            types[i] = JsJavaClassProxy::BooleanClass();
            jboolean jv = v->ToBoolean()->Value();
            values[i] = jreflect::ValueOf(env, jv);
            LOGV(" arg(%d) is boolean:%d", i, jv);
        } else if (v->IsInt32() || v->IsUint32()) {
            types[i] = JsJavaClassProxy::IntClass();
            jint jv = v->ToInt32()->Value();
            values[i] = jreflect::ValueOf(env, jv);
            LOGV(" arg(%d) is int:%d", i, jv);
        } else if (v->IsNumber()) {
            types[i] = JsJavaClassProxy::DoubleClass();
            jdouble jv = v->ToNumber()->Value();
            values[i] = jreflect::ValueOf(env, jv);
            LOGV(" arg(%d) is double:%f", i, jv);
        } /** TODO MORE **/ else {
            LOGE("Invalidate Arg type!");
            ASSERT(false);
        }
    }

更多的,从v8.h中看就可以了。

好了,先到这里吧。

V8 javascript引擎初步体验

时间: 2024-11-18 05:30:33

V8 javascript引擎初步体验的相关文章

V8 JavaScript引擎研究(一)简介

V8 JavaScript引擎简介 V8是Google公司的高效JavaScript引擎.它使用C++开发,完全开源,最著名的是使用在Chrome浏览器中作为JavaScript解析引擎. V8实现了ECMAScript-262标准,可以运行在Windows(XP及以上).Mac OS X(10.5及以上)以及使用IA-32.x64或ARM处理器的Linux系统. V8通常使用在浏览器中作为JavaScript的解析引擎,也可以嵌入到任何应用程序中使用. 基于C++的应用程序通过V8可以暴露任何

V8:V8(Javascript引擎)

ylbtech-V8:V8(Javascript引擎) Lars Bak是这个项目的组长,目前该JavaScript引擎已用于其它项目的开发.第一个版本随着第一个版本的Chrome于2008年9月2日发布. 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 1. https://baike.baidu.com/item/V8/6178125 2. 6.返回顶部 作者:ylbtech出处:http://ylbtech.cnblogs.com/本文版权归作者和博客园共有,欢迎转载

V8 JavaScript引擎研究(二)高性能探秘

V8的高性能探秘 V8项目负责人Lars Bak:V8的所有优化都不是原创的.V8组合了过往对于动态语言的各种优化技术,因而具有了非常高效的性能. 快速属性访问 JavaScript是动态编程语言,这意味着可以动态的增加或删除对象的属性. 以往实现 大多数的JavaScript引擎都是使用类似字典的数据结构来保存一个对象的属性,在这种结构下每次访问一个属性都需要动态查找其在内存中的位置. 优势: 实现简单. 劣势: 效率低.相对于Java.Smalltalk等语言,由于对象的class有着固定的

V8 JavaScript引擎研究(三)垃圾回收器的实现

V8垃圾回收机制简介 V8垃圾回收器的实现,是V8高效的一个非常重要的原因. V8在运行时自动回收不再需要使用的对象内存,也即是垃圾回收. V8使用了全暂停式(stop-the-world).分代式(generational).精确(accurate)等组合的垃圾回收机制,来确保更快的对象内存分配.更短的垃圾回收时触发的暂停以及没有内存碎片. V8的垃圾回收有如下几个特点: 当处理一个垃圾回收周期时,暂停所有程序的执行. 在大多数垃圾回收周期,每次仅处理部分堆中的对象,使暂停程序所带来的影响降至

[C#]VS2017使用google v8 Javascript引擎

V8是JavaScript渲染引擎,号称是最快的,因为品牌效应,我信了,相关介绍网上一堆,我就不粘贴了,原库是直接提供给c++调用的,这里会用到微软的ClearScript.V8(包装v8),JavaScriptEngineSwitcher.V8(包装ClearScript)两个C#库. 一.安装: 1.项目右键,选择 管理NuGet程序包 2.搜索下面4个包并安装 3.检查引用目录下面是否存在相关dll链接库,不存在需要手动添加,运行后如果碰到缺少相关dll的问题,将项目根目录下package

windows下使用VS2015编译V8 JavaScript引擎(v5.5 - 2016/09)

今天心血来潮, 下载了 v8,,然后就想着用vs编译 但是大家都苦恼的是 v8并不直接提供 vs用的项目文件和解决方案(.sln) 于是,在网上搜来搜去, 折腾来折腾去的; 终于一点一点的尝试, 可以执行 python gypfiles\gyp_v8.py -Dtarget_arch=x64 但是网上搜到的都是 python build\gyp_v8.py -Dtarget_arch=x64 可我git clone 的没有build文件夹啊, 好歹根据 https://github.com/v8

JavaScript 引擎「V8」发布 8.0 版本,内存占用量大幅下降

上周,JavaScript 引擎「V8」的开发团队在该项目官方网站上正式宣布推出最新的 8.0 版本.这次更新的重点主要集中在错误修复及性能改善上,正式的版本将在数周后随着谷歌 Chrome 80 稳定版一起发布. V8 是谷歌公司推出的开源高性能 JavaScript 引擎,主要用于提升 Web 浏览器内部 JavaScript 脚本执行的性能.V8 通过 C++ 语言编写,主要用在 Chrome 浏览器以及 Node.js 上,实现了对 ECMAScript 与 WebAssembly 的支

JavaScript 引擎 V8 执行流程概述

本文首发于 vivo互联网技术 微信公众号? 链接:https://mp.weixin.qq.com/s/t__Jqzg1rbTlsCHXKMwh6A 作者:赖勇高 本文主要讲解的是V8的技术,是V8的入门篇,主要目的是了解V8的内部机制,希望对前端,快应用,浏览器,以及nodejs同学有些帮助.这里不涉及到如何编写优秀的前端,只是对JS内部引擎技术的讲解. 一.V8来源 V8的名字来源于汽车的"V型8缸发动机"(V8发动机).V8发动机主要是美国发展起来,因为马力十足而广为人知.V8

JavaScript引擎、虚拟机、运行时环境浅析

一.JavaScript引擎: 所谓JavaScript引擎是一个专门处理JavaScript脚本的虚拟机,一般会附带在网页浏览器之中,用于解释和执行js脚本. 著名的js引擎: Mozilla:SpiderMonkey引擎,世界第一款JavaScript引擎,有C/C++编写,用于Mozilla Firefox 1.0-3.0版本 Google:V8引擎,由C++/汇编语言编写,用于chrome浏览器 微软:Chakra(查克拉,笑)引擎,用于Internet Explorer 9的32位版本