1. Pythonのバイトコード
1.1. バイトコードコンパイル
py
からpyc
を出力する。
python3 -m compileall s1.py
1.2. バイトコードディスアセンブル
Python3の場合、以下のコマンドを入れて、ディスアセンブルを行う。
sudo apt install uncompyle6
以下で、ディスアセンブルできる。-t
,-a
,-g
,-verify
,-verify-run
等が役に立つ。
uncompyle6 __pycache__/s1.cpython-38.pyc
例えば、-t
でコンパイルした場合、以下のデータが出力される。ここで、LOAD_GLOBAL
等が、Pythonインタープリターの命令である。このため、大まかな処理がどうなっているか見ることができる。
# uncompyle6 version 3.7.1
# Python bytecode 3.8 (3413)
# Decompiled from: Python 3.8.2 (default, Apr 27 2020, 15:53:34)
# [GCC 9.3.0]
# Embedded file name: s1.py
# Compiled at: 2020-06-23 10:28:06
# Size of source mod 2**32: 172 bytes
stmts (2)
0. sstmt
function_def (2)
0. mkfunc (3)
0. L. 1 0 LOAD_CODE <code_object main>
1. 2 LOAD_STR 'main'
2. 4 MAKE_FUNCTION_0 'Neither defaults, keyword-only args, annotations, nor closures'
1. store
6 STORE_NAME main
1. sstmt
call_stmt (2)
0. expr
call (2)
0. expr
L. 8 8 LOAD_NAME main
1. 10 CALL_FUNCTION_0 0 ''
1. 12 POP_TOP
---- end before transform
---- begin after transform
stmts (2)
0. function_def (2)
0. mkfunc (3)
0. L. 1 0 LOAD_CODE <code_object main>
1. 2 LOAD_STR 'main'
2. 4 MAKE_FUNCTION_0 'Neither defaults, keyword-only args, annotations, nor closures'
1. store
6 STORE_NAME main
1. call_stmt (2)
0. expr
call (2)
0. expr
L. 8 8 LOAD_NAME main
1. 10 CALL_FUNCTION_0 0 ''
1. 12 POP_TOP
stmts (2)
0. sstmt
assign (2)
0. expr
L. 2 0 LOAD_CONST 0.0
1. store
2 STORE_FAST 'total'
1. sstmt
for38 (4)
0. expr
call (3)
0. expr
L. 3 4 LOAD_GLOBAL enumerate
1. pos_arg
expr
call (3)
0. expr
6 LOAD_GLOBAL range
1. pos_arg
expr
8 LOAD_CONST 10000
2. 10 CALL_FUNCTION_1 1 ''
2. 12 CALL_FUNCTION_1 1 ''
1. get_for_iter (3)
0. 14 GET_ITER
1. _come_froms
2. 16 FOR_ITER 62 'to 62'
2. store
unpack (3)
0. 18 UNPACK_SEQUENCE_2 2
1. store
20 STORE_FAST 'i'
2. store
22 STORE_FAST '_'
3. for_block
l_stmts (2)
0. for38 (5)
0. expr
call (3)
0. expr
L. 4 24 LOAD_GLOBAL enumerate
1. pos_arg
expr
call (4)
0. expr
26 LOAD_GLOBAL range
1. pos_arg
expr
28 LOAD_CONST 1
2. pos_arg
expr
30 LOAD_CONST 10000
3. 32 CALL_FUNCTION_2 2 ''
2. 34 CALL_FUNCTION_1 1 ''
1. get_for_iter (3)
0. 36 GET_ITER
1. _come_froms
2. 38 FOR_ITER 60 'to 60'
2. store
unpack (3)
0. 40 UNPACK_SEQUENCE_2 2
1. store
42 STORE_FAST 'j'
2. store
44 STORE_FAST '_'
3. for_block (2)
0. l_stmts
aug_assign1 (4)
0. expr
L. 5 46 LOAD_FAST 'total'
1. expr
bin_op (3)
0. expr
48 LOAD_FAST 'i'
1. expr
50 LOAD_FAST 'j'
2. binary_operator
52 BINARY_MULTIPLY
2. inplace_op
54 INPLACE_ADD
3. store
56 STORE_FAST 'total'
1. 58 JUMP_BACK 38 'to 38'
4. 60 JUMP_BACK 16 'to 16'
1. lstmt
call_stmt (2)
0. expr
call (4)
0. expr
L. 6 62 LOAD_GLOBAL print
1. pos_arg
expr
64 LOAD_STR 'total='
2. pos_arg
expr
66 LOAD_FAST 'total'
3. 68 CALL_FUNCTION_2 2 ''
1. 70 POP_TOP
stmts (2)
0. assign (2)
0. expr
L. 2 0 LOAD_CONST 0.0
1. store
2 STORE_FAST 'total'
1. for38 (4)
0. expr
call (3)
0. expr
L. 3 4 LOAD_GLOBAL enumerate
1. pos_arg
expr
call (3)
0. expr
6 LOAD_GLOBAL range
1. pos_arg
expr
8 LOAD_CONST 10000
2. 10 CALL_FUNCTION_1 1 ''
2. 12 CALL_FUNCTION_1 1 ''
1. get_for_iter (3)
0. 14 GET_ITER
1. _come_froms
2. 16 FOR_ITER 62 'to 62'
2. store
unpack (3)
0. 18 UNPACK_SEQUENCE_2 2
1. store
20 STORE_FAST 'i'
2. store
22 STORE_FAST '_'
3. for_block
l_stmts (2)
0. for38 (5)
0. expr
call (3)
0. expr
L. 4 24 LOAD_GLOBAL enumerate
1. pos_arg
expr
call (4)
0. expr
26 LOAD_GLOBAL range
1. pos_arg
expr
28 LOAD_CONST 1
2. pos_arg
expr
30 LOAD_CONST 10000
3. 32 CALL_FUNCTION_2 2 ''
2. 34 CALL_FUNCTION_1 1 ''
1. get_for_iter (3)
0. 36 GET_ITER
1. _come_froms
2. 38 FOR_ITER 60 'to 60'
2. store
unpack (3)
0. 40 UNPACK_SEQUENCE_2 2
1. store
42 STORE_FAST 'j'
2. store
44 STORE_FAST '_'
3. for_block (2)
0. l_stmts
aug_assign1 (4)
0. expr
L. 5 46 LOAD_FAST 'total'
1. expr
bin_op (3)
0. expr
48 LOAD_FAST 'i'
1. expr
50 LOAD_FAST 'j'
2. binary_operator
52 BINARY_MULTIPLY
2. inplace_op
54 INPLACE_ADD
3. store
56 STORE_FAST 'total'
1. 58 JUMP_BACK 38 'to 38'
4. 60 JUMP_BACK 16 'to 16'
1. lstmt
call_stmt (2)
0. expr
call (4)
0. expr
L. 6 62 LOAD_GLOBAL print
1. pos_arg
expr
64 LOAD_STR 'total='
2. pos_arg
expr
66 LOAD_FAST 'total'
3. 68 CALL_FUNCTION_2 2 ''
1. 70 POP_TOP
def main
---- end before transform
---- begin after transform
():
total = 0.0
for i, _ in enumerate(range(10000)):
for j, _ in enumerate(range(1, 10000)):
total += i * j
print('total=', total)
main()
# okay decompiling __pycache__/s1.cpython-38.pyc
1.3. バイトコード命令
LOAD_GLOBAL
等のPythonインタープリターの命令が、121程度opcode.h
で定義されている。そして、その命令をceval.c
で処理する。
- dis --- Python バイトコードの逆アセンブラ
- Include/opcode.h
-
Python/ceval.c
-
LOAD_GLOBAL
等のPythonインタープリターの命令の処理がここで実装されている。 - また、コンパイル時に
OPCACHE_STATS
を設定するとLOAD_GLOBAL
のキャッシュヒット率等を見ることができる。
-