Truffle framework
Graal コンパイラ上でpolyglotを実現するためのOracle謹製フレームワーク
実装例:TruffleRuby, GraalPy, Sulong(LLVM bitcode interp), etc
AST Nodeの評価関数をJava + Truffle DSLを使用して定義しておくと、自動的に最適化される
https://gyazo.com/ec56a9ddad1d6ad15ef316e232f41754
code:Java
@NodeInfo(shortName = "+")
@OperationProxy.Proxyable(allowUncached = true)
public abstract class SLAddNode extends SLBinaryNode {
// long 用の特殊化コード
// 両辺とも long のときに選択される
// オーバーフローした時には例外が発生し、doSLBigInteger に置換される(rewriteOnアトリビュート)
@Specialization(rewriteOn = ArithmeticException.class)
public static long doLong(long left, long right) {
return Math.addExact(left, right);
}
// BigInteger用のコード
// 両辺とも SLBigInteger のときに選択される
// オペランドが long の場合は自動的に SLBigInteger へキャストされる
@Specialization(replaces = "doLong")
@TruffleBoundary
public static SLBigInteger doSLBigInteger(SLBigInteger left, SLBigInteger right) {
return new SLBigInteger(left.getValue().add(right.getValue()));
}
// Slow (Generic) path
// 両辺とも BigInteger へ変換可能なオブジェクトのときに選択される
@Specialization(replaces = "doSLBigInteger", guards = {"leftLibrary.fitsInBigInteger(left)", "rightLibrary.fitsInBigInteger(right)"}, limit = "3")
@TruffleBoundary
public static SLBigInteger doInteropBigInteger(Object left, Object right,
@CachedLibrary("left") InteropLibrary leftLibrary,
@CachedLibrary("right") InteropLibrary rightLibrary) {
try {
return new SLBigInteger(leftLibrary.asBigInteger(left).add(rightLibrary.asBigInteger(right)));
} catch (UnsupportedMessageException e) {
throw shouldNotReachHere(e);
}
}
// 文字列用の特殊化コード
// 両辺のどちらかが TruffleString のときに実行される(guardsアトリビュートで指定した関数で判定)
// TruffleStringでないオペランドは自動的に変換される
@Specialization(guards = "isString(left, right)")
@TruffleBoundary
public static TruffleString doString(Object left, Object right,
@Bind Node node,
@Cached SLToTruffleStringNode toTruffleStringNodeLeft,
@Cached SLToTruffleStringNode toTruffleStringNodeRight,
@Cached TruffleString.ConcatNode concatNode) {
return concatNode.execute(toTruffleStringNodeLeft.execute(node, left), toTruffleStringNodeRight.execute(node, right), SLLanguage.STRING_ENCODING, true);
}
public static boolean isString(Object a, Object b) {
return a instanceof TruffleString || b instanceof TruffleString;
}
@Fallback
public static Object typeError(Object left, Object right, @Bind Node node) {
throw SLException.typeError(node, "+", left, right);
}
}