第 6 章 実装と評価 29
6.3 評価
この節では実際のクラスファイルを使用してシステムの能力を検証する. クラスファイルの生成にはSun のJavaコンパイラを使用し,意図するクラスファイルを表すJavaソースプログラムを記述するのが困難な
場合はdjavaおよびjasminを使用して手書きでクラスファイルを生成した.
6.3.1 実行例1
下のJavaのソースプログラムをJavaコンパイラによってプログラムをコンパイルすると, 3つのクラス ファイルA.class,B.class,sample1.classが生成される.
class sample1 {
int foo(A a, B b) { int sum;
try { } finally {
sum = a.bar(3) + b.bar(2);
if (sum == 0) return 1;}
return sum; } }
class A { int bar(int n) { return n; } } class B extends A { }
sample1はtry-finally構文を持つメソッドfooを有する. Javaコンパイラはtry-finally構文の finally節をサブルーチンにコンパイルする.
システムは最初にメソッドfooのバイトコード配列を次のようなコードブロックの集合に変換する.
Entry: jsr(S1, L1) L1: goto(L2) L2: iload(3) ireturn S1: astore(5)
aload(1) iconst(3)
invokevirtual(A, bar, (I)I) aload(2)
iconst(2)
invokevirtual(A, bar, (I)I) iadd
istore(3)
iload(3) ifne(S2) iconst(1) ireturn S2(S1): ret(5)
実際のコード列には例外ハンドラが含まれるが,ここでは無視するものとする. S1,S2(S1)はサブルーチ ンブロックを表し,S2(S1)はS2がS1に属するサブルーチンであることを意味する. システムは,それぞれ のコードブロックのラベル環境を推論して次のような結果を表示する.
Entry : {CL(sample1), CL(A), CL(B), -, -, -}{} => INT
L1 : {CL(sample1), CL(A), CL(B), INT, -, ret(S1)}{} => INT L2 : {CL(sample1), CL(A), CL(B), INT, -, ret(S1)}{} => INT
S1 : (ret(S1), {(’a<*), (’b<A), (’c<A), INT, (’d<*), ret(S1)}{’L} => INT // {(’a<*), (’b<A), (’c<A), (’e<*), (’d<*), (’f<*)}{ret(S1), ’L} => INT) S2(S1) : (ret(S1), {(’a<*), (’b<A), (’c<A), INT, (’d<*), ret(S1)}{’L} => INT
// {(’a<*), (’b<A), (’c<A), INT, (’d<*), ret(S1)}{’L} => INT)
ここで,’aは型変数を表し,(’a<A)は’aが境界Aのサブクラスであることを意味する. サブルーチン内 部にメソッド呼び出しが存在するため,サブルーチンの型に制約付きの型変数が存在している。
6.3.2 実行例2
次のコードは正しいプログラムであるが, Sunのベリファイアではエラーとなる.
Entry : iconst_n(1) jsr(S1, L1) L1 : istore_(1)
aload_(0) jsr(S1, L2) L2 : astore_(0)
goto(L3) L3 : return S1 : astore_(2)
ret(2)
サブルーチンS1は, EntryブロックおよびL1ブロック双方から呼び出されている.最初の呼び出しの場 合,スタックのトップには整数がプッシュされ、次の呼び出し時にはオブジェクト参照がプッシュされてい る。Sunの仕様では、サブルーチンは内部で使用しなローカル変数については多相性を実現しているが、ス タックについては考慮されていないためエラーとなる。
我々のシステムでは次のようなラベル環境を推論する.
Entry : {CL(sample4), -, -}{} => VOID
L1 : {CL(sample4), -, ret(13)}{INT} => VOID
L2 : {CL(sample4), INT, ret(13)}{CL(sample4)} => VOID L3 : {CL(sample4), INT, ret(13)}{} => VOID
S1 : (ret(13), {(’q<*), (’r<*), ret(13)}{’F} => (’m<*) // {(’q<*), (’r<*), (’s<*)}{ret(13), ’F} => (’m<*))
6.3.3 実行例3
以下に示すのは,整数を二つ引数にとり整数型を返すメソッドのコードである.
Entry : iconst_n(1) istore_(3) iload_(1) ifeq(L1) aload_(0) astore_(3) goto(L1) L1 : iload_(1)
iload_(2) iadd goto(L2) L2 : ireturn
このコードはSunのベリファイアでは検証可能であるにも関わらず,我々のシステムではエラーとなる.
ブロックL1へのジャンプは2つの場所から生じている. 最初の場所では, ローカル変数3には整数が代入 されており,次の場所では,ローカル変数3にはオブジェクト参照が代入されている. したがって,ブロック が単相的な我々のシステムでは型付けすることができない. Sunのベリファイアアルゴリズムでは排反する 型は使用不可能な型とみなし,このローカル変数にアクセスがあったときのみエラーとするため、このよう なコードも検証可能となる。