iThink icon indicating copy to clipboard operation
iThink copied to clipboard

神器jsvu

Open hufeng opened this issue 5 years ago • 2 comments

hufeng avatar Oct 08 '19 08:10 hufeng

背景

组内的小朋友写了一篇雄文[探究js-v8引擎下的-数组-底层实现],通过分析v8的底层实现来感知js在v8中的内存分配,通过文章可以看出v8底层的优化和针对不同的场景的优化策略。小朋友主动来找我探讨里面技术点,我冒出一个想发,即使这些技术点都对,我们怎么能够验证出来呢,看代码当然不是最合适的方式,效率不高。于是我就踏上了探索之路。

字节码

在学习nodejs的过程中,我知道怎么可以通过观察js最终执行生成的字节码来看最终代码的转化。那怎么查看js最终生成的字节码呢?

测试代码如下:

function a() {
   var a = [1,2,3];
   a[4] = 5;
   console.log(a[2]);
}
a();

通过下列指令就可以查看a函数最终生成的字节码,就可以大体上看出底层的一些状态:

❯ node --print-bytecode --print-bytecode-filter=a test.js
[generated bytecode for function: a]
Parameter count 1
Frame size 32
   10 E> 0x15262f2d4952 @    0 : a0                StackCheck
   26 S> 0x15262f2d4953 @    1 : 77 00 00 25       CreateArrayLiteral [0], [0], #37
         0x15262f2d4957 @    5 : 26 fb             Star r0
   38 S> 0x15262f2d4959 @    7 : 0c 04             LdaSmi [4]
         0x15262f2d495b @    9 : 26 f9             Star r2
         0x15262f2d495d @   11 : 0c 05             LdaSmi [5]
   43 E> 0x15262f2d495f @   13 : 2e fb f9 01       StaKeyedProperty r0, r2, [1]
   51 S> 0x15262f2d4963 @   17 : 13 01 03          LdaGlobal [1], [3]
         0x15262f2d4966 @   20 : 26 f9             Star r2
   59 E> 0x15262f2d4968 @   22 : 28 f9 02 05       LdaNamedProperty r2, [2], [5]
         0x15262f2d496c @   26 : 26 fa             Star r1
         0x15262f2d496e @   28 : 0c 02             LdaSmi [2]
   64 E> 0x15262f2d4970 @   30 : 29 fb 07          LdaKeyedProperty r0, [7]
         0x15262f2d4973 @   33 : 26 f8             Star r3
   59 E> 0x15262f2d4975 @   35 : 57 fa f9 f8 09    CallProperty1 r1, r2, r3, [9]
         0x15262f2d497a @   40 : 0d                LdaUndefined
   70 S> 0x15262f2d497b @   41 : a4                Return
Constant pool (size = 3)
Handler Table (size = 0)
3

通过字节码我们可以感知到一些信息,但是这个信息还不够全面和直观,需要对字节码指令特别熟悉才行。还有没有更好的办法?

走后门 在学习v8的一些基础点的时候,了解到v8其实是有后门可以让js直接调用v8中的c++函数的,时间久了忘记是什么特性了,是时候复习一波了。 通过查询文档发现这个特性是--allow-natives-syntax

测试代码:

const a = [1,2,3];

%DebugPrint(a);

通过下列指令,开启这个特性:

❯ node --allow-natives-syntax hello.js
0x0dcdf5eea059 <JSArray[3]>

看到下列输出的时候眼泪都要流下来了,这不是我想要的啊。随着时间的推移,v8也在变化,在release版本中屏蔽了很多特性。我们只能上硬核方式了,

  1. 编译node源码,开启debug特性
  2. 编译v8代码,开启debug特性

1,2成本差不多,都很费神。 知道我发现了一个神器jsvu. 可以帮助我们安装各种js的引擎。So easy.

npm install -g jsvu

jsvu安装v8-debug. 1, 2, 3默念 见证奇迹的时刻。

❯ ~/.jsvu/v8-debug --allow-natives-syntax hello.js
Warning: unknown flag --natives_blob=/Users/hf/.jsvu/engines/v8-debug/natives_blob.bin.
Try --help for options
DebugPrint: 0x2cc50154b351: [JSArray]
 - map: 0x2cc54d0029e9 <Map(PACKED_SMI_ELEMENTS)> [FastProperties]
 - prototype: 0x2cc59d4d19a9 <JSArray[0]>
 - elements: 0x2cc50154b2c9 <FixedArray[3]> [PACKED_SMI_ELEMENTS (COW)]
 - length: 3
 - properties: 0x2cc576bc0b29 <FixedArray[0]> {
    #length: 0x2cc55ea40191 <AccessorInfo> (const accessor descriptor)
 }
 - elements: 0x2cc50154b2c9 <FixedArray[3]> {
           0: 1
           1: 2
           2: 3
 }
0x2cc54d0029e9: [Map]
 - type: JS_ARRAY_TYPE
 - instance size: 32
 - inobject properties: 0
 - elements kind: PACKED_SMI_ELEMENTS
 - unused property fields: 0
 - enum length: invalid
 - back pointer: 0x2cc576bc0471 <undefined>
 - prototype_validity cell: 0x2cc55ea40661 <Cell value= 1>
 - instance descriptors (own) #1: 0x2cc59d4d26a1 <DescriptorArray[1]>
 - transitions #1: 0x2cc59d4d26d1 <TransitionArray[4]>Transition array #1:
     0x2cc576bc46e1 <Symbol: (elements_transition_symbol)>: (transition to HOLEY_SMI_ELEMENTS) -> 0x2cc54d002ac1 <Map(HOLEY_SMI_ELEMENTS)>

 - prototype: 0x2cc59d4d19a9 <JSArray[0]>
 - constructor: 0x2cc59d4d1759 <JSFunction Array (sfi = 0x2cc55ea54189)>
 - dependent code: 0x2cc576bc0289 <Other heap object (WEAK_FIXED_ARRAY_TYPE)>
 - construction counter: 0

v8里面支持哪些内置函数呢?请移步v8/v8/blob/master/src/runtime/runtime.h

hufeng avatar Oct 09 '19 03:10 hufeng

MacBook-Pro:test allanxu$ ~/.jsvu/v8-debug --allow-natives-syntax test.js
Warning: unknown flag --natives_blob=/Users/allanxu/.jsvu/engines/v8-debug/natives_blob.bin.
Try --help for options

交流下,为啥我打印出来这样?

xxxsf avatar Jul 07 '20 14:07 xxxsf