Pythonのバイトコード一覧 (3)

ironoir.hatenablog.com

つづきです。ようやく一覧を出せそうです。ざっくり全体感を掴んでください。詳細はリファレンスを見た方が早いので。

docs.python.org

今更ですが、Python VMはスタックマシンです。そして、このリストはPython 3.9での話です。

スタック操作

スタックの中身を直接操作する命令ですね。ROTは交換、DUPは複製。POP_BLOCKはframeの中のblockをpopする。POP_EXCEPTも同様ですが、例外状態から回復するために使われる、とあります。

  • POP_TOP
  • ROT_TWO
  • ROT_THREE
  • ROT_FOUR
  • DUP_TOP
  • DUP_TOP_TWO
  • POP_BLOCK
  • 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

以上です。めちゃめちゃざっくり、個人的には全体がぼんやりわかった気がして有意義でした。高水準なバイトコードは他にもあるので、またいつか調べてみたいな。