第一个信息:常量1在python内部,它是个对象,这个对象的类型是PyLong_Type型,这是Python的整型内部实现 另外,该对象的引用数是 126 个,说明这个常量对象其实是被共享的,LOAD_CONST 指令会让它的引用数加 1。我们用的常数是 1,这个值在 Python 内部也是会经常被用到,所以引用数会这么高。 进一步发现,往栈里放...
读取第三条字节码指令,操作码等于 100,此时是 LOAD_CONST 这条指令,那么此时的操作码等于 arg += 65,因为操作码不是 EXTENDED_ARG 因此操作数不需要在乘以 256 了。 上面的计算过程用程序代码表示如下,下面的代码当中 code 就是真正的字节序列 HAVE_ARGUMENT = 90 。 def _unpack_opargs(code): extended_arg...
为了LOAD_CONST,有2个空洞需要填补,即oparg和下一条指令:static const Hole _LOAD_CONST_code_holes[3] = {{0xd, HoleKind_X86_64_RELOC_UNSIGNED, HoleValue_OPARG, NULL, 0x0},{0x46, HoleKind_X86_64_RELOC_UNSIGNED, HoleValue_CONTINUE, NULL, 0x0},};然后,所有机器代码都作为字节序列存储在...
2、LOAD_CONST 1:带入 co_consts 在索引 1 上的字面值,并将它推入(索引 0 上的字面值是 None,它表示在 co_consts 中,因为 Python 函数调用有一个隐式的返回值 None,如果没有显式的返回表达式,就返回这个隐式的值 )。 3、CALL_FUNCTION 1:告诉 Python 去调用一个函数;它需要从栈中弹出一个位置参数,然...
当从源代码编译CPython时,可以提供一个标志--enable-experimental-jit到配置脚本。这将为Python字节码生成机器代码模板。这是通过首先复制每个字节码的C代码来实现的,例如最简单的LOAD_CONST: frame->instr_ptr = next_instr;next_instr += 1;INSTRUCTION_STATS(LOAD_CONST);PyObject *value;value = GETITEM(FRAME...
LOAD_CONST 最简单的应该是LOAD_CONST(consti)了,会取出co_consts里的第consti个值。 可以看到,LOAD_CONST(1),对应了co_consts[1],就是100;LOAD_CONST(2),对应了一个字符串,而LOAD_CONST(0),恰好就是None。可以看到,与dis的输出的对应行的最后面的括号里的东西完全对应。 LOAD_NAME LOAD_NAME(namei)加载...
10 LOAD_CONST 1 ('running fun2') 12 CALL_FUNCTION 1 14 POP_TOP 5 16 LOAD_GLOBAL 2 (fun1) 18 CALL_FUNCTION 0 20 POP_TOP 7 22 LOAD_GLOBAL 3 (inspect) 24 LOAD_ATTR 4 (currentframe) 26 CALL_FUNCTION 0 28 STORE_GLOBAL 5 (y) ...
“a,b=b,a”操作:两个 LOAD_FAST 是从局部作用域中读取变量的引用,并存入栈中,接着是最关键的 ROT_TWO 操作,它会交换两个变量的引用值,然后两个 STORE_FAST 是将栈中的变量写入局部作用域中。 “a,b=1,2”操作:第一步 LOAD_CONST 把“=”号右侧的两个数字作为元组放到栈中,第二步 UNPACK_SEQUENCE...
“a,b=b,a”操作:两个 LOAD_FAST 是从局部作用域中读取变量的引用,并存入栈中,接着是最关键的 ROT_TWO 操作,它会交换两个变量的引用值,然后两个 STORE_FAST 是将栈中的变量写入局部作用域中。“a,b=1,2”操作:第一步 LOAD_CONST 把“=”号右侧的两个数字作为元组放到栈中,第二步 UNPACK_...
其中的LOAD_NAME、LOAD_CONST、BINARY_ADD和RETURN_VALUE都是字节码的指令。 Python 和 Java 的虚拟机一样,都是基于栈的虚拟机。所以,它们的指令也很相似。比如,加法操作的指令是不需要带操作数的,因为只需要取出栈顶的两个元素相加,把结果再放回栈顶就行了。