V8IgnitionInterpreter
名前: @brn (青野健利)
職業: フロントエンドエンジニア・ネイティブエンジニア
会社: Cyberagent アドテクスタジオ RightSegment・AI Messenger
ブログ: http://abcdef.gets.b6n.ch/
WhatisIgnition?
V8には今までインタープリタがなかった。
ソースコードから即full-codegenでアセンブラを生成、実行していた。
しかし、full-codegenは最適化されていない、型情報を持ったアセンブラを
大量に吐き出すため、コードサイズが大きくなってしまう。
そのため、V8は関数単位でlazy compileを行っていたのだが、
これが原因でStartupTimeが大きくなってしまうことがあった。
特に内部関数は全て再パースが必要なため、パースにかかる時間も増大した。
WhatisIgnition?
Ignitionはレジスタベースのバイトコードインタープリタ。
full-codegenが引き起こしていた問題を解決する為に実装された。
•  コードサイズの低減(50%)
•  full-codegenと比較してもわずかなパフォーマンスの劣化
•  devtoolの完全なサポート
•  full-codegenの完全な置き換え(将来的に)
•  TurboFanのフロントエンドとして、jsの再パースをせずにdeoptimizationを行う
V8sofar…
Javascript	
Ast	
FullCodegen	 Crankshaft	
Architecture(x86, Mips, Arm etc…)
V8sofar…
Javascript	
Ast	
Ignition	
TurboFan	
Architecture(x86, Mips, Arm etc…)	
*CodeAssembler
Ignition overview
Bytecode generation

バイトコードの生成はBytecodeGeneratorによって行われる
BytecodeGeneratorはAstVisitorを実装しており、各Astを巡回して、ByteCodeを生成していく。
バイトコードはBytecodeArrayBuilderによって配列として生成される。
バイトコードの生成が完了すると、
各アーキテクチャのGenerate_InterpreterEntryTrampolineが呼び出され、
インタープリタの開始コードが生成される。
Bytecode execution

バイトコードの実行は、InterpreterEntryTrampolineから各BytecodeHandlerが呼び出されて行われる。
各BytecodeHandler内では、新たに追加されたCodeStubAssemblerが、
アーキテクチャ独立のアセンブラコードを生成し、それをTurboFan経由で各アーキテクチャの
コードに変換、実行結果をaccumulatorに格納していく。
このバイトコードの実行時にプロファイリング用コードも出力しておく。
Ignition overview
Javascript	
Ast	
Ignition	
MachineCode	
InterpreterEntryTrampoline	
BytecodeArray	
BytecodeHandler	
Bytecode	
Generate
呼び出し
Browser	
呼び出し
Ignition execution
BytecodeArray	
Bytecodes	
dispatch dispatch …
BytecodeHandler	
CodeStubAssembler	
AccessorAssembler	
RawMachineAssembler	
MachineOperatorBuilder	
CodeAssembler	
BytecodeHandler	
CodeStubAssembler	
AccessorAssembler	
RawMachineAssembler	
MachineOperatorBuilder	
CodeAssembler
Ignition Bytecode
[generating	bytecode	for	function:	]	
Parameter	count	1	
Frame	size	32	
									0x75a3212fece	@				0	:	09	00													LdaConstant	[0]	
									0x75a3212fed0	@				2	:	1f	f9													Star	r1	
									0x75a3212fed2	@				4	:	02																LdaZero	
									0x75a3212fed3	@				5	:	1f	f8													Star	r2	
									0x75a3212fed5	@				7	:	20	fe	f7										Mov	<closure>,	r3	
									0x75a3212fed8	@			10	:	55	aa	01	f9	03				CallRuntime	[DeclareGlobalsForInterpreter],	r1-r3	
				0	E>	0x75a3212fedd	@			15	:	92																StackCheck	
			39	S>	0x75a3212fede	@			16	:	0a	01	02										LdaGlobal	[1],	[2]	
									0x75a3212fee1	@			19	:	1f	f9													Star	r1	
									0x75a3212fee3	@			21	:	03	01													LdaSmi	[1]	
									0x75a3212fee5	@			23	:	1f	f8													Star	r2	
									0x75a3212fee7	@			25	:	03	01													LdaSmi	[1]	
									0x75a3212fee9	@			27	:	1f	f7													Star	r3	
			39	E>	0x75a3212feeb	@			29	:	52	f9	f8	f7	05				CallUndefinedReceiver2	r1,	r2,	r3,	[5]	
									0x75a3212fef0	@			34	:	1f	fa													Star	r0	
			49	S>	0x75a3212fef2	@			36	:	96																Return	
Constant	pool	(size	=	2)	
0x75a3212fe79:	[FixedArray]	
	-	map	=	0x180f21302309	<Map(FAST_HOLEY_ELEMENTS)>	
	-	length:	2	
											0:	0x75a3212fd71	<FixedArray[4]>	
											1:	0x344fee497319	<String[3]:	add>	
[generating	bytecode	for	function:	add]	
Parameter	count	3	
Frame	size	0	
			12	E>	0x75a32130196	@				0	:	92																StackCheck	
			23	S>	0x75a32130197	@				1	:	1e	02													Ldar	a1	
			32	E>	0x75a32130199	@				3	:	2c	03	02										Add	a0,	[2]	
			37	S>	0x75a3213019c	@				6	:	96																Return
TurboFan optimization
Code optimization

Ignitionによって生成されたバイトコードはTurboFanアーキテクチャを利用して最適化される。
BytecodeGraphBuilderによってTurboFanはグラフ指向のIRを生成し、コードの最適化を行う。
最適化自体はループ・Closureの生成等でランタイム呼び出しによって実行される。
Code deoptimization

TurboFanが脱最適化を行う際は、TurboFanによって生成された、TranslatedStateオブジェクトから、
インタープリタのスタックフレームを再生成し、NotifyDeoptimizedランタイム
を呼び出して、再度インタープリタに入る。
TurboFan optimization overview
Javascript	
Ast	
Ignition	
*CodeAssembler	
Architecture(x64, Mips, Arm, etc…)	
TurboFan	
最適化
脱最適化
TurboFan optimization detail
...	
OptimizePhase	
PeelingLoop	
etc...
LoadElimination	
SimplifiedLoweringPhase	
IR Graph	
IR Node	
Operator	
etc...
IR Node	
Operator	
1. Optimize
Graph nodes
Generate Arch OP Code	
InstructionSelector	
InstructionSelectorX64	
InstructionSelectorX87
InstructionSelectorMips
InstructionSelectorArm
etc...
2. Generate new instruction
CodeGenerator	
OptimizedCode	
3. Generate Machine Code
TurboFan Inlining Caching (IC)
これまでのICの問題点

プロパティアクセスのたびに、Map(hidden class)の存在チェックと、Mapからの値のロード
を行うコードを生成しており、オブジェクトの情報もオブジェクト自身にエンコーディング
されて持っていたため、メモリを圧迫していた。
また、ファストパスかキャッシュミスヒットのいずれかの状態しかなかったため、
キャッシュミスヒットの速度低下も問題であった。
新たなIC

FeedbackVectorというコード・オブジェクトの情報に責務を持つクラスを新たに設け、
ICのオーバーヘッドを大きく減らした。
このFeedbackVectorを利用することで、以前のICではLoadIC_MissかFoundの二通りだったが、
TurboFanのICでは、fast・noninlined・missの三通りになり、LoadIC_Missのケースを減らしている。
まとめ
TurboFanのところは結構怪しい…
V8のコード追うのホントにしんどい

参考
https://github.com/v8/v8
https://v8project.blogspot.jp/2016/08/firing-up-ignition-interpreter.html
https://docs.google.com/document/d/11T2CRex9hXxoJwbYqVQ32yIPMh0uouUZLdyrtmMoL44/edit#
http://benediktmeurer.de/2017/03/01/v8-behind-the-scenes-february-edition/

V8 Iginition Interpreter