读各种资料的笔记,大多是加入个人理解,仅供个人参考,如有理解偏差概不负责(逃
V8在对JS进行解析的过程中,Non Toplevel部分仅仅被预解析,这里的预解析指的是仅仅对其进行语法检查,不会解析成抽象语法树,更不会被编译。 而Toplevel部分会被解释器完全解析,生成抽象语法树并最终生成本地代码,这个时侯编译器并不进行代码优化,唯一的任务就是尽可能快的生成本地代码。
对于Non Toplevel部分,即函数体部分。只有在该函数被调用的时候才会被编译成本地代码。如果在运行过程中该函数被编译器认定为热门函数,那么它将会被优化。
1.JavaScript是一种动态类型语言,在编译时并不能准确知道变量的类型,只可以在运行时确定,这就不像c++或者java等静态类型语言,在编译时候就可以确切知道变量的类型。因此V8 利用动态创建隐藏内部类的方式动态地将属性的内存地址记录在对象内,从而提升整体的属性访问速度。每当为某个对象添加新的属性时,V8 会自动修正其隐藏内部类。隐藏类相同的对象可以共用相同的优化后的代码。
2.优化和去优化
v8最开始采用随机采样的方式来决定函数是否为hot function(桌面版每隔1ms,移动版每隔5ms)。采样时向运行线程发送SIGPROF信号终止其运行,将运行栈的一些栈顶栈帧视为样本,如果发现有函数运行了数次,将其标记为待优化的热函数。这样做显而易见的缺点就是随机性太强,由于随机性太强带来其他的不稳定性。
现在的做法是在函数full compile(快速生成的字节码)时初始化一个递减计数器,计数器是否递减取决于函数的大小或者循环体的大小(足够小时才递减),当计数器递减为0时函数标记为待优化。
在外部函数包含内部函数时,外部函数定义的变量通过闭包的形式可以在内部函数中访问到,在对外部函数的调用结束后内部函数定义的变量停止存在,外部函数定义的变量以闭包形式继续存在。重新实例化外部函数会重新生成函数内定义的所有变量
https://medium.com/@prashantramnyc/javascript-closures-simplified-d0d23fa06ba4
7.
v8内部实现的时候对array对象有分类PACKED_SMI_ELEMENTS、PACKED_DOUBLE_ELEMENTS、PACKED_ELEMENTS、HOLEY_ELEMENTS(从特殊到一般),对array分类的标记只能从特定类型到一般类型,不可逆。如已被标记PACKED_ELEMENTS的array不可能被重新标记为PACKED_DOUBLE_ELEMENTS类型。
packed array比holey array优化时更容易,所以v8在内部对packed和holey array做了区分。array可以从packed标记过渡到holey,holey是packed的一般化
https://v8.dev/blog/elements-kinds
8.
生成相同隐藏类
从相同的起点,以相同的顺序,添加结构相同的属性