XMLVM

最近、XMLVMを触ってる。
JavaバイトコードやCILを、XMLVMの名前通りXML形式の中間表現に変換し、それをXSLTなどでC/Objective-CJavaScriptを出力している。

直近の日記がそればっかだけど、飽きずにaobenchを例にすると、Javaのコードが

    void intersect(Intersection isect, Ray ray) {
        double d = -p.dot(n);
        double v = ray.dir.dot(n);

        if (Math.abs(v) < 1.0e-6)
            return; // the plane is parallel to the ray.

        double t = -(ray.org.dot(n) + d) / v;

        if ((t > 0) && (t < isect.t)) {
            isect.hit = true;
            isect.t = t;
            isect.n.set(n);
            isect.p.set(ray.org.x + t * ray.dir.x,
						ray.org.y + t * ray.dir.y,
						ray.org.z + t * ray.dir.z);
        }
    }

DalvikのXML表現で次のようになって

    <vm:method name="intersect" signature="(Laobench/Intersection;Laobench/Ray;)V">
      <vm:signature>
        <vm:parameter type="aobench.Intersection" />
        <vm:parameter type="aobench.Ray" />
        <vm:return type="void" />
      </vm:signature>
      <dex:code register-size="14">
        <dex:var name="this" register="11" type="aobench.Sphere" />
        <dex:var name="var-register-12" register="12" param-index="0" type="aobench.Intersection" />
        <dex:var name="var-register-13" register="13" param-index="1" type="aobench.Ray" />
        <dex:const-wide-16 type="double" value="0.0" vx="8" vx-type="double" />
        <dex:iget-object kind="field" class-type="aobench.Sphere" member-type="aobench.Vec" member-name="rs" vx="0" vx-type="aobench.Vec" vy="11" vy-type="aobench.Sphere" />
        <dex:iget-object kind="field" class-type="aobench.Ray" member-type="aobench.Vec" member-name="org" vx="1" vx-type="aobench.Vec" vy="13" vy-type="aobench.Ray" />
        <dex:iget-object kind="field" class-type="aobench.Sphere" member-type="aobench.Vec" member-name="center" vx="2" vx-type="aobench.Vec" vy="11" vy-type="aobench.Sphere" />
        <dex:invoke-virtual class-type="aobench.Vec" method="sub" register="0">
          <dex:parameters>
            <dex:parameter type="aobench.Vec" register="1" />
            <dex:parameter type="aobench.Vec" register="2" />
            <dex:return type="aobench.Vec" />
          </dex:parameters>
        </dex:invoke-virtual>
        <dex:iget-object kind="field" class-type="aobench.Sphere" member-type="aobench.Vec" member-name="rs" vx="0" vx-type="aobench.Vec" vy="11" vy-type="aobench.Sphere" />
        <dex:iget-object kind="field" class-type="aobench.Ray" member-type="aobench.Vec" member-name="dir" vx="1" vx-type="aobench.Vec" vy="13" vy-type="aobench.Ray" />
        <!-- 省略 -->
        <dex:iget-object kind="field" class-type="aobench.Intersection" member-type="aobench.Vec" member-name="n" vx="0" vx-type="aobench.Vec" vy="12" vy-type="aobench.Intersection" />
        <dex:invoke-virtual class-type="aobench.Vec" method="normalize" register="0">
          <dex:parameters>
            <dex:return type="void" />
          </dex:parameters>
        </dex:invoke-virtual>
        <dex:label id="112" />
        <dex:return-void />
      </dex:code>
    </vm:method>

これをこんなXSLTで変換して

<xsl:template match="dex:add-int|dex:add-int-2addr">
  <xsl:text>    _r</xsl:text>
  <xsl:value-of select="@vx"/>
  <xsl:text>.i = _r</xsl:text>
  <xsl:value-of select="@vy"/>
  <xsl:text>.i + _r</xsl:text>
  <xsl:value-of select="@vz"/>
  <xsl:text>.i;
</xsl:text>
</xsl:template>

最終的にこうなる

void aobench_Sphere_intersect___aobench_Intersection_aobench_Ray(JAVA_OBJECT me, JAVA_OBJECT n1, JAVA_OBJECT n2)
{
    //XMLVM_BEGIN_WRAPPER[aobench_Sphere_intersect___aobench_Intersection_aobench_Ray]
    XMLVM_ENTER_METHOD("aobench.Sphere", "intersect", "?")
    XMLVMElem _r0;
    XMLVMElem _r1;
    XMLVMElem _r2;
    XMLVMElem _r3;
    XMLVMElem _r4;
    XMLVMElem _r5;
    XMLVMElem _r6;
    XMLVMElem _r7;
    XMLVMElem _r8;
    XMLVMElem _r9;
    XMLVMElem _r10;
    XMLVMElem _r11;
    XMLVMElem _r12;
    XMLVMElem _r13;
    _r11.o = me;
    _r12.o = n1;
    _r13.o = n2;
    _r8.d = 0.0;
    XMLVM_CHECK_NPE(11)
    _r0.o = ((aobench_Sphere*) _r11.o)->fields.aobench_Sphere.rs_;
    XMLVM_CHECK_NPE(13)
    _r1.o = ((aobench_Ray*) _r13.o)->fields.aobench_Ray.org_;
    XMLVM_CHECK_NPE(11)
    _r2.o = ((aobench_Sphere*) _r11.o)->fields.aobench_Sphere.center_;
    XMLVM_CHECK_NPE(0)
    aobench_Vec_sub___aobench_Vec_aobench_Vec(_r0.o, _r1.o, _r2.o);
    XMLVM_CHECK_NPE(11)
    _r0.o = ((aobench_Sphere*) _r11.o)->fields.aobench_Sphere.rs_;
    XMLVM_CHECK_NPE(13)
    _r1.o = ((aobench_Ray*) _r13.o)->fields.aobench_Ray.dir_;
    XMLVM_CHECK_NPE(0)
    _r0.d = aobench_Vec_dot___aobench_Vec(_r0.o, _r1.o);
    XMLVM_CHECK_NPE(11)
    _r2.o = ((aobench_Sphere*) _r11.o)->fields.aobench_Sphere.rs_;
    XMLVM_CHECK_NPE(11)
    _r3.o = ((aobench_Sphere*) _r11.o)->fields.aobench_Sphere.rs_;
    XMLVM_CHECK_NPE(2)
    _r2.d = aobench_Vec_dot___aobench_Vec(_r2.o, _r3.o);
    XMLVM_CHECK_NPE(11)
    _r4.d = ((aobench_Sphere*) _r11.o)->fields.aobench_Sphere.radius_;
    XMLVM_CHECK_NPE(11)
    _r6.d = ((aobench_Sphere*) _r11.o)->fields.aobench_Sphere.radius_;
    _r4.d = _r4.d * _r6.d;
    _r2.d = _r2.d - _r4.d;
    _r4.d = _r0.d * _r0.d;
    _r2.d = _r4.d - _r2.d;
    _r4.i = _r2.d > _r8.d ? 1 : (_r2.d == _r8.d ? 0 : -1);
    if (_r4.i <= 0) goto label112;
    _r0.d = -_r0.d;
    _r2.d = java_lang_Math_sqrt___double(_r2.d);
    _r5.d = _r0.d - _r2.d;
    _r0.i = _r5.d > _r8.d ? 1 : (_r5.d == _r8.d ? 0 : -1);
    // 省略
    _r0.o = ((aobench_Intersection*) _r12.o)->fields.aobench_Intersection.n_;
    XMLVM_CHECK_NPE(0)
    aobench_Vec_normalize__(_r0.o);
    label112:;
    XMLVM_EXIT_METHOD()
    return;
    //XMLVM_END_WRAPPER
}

実行してみると

$ time java -cp build/classes/ aobench.AO

real    0m2.368s
user    0m0.015s
sys     0m0.015s

$ time ./build/aobench.exe

real    1m7.242s
user    1m5.660s
sys     0m0.233s

$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 42
model name      : Intel(R) Core(TM) i7-2600K CPU @ 3.40GHz

実行速度はそれなり。

会社のJava資産をiOSに持っていけないかと実験したりパッチ投げたりしてるけど、全く枯れてなくて困るので皆さんもっと人柱になりましょう。