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

PyPy における静的解析

cocoatomo
February 15, 2018

PyPy における静的解析

cocoatomo

February 15, 2018
Tweet

More Decks by cocoatomo

Other Decks in Programming

Transcript

  1. お前, 誰よ? •ID: cocoatomo •blog: Elliptium •言語 •仕事: Java, 趣味:

    Python •活動 •pypy-ja •Python 公式ドキュメント翻訳 12೥1݄20೔༵ۚ೔
  2. 良く使うMajor Mode •ReST mode (rst.el) •昔は org-mode でメモ書き •今は Sphinx

    の影響でもっぱら reST •入力はもちろん DDSKK •AquaSKK も使用 •フォント •Inconsolata + Takao •このスライドは Osaka ですが 12೥1݄20೔༵ۚ೔
  3. モデル検査 •実行パスを全検査 •目的: 反例 (エラーを起こす入力値) を見付ける •e.g. Alloy, Java PathFinder

    (JPF) •網羅性は高い (^-^) •実行パターン数が爆発する (´・ω・`) 12೥1݄20೔༵ۚ೔
  4. 静的解析 •記号実行 •変数を本当に「変数」のまま実行 •最弱事前条件 (Weakest Precondition, WP) •ある地点に到達する (入力値の) 条件を

    求める •網羅性が高い (^-^) •偽陽性 (false positive) の可能性 (´・ω・`) 12೥1݄20೔༵ۚ೔
  5. 参考文献 以下の論文の Introduction に簡単にまと めてあります. より詳しい文献への refer もあります. Combining unit-level

    symbolic execution and system-level concrete execution for testing nasa software (ISSTA ’08) 12೥1݄20೔༵ۚ೔
  6. PyPy では... • 静的解析の手法が使われている • 変数の型の推論 • 静的単一情報 (Static Single

    Information, SSI) 形式への変換 • 変数は必ずローカル変数で代入は1回のみ • Decision Procedure • 型情報の伝播に類似が見られる • cf. Nelson-Oppen • → AOT コンパイルや JIT コンパイルの基礎となる! 12೥1݄20೔༵ۚ೔
  7. RPython Toolchain の概観 +---------+---------+ | CPython | PyPy | +=========+=========+

    | Python | Python | 静的解析!! +-------+ +---------+ | | C API | | RPython |--, v +-------+-+---------+ | translate | bare C | backend |<- +---------+---------+ backend = C, C with JIT, JVM, .CLI 12೥1݄20೔༵ۚ೔
  8. Java PathFinder と の類似 PyPy 制限された Python で Python を実装

    Java PathFinder Java で JVM を実装 instruction も Java オブジェクト! 意味論が自由に操作できる!! 12೥1݄20೔༵ۚ೔
  9. 翻訳の概観 •Control Flow Graph (フローチャート) 形式に 変換 •変数に注釈 (annotation, 型)

    を付加 •backend の型に変換 (RPython Typing, RTyping) •例外処理の変換 •GC 処理の変換 •C ソースコードの生成 (backend が C の場合) 12೥1݄20೔༵ۚ೔
  10. Control Flow Graph •フローチャート •ブロックを矢印でつなぐ •関数 → FunctionGraph インスタンス •文

    → Block インスタンス (複数かも) •pypy/objspace/flow/model.py 12೥1݄20೔༵ۚ೔
  11. Annotation (注釈) •型のこと (≠ Python の型) • = 値の集合 •静的型に変換するために必要!

    •この情報は JIT Compile でも使われる よ! •動的言語とは言え, 開発者の頭の中に は型はある (はず) 12೥1݄20೔༵ۚ೔
  12. 翻訳で遊ぼう!! 何はともあれ遊びましょう! (要 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೔༵ۚ೔
  13. 変数をクリック! •x_0 は元は x だった •t.annotate([int]) によって x_0 は int

    と判明 •SomeInteger という注釈が整数を表す •v0 は x + 1 の計算結果 •これもやっぱり整数 (SomeInteger) •v0 = x + 1 と return v1 に分離 12೥1݄20೔༵ۚ೔
  14. もうちょっと遊ぶ >>> 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೔༵ۚ೔
  15. 変換後は •代入する前の x は x_2 になった. •代入された後の x は v18

    になった. •return がある Block に v18 を渡すと v19 に名前が変わっている. •値が変化するとき, 関数をまたぐとき は必ず変数名を変える (これが SSI) 12೥1݄20೔༵ۚ೔
  16. もうちょっと遊ぶ >>> def generalize(x): ... if x: ... a =

    3 ... else: ... a = False ... return a ... >>> t = Translation(generalize) >>> t.annotate([bool]) >>> t.view() 12೥1݄20೔༵ۚ೔
  17. 変換後は •if のところで分岐が作られる •v1 には 3 も False も来る可能性がある •v1

    の注釈は SomeInteger •実は SomeBool は SomeInteger •True = 1, False = 0 となっている •上手いこと型の計算をやってくれている!! 12೥1݄20೔༵ۚ೔
  18. 参考記事 •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೔༵ۚ೔
  19. ググる単語 •型の話 •導出木 •Types and Programming Language •SSI の話 •SSA,

    SSI •Decision Procedure の話 •Nelson-Oppen 12೥1݄20೔༵ۚ೔
  20. 発表の下敷き • 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೔༵ۚ೔
  21. 注釈とは 注釈 = 型 = 値の集合 Python の型とは関係無いです. 型理論そのものについては +

    Types and Programming Languages + プログラミング言語の基礎概念 (五十嵐 淳) あたりを読むと良いかも 12೥1݄20೔༵ۚ೔
  22. 注釈の階層構造 注釈 = 型 = 値の集合 なので集合の包含関係による半順序 (≦) が決まる. その頂上と底辺には

    Top と Bottom が置かれる. (=「束構造をなす」) Bottom ≦ Char ≦ Str ≦ NullableStr ≦ Top 12೥1݄20೔༵ۚ೔
  23. オブジェクトも同様 class A(B): pass という継承関係があったとき Bottom ≦ Instance(A) ≦ Instance(B)

    ≦ NullableInstance(B) ≦ Top Bottom ≦ None ≦ NullableInstance(A) ≦ NullableInstance(B) ≦ Top となる. (要は is-a の関係) 12೥1݄20೔༵ۚ೔
  24. 補足 •Top はどんな値でも入る型 •Object (Java), Any (Scala) •primitive のことは横に置く •Bottom

    はどんな値も入らない型 •Nothing (Scala) •≦ は <: と書くとイメージしやすい人 もいるかも 12೥1݄20೔༵ۚ೔
  25. List だと •List の要素は全て同質 (homogeneous, 要素の型が同一) として扱う •List は互いに包含関係は無い •collection

    間の is-a の関係は難し い. •e.g. Java の配列 (における失敗) 12೥1݄20೔༵ۚ೔
  26. ルールで使う定義 •A: 前に出てきた型階層 (束, lattice) •V: 変数の集合 •E: V 上の同値関係

    •ある変数どうしの型が同じ, という 情報 •b: V から A への関数 •ある変数からその注釈への対応付け 12೥1݄20೔༵ۚ೔
  27. イメージ V = {a, b, c} E = {(a, c)}

    b = {a: int, b: str, c: int} のような感じ. (Python 風に書いている が, 実装とは無関係です) 注釈処理が進むに従って, V, E, b のサイ ズは大きくなっていく. 12೥1݄20೔༵ۚ೔
  28. 定義 (続き) •(b, E): 状態 •要は変数の情報 •状態 (b’, E’) は状態

    (b, E) より 一般的 (general): b(v) ≦ b’(v) かつ E ⊂ E’ •型情報は緩く, 同値情報は多く •処理が進むと状態はより一般的に なっていく 12೥1݄20೔༵ۚ೔
  29. 極端な状態 •最も一般的な状態 (= 有用な情報無し) •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೔༵ۚ೔
  30. 例: z = x + y その1 z := add(x,

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

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

    y), Bool ≦ b(x) ≦ NonNegInt, Bool ≦ b(y) ≦ NonNegInt --------------------------------- b.update({z: NonNegInt}) 12೥1݄20೔༵ۚ೔
  33. 例: 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೔༵ۚ೔
  34. 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೔༵ۚ೔
  35. 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೔༵ۚ೔
  36. ごめんなさい 上の2つの例は f = t.compile_c() すると エラーで落ちちゃいます. 原因は分かって いませんm(_ _)m

    解読してくれる方は pypy-ja へ ↓ pypy.rpython.error.TyperError: don't know how to convert from <FixedSizeListRepr * GcArray of Signed > to <PyObjRepr * PyObject> 12೥1݄20೔༵ۚ೔
  37. merge の仕事 •代入が発生したときに, 変数の注釈を (必要なら) 一般化する •注釈 a を変数 x

    に付けるコード •b.update({x: a ∨ b(x)}) •E はそのまま •このパターンは簡単 •ただし, List に関しては特別扱い 12೥1݄20೔༵ۚ೔
  38. List 注釈を merge 注釈 List(v) を List(w) という注釈が付 いている変数に merge

    b はそのまま E.append((v, w)) List の後ろに要素を表す変数 v, w があ るのがポイント!! 12೥1݄20೔༵ۚ೔
  39. 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೔༵ۚ೔
  40. meta-rule •(v, w) ∈ E が判明したら以下の2つの 作業をする •v の注釈を w

    に merge •w の注釈を v に merge •merge したことにより, 再度 E に追加 があった場合は止まるまで繰り返す 12೥1݄20೔༵ۚ೔
  41. 資料の残り部分 •EU report about translation •6.5--6.8 他の構文に対応するルール •6.9 一般化, 停止性,

    健全性に関す る証明 •6.10 動的な取り扱いについて諸々 •7 RTyping について 12೥1݄20೔༵ۚ೔
  42. まとめ •RPython Toolchain は動的型付き言語を 解析, 変換し, 静的型付け言語のプログ ラムを生成する •RPython Toolchain

    には翻訳という処理 がある •翻訳では変換の準備として RPython で 書いた処理系に型を付ける処理がある •その際, 静的解析の手法が使われている 12೥1݄20೔༵ۚ೔