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

WebAssemblyの作業をしていると、他の言語ってどうなってるんだろう、と疑問が湧きました。ふだん使っているPythonにもVMがあるので調べてみましょう。

docs.python.org

Pythonバイトコードに関する情報は、disパッケージで調べられます。リファレンスを確認すると、パッケージ直下にたくさんバイトコード関連の属性が存在するのがわかります。それぞれ、中身を見てみましょう。全ての命令コード名はdis.opnameで取得できます。数値 -> 命令名変換時に使うものだと思うので、主にデバッグ用途でしょうか。

import dis
import pprint

pprint.pprint(dis.opname)

'<0>'のように数字を含む文字列値は、その数値に対応する命令が存在しないということです。後半はほとんど埋まっていなくて意外でした。

['<0>',
 'POP_TOP',
 'ROT_TWO',
 'ROT_THREE',
 'DUP_TOP',
 'DUP_TOP_TWO',
 'ROT_FOUR',
 '<7>',
 '<8>',
 'NOP',
 'UNARY_POSITIVE',
 'UNARY_NEGATIVE',
 'UNARY_NOT',
 '<13>',
 '<14>',
 'UNARY_INVERT',
:
 '<248>',
 '<249>',
 '<250>',
 '<251>',
 '<252>',
 '<253>',
 '<254>',
 '<255>']

ちなみにdis.opmapdis.opnameとは反対に、命令名 -> 数値変換に使用します。

{'BEFORE_ASYNC_WITH': 52,
 'BINARY_ADD': 23,
 'BINARY_AND': 64,
 'BINARY_FLOOR_DIVIDE': 26,
:
 'UNPACK_SEQUENCE': 92,
 'WITH_EXCEPT_START': 49,
 'YIELD_FROM': 72,
 'YIELD_VALUE': 86}

dis.opmapdis.opname以外の属性は、さらに詳細な情報を取得するためのもののようです。

import dis
import pprint

# pprint.pprint(dis.opname)
# pprint.pprint(dis.opmap)

def print_disassemble_info(s):
    print(s, end=': ')
    pprint.pprint(getattr(dis, s))

disassemble_attributes = [
    'cmp_op',
    'hasconst', 
    'hasfree',
    'hasname',
    'hasjrel',
    'hasjabs',
    'haslocal',
    'hascompare',
]

for attr in disassemble_attributes:
    print_disassemble_info(attr)

ひとまず出力してみました。ちょっとよくわからないので引き続き、調べます。

cmp_op: ('<', '<=', '==', '!=', '>', '>=')
hasconst: [100]
hasfree: [135, 136, 137, 138, 148]
hasname: [90, 91, 95, 96, 97, 98, 101, 106, 108, 109, 116, 160]
hasjrel: [93, 110, 122, 143, 154]
hasjabs: [111, 112, 113, 114, 115, 121]
haslocal: [124, 125, 126]
hascompare: [107]