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

PyPy における静的解析

Avatar for cocoatomo cocoatomo
February 15, 2018

PyPy における静的解析

Avatar for cocoatomo

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೔༵ۚ೔