zoukankan      html  css  js  c++  java
  • 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 ", *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
  • 相关阅读:
    React生命周期, 兄弟组件之间通信
    React组件式编程Demo-用户的增删改查
    React之this.refs, 实现数据双向绑定
    CCF CSP 201812-4 数据中心
    CCF CSP 201812-4 数据中心
    PAT 顶级 1020 Delete At Most Two Characters (35 分)
    PAT 顶级 1020 Delete At Most Two Characters (35 分)
    Codeforces 1245C Constanze's Machine
    Codeforces 1245C Constanze's Machine
    CCF CSP 201712-4 行车路线
  • 原文地址:https://www.cnblogs.com/wxmdevelop/p/11358395.html
Copyright © 2011-2022 走看看