Байт-код
- 1 year ago
- 0
- 0
Байт-код ( байтко́д ; англ. bytecode , также иногда p-код , p-code от portable code ) — стандартное промежуточное представление , в которое может быть переведена компьютерная программа автоматическими средствами. По сравнению с исходным кодом , удобным для создания и чтения человеком, байт-код — это компактное представление программы, уже прошедшей синтаксический и семантический анализ. В нём в явном виде закодированы типы , области видимости и другие конструкции. С технической точки зрения байт-код представляет собой машинно-независимый код низкого уровня , генерируемый транслятором из исходного кода.
Многие современные языки программирования , особенно интерпретируемые , используют байт-код для облегчения и ускорения работы интерпретатора . Трансляция в байт-код является методом, промежуточным по эффективности между прямой интерпретацией и компиляцией в машинный код.
По форме байт-код похож на машинный код , но предназначен для исполнения не реальным процессором , а виртуальной машиной . В качестве виртуальной машины обычно выступает интерпретатор соответствующего языка программирования (иногда дополненный JIT- или AOT-компилятором ). Спецификации байт-кода и исполняющих его виртуальных машин могут сильно различаться для разных языков: часто байт-код состоит из инструкций для виртуальной машины , однако могут использоваться и машины . Тем не менее, большинство инструкций байт-кода обычно эквивалентны одной или нескольким командам ассемблера .
Байт-код называется так, потому что длина каждого кода операции традиционно составляет один байт . Каждая инструкция обычно представляет собой однобайтовый код операции (от 0 до 255), за которым могут следовать различные параметры, например, номер регистра или адрес в памяти.
Программа на байт-коде обычно выполняется интерпретатором байт-кода . Преимущество байт-кода в большей эффективности и портируемости , то есть один и тот же байт-код может исполняться на разных архитектурах , для которых реализован интерпретатор. То же самое преимущество дают непосредственно интерпретируемые языки, однако, поскольку байт-код обычно менее абстрактен и более компактен, чем исходный код, эффективность интерпретации байт-кода обычно выше, чем чистая интерпретация исходного кода или интерпретация АСД . Кроме того, интерпретатор байт-кода зачастую проще интерпретатора исходного кода и его проще перенести (портировать) на другую аппаратную платформу.
В высокопроизводительных реализациях виртуальных машин может применяться комбинация интерпретатора и JIT-компилятора , который во время исполнения программы транслирует часто используемые фрагменты байт-кода в машинный код, применяя при этом различные оптимизации. Вместо JIT-компиляции может применяться AOT-компилятор , транслирующий байт-код в машинный код предварительно, до исполнения.
В то же время возможно создание процессоров, для которых данный байт-код является непосредственно машинным кодом (такие экспериментальные процессоры создавались, например, для языков Java и Форт ).
Среди первых систем, использовавших байт-код, были O-code для BCPL (1960-е), Smalltalk (1976) , SIL (System Implementation Language) для языка Snobol-4 (1967), p-код ( p-code , 1970-е, при участии Никлауса Вирта ) для переносимых компиляторов языка программирования Pascal .
Варианты p-кода широко использовались в различных реализациях языка Pascal, например, в UCSD p-System ( UCSD Pascal ).
К интерпретируемым языкам, использующим байт-код, относятся Perl , PHP (например Zend Engine ), Ruby (начиная с версии 1.9), Python , Erlang и многие другие.
Широко распространённые платформы, использующие байт-код :
Компилятор Clipper создает исполняемый файл, в который включен байт-код, транслированный из исходного текста программы, и виртуальная машина, исполняющая этот байт-код.
Программы на Java обычно компилируются в байт-код Java . Эти универсальные файлы передаются на различные целевые машины.
, содержащиеВ ранних реализациях Visual Basic (до версии 6) использовался высокоуровневый
Высокоуровневые p-коды и байт коды применялись в СУБД , некоторых реализациях Бейсика и Паскаля .
В стандарте открытых загрузчиков Open Firmware фирмы Sun Microsystems байт-код представляет операторы языка Форт .
Код:
>>> print("Hello, World!")
Hello, World!
Байт-код:
>>> import dis #импортируем модуль "dis" - Disassembler of Python byte code into mnemonics.
>>> dis.dis('print("Hello, World!")')
1 0 LOAD_NAME 0 (print)
2 LOAD_CONST 0 ('Hello, World!')
4 CALL_FUNCTION 1
6 RETURN_VALUE
Код:
outer:
for (int i = 2; i < 1000; i++) {
for (int j = 2; j < i; j++) {
if (i % j == 0)
continue outer;
}
System.out.println(i);
}
Байт-код:
0: iconst_2
1: istore_1
2: iload_1
3: sipush 1000
6: if_icmpge 44
9: iconst_2
10: istore_2
11: iload_2
12: iload_1
13: if_icmpge 31
16: iload_1
17: iload_2
18: irem
19: ifne 25
22: goto 38
25: iinc 2, 1
28: goto 11
31: getstatic #84; //Field java/lang/System.out:Ljava/io/PrintStream;
34: iload_1
35: invokevirtual #85; //Method java/io/PrintStream.println:(I)V
38: iinc 1, 1
41: goto 2
44: return
Традиционно байт-код проектируется в стиле стековых виртуальных машин, что упрощает генерацию из AST , позволяет использовать более простую и компактную кодировку байт-кода, упростить интерпретатор и уменьшить количество машинного кода, требуемого для исполнения одной инструкции байт-кода. С другой стороны, такие варианты байт-кода для заданной программы содержат большее количество инструкций, чем байт-коды регистровых виртуальных машин, из-за чего интерпретатор должен совершить больше непрямых переходов, для которых плохо работает предсказание переходов . Байт-код для регистровых виртуальных машин имеет немного больший размер машинных кодов, однако количество инструкций по сравнению со стековым байт кодом примерно в два раза меньше, а интерпретатор — быстрее на десятки процентов . Также байт-код стековых машин сложнее для проведения оптимизаций (выражения становятся неявными, связанные инструкции не сгруппированы, выражения распределены по нескольким базовым блокам ) и требует верификации корректности использования стека .
Ошибки верификации байт-кода стековых машин приводили к появлению множества экстремально опасных уязвимостей, в частности десятков в виртуальной машине AVM2, используемой в Adobe Flash для исполнения скриптов ActionScript и нескольких в ранних популярных системах исполнения Java (JVM)
В конце 2000-х — начале 2010-х авторы компиляторов V8 (для языка JavaScript, часто реализуемого через байт-код) и Dart усомнились в том, что промежуточные байт-коды обязательны для быстрых и эффективных виртуальных машин. В этих проектах была реализована непосредственная JIT-компиляция (компиляция во время исполнения) из исходных кодов сразу в машинный код.