VisualWorks:ブロックの種類

2007/03/30 (Fri) 22:07:46 JST

VisualWorksのブロックはクロージャです。実装の都合上、ブロックはコードの内容によって次の種類に分けられます。これらの種類により、それぞれ異なるバイトコードが生成されます。

ブロック外の変数を参照している参照していない
リターンがあるfull copying blockfull block
リターンがないcopying blockclean block

clean block

[ :x | x asString ]

1 <10> push local 0
2 <F0 33> send asString
4 <65> return

レシーバやブロック外の変数を参照せず、リターンもないブロックは clean block となります。clean block は特別なバイトコードを持たず、メソッドのバイトコードに影響を与えません。

copying block

| x |
[ x := true ]

1 <CB 01> push 1 copied values
3 <47> push true
4 <DC 00> store local 0 at 0; pop
6 <D9 00> push local 0 at 0
8 <65> return

レシーバやブロック外の一時変数・引数を参照し、リターンのないブロックは copying block となります。ブロックが評価されるときにポインタがコピーして渡されることからブロック外の変数を copied values と言い (後述) 、 copied values を必要とするブロックが coping block となります。このコード例では最初のバイトコードが、ブロック外のスタックから変数を取得しています。

full block

[ ^ true ]

1 <47> push true
2 <DE 01>  outer(1) method return

レシーバやブロック外の一時変数・引数を参照せず、リターンのないブロックは full block となります。ブロック内のリターンはメソッド内のリターンと異なり、ブロック外のコンテキストの階層を指定しただけ脱出し、最終的にメソッドを終了するのが目的です。この例ではブロック外の (ブロックを実行した) コンテキストを一段階を脱出しますが、ブロックがネストすればするだけこの数値が大きくなります。

valueWithExit

BlockClosure>>valueWithExit
    ^ self value: [ ^ nil ]

このブロック内リターンの性質を利用して実装されているのが valueWithExit です。valueWithExit はブロックだけ抜けるメソッドで、次のように使われます。

1 to: 100 do: [ :i |
    [ :exit |
        1 to: 100 do: [ :j |
            "このループから抜ける"
            (i < j) ifTrue: [ exit value ]
        ]
    ] valueWithExit
]

exit に渡されるオブジェクトは [ ^ nil ] になります。ブロック内のリターンは外側のコンテキストを脱出しますから、 ifTrue: のメッセージを送ったブロックから抜けることになります。

valueWithExit のポイントは、メソッド中のリテラルである [^nil] のバイトコードと、ifTrue: のインライン展開です。[^nil] のバイトコードは次のようになります。

1 <46> push nil
2 <DE 01>  outer(1) method return

[^nil] はコンテキストを一つ脱出するブロックということになります。しかし、上の例では ifTrue: の中でブロックを評価していますから、コードだけ見れば(ifTrue: を含む)二つのコンテキストを脱出しなければならないように見えます。ところが ifTrue: はインライン展開されるので、バイトコードレベルでは ifTrue: のブロックは存在しないのです。というわけで、コンテキストを一つ脱出すれば無事内側のループを抜けられるようになります。

full copying block

| x |
[ x := true. ^ nil ]

1 <D4 00> create array size 1
3 <4C> store local 0; pop
4 <10> push local 0
5 <F7 00 01> make full copying block (1)
8 <65> return

ブロック外の変数を参照し、かつリターンがあると full copying block になります。


Inverse Pages: VisualWorks