例示できるナニ

短かくて理解し易げなソレが何かないものか、と試行錯誤。

gosh> (define (add (x y) (+ x y)))       
add
gosh> (disasm (lambda (x) (+ (add x 1) 2)))
main_code (name=#f, code=0x80f6ea0, size=8, const=1, stack=11):
args: #f
     0 PRE-CALL(2) 6
     2 LREF0-PUSH               ; x
     3 CONSTI-PUSH(1) 
     4 GREF-CALL(2) #<identifier user#add>; (add x 1)
     6 NUMADDI(2)               ; (+ (add x 1) 2)
     7 RET 
#<undef>
gosh> (disasm (lambda (x y) (+ (add x 1) y)))
main_code (name=#f, code=0x80f8e60, size=10, const=1, stack=11):
args: #f
     0 PRE-CALL(2) 6
     2 LREF1-PUSH               ; x
     3 CONSTI-PUSH(1) 
     4 GREF-CALL(2) #<identifier user#add>; (add x 1)
     6 PUSH 
     7 LREF0                    ; y
     8 NUMADD2                  ; (+ (add x 1) y)
     9 RET 
#<undef>
gosh> 

即値は最適化されてしまう。ある意味凄い。ちなみに add という関数を使わない場合にはこうなる。

gosh> (disasm (lambda (x y) (+ (+ x 1) y)))
main_code (name=#f, code=0x80d73a8, size=6, const=0, stack=1):
args: #f
     0 LREF1                    ; x
     1 NUMADDI(1)               ; (+ x 1)
     2 PUSH 
     3 LREF0                    ; y
     4 NUMADD2                  ; (+ (+ x 1) y)
     5 RET 
#<undef>
gosh> 

あげ。こっちの方が分かりやすいじゃん (駄目
推測ベースで書くと

  • lexical address の (0 1) から値を取り出して val0 にセット
  • val0 と 1 を加えて val0 に
  • val0 を push
  • lexical address の (0 0) から値を取り出して val0 にセット
  • pop した値と val0 を加えて val0 にセット

ってカンジなのだろうか。試した所では上記な形だと x と y な引数でないと PUSH が最適化されてしまうみたい。とりあえず PUSH の説明としては

val0 レジスタの値をスタックに push する。

で良いのでしょうか。とりあえず書いてみる。