2009年10月24日土曜日

Java で Continuation 01

なんとか目処が付いた。GAE/Jでどうやって動くかが楽しみ。簡単なサンプルで正常系1パス通った程度の完成度。あとは、いいデバッガ探してパターンつぶすだね。


ちなみに、Java の勉強も兼ねていたが、「バイトコードが読める」ようになるというのは。。。(^^ゞ



処理について
・Java では、肝になる goto をコンパイラが禁止しているため、バイトコードレベルで処理を埋め込む必要がある。
・バイトコードを弄くるためのツールは、AspectJ、Javassist、BCEL、ASM などが候補に。最終的に ASM に落ち着く。
・大きな流れは、
-Annotation や Serializable インターフェースを目印に、継続に必要な、現在のコンテキストの変数をかき集める。
-新たなインナークラスに保持させ、まとめてシリアライズ。
-継続時は、上記の逆を行う。callcc で読み込み先に飛ぶための switch & goto 文を展開。


処理埋め込み前

package com.blogspot.urasandesu;

import com.blogspot.urasandesu.asm.annotation.Target;

public class ContinuationTest {

private Continuation c;
private boolean first;

@Target
public void hoge() {

if (c != null) {
c.callcc();
}

int x = 0;
int y = 0;

if (Math.random() < 0.5) {
x = 50;
y = 50;
}
else {
x = 100;
y = 100;
}

c = new Continuation();
if (!first) {
first = true;
c.save();
}

System.out.println("x: " + x + ", y: " + y);
}

}



処理埋め込み後

package com.blogspot.urasandesu;

import java.io.Serializable;

import org.objectweb.asm.Opcodes;

import com.blogspot.urasandesu.asm.annotation.Target;
import com.blogspot.urasandesu.asm.util.MethodKey;

public class ContinuationTest {

private Continuation c;
private boolean first;

public static final class _306F51 implements Serializable {
public boolean first;
public int x;
public int y;
}

@Target
public void hoge() {

_306F51 _306F51 = new _306F51();

if (c != null) {
c.callcc();
switch (c.getIndex()) {
case 0:
goto LABEL0; // 実際はコンパイルエラー。イメージ。
}
}

int x = 0;
int y = 0;

if (Math.random() < 0.5) {
x = 50;
y = 50;
}
else {
x = 100;
y = 100;
}

c = new Continuation();
_306F51.first = first;
_306F51.x = x;
_306F51.y = y;
if (false) {
LABEL0: {
_306F51 =
(_306F51)c.load(
new ContinuationKey(
"com/blogspot/urasandesu/ContinuationTest",
new MethodKey(
Opcodes.ACC_PUBLIC,
"hoge",
"()V",
null,
null
)
)
);
first = _306F51.first;
x = _306F51.x;
y = _306F51.y;
}
}
if (!first) {
first = true;
c.save(
new ContinuationKey(
"com/blogspot/urasandesu/ContinuationTest",
new MethodKey(
Opcodes.ACC_PUBLIC,
"hoge",
"()V",
null,
null
)
),
_306F51
);
}

System.out.println("x: " + x + ", y: " + y);
}

}