ECMAScript, JavaScript, C++ | |
lv5の実装進捗
test262はもちろん全てpassしているので安心です.
「天下のJSCさんもやってないからー」と言いつつやってなかったのですが... ある日,
https://lists.webkit.org/pipermail/webkit-dev/2011-November/018618.html
なーんてことがあり, JSCさんもやってしまったのでいよいよ言い訳が通じなくなって実装しました.
一部ASCIIな文字列をASCIIのまま持ちます. これで多くのStringLiteralが該当し, memoryが節約されます.
JSCの場合はWebCoreも含むので規模が大きく, はじめASCII, 場合によってはUChar*持つよという実装です.
その点lv5はそこまで大きくないことを利用して過激な方針, すなわち8bitなら8bit, 16bitなら16bitで完全に分離し, それぞれdown castでもしてtemplateで引き取るという実装にしました.
V8もそんな感じ(TwoByte or ASCII)ですが, あちらはStringに上げてaccessする度にdown castするので, String周りのalgorithmなら分岐回数小さい分高速に動作します. ただしcodeがシッチャカメッチャカになります.
また毎回templateで触るのも外部的には触りづらかろうということで, generalなinterfaceも用意しました. こっちで触れば綺麗にかけます. ただし, 速度が気になるなら...
大規模改修を行い, 変数解析をparserへ移しました.
これにより, compilerの時点で解析しながら確定したらrepatchingというろくでもないことをする必要がなくなり(以前はそんな実装だったのです...), よりagressiveなbytecodeを変数について吐けるようになりました.
またこの他, 細かな挙動, 例えば環境を作るとかinstantiationといったものまですべてbytecodeに埋め込まれる事になりました. これによりruntime処理のほとんどがbytecode自体に埋め込まれ, bytecodeがほぼ全ての情報を埋めこまれた状態で保持されることになりました.
この変更はbytecodeにほぼ全ての情報を埋め込むことにより, JITをbytecode to machine code compilerで済ませるということを見据えています.
結構agressiveで, 例えば
function test() { var i = "OK"; function testing() { } }
は以下のbytecodeに展開されます. (lv5 --dis 001.js)
[code] depth: 1 local: 0 heap: 0 00000: INSTANTIATE_DECLARATION_BINDING 0 0 00003: BUILD_FUNCTION 0 00005: STORE_GLOBAL 0 0 0 00009: POP_TOP 00010: STOP_CODE [code] depth: 0 local: 0 heap: 0 00000: STOP_CODE
1つ目のcodeがglobal codeなので, それを考慮してみると, 実質的には,
[code] depth: 0 local: 0 heap: 0 00000: STOP_CODE
STOP_CODEしか残っていません. testingに至っては消去されます.
evalとかwithとか入るともちろんきちんと動作するようにbytecodeが変化します.
あと, Functionのdeclarationとかそういう情報まですべてbytecodeに入っています.
HEAP変数を作って, environmentが必要になると,
function test() { var i = 20; function inner() { print(i); } inner(); } test();
[code] depth: 2 local: 0 heap: 0 00000: INSTANTIATE_DECLARATION_BINDING 0 0 00003: BUILD_FUNCTION 0 00005: STORE_GLOBAL 0 0 0 00009: POP_TOP 00010: CALL_GLOBAL 0 0 0 00014: CALL 0 00016: POP_TOP 00017: STOP_CODE [code] depth: 3 local: 1 heap: 1 00000: BUILD_ENV 1 00002: INSTANTIATE_HEAP_BINDING 0 0 0 00006: BUILD_FUNCTION 0 00008: STORE_LOCAL 0 00010: POP_TOP 00011: PUSH_INT32 20 00013: STORE_HEAP 0 0 0 00017: POP_TOP 00018: CALL_LOCAL 0 00020: CALL 0 00022: POP_TOP 00023: STOP_CODE [code] depth: 3 local: 0 heap: 0 00000: CALL_GLOBAL 0 0 0 00004: LOAD_HEAP 1 0 0 00008: CALL 1 00010: POP_TOP 00011: STOP_CODE
BUILD_ENVがbytecodeに入っています.
ちなみにLOAD_HEAPの1はSymbol引き, 0はenvironmentの階層という情報で, これとoffset情報0を利用してHEAP変数lookupは一度も辞書を引きません.