32.12. dis — Python バイトコードの逆アセンブラ¶
Source code: Lib/dis.py
dis モジュールは CPython バイトコード (bytecode) を逆アセンブルすることでバイトコードの解析をサポートします。 このモジュールが入力として受け取る CPython バイトコードはファイル Include/opcode.h に定義されており、 コンパイラとインタプリタが使用しています。
CPython 実装の詳細: バイトコードは CPython インタプリタの実装詳細です! Python のバージョン 間でバイトコードの追加や、削除、変更がないという保証はありません。この モジュールを使用することによって Python の異なる VM または異なるリリース の間で動作すると考えるべきではありません。
例: 以下の関数 myfunc() を考えると
def myfunc(alist):
return len(alist)
myfunc() の逆アセンブル結果を得るために次のコマンドを使うことができます
>>> dis.dis(myfunc)
2 0 LOAD_GLOBAL 0 (len)
3 LOAD_FAST 0 (alist)
6 CALL_FUNCTION 1
9 RETURN_VALUE
("2" は行番号です)。
dis モジュールは次の関数と定数を定義します:
-
dis.dis([bytesource])¶ bytesource オブジェクトを逆アセンブルします。 bytesource はモジュール、クラス、関数、あるいはコードオブジェクトのいずれかを示します。 モジュールに対しては、すべての関数を逆アセンブルします。クラスに対しては、すべてのメソッドを逆アセンブルします。 単一のコード列に対しては、バイトコード命令ごとに 1 行を出力します。 オブジェクトが与えられない場合は、最後のトレースバックを逆アセンブルします。
-
dis.distb([tb])¶ トレースバックのスタックの先頭の関数を逆アセンブルします。 Noneが渡された場合は最後のトレースバックを使います。例外を引き起こした命令が表示されます。
-
dis.disassemble(code[, lasti])¶ コードオブジェクトを逆アセンブルします。 lasti が与えられた場合は、最後の命令を示します。出力は次のようなカラムに分割されます:
- 各行の最初の命令に対する行番号。
- 現在の命令。
-->として示されます。 - ラベル付けされた命令。
>>とともに表示されます。 - 命令のアドレス。
- 命令コード名。
- 命令パラメタ。
- パラメタの解釈を括弧で囲んだもの。
パラメタの解釈は、ローカル変数とグローバル変数の名前、定数の値、 分岐先、比較命令を認識します。
-
dis.disco(code[, lasti])¶ disassemble()の別名。よりタイプしやすく、以前の Python リリースと互換性があります。
-
dis.findlinestarts(code)¶ このジェネレータ関数は、コードオブジェクト code の
co_firstlinenoとco_lnotab属性を使い、ソースコード内の行が始まる場所であるオフセットを 求めます。これらは(offset, lineno)の対として生成されます。
-
dis.findlabels(code)¶ ジャンプ先であるコードオブジェクト code のすべてのオフセットを 求め、これらのオフセットのリストを返します。
-
dis.opname¶ 命令コード名のリスト。バイトコードをインデクスに使って参照できます。
-
dis.opmap¶ 命令コード名をバイトコードに対応づける辞書。
-
dis.cmp_op¶ すべての比較命令の名前のリスト。
-
dis.hasconst¶ 定数パラメタを持つバイトコードのリスト。
-
dis.hasfree¶ 自由変数にアクセスするバイトコードのリスト。
-
dis.hasname¶ 名前によって属性にアクセスするバイトコードのリスト。
-
dis.hasjrel¶ 相対ジャンプ先を持つバイトコードのリスト。
-
dis.hasjabs¶ 絶対ジャンプ先を持つバイトコードのリスト。
-
dis.haslocal¶ ローカル変数にアクセスするバイトコードのリスト。
-
dis.hascompare¶ ブール命令のバイトコードのリスト。
32.12.1. Python バイトコード命令¶
現在 Python コンパイラは次のバイトコード命令を生成します。
-
STOP_CODE()¶ コンパイラにコードの終わりを知らせます。インタプリタでは使われません。
-
NOP()¶ なにもしないコード。バイトコードオプティマイザでプレースホルダとして使われます。
-
POP_TOP()¶ スタックの先頭 (TOS) の要素を取り除きます。
-
ROT_TWO()¶ スタックの先頭の 2 つの要素を入れ替えます。
-
ROT_THREE()¶ スタックの二番目と三番目の要素の位置を 1 つ上げ、先頭を三番目へ下げます。
-
ROT_FOUR()¶ スタックの二番目、三番目および四番目の位置を 1 つ上げ、先頭を四番目に下げます。
-
DUP_TOP()¶ スタックの先頭にある参照の複製を作ります。
単項命令はスタックの先頭を取り出して操作を適用し、結果をスタックへプッシュし戻します。
-
UNARY_POSITIVE()¶ TOS = +TOSに対応します。
-
UNARY_NEGATIVE()¶ TOS = -TOSに対応します。
-
UNARY_NOT()¶ TOS = not TOSに対応します。
-
UNARY_CONVERT()¶ TOS = `TOS`に対応します。
-
UNARY_INVERT()¶ TOS = ~TOSに対応します。
-
GET_ITER()¶ TOS = iter(TOS)に対応します。
二項命令はスタックの先頭 (TOS) と先頭から二番目の要素をスタックから取り除きます。 命令を実行し、スタックへ結果をプッシュし戻します。
-
BINARY_POWER()¶ TOS = TOS1 ** TOSに対応します。
-
BINARY_MULTIPLY()¶ TOS = TOS1 * TOSに対応します。
-
BINARY_DIVIDE()¶ from __future__ import divisionが有効でないときのTOS = TOS1 / TOSに対応します。
-
BINARY_FLOOR_DIVIDE()¶ TOS = TOS1 // TOSに対応します。
-
BINARY_TRUE_DIVIDE()¶ from __future__ import divisionが有効なときのTOS = TOS1 / TOSに対応します。
-
BINARY_MODULO()¶ TOS = TOS1 % TOSに対応します。
-
BINARY_ADD()¶ TOS = TOS1 + TOSに対応します。
-
BINARY_SUBTRACT()¶ TOS = TOS1 - TOSに対応します。
-
BINARY_SUBSCR()¶ TOS = TOS1[TOS]に対応します。
-
BINARY_LSHIFT()¶ TOS = TOS1 << TOSに対応します。
-
BINARY_RSHIFT()¶ TOS = TOS1 >> TOSに対応します。
-
BINARY_AND()¶ TOS = TOS1 & TOSに対応します。
-
BINARY_XOR()¶ TOS = TOS1 ^ TOSに対応します。
-
BINARY_OR()¶ TOS = TOS1 | TOSに対応します。
インプレース命令は TOS と TOS1 を取り除いて結果をスタックへプッシュするという点で二項命令と似ています。 しかし、TOS1 がインプレース命令をサポートしている場合には操作が直接 TOS1 に行われます。 また、操作結果の TOS は (常に同じというわけではありませんが) 元の TOS1 と同じオブジェクトになることが多いです。
-
INPLACE_POWER()¶ インプレースの
TOS = TOS1 ** TOSに対応します。
-
INPLACE_MULTIPLY()¶ インプレースの
TOS = TOS1 * TOSに対応します。
-
INPLACE_DIVIDE()¶ from __future__ import divisionが有効でないときのインプレースのTOS = TOS1 / TOSに対応します。
-
INPLACE_FLOOR_DIVIDE()¶ インプレースの
TOS = TOS1 // TOSに対応します。
-
INPLACE_TRUE_DIVIDE()¶ from __future__ import divisionが有効なときのインプレースのTOS = TOS1 / TOSに対応します。
-
INPLACE_MODULO()¶ インプレースの
TOS = TOS1 % TOSに対応します。
-
INPLACE_ADD()¶ インプレースの
TOS = TOS1 + TOSに対応します。
-
INPLACE_SUBTRACT()¶ インプレースの
TOS = TOS1 - TOSに対応します。
-
INPLACE_LSHIFT()¶ インプレースの
TOS = TOS1 << TOSに対応します。
-
INPLACE_RSHIFT()¶ インプレースの
TOS = TOS1 >> TOSに対応します。
-
INPLACE_AND()¶ インプレースの
TOS = TOS1 & TOSに対応します。
-
INPLACE_XOR()¶ インプレースの
TOS = TOS1 ^ TOSに対応します。
-
INPLACE_OR()¶ インプレースの
TOS = TOS1 | TOSに対応します。
スライス命令コードは最大 3 つのパラメタを取ります。
-
SLICE+0()¶ TOS = TOS[:]に対応します。
-
SLICE+1()¶ TOS = TOS1[TOS:]に対応します。
-
SLICE+2()¶ TOS = TOS1[:TOS]に対応します。
-
SLICE+3()¶ TOS = TOS2[TOS1:TOS]に対応します。
スライス代入はさらにもう 1 つのパラメタを必要とします。 他の文と同じく、これらはスタックに何もプッシュしません。
-
STORE_SLICE+0()¶ TOS[:] = TOS1に対応します。
-
STORE_SLICE+1()¶ TOS1[TOS:] = TOS2に対応します。
-
STORE_SLICE+2()¶ TOS1[:TOS] = TOS2に対応します。
-
STORE_SLICE+3()¶ TOS2[TOS1:TOS] = TOS3に対応します。
-
DELETE_SLICE+0()¶ del TOS[:]に対応します。
-
DELETE_SLICE+1()¶ del TOS1[TOS:]に対応します。
-
DELETE_SLICE+2()¶ del TOS1[:TOS]に対応します。
-
DELETE_SLICE+3()¶ del TOS2[TOS1:TOS]に対応します。
-
STORE_SUBSCR()¶ TOS1[TOS] = TOS2に対応します。
-
DELETE_SUBSCR()¶ del TOS1[TOS]に対応します。
その他の命令コード。
-
PRINT_ITEM_TO()¶ PRINT_ITEMと似ていますが、TOS から二番目の要素を TOS にあるファイル互換オブジェクトへ出力します。 これは拡張 print 文で使われます。
-
PRINT_NEWLINE_TO()¶ PRINT_NEWLINEと似ていますが、TOSのファイル互換オブジェクトに改行を表示します。 これは拡張 print 文で使われます。
-
LIST_APPEND(i)¶ list.append(TOS[-i], TOS)を呼びます。リスト内包表記を実装するために使われます。 要素が取り除かれる間、リストオブジェクトはスタックに残るので、ループの 反復をさらに行えます。
-
LOAD_LOCALS()¶ 現在のスコープのローカルな名前空間 (locals) への参照をスタックにプッシュします。 これはクラス定義のためのコードで使われます: クラス本体が評価された後、locals はクラス定義へ渡されます。
-
RETURN_VALUE()¶ 関数の呼び出し元へ TOS を返します。
-
IMPORT_STAR()¶ '_'で始まっていないすべてのシンボルをモジュール TOS から直接ローカル名前空間へロードします。 モジュールはすべての名前をロードした後にポップされます。 この命令コードはfrom module import *に対応します。
-
EXEC_STMT()¶ exec TOS2,TOS1,TOSに対応します。コンパイラは指定されなかったオプションのパラメタをNoneで埋めます。
-
POP_BLOCK()¶ ブロックスタックからブロックを一つ取り除きます。 フレームごとにブロックのスタックがあり、ネストしたループや try 文などを表しています。
-
END_FINALLY()¶ finally節を終了します。 インタプリタは例外を再送出しなければならないかどうか、あるいは、 関数から return して外側の次のブロックに続くかどうかを再度判断します。
-
BUILD_CLASS()¶ 新しいクラスオブジェクトを作成します。TOSはメソッド辞書、TOS1は基底クラスの名前のタプル、TOS2はクラス名です。
-
SETUP_WITH(delta)¶ この命令コードは、with ブロックが開始する前にいくつかの命令を行います。 まず、コンテキストマネージャから
__exit__()をロードし、 後からWITH_CLEANUPで使うためにスタックにプッシュします。 そして、__enter__()が呼び出され、 delta を指す finally ブロックがプッシュされます。最後に、enter メソッドを呼び出した 結果がスタックにプッシュされます。次の命令コードはこれを無視 (POP_TOP) するか、変数に保存 (STORE_FAST,STORE_NAME, またはUNPACK_SEQUENCE) します。
-
WITH_CLEANUP()¶ with式ブロックを抜けるときに、スタックをクリーンアップします。 スタックの先頭は 1–3 個の値で、それらはなぜ/どのように finally 節に 到達したかを表しています:- TOP =
None - (TOP, SECOND) = (
WHY_{RETURN,CONTINUE}), retval - TOP =
WHY_*; no retval below it - (TOP, SECOND, THIRD) = exc_info()
これらの値の下には、コンテキストマネージャーの
__exit__()結合メソッド (bound method) である EXIT があります。最後のケースでは、
EXIT(TOP, SECOND, THIRD)が呼ばれ、それ以外ではEXIT(None, None, None)が呼ばれます。EXIT はスタックから取り除かれ、その上の値は順序を維持したまま残されます。 加えて、スタックが例外処理中であることを示し、 かつ 関数呼び出しが true 値を返した場合、
END_FINALLYが例外を再送出することを防ぐため、この情報は削除されます ("zapped")。 (しかし、 non-local goto は再開されます)- TOP =
以下の命令コードはすべて引数を必要とします。引数は 2 バイトで、最上位バイトが後になります。
-
STORE_NAME(namei)¶ name = TOSに対応します。 namei はコードオブジェクトの属性co_namesにおける name のインデクスです。 コンパイラは可能ならばSTORE_FASTまたはSTORE_GLOBALを使おうとします。
-
DELETE_NAME(namei)¶ del nameに対応します。 namei はコードオブジェクトのco_names属性へのインデクスです。
-
UNPACK_SEQUENCE(count)¶ TOS を count 個の個別の値にアンパックして、右から左の順にスタックに置きます。
-
DUP_TOPX(count)¶ count 個の要素を順番を保ちながら複製します。 実装上の制限から、 count は 1以上 から 5 以下でなければなりません。
-
STORE_ATTR(namei)¶ TOS.name = TOS1に対応します。 namei はco_namesにおける名前のインデクスです。
-
DELETE_ATTR(namei)¶ del TOS.nameに対応します。co_namesへのインデクスとして namei を使います。
-
STORE_GLOBAL(namei)¶ STORE_NAMEと同じように動作しますが、 name をグローバルとして保存します。
-
DELETE_GLOBAL(namei)¶ DELETE_NAMEと同じように動作しますが、グローバルの name を削除します。
-
LOAD_CONST(consti)¶ co_consts[consti]をスタックにプッシュします。
-
LOAD_NAME(namei)¶ co_names[namei]に関連付けられた値をスタックにプッシュします。
-
BUILD_TUPLE(count)¶ スタックから count 個の要素を消費してタプルを作り出し、できたタプルをスタックにプッシュします。
-
BUILD_LIST(count)¶ BUILD_TUPLEと同じように動作しますが、リストを作り出します。
-
BUILD_SET(count)¶ BUILD_TUPLEと同じように動作しますが、set を作り出します。バージョン 2.7 で追加.
-
BUILD_MAP(count)¶ スタックに新しい辞書オブジェクトをプッシュします。 辞書は count 個のエントリを持つサイズに設定されます。
-
LOAD_ATTR(namei)¶ TOS を
getattr(TOS, co_names[namei])と入れ替えます。
-
COMPARE_OP(opname)¶ ブール命令を実行します。命令名は
cmp_op[opname]にあります。
-
IMPORT_NAME(namei)¶ モジュール
co_names[namei]をインポートします。 TOS と TOS1 がポップされ、__import__()の fromlist と level 引数になります。 モジュールオブジェクトはスタックへプッシュされます。現在の名前空間は影響されません: 適切な import 文のためには、後続のSTORE_FAST命令が名前空間を変更します。
-
IMPORT_FROM(namei)¶ TOS にあるモジュールから属性
co_names[namei]をロードします。 作成されたオブジェクトはスタックにプッシュされ、後続のSTORE_FAST命令によって保存されます。
-
JUMP_FORWARD(delta)¶ バイトコードカウンタを delta だけ増加させます。
-
POP_JUMP_IF_TRUE(target)¶ TOS が真ならば、バイトコードカウンタを target に設定します。 TOS はポップされます。
-
POP_JUMP_IF_FALSE(target)¶ TOS が偽ならば、バイトコードカウンタを target に設定します。 TOS はポップされます。
-
JUMP_IF_TRUE_OR_POP(target)¶ TOS が真ならば、バイトコードカウンタを target に設定し、TOS は スタックに残されます。そうでない (TOS が偽) なら、TOS はポップされます。
-
JUMP_IF_FALSE_OR_POP(target)¶ TOS が偽ならば、バイトコードカウンタを target に設定し、TOS は スタックに残されます。そうでない (TOS が真) なら、TOS はポップされます。
-
JUMP_ABSOLUTE(target)¶ バイトコードカウンタを target に設定します。
-
FOR_ITER(delta)¶ TOSはイテレータです。そのnext()メソッドを呼び出します。 新しい値が yield された場合は、それをスタックにプッシュします (イテレータはその下に残されます)。 イテレータの呼び出しで要素が尽きたことが示された場合は、TOSがポップされます。 そして、バイトコードカウンタが delta だけ増やされます。
-
LOAD_GLOBAL(namei)¶ co_names[namei]という名前のグローバルをスタック上にロードします。
-
SETUP_LOOP(delta)¶ ループのためのブロックをブロックスタックにプッシュします。 ブロックは現在の命令から delta バイトの大きさを占めます。
-
SETUP_EXCEPT(delta)¶ try-except 節から try ブロックをブロックスタックにプッシュします。 delta は最初の except ブロックを指します。
-
SETUP_FINALLY(delta)¶ try-except 節から try ブロックをブロックスタックにプッシュします。 delta は finally ブロックを指します。
-
STORE_MAP()¶ key, value のペアを辞書に格納します。 key と value をポップする一方、辞書はスタックに残されます。
-
LOAD_FAST(var_num)¶ ローカルな
co_varnames[var_num]への参照をスタックにプッシュします。
-
STORE_FAST(var_num)¶ TOS をローカルな
co_varnames[var_num]の中に保存します。
-
DELETE_FAST(var_num)¶ ローカルな
co_varnames[var_num]を削除します。
-
LOAD_CLOSURE(i)¶ セルと自由変数の記憶領域のスロット i に含まれるセルへの参照をプッシュします。 i が co_cellvars の長さより小さければ、変数の名前は
co_cellvars[i]です。 そうでなければco_freevars[i - len(co_cellvars)]です。
-
LOAD_DEREF(i)¶ セルと自由変数の記憶領域のスロット i に含まれるセルをロードします。 セルが持つオブジェクトへの参照をスタックにプッシュします。
-
STORE_DEREF(i)¶ セルと自由変数の記憶領域のスロット i に含まれるセルへTOSを保存します。
-
SET_LINENO(lineno)¶ この命令コードは廃止されました。
-
RAISE_VARARGS(argc)¶ 例外を発生させます。 argc は raise 文へ与えるパラメタの数を 0 から 3 の 範囲で示します。 ハンドラは TOS2 をトレースバック、TOS1 をパラメタ、TOS を例外として探します。
-
CALL_FUNCTION(argc)¶ 関数を呼び出します。 argc の下位バイトは位置パラメタの数を、上位バイトはキーワードパラメタの数を示します。 スタック上では、最初にキーワードパラメタが見つかります。 それぞれのキーワード引数に対しては、値がキーより上に来ます。 スタック上のキーワードパラメタの下に位置パラメタがあり、最も右のパラメタが先頭になります。 スタック上のパラメタの下には、呼び出される関数オブジェクトが置かれます。 すべての関数引数をポップし、関数自体もスタックから取り除き、戻り値をプッシュします。
-
MAKE_FUNCTION(argc)¶ 新しい関数オブジェクトをスタックにプッシュします。 TOS は関数に関連付けられたコードです。 関数オブジェクトは TOS の下にある argc デフォルトパラメタをもつように定義されます。
-
MAKE_CLOSURE(argc)¶ 新しい関数オブジェクトを作り出し、その func_closure スロットを設定し、スタックにプッシュします。 TOS は関数に関連付けられたコードで、TOS1 はクロージャの自由変数に対するセルを格納したタプルです。 関数はセルの前にある argc デフォルトパラメタも持っています。
-
BUILD_SLICE(argc)¶ スライスオブジェクトをスタックにプッシュします。 argc は2あるいは3でなければなりません。 2 ならば
slice(TOS1, TOS)がプッシュされます。 3 ならばslice(TOS2, TOS1, TOS)がプッシュされます。 これ以上の情報については、slice()組み込み関数を参照してください。
-
EXTENDED_ARG(ext)¶ デフォルトの 2 バイトに収まりきらない大きな引数を持つあらゆる命令コードの前に置かれます。 ext は追加の 2 バイトを保持し、後続の命令コードの引数と組み合わされます。 それらは 4 バイト引数を構成し、 ext はその最上位バイトです。
-
CALL_FUNCTION_VAR(argc)¶ 関数を呼び出します。 argc は
CALL_FUNCTIONと同じように解釈されます。 スタックの先頭の要素は可変引数リストを含んでおり、その後にキーワード引数と位置引数が続きます。
-
CALL_FUNCTION_KW(argc)¶ 関数を呼び出します。 argc は
CALL_FUNCTIONと同じように解釈されます。 スタックの先頭の要素はキーワード引数辞書を含んでおり、その後に明示的なキーワード引数と位置引数が続きます。
-
CALL_FUNCTION_VAR_KW(argc)¶ 関数を呼び出します。 argc は
CALL_FUNCTIONと同じように解釈されます。 スタックの先頭の要素はキーワード引数辞書を含んでおり、その後に変数引数のタプルが続き、 さらに明示的なキーワード引数と位置引数が続きます。
-
HAVE_ARGUMENT()¶ これは実際の命令コードではありません。引数を取らない命令コード
< HAVE_ARGUMENTと、 引数を取る命令コード>= HAVE_ARGUMENTの分割行を表します。
