深入V8引擎-枚举+位运算实现参数配置
不知不觉都快月底了,看了看上一篇还是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引擎-枚举+位运算实现参数配置的更多相关文章
- POJ 2436 二进制枚举+位运算
题意:给出n头牛的得病的种类情况,一共有m种病,要求找出最多有K种病的牛的数目: 思路:二进制枚举(得病处为1,否则为0,比如得了2 1两种病,代号就是011(十进制就是3)),首先枚举出1的个数等于 ...
- c#枚举位运算操作
抛出预设问题 需要有一个npc需要在一周中的,周一,周二,周三会出现,其他时间不可见 解决问题 因为一周时间是固定的,所以创建枚举类型比较合适,如下 enum Days { None, Sunday, ...
- [poj]开关类问题 枚举 位运算
poj 1222 EXTENDED LIGHTS OUT 开关只有两种方案 按和不按,按两次相当于关 只用枚举第一排开关的按法即可,剩下的行为使上一排的灯全部关闭,按法可以确定,并且是唯一的. 最后 ...
- BZOJ 1647 [Usaco2007 Open]Fliptile 翻格子游戏:部分枚举 位运算
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1647 题意: 在一个n*m(1 <= n,m <= 15)的棋盘上,每一个格子 ...
- AcWing95. 费解的开关 枚举+位运算
这道题的确比较难想,首先我们知道图比较小,有可能是枚举,那么该如何枚举呢??? 你可以发现,我们只要把第一排定了,并且保证第一排不准动,那么答案就定了 也就是说,我们首先用二进制枚举,枚举第一行需要翻 ...
- POJ 1753 bfs+位运算
T_T ++运算符和+1不一样.(i+1)%4 忘带小括号了.bfs函数是bool 型,忘记返回false时的情况了.噢....debug快哭了...... DESCRIPTION:求最少的步骤.使得 ...
- C#枚举中的位运算权限分配浅谈
常用的位运算主要有与(&), 或(|)和非(~), 比如: 1 & 0 = 0, 1 | 0 = 1, ~1 = 0 在设计权限时, 我们可以把权限管理操作转换为C#位运算来处理. 第 ...
- C#学习笔记-----C#枚举中的位运算权限分配
一.基础知识 什么是位运算? 用二进制来计算,1&2:这就是位运算,其实它是将0001与0010做位预算 得到的结果是 0011,也就是3 2.位预算有多少种?(我们就将几种我们权限中会 ...
- POJ 2531 Network Saboteur 位运算子集枚举
题目: http://poj.org/problem?id=2531 这个题虽然是个最大割问题,但是分到dfs里了,因为节点数较少.. 我试着位运算枚举了一下,开始超时了,剪了下枝,1079MS过了. ...
随机推荐
- 【原创】Hibernate自动生成(2)
本实战是博主初次学习Java,分析WCP源码时,学习HibernateTools部分的实战,由于初次接触,难免错误,仅供参考,希望批评指正. 开发环境: Eclipse Version: Photon ...
- 九度OJ 1192:回文字符串 (基础题)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:3807 解决:1778 题目描述: 给出一个长度不超过1000的字符串,判断它是不是回文(顺读,逆读均相同)的. 输入: 输入包括一行字符串 ...
- 1.BeanFactory解析
package org.springframework.beans.factory; import org.springframework.beans.BeansException; import o ...
- C++, Java和C#的编译、链接过程解析
总是感觉java是解释性语言,转载下一篇感觉写的容易理解的文章 转自 http://www.cnblogs.com/rush/p/3155665.html 1.1.1 摘要 我们知道计算机不能直接理解 ...
- [闲来无事,从头再来][C51篇]导读
目 的: 通过学习C51,熟悉单片机,熟悉C语言,熟悉单片机系统的外部电路. 方 法: 通过看书和使用板子做实验来进行学习 参考资料: <新概念51单片机C语言教程& ...
- postgres=# psql -U postgres -h 127.0.0.1 -p 5432 -d dreamstart_dev -w
postgres=# psql -U postgres -h 127.0.0.1 -p 5432 -d dreamstart_dev -wpostgres-# \dNo relations found ...
- What is MEAN?
MEAN.JS is a full-stack JavaScript open-source solution, which provides a solid starting point for M ...
- Nvidia NVENC 硬编码预研总结
本篇博客记录NVENC硬编码的预研过程 github: https://github.com/MarkRepo/NvencEncoder 步骤如下: (1)环境搭建 (2)demo编译,测试,ARG ...
- mini2440移植uboot 2014.04(三)
我修改的代码已经上传到github上,地址:https://github.com/qiaoyuguo/u-boot-2014.04-mini2440.git 参考文档: s3c2440手册(下载地址) ...
- App开发流程之创建项目和工程基本配置
我的开发环境为:Mac OS X EI Capitan(10.11.6),Xcode 7.3.1 首先说明一下这个项目的初衷,我并非要创建一个完整的上架应用,旨在创建一个可运行的,通用配置.架构,提供 ...