Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PyPy における静的解析

PyPy における静的解析

cocoatomo
PRO

February 15, 2018
Tweet

More Decks by cocoatomo

Other Decks in Programming

Transcript

  1. PyPyにおける
    静的解析
    -- 動的言語に静的型を --
    by cocoatomo
    第8回ありえるえりあ勉強会
    2012/01/20
    12೥1݄20೔༵ۚ೔

    View Slide

  2. アジェンダ
    •自己紹介
    •研究テーマ「静的解析」
    •PyPy ではどう使われているか
    •静的解析とは
    •注釈 (annotation) とは
    •変数に注釈を付ける
    12೥1݄20೔༵ۚ೔

    View Slide

  3. 発表内容
    •この発表で得られるもの
    •RPython Toolchain の概観
    •translatorshell.py での遊び方
    •背景にある理論
    •型の見付け方
    •主に静的解析まわり
    12೥1݄20೔༵ۚ೔

    View Slide

  4. アジェンダ
    •→自己紹介
    •研究テーマ「静的解析」
    •PyPy ではどう使われているか
    •静的解析とは
    •注釈 (annotation) とは
    •変数に注釈を付ける
    12೥1݄20೔༵ۚ೔

    View Slide

  5. お前, 誰よ?
    •ID: cocoatomo
    •blog: Elliptium
    •言語
    •仕事: Java, 趣味: Python
    •活動
    •pypy-ja
    •Python 公式ドキュメント翻訳
    12೥1݄20೔༵ۚ೔

    View Slide

  6. お前, 誰よ?
    •理論好き
    •所属その1: 品川にある浅草っぽい会社
    •所属その2: 社会人博士
    •プログラムの検証まわりをやりたい
    なー, と今年度入学
    •今日はこっちの活動に関係する話で

    12೥1݄20೔༵ۚ೔

    View Slide

  7. 好きなエディタ
    アリエルネットワークでは入社時に好きな
    エディタを言わされると聞いて...
    Emacs
    2006年くらいから CarbonEmacs & Meadow,
    CocoaEmacs & Emacs (on Windows) と変遷
    12೥1݄20೔༵ۚ೔

    View Slide

  8. 良く使うMajor Mode
    •ReST mode (rst.el)
    •昔は org-mode でメモ書き
    •今は Sphinx の影響でもっぱら reST
    •入力はもちろん DDSKK
    •AquaSKK も使用
    •フォント
    •Inconsolata + Takao
    •このスライドは Osaka ですが
    12೥1݄20೔༵ۚ೔

    View Slide

  9. アジェンダ
    •自己紹介
    •→研究テーマ「静的解析」
    •PyPy ではどう使われているか
    •静的解析とは
    •注釈 (annotation) とは
    •変数に注釈を付ける
    12೥1݄20೔༵ۚ೔

    View Slide

  10. 研究テーマ
    「プログラムの品質を楽に上げたい」
    プログラム実行前の検証の自動化
    その手段として,
    ・実行しなくても分かる情報
    ・部分的に実行して分かる情報
    が知りたい
    e.g. Eclipse, FindBugs
    cf. Formal Method (形式手法)
    12೥1݄20೔༵ۚ೔

    View Slide

  11. 検証手法
    •検証と言うと普通は…⋯…⋯

    •テスト
    •具体値で実行
    •最も馴染み深い
    •偽陽性 (false positive) が無い(^-^)
    •網羅性が悪い(´・ω・`)
    12೥1݄20೔༵ۚ೔

    View Slide

  12. モデル検査
    •実行パスを全検査
    •目的: 反例 (エラーを起こす入力値)
    を見付ける
    •e.g. Alloy, Java PathFinder (JPF)
    •網羅性は高い (^-^)
    •実行パターン数が爆発する
    (´・ω・`)
    12೥1݄20೔༵ۚ೔

    View Slide

  13. 静的解析
    •記号実行
    •変数を本当に「変数」のまま実行
    •最弱事前条件 (Weakest Precondition, WP)
    •ある地点に到達する (入力値の) 条件を
    求める
    •網羅性が高い (^-^)
    •偽陽性 (false positive) の可能性
    (´・ω・`)
    12೥1݄20೔༵ۚ೔

    View Slide

  14. 参考文献
    以下の論文の Introduction に簡単にまと
    めてあります.
    より詳しい文献への refer もあります.
    Combining unit-level symbolic
    execution and system-level concrete
    execution for testing nasa software
    (ISSTA ’08)
    12೥1݄20೔༵ۚ೔

    View Slide

  15. 発表の注意事項
    •質問は随時受け付けます
    •斧を投げる場合は, お手柔らかにお願
    いします
    12೥1݄20೔༵ۚ೔

    View Slide

  16. アジェンダ
    •自己紹介
    •研究テーマ「静的解析」
    •→PyPy ではどう使われているか
    •静的解析とは
    •注釈 (annotation) とは
    •変数に注釈を付ける
    12೥1݄20೔༵ۚ೔

    View Slide

  17. PyPy では...
    • 静的解析の手法が使われている
    • 変数の型の推論
    • 静的単一情報 (Static Single Information, SSI)
    形式への変換
    • 変数は必ずローカル変数で代入は1回のみ
    • Decision Procedure
    • 型情報の伝播に類似が見られる
    • cf. Nelson-Oppen
    • → AOT コンパイルや JIT コンパイルの基礎となる!
    12೥1݄20೔༵ۚ೔

    View Slide

  18. RPython Toolchain
    の概観
    +---------+---------+
    | CPython | PyPy |
    +=========+=========+
    | Python | Python | 静的解析!!
    +-------+ +---------+ |
    | C API | | RPython |--, v
    +-------+-+---------+ | translate
    | bare C | backend |+---------+---------+
    backend = C, C with JIT, JVM, .CLI
    12೥1݄20೔༵ۚ೔

    View Slide

  19. Java PathFinder と
    の類似
    PyPy
    制限された Python で Python を実装
    Java PathFinder
    Java で JVM を実装
    instruction も Java オブジェクト!
    意味論が自由に操作できる!!
    12೥1݄20೔༵ۚ೔

    View Slide

  20. 翻訳の概観
    •Control Flow Graph (フローチャート) 形式に
    変換
    •変数に注釈 (annotation, 型) を付加
    •backend の型に変換 (RPython Typing,
    RTyping)
    •例外処理の変換
    •GC 処理の変換
    •C ソースコードの生成 (backend が C の場合)
    12೥1݄20೔༵ۚ೔

    View Slide

  21. Control Flow Graph
    12೥1݄20೔༵ۚ೔

    View Slide

  22. Control Flow Graph
    •フローチャート
    •ブロックを矢印でつなぐ
    •関数 → FunctionGraph インスタンス
    •文 → Block インスタンス (複数かも)
    •pypy/objspace/flow/model.py
    12೥1݄20೔༵ۚ೔

    View Slide

  23. Annotation (注釈)
    •型のこと (≠ Python の型)
    • = 値の集合
    •静的型に変換するために必要!
    •この情報は JIT Compile でも使われる
    よ!
    •動的言語とは言え, 開発者の頭の中に
    は型はある (はず)
    12೥1݄20೔༵ۚ೔

    View Slide

  24. 翻訳で遊ぼう!!
    何はともあれ遊びましょう! (要 PyGame)
    $ hg clone ssh://[email protected]/
    pypyja/pypy pypyja
    $ cd pypyja
    $ python pypy/bin/translatorshell.py
    # 色々説明がずらずらと...
    >>> def succ(x):
    ... return x + 1
    >>> t = Translation(succ)
    >>> t.view()
    12೥1݄20೔༵ۚ೔

    View Slide

  25. Control Flow Graph!
    12೥1݄20೔༵ۚ೔

    View Slide

  26. 型付けよう!
    >>> t.annotate([int])
    >>> t.view()
    12೥1݄20೔༵ۚ೔

    View Slide

  27. 型付いた!
    12೥1݄20೔༵ۚ೔

    View Slide

  28. 変数をクリック!
    •x_0 は元は x だった
    •t.annotate([int]) によって x_0 は
    int と判明
    •SomeInteger という注釈が整数を表す
    •v0 は x + 1 の計算結果
    •これもやっぱり整数 (SomeInteger)
    •v0 = x + 1 と return v1 に分離
    12೥1݄20೔༵ۚ೔

    View Slide

  29. もうちょっと遊ぶ
    >>> def ssi(x, y):
    ... x = x + y
    ... return x
    ...
    >>> t = Translation(ssi)
    [flowgraph] (__main__:1)ssi
    >>> t.annotate([int, int])
    >>> t.view()
    12೥1݄20೔༵ۚ೔

    View Slide

  30. さてどうなるか?
    変数 x に注目…⋯…⋯
    12೥1݄20೔༵ۚ೔

    View Slide

  31. こんなグラフに
    12೥1݄20೔༵ۚ೔

    View Slide

  32. 変換後は
    •代入する前の x は x_2 になった.
    •代入された後の x は v18 になった.
    •return がある Block に v18 を渡すと
    v19 に名前が変わっている.
    •値が変化するとき, 関数をまたぐとき
    は必ず変数名を変える (これが SSI)
    12೥1݄20೔༵ۚ೔

    View Slide

  33. もうちょっと遊ぶ
    >>> def generalize(x):
    ... if x:
    ... a = 3
    ... else:
    ... a = False
    ... return a
    ...
    >>> t = Translation(generalize)
    >>> t.annotate([bool])
    >>> t.view()
    12೥1݄20೔༵ۚ೔

    View Slide

  34. こんなグラフに
    12೥1݄20೔༵ۚ೔

    View Slide

  35. 変換後は
    •if のところで分岐が作られる
    •v1 には 3 も False も来る可能性がある
    •v1 の注釈は SomeInteger
    •実は SomeBool は SomeInteger
    •True = 1, False = 0 となっている
    •上手いこと型の計算をやってくれている!!
    12೥1݄20೔༵ۚ೔

    View Slide

  36. 是非遊ぼう
    難しくないので, 是非遊んでみよう!
    12೥1݄20೔༵ۚ೔

    View Slide

  37. 参考記事
    •Let's translate.py! - PyPy Advent
    Calendar 2011
    •http://blog.elliptium.net/
    2011/12/Let-s-translate-py---
    PyPy-Advent-Calendar-2011
    •Mac で PyGame のインストール
    •http://blog.elliptium.net/
    2012/01/Mac-PyGame
    12೥1݄20೔༵ۚ೔

    View Slide

  38. アジェンダ
    •自己紹介
    •研究テーマ「静的解析」
    •PyPy ではどう使われているか
    •→静的解析とは
    •注釈 (annotation) とは
    •変数に注釈を付ける
    12೥1݄20೔༵ۚ೔

    View Slide

  39. さて
    ここから理論の話になるわけですが
    12೥1݄20೔༵ۚ೔

    View Slide

  40. さてさて
    正直, 全速力で解説しないと
    終わらないわけで
    12೥1݄20೔༵ۚ೔

    View Slide

  41. さてさてさて
    頑張って追っかけてきてください!
    12೥1݄20೔༵ۚ೔

    View Slide

  42. ググる単語
    •型の話
    •導出木
    •Types and Programming Language
    •SSI の話
    •SSA, SSI
    •Decision Procedure の話
    •Nelson-Oppen
    12೥1݄20೔༵ۚ೔

    View Slide

  43. 発表の下敷き
    • PyPy ドキュメント
    • 原文: http://doc.pypy.org/en/latest/
    • 訳文: http://readthedocs.org/docs/pypyja/en/
    latest/
    • translation.html, rtyper.html のあたり
    • まだ翻訳が足りない
    → I want you for pypy-ja!
    • EU report about translation
    • https://bitbucket.org/pypy/extradoc/raw/tip/eu-
    report/D05.1_Publish_on_translating_a_very-high-
    level_description.pdf
    12೥1݄20೔༵ۚ೔

    View Slide

  44. 動的言語での
    静的解析
    ↑「お前は何を言っているんだ!?」↑
    (画像略)
    12೥1݄20೔༵ۚ೔

    View Slide

  45. 静的解析の目標
    •プログラムが正しく動作することの検証
    •もしくはその条件を求める
    •バグの発生条件を求める
    •プログラム修正の妥当性の検証
    •などなど...
    •↑以上を実行せずに解析する
    12೥1݄20೔༵ۚ೔

    View Slide

  46. なんで静的解析が
    必要なの?
    RPython Toolchain の目的
    「変数に型を付け
    静的型付け言語のプログラムに変換する.
    そしてその情報から高速化を行う.」

    静的解析が必要
    12೥1݄20೔༵ۚ೔

    View Slide

  47. 静的解析の敵
    •一般的な静的解析を阻む要素
    •条件分岐 (実行パターンが増える)
    •ループ (事後条件求めるのが難しい)
    •多態 (継承, 動的型付けなど)
    •eval (値の中身で処理が変わる)
    •などなど...
    12೥1݄20೔༵ۚ೔

    View Slide

  48. どう解析して
    いるのか?
    •RPython でさえ動的すぎる
    •変数の型宣言無い
    •変数に複数回代入できる
    •クラスの継承がある
    •→ しょうがないので前から順に解析して
    いく(´・ω・`)
    •Hindley-Milner 型推論みたいなかっこ
    いいことはできない(´・ω・`)
    12೥1݄20೔༵ۚ೔

    View Slide

  49. アジェンダ
    •自己紹介
    •研究テーマ「静的解析」
    •PyPy ではどう使われているか
    •静的解析とは
    •→注釈 (annotation) とは
    •変数に注釈を付ける
    12೥1݄20೔༵ۚ೔

    View Slide

  50. 注釈とは
    注釈 = 型 = 値の集合
    Python の型とは関係無いです.
    型理論そのものについては
    + Types and Programming Languages
    + プログラミング言語の基礎概念 (五十嵐
    淳)
    あたりを読むと良いかも
    12೥1݄20೔༵ۚ೔

    View Slide

  51. Annotator (注釈器)
    •RPython スクリプトを前から順に解釈
    •扱う注釈
    •str, char, float などの組み込み型
    •オブジェクト
    •collection (list, dict,...)
    •定数
    •Nullable な注釈もある
    12೥1݄20೔༵ۚ೔

    View Slide

  52. 注釈の階層構造
    注釈 = 型 = 値の集合
    なので集合の包含関係による半順序 (≦)
    が決まる. その頂上と底辺には Top と
    Bottom が置かれる. (=「束構造をなす」)
    Bottom ≦ Char ≦ Str ≦ NullableStr
    ≦ Top
    12೥1݄20೔༵ۚ೔

    View Slide

  53. こんな感じ
    12೥1݄20೔༵ۚ೔

    View Slide

  54. オブジェクトも同様
    class A(B):
    pass
    という継承関係があったとき
    Bottom ≦ Instance(A) ≦ Instance(B)
    ≦ NullableInstance(B) ≦ Top
    Bottom ≦ None ≦ NullableInstance(A)
    ≦ NullableInstance(B) ≦ Top
    となる. (要は is-a の関係)
    12೥1݄20೔༵ۚ೔

    View Slide

  55. 補足
    •Top はどんな値でも入る型
    •Object (Java), Any (Scala)
    •primitive のことは横に置く
    •Bottom はどんな値も入らない型
    •Nothing (Scala)
    •≦ は もいるかも
    12೥1݄20೔༵ۚ೔

    View Slide

  56. List だと
    •List の要素は全て同質 (homogeneous,
    要素の型が同一) として扱う
    •List は互いに包含関係は無い
    •collection 間の is-a の関係は難し
    い.
    •e.g. Java の配列 (における失敗)
    12೥1݄20೔༵ۚ೔

    View Slide

  57. アジェンダ
    •自己紹介
    •研究テーマ「静的解析」
    •PyPy ではどう使われているか
    •静的解析とは
    •注釈 (annotation) とは
    •→変数に注釈を付ける
    12೥1݄20೔༵ۚ೔

    View Slide

  58. 注釈付けのルール
    •ルールとは, ある変数の型情報から別
    の変数の型情報を導き出す形式的規則
    •型を知る手掛かり
    •型導出木に近い雰囲気
    •1つの文からいくつかルールが出てくる
    •次で見る通り1つ1つは難しくない
    •このルールに従って注釈を決めていく
    12೥1݄20೔༵ۚ೔

    View Slide

  59. ルールで使う定義
    •A: 前に出てきた型階層 (束, lattice)
    •V: 変数の集合
    •E: V 上の同値関係
    •ある変数どうしの型が同じ, という
    情報
    •b: V から A への関数
    •ある変数からその注釈への対応付け
    12೥1݄20೔༵ۚ೔

    View Slide

  60. イメージ
    V = {a, b, c}
    E = {(a, c)}
    b = {a: int, b: str, c: int}
    のような感じ. (Python 風に書いている
    が, 実装とは無関係です)
    注釈処理が進むに従って, V, E, b のサイ
    ズは大きくなっていく.
    12೥1݄20೔༵ۚ೔

    View Slide

  61. 定義 (続き)
    •(b, E): 状態
    •要は変数の情報
    •状態 (b’, E’) は状態 (b, E) より
    一般的 (general):
    b(v) ≦ b’(v) かつ E ⊂ E’
    •型情報は緩く, 同値情報は多く
    •処理が進むと状態はより一般的に
    なっていく
    12೥1݄20೔༵ۚ೔

    View Slide

  62. 極端な状態
    •最も一般的な状態 (= 有用な情報無し)
    •b_max(v) = Top,
    E_max = {(v1, v2) | v1, v2 ∈ V}
    •全部の変数が object 型
    •最も一般的でない状態 (= 全ての変数が未初期
    化)
    •b_min(v) = Bottom,
    E_min = {(v, v) | v ∈ V}
    •注釈付けの開始前の状態
    12೥1݄20೔༵ۚ೔

    View Slide

  63. 注釈器の目標
    •最も一般的でない状態を求めること
    •基本的には処理の流れに沿って, 初
    期状態 (b_min, E_min) を拡大させ
    ていく
    •ループ ← 静的解析の敵!
    •一般化されなくなるまで注釈を計算
    しつづける
    12೥1݄20೔༵ۚ೔

    View Slide

  64. 例: __add__
    •中置演算子“+”についてのルール
    •オーバーロードされているので複数
    ルールがある
    •z := add(x, y) という状況を考える
    •(z = x + y でいいんだけど文献に合
    わせた)
    12೥1݄20೔༵ۚ೔

    View Slide

  65. 例: z = x + y その1
    z := add(x, y),
    b(x) = Int, Bool ≦ b(y) ≦ Int
    ---------------------------------
    b.update({z: Int})
    12೥1݄20೔༵ۚ೔

    View Slide

  66. 例: z = x + y その2
    z := add(x, y),
    Bool ≦ b(x) ≦ Int, b(y) = Int
    ---------------------------------
    b.update({z: Int})
    12೥1݄20೔༵ۚ೔

    View Slide

  67. 例: z = x + y その3
    z := add(x, y),
    Bool ≦ b(x) ≦ NonNegInt,
    Bool ≦ b(y) ≦ NonNegInt
    ---------------------------------
    b.update({z: NonNegInt})
    12೥1݄20೔༵ۚ೔

    View Slide

  68. 例: z = x + y その4
    z := add(x, y),
    Char ≦ b(x) ≦ NullableStr,
    Char ≦ b(y) ≦ NullableStr
    ---------------------------------
    b.update({z: Str})
    注. x または y が None である可能性は
    テストの方で潰しておく必要がある
    12೥1݄20೔༵ۚ೔

    View Slide

  69. 案外簡単?
    ここまでのパターンでの注釈付けは素直
    list やユーザが作成したクラスのオブ
    ジェクトのような他のオブジェクトを格納
    できる何かが出てくると難しくなる.
    (= aliasing と呼ばれる)
    C のポインタでも同様の静的解析上の困難
    が生まれる
    12೥1݄20೔༵ۚ೔

    View Slide

  70. List の注釈
    •将来どこで要素が格納されるか分から
    ない
    •List インスタンスを参照しているとこ
    ろを全て把握していないといけない
    •List の注釈は難しい! 困った!!
    •→ ではどうやって対処するか?
    12೥1݄20೔༵ۚ೔

    View Slide

  71. merge 手続きと
    meta-rule
    •merge 手続き
    •情報を追加する手続き
    •meta-rule
    •情報を伝播させるルール
    •Nelson-Oppen: Simplification by
    cooperating decision procedures
    12೥1݄20೔༵ۚ೔

    View Slide

  72. merge 手続き
    (再び translatorshell.py を起動)
    >>> def bool_list():
    ... l = [True]
    ... return l # l <= List(Bool)
    ...
    >>> t = Translation(bool_list)
    [flowgraph] (__main__:1)bool_list
    >>> t.annotate()
    >>> t.view()
    12೥1݄20೔༵ۚ೔

    View Slide

  73. merge 手続き
    >>> def merge():
    ... l = [True]
    ... l.append(3)
    ... return l # l <= List(Int)
    ...
    >>> t = Translation(merge)
    [flowgraph] (__main__:1)merge
    >>> t.annotate()
    >>> t.view()
    12೥1݄20೔༵ۚ೔

    View Slide

  74. ごめんなさい
    上の2つの例は f = t.compile_c() すると
    エラーで落ちちゃいます. 原因は分かって
    いませんm(_ _)m
    解読してくれる方は pypy-ja へ

    pypy.rpython.error.TyperError: don't
    know how to convert from
    > to
    12೥1݄20೔༵ۚ೔

    View Slide

  75. merge の仕事
    •代入が発生したときに, 変数の注釈を
    (必要なら) 一般化する
    •注釈 a を変数 x に付けるコード
    •b.update({x: a ∨ b(x)})
    •E はそのまま
    •このパターンは簡単
    •ただし, List に関しては特別扱い
    12೥1݄20೔༵ۚ೔

    View Slide

  76. List 注釈を merge
    注釈 List(v) を List(w) という注釈が付
    いている変数に merge
    b はそのまま
    E.append((v, w))
    List の後ろに要素を表す変数 v, w があ
    るのがポイント!!
    12೥1݄20೔༵ۚ೔

    View Slide

  77. list#__getitem__
    List の要素の変数はこんなふうに使う
    z := x[y], b(x) = List(v)
    ---------------------------
    E.append((z’, v))
    b.update({z: b(z’)})
    x: List(v) の方の要素型の変更が E にあ
    る (z’, v) を通して z の注釈に波及す
    る!!
    12೥1݄20೔༵ۚ೔

    View Slide

  78. meta-rule
    •(v, w) ∈ E が判明したら以下の2つの
    作業をする
    •v の注釈を w に merge
    •w の注釈を v に merge
    •merge したことにより, 再度 E に追加
    があった場合は止まるまで繰り返す
    12೥1݄20೔༵ۚ೔

    View Slide

  79. 資料の残り部分
    •EU report about translation
    •6.5--6.8 他の構文に対応するルール
    •6.9 一般化, 停止性, 健全性に関す
    る証明
    •6.10 動的な取り扱いについて諸々
    •7 RTyping について
    12೥1݄20೔༵ۚ೔

    View Slide

  80. 大丈夫
    ここまでついて来れた人なら読めます!
    12೥1݄20೔༵ۚ೔

    View Slide

  81. まとめ
    •RPython Toolchain は動的型付き言語を
    解析, 変換し, 静的型付け言語のプログ
    ラムを生成する
    •RPython Toolchain には翻訳という処理
    がある
    •翻訳では変換の準備として RPython で
    書いた処理系に型を付ける処理がある
    •その際, 静的解析の手法が使われている
    12೥1݄20೔༵ۚ೔

    View Slide

  82. おしまい
    ご静聴ありがとうございました
    12೥1݄20೔༵ۚ೔

    View Slide