Pythonのバイトコード一覧 (3)
つづきです。ようやく一覧を出せそうです。ざっくり全体感を掴んでください。詳細はリファレンスを見た方が早いので。
今更ですが、Python VMはスタックマシンです。そして、このリストはPython 3.9での話です。
スタック操作
スタックの中身を直接操作する命令ですね。ROTは交換、DUPは複製。POP_BLOCKはframeの中のblockをpopする。POP_EXCEPTも同様ですが、例外状態から回復するために使われる、とあります。
数値演算
ここは割とわかりやすい。UNARYは単項演算、BINARYは二項演算。INPLACEは+=
みたいに、結果をすぐ元の変数に上書きするような演算ですね。行列に関する演算があるのが不思議(でもない?)。
- UNARY_POSITIVE
- UNARY_NEGATIVE
- BINARY_POWER
- BINARY_MULTIPLY
- BINARY_MATRIX_MULTIPLY
- BINARY_FLOOR_DIVIDE
- BINARY_TRUE_DIVIDE
- BINARY_MODULO
- BINARY_ADD
- BINARY_SUBTRACT
- BINARY_SUBSCR
- INPLACE_POWER
- INPLACE_MULTIPLY
- INPLACE_MATRIX_MULTIPLY
- INPLACE_FLOOR_DIVIDE
- INPLACE_TRUE_DIVIDE
- INPLACE_MODULO
- INPLACE_ADD
- INPLACE_SUBTRACT
ビット演算
これもわかりやすい。いかにもVMっぽい。
- UNARY_INVERT
- BINARY_LSHIFT
- BINARY_RSHIFT
- BINARY_AND
- BINARY_XOR
- BINARY_OR
- INPLACE_LSHIFT
- INPLACE_RSHIFT
- INPLACE_AND
- INPLACE_XOR
- INPLACE_OR
論理演算
戻り値がboolの演算。COMPARE_OPは実際には前回に紹介した等号不等号のリストdis.cmp_op
を使うみたいです。他はそれぞれnot
is
contains
演算子ですね。
- UNARY_NOT
- COMPARE_OP
- IS_OP
- CONTAINS_OP
ロード操作
必ずしもLOADだけで始まっていませんが、BUILDで始まる命令は値を作った後でスタックにプッシュするものです。なのでこれらをロード操作に単純に入れていいのかは迷うところではあります。BUILDの対象として各種のPythonの基本型が網羅されている感じですね。
- LOAD_CONST
- LOAD_NAME
- UNPACK_SEQUENCE
- BUILD_TUPLE
- BUILD_LIST
- BUILD_SET
- BUILD_MAP
- BUILD_CONST_KEY_MAP
- BUILD_STRING
- LOAD_GLOBAL
- LOAD_FAST
- LOAD_CLOSURE
- LOAD_DEREF
- LOAD_CLASSDEREF
- LOAD_METHOD
- BUILD_SLICE
ストア操作
STOREは、スタックの値を変数(=メモリ)に入れる操作ですね。対になるように並べましたが、DELETEはストア操作かというと微妙ですね(変数を消すdel
演算子)。
- STORE_SUBSCR
- DELETE_SUBSCR
- STORE_NAME
- DELETE_NAME
- UNPACK_EX
- STORE_ATTR
- DELETE_ATTR
- STORE_GLOBAL
- DELETE_GLOBAL
- STORE_FAST
- DELETE_FAST
- STORE_DEREF
- DELETE_DEREF
ジャンプ
個人的にはもう少したくさんJUMP命令があるのかと思ったら、意外とシンプル。何をするのかも名前で明確ですね。
- JUMP_FORWARD
- POP_JUMP_IF_TRUE
- POP_JUMP_IF_FALSE
- JUMP_IF_NOT_EXC_MATCH
- JUMP_IF_TRUE_OR_POP
- JUMP_IF_FALSE_OR_POP
- JUMP_ABSOLUTE
コルーチン関連
この分類だけ他と比較して異質さを放っていたので、リファレンスと同じ分類をそのまま持ってきました。これだけでも、コルーチン関連の処理がPythonにとってどういうものだったのかが垣間見えます。Guidoが入れさせた、他と少し浮いた扱い、そんな風に見えるのは穿ち過ぎでしょうか。
- GET_AWAITABLE
- GET_AITER
- GET_ANEXT
- END_ASYNC_FOR
- BEFORE_ASYNC_WITH
- SETUP_ASYNC_WITH
関数呼出/返却/例外
関数関連の命令ですが、例外関連の命令がちらほら見えるのがそれっぽいですね。YIELDはジェネレータ関連ですね。
- RETURN_VALUE
- YIELD_VALUE
- YIELD_FROM
- RERAISE
- WITH_EXCEPT_START
- LOAD_ASSERTION_ERROR
- SETUP_FINALLY
- RAISE_VARARGS
- CALL_FUNCTION
- CALL_FUNCTION_KW
- CALL_FUNCTION_EX
- CALL_METHOD
その他演算
ちょっと分類しづらい命令を集めてみました。高水準というか、よく使う操作なので最適化用にある命令が多いのでしょうか。
- GET_ITER
- GET_YIELD_FROM_ITER
- PRINT_EXPR
- SET_ADD
- LIST_APPEND
- MAP_ADD
- LIST_TO_TUPLE
- LIST_EXTEND
- SET_UPDATE
- DICT_UPDATE
- DICT_MERGE
- LOAD_ATTR
- FOR_ITER
- MAKE_FUNCTION
- FORMAT_VALUE
その他
さらに枠から外れそうなものを集めました。と言いつつ、よく見ると他の分類に入れられそうな命令もありますね。SETUP_WITHとかは制御構造なので関数のところにおいてもいいかも。IMPORTとかも1つの命令なんですね。HAVE_ARGUMENTとかは「厳密にはopcodeではない」とか書かれてますね。
- NOP
- SETUP_ANNOTATIONS
- IMPORT_STAR
- LOAD_BUILD_CLASS
- SETUP_WITH
- IMPORT_NAME
- IMPORT_FROM
- EXTENDED_ARG
- HAVE_ARGUMENT
以上です。めちゃめちゃざっくり、個人的には全体がぼんやりわかった気がして有意義でした。高水準なバイトコードは他にもあるので、またいつか調べてみたいな。