V8世界探险 (1)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/lusing/article/details/53035185

V8世界探险 (1) - v8 API概览

v8是Google开发的JavaScript引擎,自推出后就对js生态产生了巨大的影响。比如产生了运行在服务端的Node.js的巨大生态。

这么好玩的东西,我们当然要冲起去看看它的内部是如何实现的了。

Hello,v8 World!

首先好玩的一点是,v8可以作为一个库来嵌入到其它的应用中。

我们废话不多说,直接上代码.这是Google官方的调用在代码中嵌入一个v8引擎的例子,地址在:https://chromium.googlesource.com/v8/v8/+/branch-heads/4.8/samples/hello-world.cc

// 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); }

};

int main(int argc, char* argv[]) {

  // Initialize V8.

  V8::InitializeICU();

  V8::InitializeExternalStartupData(argv[0]);

  Platform* platform = platform::CreateDefaultPlatform();

  V8::InitializePlatform(platform);

  V8::Initialize();

  // Create a new Isolate and make it the current one.

  ArrayBufferAllocator allocator;

  Isolate::CreateParams create_params;

  create_params.array_buffer_allocator = &allocator;

  Isolate* isolate = Isolate::New(create_params);

  {

    Isolate::Scope isolate_scope(isolate);

    // Create a stack-allocated handle scope.

    HandleScope handle_scope(isolate);

    // Create a new context.

    Local<Context> context = Context::New(isolate);

    // 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(isolate, "'Hello' + ', World!'",

                            NewStringType::kNormal).ToLocalChecked();

    // Compile the source code.

    Local<Script> script = Script::Compile(context, source).ToLocalChecked();

    // Run the script to get the result.

    Local<Value> result = script->Run(context).ToLocalChecked();

    // Convert the result to an UTF8 string and print it.

    String::Utf8Value utf8(result);

    printf("%s\n", *utf8);

  }

  // Dispose the isolate and tear down V8.

  isolate->Dispose();

  V8::Dispose();

  V8::ShutdownPlatform();

  delete platform;

  return 0;

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

我们从中可以看到几个重要的类: 

* V8:这个是个大杂烩的工具类,从初始化到关闭平台都离不开它。 

* ArrayBuffer是v8的数据类型,下面我们会来一张v8的数据结构图。 

* Isolate是v8中最重要的功能类,代表了一个v8引擎的实例。它不是线程安全的,如果在线程不安全情况下运行需要加锁。 

* Local是v8中存储对象的结构,代表了被GC管理的对象引用。与其对应的就是持久性对象,如Global和Persistent。 

* Context代表了在沙箱中运行的上下文。与Java一样,JavaScript也运行在一个沙箱安全环境中。 

* Script代表了运行在v8中的脚本。

上面使用的都是v8的公开API。这些API代表了v8的主要功能和主要数据结构。 

我们先看一张v8的API的大图:

对象与句柄

与C/C++与Rust等存在栈式管理的语言不同,JavaScript并没有栈上分配这样的概念。但是在v8的实现中,是有通过栈式管理作用域的数据结构,就是例程中我们所看到的HandleScope。 

另外还有SealHandleScope类,将当前的HandleScope封装起来,强制需要创建新的HandleScope.

v8中的对象按生命周期可以分为两类,由GC管理的局部对象Local,还有持久性的对象。 

持久性的对象分为:一次性的永续对象Eternal,和全局性的PersistentBase。 

PersistentBase根据管理所有权方式的不同,采用赋值和复制方式的叫做Persistent,采用移动语义的叫做Global. 

还有个UniquePersistent的模块类,其实是Global的别名。C++11中定义模板别名的方式,之前我们有文章讲过了:

template <class T> using UniquePersistent = Global<T>;

1

从例子中我们可以看到,通常我们使用的变量都是Local为主。不管是Context,String,Script还是Value都是通过Local模板来进行管理的:

    // Create a new context.

    Local<Context> context = Context::New(isolate);

    Local<String> source =

        String::NewFromUtf8(isolate, "'Hello' + ', World!'",

                            NewStringType::kNormal).ToLocalChecked();

    // Compile the source code.

    Local<Script> script = Script::Compile(context, source).ToLocalChecked();

    // Run the script to get the result.

    Local<Value> result = script->Run(context).ToLocalChecked();

1

2

3

4

5

6

7

8

9

现在并没有一个共同的Handle基类,Local,Eternal和PersistentBase之间没有共基类的关系。

由于返回值也大部分是Local,为了强制代码判空,v8经常使用MaybeLocal的模块,它是Local的一个封装。

我们再画一个图来回顾下它们之间的关系:

脚本相关的API

脚本相关的API主要涉及到三个部分:源代码,编译后的脚本代码和编译器三部分。 

源代码表示的类是ScriptOrigin和ScriptOriginOptions. 

编译之后的脚本,按照是否跟上下文绑定,分为UnboundScript和Script两种。 

编译器是ScriptCompiler.

另外,脚本的运行时信息也是很重要的结构,v8提供了包装错误信息的Message类,提供跟踪栈信息的StackTrace和StackFrame。

v8的数据类型

我们先看个数据类型的图,如果对于ES6不太熟悉的同学,可能对于某些ES6新增的类型会有些疑惑。不过不用担心,后面如果有会用到ES6的知识的话,我会尽可能做一些快餐式的简介。

所有的v8数据类型都继承自Data类。 

这个类非常简单:

/**

 * The superclass of values and API object templates.

 */

class V8_EXPORT Data {

  private:

  Data();

};

1

2

3

4

5

6

7

首先继承自Data的是一个跟js无关的NativeWeakMap: 

同时让大家继续体验下几乎一切皆Local的感受,基本上每个类型都要加上Local<>模板管理一下:

/**

 * A map whose keys are referenced weakly. It is similar to JavaScript WeakMap

 * but can be created without entering a v8::Context and hence shouldn't

 * escape to JavaScript.

 */

class V8_EXPORT NativeWeakMap : public Data {

 public:

  static Local<NativeWeakMap> New(Isolate* isolate);

  void Set(Local<Value> key, Local<Value> value);

  Local<Value> Get(Local<Value> key);

  bool Has(Local<Value> key);

  bool Delete(Local<Value> key);

};

1

2

3

4

5

6

7

8

9

10

11

12

13

Value类是所有的JavaScript类型的基类,它有两个巨大的子类,一个是代表原始类型的Primitive,一个就是所有js对象之根Object类。当然,还有个实现上用途的包装C++ void*指针的External类。

ES6新增了Symbol类型,它和String共同派生自Name类型。 

虽然JavaScript的数都是浮点数,但是在v8的实现里,整数仍然是大行其道的。

对象类型中,Promise, Proxy, ArrayBufferView这些都是ES6新增的。有些还需要–harmony选项的支持。 

剩下是对于原始类型的包装,如NumberObject, BooleanObject, StringObject, SymbolObject。 

还有的就是Date日期类和RegExp正则表达式类两个内置类的支持,也在API中。

最后,直接继承自Data的,还有4个类: 

* Private:私有的符号 

* Template:模板,分为函数模板和对象模板。这两个在后面我们分析v8的实现中有重要意义,因为它们是将JavaScript函数或者对象绑定到C++相应的对象上的重要工具。 

* 两个签名类,用于调用时检验用

小结

这一节新增的概念可能有点多。我们尝试小结一下: 

v8提供了可供外部调用的一系列的API: 

* Isolate:提供了一个v8虚拟机的实例 

* Context:提供了一个沙箱,也就是独立的上下文可以运行Isolate 

* v8通过HandleScope栈式管理内存 

* Local<>是最常用的变量分配方式 

* v8的数据类型基类是Data,所有js对象的基类是Value。Value下面分Primitive和Object

最后引用一个新概念,v8为了提升性能,引入了一个高效的编译器Crankshaft.

好了,这一讲就这么多。

--------------------- 

版权声明:本文为CSDN博主「Jtag特工」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/lusing/article/details/53035185

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

Android原生编解码接口 MediaCodec 之——踩坑

版权声明:本文为博主原创文章,遵循CC4.0BYSA版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/gb702250823/article/details/81669684希望我们尊重每个人的成果,转载请标明出处:https://blog.csdn.net/gb702250823/a

DAO与DAL的区别

版权声明:本文为博主原创文章,遵循CC4.0BYSA(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fcreativecommons.org%2Flicenses%2Fbysa%2F4.0%2F)版权协议,转载请附上原文出处链接和本声明。本文链接:https://blo

EleasticSearch 线上大索引按日期分割

版权声明:本文为博主原创文章,遵循CC4.0BYSA版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/Norman\_Hu/article/details/899175691\.背景由于项目初期设计问题,采集到es的业务日志只使用了一个索引(index),随着线上日志量的增长,es很

Spring Boot 项目瘦身指南,瘦到不可思议!

点击“开发者技术前线”,选择“星标”在看|星标|留言, 真爱版权声明:本文为CSDN博主「yjgithub」的原创文章,遵循CC4.0BYSA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/yjgithub/article/details/8047