jvm backend in PyPy

PyPy (正確には RPython toolchain) の jvm backend への翻訳処理の設計を知りたくてソースコードを追い掛けてみた.

ややメモ書きっぽい感じだが, ほぼ自分用メモということで許してください.

(以下, パスは全て pypy のルートディレクトリを起点としている.)

入口

pypy/translator/jvm/genjvm.py の GenJvm クラス. たぶんだけど. pydoc はこんな感じ.

""" Master object which guides the JVM backend along.  To use,
create with appropriate parameters and then invoke
generate_source().  *You can not use one of these objects more than
once.* """

バイトコード吐いてるのが pypy/translator/jvm/generator.py の JVMGenerator. 既存の何かを使ってたわけではなく, 自作していたのか…… しかも raise NotImplementedError がそこかしこに見える……

これ作った人すごいなぁ. javac 相当のものを RPython で実装しているし. Antonio Cuni さんの仕事はどこまでなんだろうか?

GenJvm#generate_source

これを呼ぶと処理をしてくれるらしいのでここから読む.

メソッドの実装はこんな感じ.

def generate_source(self):
    """ Creates the sources, and returns a JvmGeneratedSource object
    for manipulating them """
    GenOO.generate_source(self)
    self.jvmsrc.set_jasmin_files(self.db.jasmin_files())
    return self.jvmsrc

Jasmin という jvm アセンブラを使っているようだ. Jasmin home page 処理は, 親クラスである GenOO の generate_source メソッドに処理を投げて, 出来上がった jasmin ファイルを jvmsrc 属性に格納して返しているようだ.

さてこのメインの処理を行っていそうなメソッドを覗いてみよう.

pypy/translator/oosupport/genoo.py を開く.

GenOO#generate_source

def generate_source(self):
    self.ilasm = self.create_assembler()
    self.fix_names()
    self.gen_entrypoint()
    self.gen_pendings()
    self.db.gen_constants(self.ilasm)
    self.ilasm.close()

う〜む, 綺麗だ. 文句の付けようが無い. だいたいどんな処理をやっているのか分かりやすくて良い.

GenJvm#create_assembler

まず処理の主体となるであろうアセンブラを用意しているところから見る. デフォルト実装は raise NotImplementedError となっていて, GenJvm クラスでは以下の実装になっていた.

def create_assembler(self):
    """ Creates and returns a Generator object according to the
    configuration.  Right now, however, there is only one kind of
    generator: JasminGenerator """
    return JasminGenerator(self.db, self.jvmsrc.javadir)

JasminGenerator クラスは pypy/translator/jvm/generator.py にある.

JasminGenerator のコンストラクタはいったん置いといて, 次の処理の中身を見てみる.

GenOO#fix_names

def fix_names(self):
    # it could happen that two distinct graph have the same name;
    # here we assign an unique name to each graph.
    names = set()
    for graph in self.translator.graphs:
        base_name = graph.name
        i = 0 ...

Licenses