This article needs additional citations for verification. (January 2009) |
Program execution |
---|
General concepts |
Types of code |
Compilation strategies |
Notable runtimes |
|
Notable compilers & toolchains |
|
Байт-код (также называемый переносимым кодом или p-кодом ) — это форма набора инструкций, разработанная для эффективного выполнения программным интерпретатором . В отличие от исходного кода , читаемого человеком [1] , байт-коды представляют собой компактные числовые коды, константы и ссылки (обычно числовые адреса), которые кодируют результат синтаксического анализа компилятором и выполнения семантического анализа таких вещей, как тип, область действия и глубина вложенности объектов программы.
Название байт-код происходит от наборов инструкций, которые имеют однобайтовые коды операций, за которыми следуют необязательные параметры. Промежуточные представления, такие как байт-код, могут выводиться реализациями языка программирования для облегчения интерпретации , или они могут использоваться для уменьшения зависимости от оборудования и операционной системы , позволяя одному и тому же коду работать кроссплатформенно , на разных устройствах. Байт-код часто может быть либо напрямую выполнен на виртуальной машине ( машина p-кода , т. е. интерпретатор), либо он может быть дополнительно скомпилирован в машинный код для лучшей производительности.
Поскольку инструкции байт-кода обрабатываются программным обеспечением, они могут быть произвольно сложными, но тем не менее часто схожи с традиционными аппаратными инструкциями: виртуальные стековые машины являются наиболее распространенными, но были также построены виртуальные регистровые машины . [2] [3] Различные части часто могут храниться в отдельных файлах, похожих на объектные модули , но динамически загружаемых во время выполнения.
Программа байт-кода может быть выполнена путем разбора и непосредственного выполнения инструкций по одной за раз. Этот вид интерпретатора байт-кода очень портативен. Некоторые системы, называемые динамическими трансляторами или компиляторами just-in-time (JIT), транслируют байт-код в машинный код по мере необходимости во время выполнения . Это делает виртуальную машину аппаратно-зависимой, но не теряет переносимости байт-кода. Например, код Java и Smalltalk обычно хранится в формате байт-кода, который обычно затем компилируется JIT для трансляции байт-кода в машинный код перед выполнением. Это вносит задержку перед запуском программы, когда байт-код компилируется в машинный код, но значительно повышает скорость выполнения по сравнению с интерпретацией исходного кода напрямую, обычно примерно на порядок (в 10 раз). [4]
Из-за его преимущества в производительности, сегодня многие реализации языка выполняют программу в два этапа, сначала компилируя исходный код в байт-код, а затем передавая байт-код в виртуальную машину. Существуют виртуальные машины на основе байт-кода такого рода для Java , Raku , Python , PHP , [a] Tcl , mawk и Forth (однако Forth редко компилируется через байт-коды таким образом, и его виртуальная машина вместо этого более общая). Реализации Perl и Ruby 1.8 вместо этого работают, проходя по абстрактному синтаксическому древовидному представлению, полученному из исходного кода.
Совсем недавно авторы V8 [1] и Dart [7] оспорили идею о том, что промежуточный байт-код необходим для быстрой и эффективной реализации VM. Обе эти реализации языка в настоящее время выполняют прямую JIT-компиляцию из исходного кода в машинный код без промежуточного байт-кода. [8]
disassemble
функцию [10] , которая выводит на стандартный вывод базовый код указанной функции. Результат зависит от реализации и может быть разрешен или не разрешен в байт-код. Его проверка может использоваться для отладки и оптимизации. [11] Steel Bank Common Lisp , например, выдает:( дизассемблировать ' ( lambda ( x ) ( print x ))) ; дизассемблирование для (LAMBDA (X)) ; 2436F6DF: 850500000F22 TEST EAX, [#x220F0000] ; точка входа без аргументов для анализа ; E5: 8BD6 MOV EDX, ESI ; E7: 8B05A8F63624 MOV EAX, [#x2436F6A8] ; #<объект FDEFINITION для PRINT> ; ED: B904000000 MOV ECX, 4 ; F2: FF7504 PUSH DWORD PTR [EBP+4] ; F5: FF6005 JMP DWORD PTR [EAX+5] ; F8: CC0A BREAK 10 ; ловушка ошибки ; FA: 02 БАЙТ #X02 ; FB: 18 БАЙТ #X18 ; НЕВЕРНЫЙ-АРГ-СЧЕТЧИК-ОШИБКА ; FC: 4F БАЙТ #X4F ; ECX
>>> import dis # "dis" - Дизассемблер байт-кода Python в мнемонические символы. >>> dis . dis ( 'print("Hello, World!")' ) 1 0 LOAD_NAME 0 (print) 2 LOAD_CONST 0 ('Hello, World!') 4 CALL_FUNCTION 1 6 RETURN_VALUE
[…] Фактически, формат в основном тот же самый в
MS-DOS
3.3 - 8.0,
PC DOS
3.3 - 2000, включая русские, литовские, китайские и японские выпуски, а также в Windows NT, 2000 и XP […]. Есть незначительные различия и несовместимости, но общий формат не менялся на протяжении многих лет. […] Некоторые записи данных содержат обычные таблицы […] Однако большинство записей содержат
исполняемый код
, интерпретируемый каким-либо
интерпретатором p-кода
во *
время выполнения
*, включая условные переходы и тому подобное. Вот почему драйвер
KEYB
занимает такой большой объем памяти по сравнению с табличными драйверами клавиатуры, которые можно реализовать за 3–4 Кб, получив тот же уровень функциональности, за исключением интерпретатора. […]
[…] Маттиас [Р.] Пол […] предупреждает, что версия драйвера клавиатуры
для IBM PC DOS
использует некоторые внутренние процедуры, которые не распознаются драйвером
Microsoft
, поэтому, если возможно, следует использовать
версии
IBM
KEYB.COM
и
KEYBOARD.SYS
вместо смешивания версий Microsoft и IBM […]
(Примечание. Под «процедурами» здесь подразумеваются некоторые дополнительные байт-коды в файле IBM KEYBOARD.SYS, не поддерживаемые версией драйвера KEYB от Microsoft.)
Multiplan
не был скомпилирован в
машинный код
, а в своего рода байт-код, который запускался интерпретатором
,
чтобы сделать Multiplan переносимым на широко варьирующееся оборудование того времени. Этот байт-код различал машинно-специфический
формат с плавающей точкой
для вычислений и внешний (стандартный) формат, который был
двоично-десятичным
(BCD). Инструкции PACK и UNPACK преобразовывались между ними.