untyped
(无类型)。
JAVASCRIPT
是个无类型的语言,这导致了如x=y+z
这种表达式可以有很多含义。
y
,z
是数字,则+
表示加法。y
,z
是字符串,则+
表示字符串连接。而JS引擎内部则使用“
细粒度
”的类型,比如:
- 32-bit* integer。
- 64-bit* floating-point。
这就要求js类型-js引擎类型,需要做“boxed/unboxed(装箱/解箱)”,在处理一次
x=y+z
这种计算,需要经过的步骤如下。
- 从内存,读取
x=y+z
的操作符。- 从内存,读取
y
,z
。- 检查y,z类型,确定操作的行为。
unbox y,z
。- 执行操作符的行为。
box x
。- 把
x
写入内存。只有第
5
步骤是真正有效的操作,其他步骤都是为第5
步骤做准备/收尾,JAVASCRIPT
的untyped
特性很好用,但也为此付出了很大的性能代价。
JIT
。
先看看
JIT
对untyped
的优化,在JIT
下,执行x=y+z
流程。
- 从内存,读取
x=y+z
的操作符。- 从内存,读取
y
,z
。- 检查
y
,z
类型,确定操作的行为。unbox y,z
。- 执行 操作符 的行为。
box x
。- 把
x
写入内存。其中
1
,2
步骤由CPU
负责,7
步骤JIT
把结果保存在寄存器里。但可惜不是所有情况都能使用JIT,当number+number
,string+string
等等可以使用JIT
,但特殊情况,如:number+undefined
就不行了,只能走旧解析器。- 新引擎还对“对象属性”访问做了优化,解决方案叫
inline caching
,简称:IC
。简单的说,就是做cache
。但如果当list
很大时,这种方案反而影响效率。
Type-specializing JIT
Type-specializing JIT
引擎用来处理typed
类型(声明类型)变量,但JAVASCRIPT
都是untype
类型的。
Type-specializing JIT
的解决方案是:
- 先通过扫描,监测类型。
- 通过编译优化(优化对象不仅仅只是“类型”,还包括对JS代码的优化,但核心是类型优化),生成类型变量。
- 再做后续计算。
Type-specializing JIT
的执行x=y+z
流程:
- 从内存,读取
x=y+z
的操作符。- 从内存,读取
y
,z
。- 检查
y
,z
类型,确定操作的行为。unbox y,z
。- 执行操作符的行为。
box x
。- 把
x
写入内存。代价是:
- 前置的扫描类型
- 编译优化。
所以·Type-specializing JIT·的应用是有选择性,选择使用这个引擎的场景包括:
- 热点代码。
- 通过启发式算法估算出来的有价值的代码。
另外,有2点也需要注意:
- 当变量类型 发生变化时,引擎有2种处理方式:
- 少量变更,重编译,再执行。
- 大量变更,交给JIT执行。
数组
,object properties
, 闭包变量 不在优化范畴之列。