ちなみに、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);
}
}
0 件のコメント:
コメントを投稿