不知不觉都快月底了,看了看上一篇还是6号写的,惭愧惭愧,说好的坚持。为了证明没有偷懒(其实还是沉迷了一会dota2),先上一个图自证清白。

基本上从初始化引擎,到Isolate、handleScope、Context一直到编译其实都有记录,但是实在是无从下手。虽说我的博客也没有什么教学意义,但是至少也需要有一个中心和结论。很遗憾,上述的每一步都并互有关联,也就是单独拿出来写毫无意义。而从整体架构来阐述,然后细化到这每一步,我又还没有到那个境界。因此,综合考虑下,决定先暂时放弃逐步解析,优先产出一些有意义的东西。

这一篇的内容属于V8中(或许是C++独有)使用比较普遍的一个技巧,很多模块都有使用。

当初在入门学JS的时候,到了ajax那里,跟着视频学封装。老师讲,如果参数过多,就包装成封装一个对象,这样只需要一个参数就可以了。当时我想着,一个对象也好麻烦啊,还不如封装的时候自己定义一下,如果传1,就代表是"GET"请求,传2,就代表"POST"等等。没想到,当初天真的想法,竟然在C++里面实现了。

下面开始正文,首先需要简单介绍一下枚举,话说各位用过TS的大佬应该都懂,或者接触过protobuf这些数据格式化库也有。枚举在很多语言中都有,定义简单说就是一系列的常量集合,通常用来做简单配置。如果没有指定值,那么就是0、1、2...依次增加,举例如下。

enum fruit {
apple,
banana,
pear,
orange = ,
}; int main(int argc, const char * argv[]) {
cout << "enum apple is " << fruit::apple << endl;
cout << "enum banana is " << fruit::banana << endl;
cout << "enum pear is " << fruit::pear << endl;
cout << "enum orange is " << fruit::orange << endl;
return ;
}

这里我们定义了一个枚举类型,依次打印每一个值,会得到0、1、2,而第四个由于手动指定了值,所以会得到5。如果不去手动指定值,从JS的角度来看枚举有点类似于一个颠倒形式的数组,比如说定义['apple', 'banana', 'pear'],通过下标0、1、2可以取到对应的值,而枚举恰恰相反,通过枚举值取到的是"下标"。大部分简单的配置情况下,是不用去关心枚举具体的值。这样,关于枚举就介绍完了,很简单。

接下来,来看看V8是如何利用这个数据类型来实现参数配置。在对JS源码字符串的编译过程中,有一个类十分重要,负责记录String => AST的过程,名为ParseInfo,这里不去探究转换过程,单纯看一下这个类的标记配置相关,类定义如下。

namespace v8 {
namespace interval { // A container for the inputs, configuration options, and outputs of parsing.
/**
* 有5个构造函数和大量私有属性
*/
class ParseInfo {
public:
explicit ParseInfo(AccountingAllocator* zone_allocator);
explicit ParseInfo(Isolate*);
ParseInfo(Isolate*, AccountingAllocator* zone_allocator);
ParseInfo(Isolate* isolate, Handle<Script> script);
ParseInfo(Isolate* isolate, Handle<SharedFunctionInfo> shared);
private:
// Various configuration flags for parsing.
enum Flag {
kToplevel = << ,
kEager = << ,
kEval = << ,
kStrictMode = << ,
kNative = << ,
// ...more
};
unsigned flags_;
void SetFlag(Flag f) { flags_ |= f; }
void SetFlag(Flag f, bool v) { flags_ = v ? flags_ | f : flags_ & ~f; }
bool GetFlag(Flag f) const { return (flags_ & f) != ; }
};

省略了很多代码,这个类真的超级大,特别是构造函数,虽说内部走的Isolate那一个,但是变向的调用会走全套构造。目前只需要关心私有属性枚举Flag和其相关的三个方法,Flag负责标记编译的代码的一些特征,比如说[native code]、module、IIFE、'strict mode'等等。

枚举Flag的定义有点意思,除去了正常的语义化集合,每一项都给了具体的值,依次为1、2、4、8...,后面会解释原因。flags_就代表了整个Flag的配置,类型比较狗,只注明了一个无符号类型,大部门情况下编译器会认为是一个unsigned int。剩下的三个方法则是根据参数来调整flag_的值,具体实现非常简单,但是理解起来有点恶心,全是位运算。

如果要理解这个操作的原理,需要从二进制的角度来理解,枚举类型的每一个值,其实代表的是二进制的1、10、100、1000等等,所以flags_其实也需要从二进制来理解,默认情况是一个全0的数。这样再来看SetFlag方法,假设解析中发现字符串"strict mode",此时需要调用SetFlag(Flag::kStrictMode)来设置参数,或运算表示只要有一个是1即置1,所以flags_的第4位会被置位1,值就变成了1000。

那么GetFlag就很好理解了,传入一个Flag枚举值,由于与运算需要两个都是1才会为真,而传入的总为1,所以只要flag_对应的位为1(即被设置过)就会返回真。

而SetFlag的重载方法则是一个扩展,当第二个参数为true时,使用与单参数一致。当第二个参数为false时,会将该位置0,也就是取消这个配置。

这样,用一个数字就可以代表非常多的编译参数。在应用时,直接取出数字对应位数的值,如果为1,说明该配置为真,否则为假,即简单,又很高效。当然,这个方法的局限性也很明显,只能针对布尔值的配置,如果是复杂类型那还是需要一个xxxoptions的类来管理。

因为实在太简单了,所以我也懒得画图,应该能理解吧。

深入V8引擎-枚举+位运算实现参数配置的更多相关文章

  1. POJ 2436 二进制枚举+位运算

    题意:给出n头牛的得病的种类情况,一共有m种病,要求找出最多有K种病的牛的数目: 思路:二进制枚举(得病处为1,否则为0,比如得了2 1两种病,代号就是011(十进制就是3)),首先枚举出1的个数等于 ...

  2. c#枚举位运算操作

    抛出预设问题 需要有一个npc需要在一周中的,周一,周二,周三会出现,其他时间不可见 解决问题 因为一周时间是固定的,所以创建枚举类型比较合适,如下 enum Days { None, Sunday, ...

  3. [poj]开关类问题 枚举 位运算

    poj 1222  EXTENDED LIGHTS OUT 开关只有两种方案 按和不按,按两次相当于关 只用枚举第一排开关的按法即可,剩下的行为使上一排的灯全部关闭,按法可以确定,并且是唯一的. 最后 ...

  4. BZOJ 1647 [Usaco2007 Open]Fliptile 翻格子游戏:部分枚举 位运算

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1647 题意: 在一个n*m(1 <= n,m <= 15)的棋盘上,每一个格子 ...

  5. AcWing95. 费解的开关 枚举+位运算

    这道题的确比较难想,首先我们知道图比较小,有可能是枚举,那么该如何枚举呢??? 你可以发现,我们只要把第一排定了,并且保证第一排不准动,那么答案就定了 也就是说,我们首先用二进制枚举,枚举第一行需要翻 ...

  6. POJ 1753 bfs+位运算

    T_T ++运算符和+1不一样.(i+1)%4 忘带小括号了.bfs函数是bool 型,忘记返回false时的情况了.噢....debug快哭了...... DESCRIPTION:求最少的步骤.使得 ...

  7. C#枚举中的位运算权限分配浅谈

    常用的位运算主要有与(&), 或(|)和非(~), 比如: 1 & 0 = 0, 1 | 0 = 1, ~1 = 0 在设计权限时, 我们可以把权限管理操作转换为C#位运算来处理. 第 ...

  8. C#学习笔记-----C#枚举中的位运算权限分配

    一.基础知识 什么是位运算? 用二进制来计算,1&2:这就是位运算,其实它是将0001与0010做位预算   得到的结果是 0011,也就是3  2.位预算有多少种?(我们就将几种我们权限中会 ...

  9. POJ 2531 Network Saboteur 位运算子集枚举

    题目: http://poj.org/problem?id=2531 这个题虽然是个最大割问题,但是分到dfs里了,因为节点数较少.. 我试着位运算枚举了一下,开始超时了,剪了下枝,1079MS过了. ...

随机推荐

  1. 【BZOJ4033】[HAOI2015]树上染色 树形DP

    [BZOJ4033][HAOI2015]树上染色 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染 ...

  2. Earth Hour(最短路)

    Earth Hour Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 125536/65536 K (Java/Others)Total ...

  3. hdu 2108 Shape of HDU【判断多边形是否是凸多边形模板】

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=2108 http://acm.hust.edu.cn/vjudge/contest/view.action ...

  4. Dajngo admin使用

    Dajngo admin使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.你可以在项目的 settings.py 中的 INS ...

  5. Android系统移植与调试之------->安装apk时出现错误Failure [INSTALL_FAILED_DEXOPT]问题解决的方法

    在android4.0源码里面编译出来apk后,用adb install (或adb install -r 重装)安装时,报错[INSTALL_FAILED_DEXOPT]. xu@xu-PC:~$ ...

  6. python -virtualenvwrapper 切换不同的python版本

    环境: 安装了python2.7和python3.4, 两个版本都安装了virtualenv和virtualenvwrapper 在windows cmd中键入mkvirtualenv -p C:\P ...

  7. linux 中 用户管理 (composer 时不能root 遇到)

    linux 是支持多用户的,可以同时多个用户在线操作,这点与 Windows 不同. 在我们项目组 操作linux 服务器时,可进行多用户管理,并赋予不同权限,下面是我学习并用的比较频繁的命令: 1. ...

  8. 打开或者 关闭 php 的错误报告

    一般线上的环境,我会 php的报错信息屏蔽掉,php.ini 设置的办法 如下: display_errors = Off error_reporting = E_ALL 在代码中,可以这样~~: e ...

  9. sonarQube使用maven进行检查

    1.在maven的中找到setting配置文件.在setting.xml中增加sonarqube配置.如下: <profiles> <profile> <id>so ...

  10. 3.08课·········switch case及if else嵌套(日期格式)

    switch case switch (n) { : break; : break; . . . case n: break; } 1.switch case必须与break一同使用,每一个case后 ...