Save 37% off PRO during our Black Friday Sale! »

PyPy における静的解析

85401912c23c7d5e656c08e7a751e95c?s=47 cocoatomo
February 15, 2018

PyPy における静的解析

85401912c23c7d5e656c08e7a751e95c?s=128

cocoatomo

February 15, 2018
Tweet

Transcript

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

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

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

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

    12೥1݄20೔༵ۚ೔
  5. お前, 誰よ? •ID: cocoatomo •blog: Elliptium •言語 •仕事: Java, 趣味:

    Python •活動 •pypy-ja •Python 公式ドキュメント翻訳 12೥1݄20೔༵ۚ೔
  6. お前, 誰よ? •理論好き •所属その1: 品川にある浅草っぽい会社 •所属その2: 社会人博士 •プログラムの検証まわりをやりたい なー, と今年度入学

    •今日はこっちの活動に関係する話で す 12೥1݄20೔༵ۚ೔
  7. 好きなエディタ アリエルネットワークでは入社時に好きな エディタを言わされると聞いて... Emacs 2006年くらいから CarbonEmacs & Meadow, CocoaEmacs &

    Emacs (on Windows) と変遷 12೥1݄20೔༵ۚ೔
  8. 良く使うMajor Mode •ReST mode (rst.el) •昔は org-mode でメモ書き •今は Sphinx

    の影響でもっぱら reST •入力はもちろん DDSKK •AquaSKK も使用 •フォント •Inconsolata + Takao •このスライドは Osaka ですが 12೥1݄20೔༵ۚ೔
  9. アジェンダ •自己紹介 •→研究テーマ「静的解析」 •PyPy ではどう使われているか •静的解析とは •注釈 (annotation) とは •変数に注釈を付ける

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

    cf. Formal Method (形式手法) 12೥1݄20೔༵ۚ೔
  11. 検証手法 •検証と言うと普通は…⋯…⋯ ↓ •テスト •具体値で実行 •最も馴染み深い •偽陽性 (false positive) が無い(^-^)

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

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

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

    symbolic execution and system-level concrete execution for testing nasa software (ISSTA ’08) 12೥1݄20೔༵ۚ೔
  15. 発表の注意事項 •質問は随時受け付けます •斧を投げる場合は, お手柔らかにお願 いします 12೥1݄20೔༵ۚ೔

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

    12೥1݄20೔༵ۚ೔
  17. PyPy では... • 静的解析の手法が使われている • 変数の型の推論 • 静的単一情報 (Static Single

    Information, SSI) 形式への変換 • 変数は必ずローカル変数で代入は1回のみ • Decision Procedure • 型情報の伝播に類似が見られる • cf. Nelson-Oppen • → AOT コンパイルや JIT コンパイルの基礎となる! 12೥1݄20೔༵ۚ೔
  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೔༵ۚ೔
  19. Java PathFinder と の類似 PyPy 制限された Python で Python を実装

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

    を付加 •backend の型に変換 (RPython Typing, RTyping) •例外処理の変換 •GC 処理の変換 •C ソースコードの生成 (backend が C の場合) 12೥1݄20೔༵ۚ೔
  21. Control Flow Graph 12೥1݄20೔༵ۚ೔

  22. Control Flow Graph •フローチャート •ブロックを矢印でつなぐ •関数 → FunctionGraph インスタンス •文

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

    •この情報は JIT Compile でも使われる よ! •動的言語とは言え, 開発者の頭の中に は型はある (はず) 12೥1݄20೔༵ۚ೔
  24. 翻訳で遊ぼう!! 何はともあれ遊びましょう! (要 PyGame) $ hg clone ssh://hg@bitbucket.org/ pypyja/pypy pypyja

    $ cd pypyja $ python pypy/bin/translatorshell.py # 色々説明がずらずらと... >>> def succ(x): ... return x + 1 >>> t = Translation(succ) >>> t.view() 12೥1݄20೔༵ۚ೔
  25. Control Flow Graph! 12೥1݄20೔༵ۚ೔

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

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

  28. 変数をクリック! •x_0 は元は x だった •t.annotate([int]) によって x_0 は int

    と判明 •SomeInteger という注釈が整数を表す •v0 は x + 1 の計算結果 •これもやっぱり整数 (SomeInteger) •v0 = x + 1 と return v1 に分離 12೥1݄20೔༵ۚ೔
  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೔༵ۚ೔
  30. さてどうなるか? 変数 x に注目…⋯…⋯ 12೥1݄20೔༵ۚ೔

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

  32. 変換後は •代入する前の x は x_2 になった. •代入された後の x は v18

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

    3 ... else: ... a = False ... return a ... >>> t = Translation(generalize) >>> t.annotate([bool]) >>> t.view() 12೥1݄20೔༵ۚ೔
  34. こんなグラフに 12೥1݄20೔༵ۚ೔

  35. 変換後は •if のところで分岐が作られる •v1 には 3 も False も来る可能性がある •v1

    の注釈は SomeInteger •実は SomeBool は SomeInteger •True = 1, False = 0 となっている •上手いこと型の計算をやってくれている!! 12೥1݄20೔༵ۚ೔
  36. 是非遊ぼう 難しくないので, 是非遊んでみよう! 12೥1݄20೔༵ۚ೔

  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೔༵ۚ೔
  38. アジェンダ •自己紹介 •研究テーマ「静的解析」 •PyPy ではどう使われているか •→静的解析とは •注釈 (annotation) とは •変数に注釈を付ける

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

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

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

  42. ググる単語 •型の話 •導出木 •Types and Programming Language •SSI の話 •SSA,

    SSI •Decision Procedure の話 •Nelson-Oppen 12೥1݄20೔༵ۚ೔
  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೔༵ۚ೔
  44. 動的言語での 静的解析 ↑「お前は何を言っているんだ!?」↑ (画像略) 12೥1݄20೔༵ۚ೔

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

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

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

    (値の中身で処理が変わる) •などなど... 12೥1݄20೔༵ۚ೔
  48. どう解析して いるのか? •RPython でさえ動的すぎる •変数の型宣言無い •変数に複数回代入できる •クラスの継承がある •→ しょうがないので前から順に解析して いく(´・ω・`)

    •Hindley-Milner 型推論みたいなかっこ いいことはできない(´・ω・`) 12೥1݄20೔༵ۚ೔
  49. アジェンダ •自己紹介 •研究テーマ「静的解析」 •PyPy ではどう使われているか •静的解析とは •→注釈 (annotation) とは •変数に注釈を付ける

    12೥1݄20೔༵ۚ೔
  50. 注釈とは 注釈 = 型 = 値の集合 Python の型とは関係無いです. 型理論そのものについては +

    Types and Programming Languages + プログラミング言語の基礎概念 (五十嵐 淳) あたりを読むと良いかも 12೥1݄20೔༵ۚ೔
  51. Annotator (注釈器) •RPython スクリプトを前から順に解釈 •扱う注釈 •str, char, float などの組み込み型 •オブジェクト

    •collection (list, dict,...) •定数 •Nullable な注釈もある 12೥1݄20೔༵ۚ೔
  52. 注釈の階層構造 注釈 = 型 = 値の集合 なので集合の包含関係による半順序 (≦) が決まる. その頂上と底辺には

    Top と Bottom が置かれる. (=「束構造をなす」) Bottom ≦ Char ≦ Str ≦ NullableStr ≦ Top 12೥1݄20೔༵ۚ೔
  53. こんな感じ 12೥1݄20೔༵ۚ೔

  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೔༵ۚ೔
  55. 補足 •Top はどんな値でも入る型 •Object (Java), Any (Scala) •primitive のことは横に置く •Bottom

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

    間の is-a の関係は難し い. •e.g. Java の配列 (における失敗) 12೥1݄20೔༵ۚ೔
  57. アジェンダ •自己紹介 •研究テーマ「静的解析」 •PyPy ではどう使われているか •静的解析とは •注釈 (annotation) とは •→変数に注釈を付ける

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

  59. ルールで使う定義 •A: 前に出てきた型階層 (束, lattice) •V: 変数の集合 •E: V 上の同値関係

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

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

    (b, E) より 一般的 (general): b(v) ≦ b’(v) かつ E ⊂ E’ •型情報は緩く, 同値情報は多く •処理が進むと状態はより一般的に なっていく 12೥1݄20೔༵ۚ೔
  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೔༵ۚ೔
  63. 注釈器の目標 •最も一般的でない状態を求めること •基本的には処理の流れに沿って, 初 期状態 (b_min, E_min) を拡大させ ていく •ループ

    ← 静的解析の敵! •一般化されなくなるまで注釈を計算 しつづける 12೥1݄20೔༵ۚ೔
  64. 例: __add__ •中置演算子“+”についてのルール •オーバーロードされているので複数 ルールがある •z := add(x, y) という状況を考える

    •(z = x + y でいいんだけど文献に合 わせた) 12೥1݄20೔༵ۚ೔
  65. 例: z = x + y その1 z := add(x,

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

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

    y), Bool ≦ b(x) ≦ NonNegInt, Bool ≦ b(y) ≦ NonNegInt --------------------------------- b.update({z: NonNegInt}) 12೥1݄20೔༵ۚ೔
  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೔༵ۚ೔
  69. 案外簡単? ここまでのパターンでの注釈付けは素直 list やユーザが作成したクラスのオブ ジェクトのような他のオブジェクトを格納 できる何かが出てくると難しくなる. (= aliasing と呼ばれる) C

    のポインタでも同様の静的解析上の困難 が生まれる 12೥1݄20೔༵ۚ೔
  70. List の注釈 •将来どこで要素が格納されるか分から ない •List インスタンスを参照しているとこ ろを全て把握していないといけない •List の注釈は難しい! 困った!!

    •→ ではどうやって対処するか? 12೥1݄20೔༵ۚ೔
  71. merge 手続きと meta-rule •merge 手続き •情報を追加する手続き •meta-rule •情報を伝播させるルール •Nelson-Oppen: Simplification

    by cooperating decision procedures 12೥1݄20೔༵ۚ೔
  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೔༵ۚ೔
  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೔༵ۚ೔
  74. ごめんなさい 上の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೔༵ۚ೔
  75. merge の仕事 •代入が発生したときに, 変数の注釈を (必要なら) 一般化する •注釈 a を変数 x

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

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

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

    健全性に関す る証明 •6.10 動的な取り扱いについて諸々 •7 RTyping について 12೥1݄20೔༵ۚ೔
  80. 大丈夫 ここまでついて来れた人なら読めます! 12೥1݄20೔༵ۚ೔

  81. まとめ •RPython Toolchain は動的型付き言語を 解析, 変換し, 静的型付け言語のプログ ラムを生成する •RPython Toolchain

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