Документация Python неофициальный перевод
Содержание страницы

32.12. dis – Дизассемблер байт-кода Pythondis – Disassembler for Python bytecode

Исходный код: Lib/dis.py


Модуль dis поддерживает анализ байт-кода CPython путём eго дизассемблирования. Байт-код CPython, который этот модуль принимает на вход, определён в файле Include/opcode.h и используется компилятором и интерпретатором.

Особенность реализации CPython: Байт-код – деталь реализации интерпретатора CPython! Не гарантируется, что байт-код не будет добавлен, удалён или изменён в разных версиях Python. Не следует рассчитывать, что этот модуль будет работать в других виртуальных машинах Python или в других выпусках Python.

Пример: Дана функция myfunc():

def myfunc(alist):
    return len(alist)

следующая команда позволяет получить дизассемблированный код myfunc():

>>> dis.dis(myfunc)
  2           0 LOAD_GLOBAL              0 (len)
              3 LOAD_FAST                0 (alist)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE

(«2» – это номер строки).

Модуль dis определяет следующие функции и константы:

dis.dis([bytesource])

Дизассемблирует объект bytesource. bytesource может обозначать модуль, класс, метод, функцию или объект кода. Для модуля дизассемблируются все функции. Для класса – все методы. Для отдельной последовательности кода выводится одна строка на каждую инструкцию байткода. Если объект не указан, дизассемблируется последний traceback.

dis.distb([tb])

Дизассемблирует функцию на вершине стека traceback, используя последний traceback, если ни один не был передан. Инструкция, вызвавшая исключение, отмечается.

dis.disassemble(code[, lasti])

Дизассемблирует объект кода, указывая последнюю инструкцию, если был указан lasti. Вывод разделён на следующие столбцы:

  1. номер строки для первой инструкции каждой строки

  2. текущая инструкция, помечена как -->,

  3. инструкция с меткой, помечена >>,

  4. адрес инструкции,

  5. название кода операции,

  6. параметры операции и

  7. интерпретация параметров в скобках.

Интерпретация параметров распознаёт имена локальных и глобальных переменных, константные значения, цели переходов и операторы сравнения.

dis.disco(code[, lasti])

Синоним для disassemble(). Его удобнее набирать, и он сохранён для совместимости с более ранними версиями Python.

dis.findlinestarts(code)

Эта функция-генератор использует атрибуты co_firstlineno и co_lnotab объекта кода code для поиска смещений, соответствующих началам строк в исходном коде. Они возвращаются в виде пар (offset, lineno).

dis.findlabels(code)

Определяет все смещения в объекте кода code, которые являются целями перехода, и\nвозвращает список этих смещений.

dis.opname

Последовательность имён операций, индексируемая с помощью байткода.

dis.opmap

Словарь, сопоставляющий имена операций с байткодами.

dis.cmp_op

Последовательность всех имён операций сравнения.

dis.hasconst

Последовательность байткодов, обращающихся к константе.

dis.hasfree

Последовательность байткодов, обращающихся к свободной переменной.

dis.hasname

Последовательность байткодов, обращающихся к атрибуту по имени.

dis.hasjrel

Последовательность байткодов, имеющих относительную цель перехода.

dis.hasjabs

Последовательность байткодов, имеющих абсолютную цель перехода.

dis.haslocal

Последовательность байткодов, обращающихся к локальной переменной.

dis.hascompare

Последовательность байткодов логических операций.

32.12.1. Инструкции байт-кода PythonPython Bytecode Instructions

В настоящее время компилятор Python генерирует следующие инструкции байткода.

STOP_CODE()

Указывает компилятору на конец кода, не используется интерпретатором.

NOP()

Код, который ничего не делает. Используется в качестве заполнителя оптимизатором байт-кода.

POP_TOP()

Удаляет элемент с вершины стека (TOS).

ROT_TWO()

Меняет местами два верхних элемента стека.

ROT_THREE()

Поднимает второй и третий элементы стека на одну позицию вверх, перемещает верхний вниз на третью позицию.

ROT_FOUR()

Поднимает второй, третий и четвёртый элементы стека на одну позицию вверх, перемещает верхний элемент вниз на четвёртую позицию.

DUP_TOP()

Дублирует ссылку на вершине стека.

Унарные операции берут верхушку стека, применяют операцию и помещают результат обратно в стек.

UNARY_POSITIVE()

Реализует TOS = +TOS.

UNARY_NEGATIVE()

Реализует TOS = -TOS.

UNARY_NOT()

Реализует TOS = not TOS.

UNARY_CONVERT()

Реализует TOS = `TOS`.

UNARY_INVERT()

Реализует TOS = ~TOS.

GET_ITER()

Реализует TOS = iter(TOS).

Бинарные операции удаляют из стека элемент с вершины (TOS) и второй сверху элемент стека (TOS1). Они выполняют операцию и помещают результат обратно в стек.

BINARY_POWER()

Реализует TOS = TOS1 ** TOS.

BINARY_MULTIPLY()

Реализует TOS = TOS1 * TOS.

BINARY_DIVIDE()

Реализует TOS = TOS1 / TOS, когда from __future__ import division не действует.

BINARY_FLOOR_DIVIDE()

Реализует TOS = TOS1 // TOS.

BINARY_TRUE_DIVIDE()

Реализует TOS = TOS1 / TOS, когда from __future__ import division действует.

BINARY_MODULO()

Реализует TOS = TOS1 % TOS.

BINARY_ADD()

Реализует TOS = TOS1 + TOS.

BINARY_SUBTRACT()

Реализует TOS = TOS1 - TOS.

BINARY_SUBSCR()

Реализует TOS = TOS1[TOS].

BINARY_LSHIFT()

Реализует TOS = TOS1 << TOS.

BINARY_RSHIFT()

Реализует TOS = TOS1 >> TOS.

BINARY_AND()

Реализует TOS = TOS1 & TOS.

BINARY_XOR()

Реализует TOS = TOS1 ^ TOS.

BINARY_OR()

Реализует TOS = TOS1 | TOS.

Операции на месте аналогичны бинарным: они также удаляют TOS и TOS1 и помещают результат обратно в стек, но операция выполняется на месте, если TOS1 это поддерживает, и результирующий TOS может (но не обязан) быть исходным TOS1.

INPLACE_POWER()

Реализует операцию на месте TOS = TOS1 ** TOS.

INPLACE_MULTIPLY()

Реализует операцию на месте TOS = TOS1 * TOS.

INPLACE_DIVIDE()

Реализует TOS = TOS1 / TOS на месте, когда from __future__ import division не действует.

INPLACE_FLOOR_DIVIDE()

Реализует операцию на месте TOS = TOS1 // TOS.

INPLACE_TRUE_DIVIDE()

Реализует TOS = TOS1 / TOS на месте, когда from __future__ import division действует.

INPLACE_MODULO()

Реализует операцию на месте TOS = TOS1 % TOS.

INPLACE_ADD()

Реализует операцию на месте TOS = TOS1 + TOS.

INPLACE_SUBTRACT()

Реализует операцию на месте TOS = TOS1 - TOS.

INPLACE_LSHIFT()

Реализует операцию на месте TOS = TOS1 << TOS.

INPLACE_RSHIFT()

Реализует операцию на месте TOS = TOS1 >> TOS.

INPLACE_AND()

Реализует операцию на месте TOS = TOS1 & TOS.

INPLACE_XOR()

Реализует операцию на месте TOS = TOS1 ^ TOS.

INPLACE_OR()

Реализует операцию на месте TOS = TOS1 | TOS.

Опкоды среза принимают до трёх параметров.

SLICE+0()

Реализует TOS = TOS[:].

SLICE+1()

Реализует TOS = TOS1[TOS:].

SLICE+2()

Реализует TOS = TOS1[:TOS].

SLICE+3()

Реализует TOS = TOS2[TOS1:TOS].

Присваивание среза требует ещё один дополнительный параметр. Как и любая инструкция, они ничего не помещают в стек.

STORE_SLICE+0()

Реализует TOS[:] = TOS1.

STORE_SLICE+1()

Реализует TOS1[TOS:] = TOS2.

STORE_SLICE+2()

Реализует TOS1[:TOS] = TOS2.

STORE_SLICE+3()

Реализует TOS2[TOS1:TOS] = TOS3.

DELETE_SLICE+0()

Реализует del TOS[:].

DELETE_SLICE+1()

Реализует del TOS1[TOS:].

DELETE_SLICE+2()

Реализует del TOS1[:TOS].

DELETE_SLICE+3()

Реализует del TOS2[TOS1:TOS].

STORE_SUBSCR()

Реализует TOS1[TOS] = TOS2.

DELETE_SUBSCR()

Реализует del TOS1[TOS].

Разные опкоды.

PRINT_EXPR()

Реализует выражение-инструкцию для интерактивного режима. TOS удаляется из стека и выводится на печать. В неинтерактивном режиме выражение-инструкция завершается с помощью POP_TOP.

PRINT_ITEM()

Выводит TOS в файлоподобный объект, связанный с sys.stdout. Есть одна такая инструкция для каждого элемента в операторе print.

PRINT_ITEM_TO()

Как PRINT_ITEM, но выводит элемент, второй от TOS, в файлоподобный объект на TOS. Это используется расширенным оператором print.

PRINT_NEWLINE()

Выводит новую строку на sys.stdout. Это генерируется как последняя операция оператора print, если только оператор не заканчивается запятой.

PRINT_NEWLINE_TO()

Как PRINT_NEWLINE, но выводит новую строку в файлоподобный объект на TOS. Это используется расширенным оператором print.

BREAK_LOOP()

Завершает цикл при выполнении оператора break.

CONTINUE_LOOP(target)

Продолжает цикл при выполнении оператора continue. target – это адрес, на который нужно перейти (должен быть инструкция FOR_ITER).

LIST_APPEND(i)

Вызывает list.append(TOS[-i], TOS). Используется для реализации списковых включений. Хотя добавленное значение извлекается из стека, объект списка остаётся в стеке, чтобы быть доступным для последующих итераций цикла.

LOAD_LOCALS()

Помещает ссылку на локальные переменные текущей области видимости в стек. Это используется в коде для определения класса: после вычисления тела класса локальные переменные передаются определению класса.

RETURN_VALUE()

Возвращает TOS вызывающей стороне функции.

YIELD_VALUE()

Извлекает TOS из стека и выдаёт его из генератор.

IMPORT_STAR()

Загружает все имена, не начинающиеся с '_', из модуля TOS в локальное пространство имён. Модуль удаляется после загрузки всех имён. Этот опкод реализует from module import *.

EXEC_STMT()

Реализует exec TOS2,TOS1,TOS. Компилятор заполняет отсутствующие необязательные параметры значением None.

POP_BLOCK()

Удаляет один блок из стека блоков. В каждом фрейме есть стек блоков, представляющий вложенные циклы, операторы try и т.п.

END_FINALLY()

Завершает предложение finally. Интерпретатор запоминает, нужно ли повторно возбуждать исключение или функция возвращает значение, и продолжает со следующим внешним блоком.

BUILD_CLASS()

Создаёт новый объект класса. TOS – словарь методов, TOS1 – кортеж имён базовых классов, а TOS2 – имя класса.

SETUP_WITH(delta)

Эта инструкция выполняет несколько операций перед началом блока with. Во-первых, она загружает __exit__() из менеджера контекста и помещает его в стек для последующего использования WITH_CLEANUP. Затем вызывается __enter__(), и в стек помещается блок finally, указывающий на delta. Наконец, результат вызова метода enter помещается в стек. Следующая инструкция либо игнорирует его (POP_TOP), либо сохраняет в переменную(ые) (STORE_FAST, STORE_NAME или UNPACK_SEQUENCE).

WITH_CLEANUP()

Очищает стек при выходе из блока оператора with. На вершине стека находятся 1–3 значения, указывающие, как/почему был выполнен блок finally:

  • TOP = None

  • (TOP, SECOND) = (WHY_{RETURN,CONTINUE}), retval

  • TOP = WHY_*; retval под ним отсутствует

  • (TOP, SECOND, THIRD) = exc_info()

Под ними находится EXIT, привязанный метод __exit__() менеджера контекста.

В последнем случае вызывается EXIT(TOP, SECOND, THIRD), иначе EXIT(None, None, None).

ВЫХОД удаляется из стека, оставляя значения над ним в том же порядке. Кроме того, если стек представляет исключение, и вызов функции возвращает «истинное» значение, эта информация «стирается», чтобы предотвратить повторное возбуждение исключения через END_FINALLY. (Но нелокальные переходы всё же следует возобновлять.)

Все следующие опкоды требуют аргументов. Аргумент занимает два байта, причём старший байт идёт последним.

STORE_NAME(namei)

Реализует name = TOS. namei – это индекс name в атрибуте co_names объекта кода. Компилятор пытается использовать STORE_FAST или STORE_GLOBAL, если возможно.

DELETE_NAME(namei)

Реализует del name, где namei – это индекс в атрибут co_names объекта кода.

UNPACK_SEQUENCE(count)

Распаковывает TOS в count отдельных значений, которые помещаются в стек справа налево.

DUP_TOPX(count)

Дублирует count элементов, сохраняя их порядок. Из-за ограничений реализации count должен быть от 1 до 5 включительно.

STORE_ATTR(namei)

Реализует TOS.name = TOS1, где namei – это индекс имени в co_names.

DELETE_ATTR(namei)

Реализует del TOS.name, используя namei как индекс в co_names.

STORE_GLOBAL(namei)

Работает как STORE_NAME, но сохраняет имя как глобальное.

DELETE_GLOBAL(namei)

Работает как DELETE_NAME, но удаляет глобальное имя.

LOAD_CONST(consti)

Помещает co_consts[consti] в стек.

LOAD_NAME(namei)

Помещает значение, связанное с co_names[namei], в стек.

BUILD_TUPLE(count)

Создаёт кортеж, потребляя count элементов из стека, и помещает полученный кортеж в стек.

BUILD_LIST(count)

Работает как BUILD_TUPLE, но создаёт список.

BUILD_SET(count)

Работает как BUILD_TUPLE, но создаёт множество.

Новое в версии 2.7.

BUILD_MAP(count)

Помещает новый объект словаря в стек. Словарь предварительно настраивается на хранение count записей.

LOAD_ATTR(namei)

Заменяет TOS на getattr(TOS, co_names[namei]).

COMPARE_OP(opname)

Выполняет логическую операцию. Имя операции можно найти в cmp_op[opname].

IMPORT_NAME(namei)

Импортирует модуль co_names[namei]. TOS и TOS1 извлекаются и предоставляют аргументы fromlist и level для __import__(). Объект модуля помещается в стек. Текущее пространство имён не затрагивается: для корректного оператора import последующая инструкция STORE_FAST изменяет пространство имён.

IMPORT_FROM(namei)

Загружает атрибут co_names[namei] из модуля, находящегося в TOS. Полученный объект помещается в стек для последующего сохранения инструкцией STORE_FAST.

JUMP_FORWARD(delta)

Увеличивает счётчик байт-кода на delta.

POP_JUMP_IF_TRUE(target)

Если TOS истинно, устанавливает счётчик байткода в target. TOS извлекается из стека.

POP_JUMP_IF_FALSE(target)

Если TOS ложно, устанавливает счётчик байткода в target. TOS извлекается из стека.

JUMP_IF_TRUE_OR_POP(target)

Если TOS истинно, устанавливает счётчик байткода в target и оставляет TOS на стеке. В противном случае (TOS ложно) TOS извлекается.

JUMP_IF_FALSE_OR_POP(target)

Если TOS ложно, устанавливает счётчик байткода в target и оставляет TOS на стеке. В противном случае (TOS истинно) TOS извлекается.

JUMP_ABSOLUTE(target)

Устанавливает счётчик байткода в target.

FOR_ITER(delta)

TOS – это итератор. Вызвать его метод next(). Если он возвращает новое значение, поместить его в стек (оставив итератор под ним). Если итератор сообщает, что он исчерпан, TOS извлекается, и счётчик байткода увеличивается на delta.

LOAD_GLOBAL(namei)

Загружает глобальную переменную co_names[namei] в стек.

SETUP_LOOP(delta)

Помещает блок для цикла в стек блоков. Блок начинается с текущей инструкции и имеет размер delta байт.

SETUP_EXCEPT(delta)

Помещает блок try из конструкции try-except в стек блоков. delta указывает на первый блок except.

SETUP_FINALLY(delta)

Pushes a try block from a try-except clause onto the block stack. delta points to the finally block.

STORE_MAP()

Сохраняет пару ключ-значение в словаре. Извлекает ключ и значение, оставляя словарь в стеке.

LOAD_FAST(var_num)

Помещает ссылку на локальную переменную co_varnames[var_num] в стек.

STORE_FAST(var_num)

Сохраняет TOS в локальную переменную co_varnames[var_num].

DELETE_FAST(var_num)

Удаляет локальную переменную co_varnames[var_num].

LOAD_CLOSURE(i)

Помещает ссылку на ячейку, содержащуюся в слоте i хранилища ячеек и свободных переменных. Имя переменной – co_cellvars[i], если i меньше длины co_cellvars. В противном случае – co_freevars[i - len(co_cellvars)].

LOAD_DEREF(i)

Загружает ячейку, содержащуюся в слоте i хранилища ячеек и свободных переменных. Помещает ссылку на объект, который содержит ячейка, в стек.

STORE_DEREF(i)

Сохраняет TOS в ячейку, содержащуюся в слоте i хранилища ячеек и свободных переменных.

SET_LINENO(lineno)

Этот опкод устарел.

RAISE_VARARGS(argc)

Вызывает исключение. argc указывает количество аргументов инструкции raise, от 0 до 3. Обработчик находит traceback как TOS2, параметр как TOS1, а исключение как TOS.

CALL_FUNCTION(argc)

Вызывает вызываемый объект. Младший байт argc указывает количество позиционных аргументов, старший байт – количество именованных аргументов. Стек содержит именованные аргументы сверху (если есть), затем позиционные аргументы под ними (если есть), затем вызываемый объект под ними. Каждый именованный аргумент представлен двумя значениями в стеке: имя аргумента и его значение, при этом значение аргумента находится выше имени в стеке. Позиционные аргументы помещаются в стек в порядке передачи вызываемому объекту, причём самый правый позиционный аргумент – сверху. CALL_FUNCTION извлекает все аргументы и вызываемый объект из стека, вызывает вызываемый объект с этими аргументами и помещает возвращаемое значение, возвращённое вызываемым объектом.

MAKE_FUNCTION(argc)

Помещает новый объект функции в стек. TOS – это код, связанный с функцией. Функция определяется как имеющая argc параметров по умолчанию, которые находятся ниже TOS.

MAKE_CLOSURE(argc)

Создаёт новый объект функции, устанавливает его слот func_closure и помещает его в стек. TOS – это код, связанный с функцией, TOS1 – кортеж, содержащий ячейки для свободных переменных замыкания. Функция также имеет argc параметров по умолчанию, которые находятся ниже ячеек.

BUILD_SLICE(argc)

Помещает объект среза в стек. argc должен быть 2 или 3. Если равно 2, помещается slice(TOS1, TOS); если 3, помещается slice(TOS2, TOS1, TOS). Подробнее см. встроенную функцию slice().

EXTENDED_ARG(ext)

Добавляет префикс к любой опкоду, чей аргумент слишком велик, чтобы поместиться в стандартные два байта. ext содержит два дополнительных байта, которые вместе с аргументом последующего опкода образуют четырёхбайтовый аргумент, причём ext является двумя старшими байтами.

CALL_FUNCTION_VAR(argc)

Вызывает вызываемый объект, аналогично CALL_FUNCTION. argc представляет количество ключевых и позиционных аргументов, так же как CALL_FUNCTION. Вершина стека содержит итерируемый объект с дополнительными позиционными аргументами. Под ним находятся ключевые аргументы (если есть), позиционные аргументы (если есть) и вызываемый объект, так же как CALL_FUNCTION. Перед вызовом вызываемого объекта итерируемый объект «распаковывается», и его содержимое добавляется к переданным позиционным аргументам. Итерируемый объект игнорируется при вычислении значения argc.

CALL_FUNCTION_KW(argc)

Вызывает вызываемый объект, аналогично CALL_FUNCTION. argc представляет количество ключевых и позиционных аргументов, так же как CALL_FUNCTION. Вершина стека содержит отображение (mapping) с дополнительными ключевыми аргументами. Под ним находятся ключевые аргументы (если есть), позиционные аргументы (если есть) и вызываемый объект, так же как CALL_FUNCTION. Перед вызовом вызываемого объекта отображение на вершине стека «распаковывается», и его содержимое добавляется к переданным ключевым аргументам. Отображение на вершине стека игнорируется при вычислении значения argc.

CALL_FUNCTION_VAR_KW(argc)

Вызывает вызываемый объект, аналогично CALL_FUNCTION_VAR и CALL_FUNCTION_KW. argc представляет количество ключевых и позиционных аргументов, так же как CALL_FUNCTION. Вершина стека содержит отображение, как в CALL_FUNCTION_KW. Под ним находится итерируемый объект, как в CALL_FUNCTION_VAR. Под ними находятся ключевые аргументы (если есть), позиционные аргументы (если есть) и вызываемый объект, так же как CALL_FUNCTION. Перед вызовом вызываемого объекта отображение и итерируемый объект «распаковываются», и их содержимое передаётся как ключевые и позиционные аргументы соответственно, так же как в CALL_FUNCTION_VAR и CALL_FUNCTION_KW. Отображение и итерируемый объект игнорируются при вычислении значения argc.

HAVE_ARGUMENT()

Это не совсем опкод. Он определяет разделительную линию между опкодами, которые не принимают аргументы < HAVE_ARGUMENT, и теми, которые принимают >= HAVE_ARGUMENT.