Subscribed unsubscribe Subscribe Subscribe

枕を欹てて聴く

香炉峰の雪は簾を撥げて看る

iv / lv5 VM engine

JavaScript ECMAScript C++

『ゆるゆり』 のOPが頭から離れなかったのですが, 最近EDも頭から離れなくなってきました...

https://github.com/Constellation/iv

iv / lv5のVM engine化がとりあえず完了し, byte codeにcompileしてstack VMで実行するengineになりました!! 今まで「ECMAScript engineをー」と言われるたびに, 「といっても, ASTのInterpreterなんですけどね」と言っていたのですが, これで心置きなくengineを名乗れそうな気がします.


ちなみに, AST Interpreterですが, 抽象化の結果ひとつのengineでどちらも使えるとかいうかなり怪しいことになっており, --interp optionを付けるとInterpreterで評価することができます(はっきりわかるほどVMの方が速いです. optimizationなどもVMの方に力を注いだため, Interpreterはかなり素直な構成のままになっています). こちらのInterpreterはECMA262 5thの評価をかなり逐次的に行った物であり, それはそれで価値があると思っています.


もちろんのことながら仕様準拠が第一です. VMについてInterpreter時からのregressionはありません. sputniktests, es5conformance suiteで確認しました.
SunSpiderなど実は走るので, 興味のある方は是非. JITやPolymorphic Inline Cache, IR RegExpなどやっていないので, もちろん最近のengineと比べればとても遅いですが, 意外と高速です.

楽しいbytecode

きちんとstackに変数を割りつけるbytecodeを吐きます. --dis optionをつけるとbytecodeをprintし, 例えば,

function loop(last) {
  for (var i = 0; i < last; ++i) {
    print(i);
  }
}
loop(100000);
[code] stack: 3 locals: 0
00000: MAKE_CLOSURE 0
00003: STORE_GLOBAL 0
00006: POP_TOP
00007: CALL_GLOBAL 0
00010: LOAD_CONST 0
00013: CALL 1
00016: POP_TOP_AND_RET
00017: STOP_CODE
[code] stack: 5 locals: 2
00000: LOAD_CONST 0
00003: STORE_LOCAL 1
00006: POP_TOP
00007: LOAD_LOCAL 1
00010: LOAD_LOCAL 0
00013: BINARY_LT
00014: POP_JUMP_IF_FALSE 34
00017: CALL_GLOBAL 2
00020: LOAD_LOCAL 1
00023: CALL 1
00026: POP_TOP_AND_RET
00027: INCREMENT_LOCAL 1
00030: POP_TOP
00031: JUMP_ABSOLUTE 7
00034: STOP_CODE

とoutputします. 上の方がglobalで, 下のcodeがfunction loopです. きちんとstackに割り振られていますね. もちろん,

function test() {
  eval("var i = 20;");
  print(i);
}
test();
[code] stack: 2 locals: 0
00000: MAKE_CLOSURE 0
00003: STORE_GLOBAL 0
00006: POP_TOP
00007: CALL_GLOBAL 0
00010: CALL 0
00013: POP_TOP_AND_RET
00014: STOP_CODE
[code] stack: 3 locals: 0
00000: CALL_NAME 0
00003: LOAD_CONST 0
00006: EVAL 1
00009: POP_TOP_AND_RET
00010: CALL_NAME 1
00013: LOAD_NAME 2
00016: CALL 1
00019: POP_TOP_AND_RET
00020: STOP_CODE

という風に, arguments, eval, with対策もバッチリです. (iのlookupがLOAD_NAMEによるdynamic lookupに変わっている)

lv6 shift project

stack VMだと, peephole optimizationをやってもたいして感があり, また今は1 passでbytecodeを吐くためにかなりacrobaticな感じなのですが, IR作ってやるというのも, IR作ってもう一周するほどいい感じの速度が出るとも思えないので, とりあえず長ーい目でregister VMを調べていこうかなと思っています.
抽象化によって意外とInterpreterとVMの同居とかできてしまったので, moduleの形で, JIT engineを研究するのも面白そうです.
あとは環境の辞書をもう少し効率的に配列などに割りつける, そしてみんな大好きPolymorphic Inline Cacheを実装するなど, 面白そうですね.
正規表現engineが仕様準拠していないので, これを実装しないと...
GCも書きたいですよね... というのも, 今は64bitではJSValが128bitなんです. でもですね, nun boxingというのがありまして, これを使うとこれが64bitに収まるのですね... value representation in javascript implementations -- wingolog しかしBoehmGCを使っている以上, address値をいじるとmarkしてくれなくなってしまうので, これができないのです. 1 wordにはいるとか魅力的すぎる...
V8のsrc codeもバリバリ読みたい...

などと遥かな目標を書き連ねる作業を...

補足

昨年10月, 雨降りしきる某所(いざっ! という感じで行く場所)にて, えらい大言を吐いていて

  1. Interpreterの完成
  2. ICUの依存削除
  3. VM化
  4. 自作GC実装 (Boehm GCでなく)

を掲げていたのですが, なんだかんだで3つ終わりました! 案外なんとかなりますね.
大言吐いておくと, やらないとーってなるのでおすすめです.

名前

ちなみにVMの名前はrailgunです. https://github.com/Constellation/iv/tree/master/src/lv5/railgun
旧来のInterpreterはteleporterという名前になっています https://github.com/Constellation/iv/tree/master/src/lv5/teleporter
由来はもうなんかアレですね.