uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

どう書く?org課題「inline/embeded bytecode assembly」とインラインJavaについて

どう書く.org課題の「inline/embeded bytecode assembly」をやってみました。

手っ取り早くjavassistで。

@Grab('javassist:javassist:3.8.0.GA')
import javassist.*;

ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("DuffsDevice");
CtMethod m = CtNewMethod.make("""
    public static void copy(byte[] to, byte[] from) {
        int count = from.length;
        int i = 0;
        switch (count % 8) {
            case 7: to[i] = from[i++];
            case 6: to[i] = from[i++];
            case 5: to[i] = from[i++];
            case 4: to[i] = from[i++];
            case 3: to[i] = from[i++];
            case 2: to[i] = from[i++];
            case 1: to[i] = from[i++];
            case 0:;
        }
        while (i < count) {  
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
            to[i] = from[i++];
        }
    }
}""", cc);

cc.addMethod(m);

def dev = cc.toClass().newInstance()
def to = new byte[3]
dev.copy(to, [1,2,3] as byte[])

to.each { println it }

対象コードはJava版のを使わせていただきました。

動的型付けではない、静的型付けの高速なJavaのセマンティクスで動くコードをGroovyコードに追加できるということで、ある種の高速化テクニックになるかもしれません。もちろん、そんなことするぐらいならあらかじめjavacしとけという話にはなるんですが、何らかの理由でjavacを使えないという状況、例えばGAE/J上のような環境で、オンザフライJavaコンパイルして動くようなことができるかもね。javaassistがGAE/J上で動作するかは不明ですが。

あと、ASTBuilder.fromCode()で用いられている「クロージャを文字列に変換する」技術を使えば、GroovyのクロージャをJavaのブロックと解釈させるようなこともできるかもしれませんね。


てなことを、実は昔も妄想で書いてます

ちなみに、この種の感想(部分的に静的タイピングでいいから高速化したい!)は誰もが思うことのようで、過去に@Typedアノテーションみたいなかたちで提案されたりしています。しかし、Groovyに取り入れられていないのは、意図的ではあるようですね(少なくとも気づいていないという訳ではない)。