Байт-код

Поделись знанием:
Перейти к: навигация, поиск

В программировании, байт-код или байтко́д (англ. bytecode или p-code от portable code) — это промежуточное представление[en], в которое может быть переведена компьютерная программа. По сравнению с исходным кодом, удобным для создания и чтения человеком, байт-код — это компактное представление программы, уже прошедшей синтаксический и семантический анализ. В нём в явном виде закодированы типы, области видимости и т. п. С технической точки зрения, байт-код представляет собой машинно-независимый код низкого уровня, генерируемый транслятором из исходного кода.

Многие современные языки программирования, особенно интерпретируемые, используют байт-код для облегчения и ускорения работы интерпретатора. Трансляция в байт-код является методом, промежуточным по эффективности между прямой интерпретацией и компиляцией в машинный код.

По форме байт-код похож на машинный код, но предназначен для исполнения не реальным процессором, а виртуальной машиной. В качестве виртуальной машины обычно выступает интерпретатор соответствующего языка программирования (иногда дополненный JIT- или AOT-компилятором). Спецификации байт-кода и исполняющих его виртуальных машин могут сильно различаться для разных языков: часто байт-код состоит из инструкций для стековой[en] виртуальной машины[1], однако могут использоваться и регистровые[en] машины[2][3]. Тем не менее, большинство инструкций байт-кода обычно эквивалентны одной или нескольким командам ассемблера.

Байт-код называется так, потому что длина каждого кода операции традиционно составляет один байт. Каждая инструкция обычно представляет собой однобайтовый код операции (от 0 до 255), за которым могут следовать различные параметры, например, номер регистра или адрес в памяти.





Исполнение

Программа на байт-коде обычно выполняется интерпретатором байт-кода. Преимущество байт-кода в большей эффективности и портируемости, то есть один и тот же байт-код может исполняться на разных платформах и архитектурах, для которых реализован интерпретатор. То же самое преимущество дают непосредственно интерпретируемые языки, однако, поскольку байт-код обычно менее абстрактен и более компактен, чем исходный код, эффективность интерпретации байт-кода обычно выше, чем чистая интерпретация исходного кода или интерпретация АСД. Кроме того, интерпретатор байт-кода зачастую проще интерпретатора исходного кода и его проще перенести (портировать) на другую аппаратную платформу.

В высокопроизводительных реализациях виртуальных машин может применяться комбинация интерпретатора и JIT-компилятора, который во время исполнения программы транслирует часто используемые фрагменты байт-кода в машинный код, применяя при этом различные оптимизации. Вместо JIT-компиляции может применяться AOT-компилятор, транслирующий байт-код в машинный код предварительно, до исполнения.

В то же время возможно создание процессоров, для которых данный байт-код является непосредственно машинным кодом (такие экспериментальные процессоры создавались, например, для языков Java и Форт).

История

Среди первых систем, использовавших байт-код, были O-code для BCPL (1960-е), Smalltalk (1976)[4], SIL (System Implementation Language) для языка Snobol-4 (1967), p-код (p-code, 1970-е, при участии Никлауса Вирта) для переносимых компиляторов языка программирования Pascal[5][6][7].

Варианты p-кода широко использовались в различных реализациях языка Pascal, например, в UCSD p-System (UCSD Pascal).[8]

Примеры

К интерпретируемым языкам, использующим байт-код, относятся Perl, PHP (например Zend Engine), Ruby (начиная с версии 1.9), Python, Erlang и многие другие.

Чрезвычайно широко распространены платформы, использующие байт-коды[9]:

  • Байт-код Java (стековая виртуальная машина), исполняемый различными виртуальными машинами Java (англ. Java Virtual Machine, JVM)[10][11]. Платформа была создана компанией Sun для языка Java, но стала использоваться и для других языков; существуют десятки высокопроизводительных реализаций JVM, использующих JIT-компиляторы.
    • Существуют варианты трансляции Java в байт-код регистровых машин, например, в виртуальной машине Dalvik (с JIT компиляцией) или при AOT-компиляции в ART
  • Платформа Microsoft .NET использует стековый байт-код Intermediate Language (CIL, MSIL)[8], исполняемый с помощью Common Language Runtime (CLR). См. Управляемый код. Данная платформа была создана Microsoft для языков C# и других.
  • Скриптовый язык JavaScript выполняется различными высокопроизводительными движками, в основном, встроенными в веб-браузеры, часто с возможностью JIT-оптимизации. Многие движки построены с применением байт-кода, однако программы на Javascript распространяются в виде исходных кодов.
  • Скриптовый язык ActionScript транслируется в стековый байт-код, распространяется в составе swf и pdf файлов, и выполняется виртуальными машинами в Adobe Flash и Adobe Acrobat.

Компилятор Clipper создает исполняемый файл, в который включен байт-код, транслированный из исходного текста программы, и виртуальная машина, исполняющая этот байт-код.

Программы на Java обычно компилируются в class-файлы, содержащие байт-код Java. Эти универсальные файлы передаются на различные целевые машины.

В ранних реализациях Visual Basic (до версии 6) использовался высокоуровневый p-code[9]

Высокоуровневые P-коды и байт коды применялись в СУБД, некоторых реализациях BASIC и Паскаля.

В стандарте открытых загрузчиков Open Firmware фирмы Sun Microsystems байт-код представляет операторы языка Forth.

Критика

Традиционно байт-код проектируется в стиле стековых виртуальных машин, что упрощает генерацию из AST, позволяет использовать более простую и компактную кодировку байт-кода, упростить интерпретатор и уменьшить количество машинного кода, требуемого для исполнения одной инструкции байт-кода. С другой стороны, такие варианты байт-кода для заданной программы содержат большее количество инструкций, чем байт-коды регистровых виртуальных машин, из-за чего интерпретатор должен совершить больше непрямых переходов, для которых плохо работает предсказание переходов[3]. Байт-код для регистровых виртуальных машин имеет немного больший размер машинных кодов, однако количество инструкций по сравнению со стековым байт кодом примерно в два раза меньше, а интерпретатор - быстрее на десятки процентов[3]. Также байт-код стековых машин сложнее для проведения оптимизаций (выражения становятся неявными, связанные инструкции не сгруппированы, выражения распределены по нескольким базовым блокам)[12] и требует верификации корректности использования стека[13].

Ошибки верификации байт-кода стековых машин приводили к появлению множества экстремально опасных уязвимостей, в частности десятков в виртуальной машине AVM2, используемой в Adobe Flash для исполнения скриптов ActionScript[14][15][16] и нескольких в ранних популярных системах исполнения Java (JVM)[17][18]

В конце 2000-х - начале 2010-х авторы компиляторов V8 (для языка JavaScript, часто реализуемого через байт-код)[19] и Dart[20] усомнились в том, что промежуточные байткоды обязательны для быстрых и эффективных виртуальных машин. В этих проектах была реализована непосредственная JIT-компляция (компиляция во время исполнения) из исходных кодов сразу в машинный код.[21]

Напишите отзыв о статье "Байт-код"

Примечания

  1. Terence Parr. Language Implementation Patterns — Pragmatic Bookshelf, December 2009, ISBN 978-1-934356-45-6 [www.safaribooksonline.com/library/view/language-implementation-patterns/9781680500097/f_0093.html «Part 3: Building Interpreters. Pattern 27 Stack-Based Bytecode Interpreter»]
  2. Terence Parr. Language Implementation Patterns — Pragmatic Bookshelf, December 2009, ISBN 978-1-934356-45-6 [www.safaribooksonline.com/library/view/language-implementation-patterns/9781680500097/f_0094.html «Part 3: Building Interpreters. Pattern 28 Register-Based Bytecode Interpreter»]
  3. 1 2 3 Yunhe Shi, David Gregg, Andrew Beatty, M. Anton Ertl Virtual Machine Showdown: Stack Versus Registers (англ.) // VEE '05: Proceedings of the 1st ACM/USENIX international conference on Virtual execution environments. — Chicago, Illinois, USA: ACM, 2005. — P. 153 - 163. — ISBN 1-59593-047-7. — DOI:10.1145/1064979.1065001.
  4. [www.cs.purdue.edu/homes/jv/events/PBD13/slides/MarioWolczko.pdf Bringing Performanceand Scalability toDynamic Languages] // Mario Wolczko, Oracle 2012 слайд 7
  5. [www.osp.ru/pcworld/2001/04/161427/ Руслан Богатырев. Летопись языков Паскаль], Мир ПК, № 04/2001
  6. [books.google.ru/books?id=7EES26vGz38C&pg=PA517&lpg=PA517& Компиляторы: принципы, технологии и инструментарий] - Вильямс, ISBN 9785845901897, стр 517 "12.2 Компиляторы Pascal"
  7. [www.threedee.com/jcm/psystem/ THE UCSD P-SYSTEM MUSEUM], 2004
  8. 1 2 [books.google.ru/books?id=2J72ZJOwr_gC&pg=PA92&lpg=PA92& Understanding .NET: A Tutorial and Analysis], David Chappell, David Wayne Chappell, 2002, ISBN 9780201741629 page 92
  9. 1 2 [www1.cs.columbia.edu/~eaddy/publications/csharpvsjava-eaddy-ddj-feb01.htm C# Versus Java] / Dr. Dobb's Journal February 2001
  10. www.javaworld.com/article/2077233/core-java/bytecode-basics.html 1996
  11. Алан Джок. [www.osp.ru/cw/2001/06/9339/ Компиляторы, интерпретаторы и байт-код]. «Computerworld Россия», № 06, 2001. Проверено 18 мая 2015.
  12. Ando Saabas, Tarmo Uustalu [cs.ioc.ee/~tarmo/papers/bytecode07.pdf Type systems for optimizing stack-based code] // Electronic Notes in Theoretical Computer Science. — 2007. — Вып. 190.1. — С. 103-119.. — DOI:10.1016/j.entcs.2007.02.063.: "virtual stack or virtual register VMs can be executed more efficiently using an interpreter. Virtual register machines can be an attractive alternative to stack architectures because they allow the number of executed VM instructions to be substantially reduced."
  13. Gerwin Klein and Martin Wildmoser, [www4.in.tum.de/publ/papers/KleinW-TPHOLs03.pdf Verified Bytecode Subroutines] // Journal of Automated Reasoning 30.3-4 (2003): 363-398. "Bytecode verification is a static check for bytecode safety. Its purpose is to ensure that the JVM only executes safe code: no operand stack over- or underflows, no ill-formed instructions, no type errors"
  14. Mark Dowd (X-Force Researcher IBM Internet Security Systems), [www.inf.fu-berlin.de/groups/ag-si/compsec_assign/Dowd2008.pdf Leveraging the ActionScript Virtual Machine], IBM 2008 "if there was a way to execute AS3 instructions that had never been verified, it would be quite dangerous. Unverified instructions would be able to manipulate the native runtime stack ... The attack works by manipulating a data structure used by the AVM2 verifier such that it doesn’t correctly verify the ActionScript instructions for a given method"
  15. Haifei Li, [www.fortiguard.com/files/CanSecWest2011_Flash_ActionScript.pdf Understanding and Exploiting Flash ActionScript Vulnerabilities], 2011 "Bytecode -> Verification process ... ActionScript Vulnerabilities are due to various program flow calculating errors in the Verification/Generation Process (the Verification Flow and the Execution Flow are not the same)"
  16. Haifei Li (Microsoft), [recon.cx/2012/schedule/attachments/43_Inside_AVM_REcon2012.pdf Inside AVM] // REcon 2012, Montreal "Most Flash vulnerabilities are ActionScript-related ... Faults on verification cause highly-dangerous JIT type confusion vulnerabilities. • highly-dangerous means perfect exploitation: bypassing ASLR+DEP, with %100 reliability, no heapSpray, no JITSpray. • JIT type confusion bugs are due to faults in the verification of AVM!"
  17. The last stage of delirium research group, [www.blackhat.com/presentations/bh-asia-02/LSD/bh-asia-02-lsd.pdf Java and Java Virtual Machine security vulnerabilities and their exploitation techniques], BlackHat 2002: "The flaw stemmed from the fact that Bytecode Verifier did not properly perform the bytecode flow analysis"
  18. [www.ijarcsse.com/docs/papers/Volume_3/3_March2013/V3I3-0108.pdf Verification of Bytecode in a Virtual machine] // International Journal of Advanced Research in Computer Science and Software Engineering Vol.3 Issue 3 March 2013, ISSN 2277-128X: "Java byte code verification has been studied extensively from a correctness perspective, and several vulnerabilities have been found and eliminated in this process"
  19. [developers.google.com/v8/design#mach_code Dynamic Machine Code Generation]. Google.
  20. Loitsch, Florian [www.dartlang.org/articles/why-not-bytecode/ Why Not a Bytecode VM?]. Google.
  21. Dr. Axel Rauschmayer. [www.2ality.com/2012/01/bytecode-myth.html JavaScript myth: JavaScript needs a standard bytecode] (англ.).

Отрывок, характеризующий Байт-код

Одно, другое, третье ядро пролетало над ним, ударялось впереди, с боков, сзади. Пьер сбежал вниз. «Куда я?» – вдруг вспомнил он, уже подбегая к зеленым ящикам. Он остановился в нерешительности, идти ему назад или вперед. Вдруг страшный толчок откинул его назад, на землю. В то же мгновенье блеск большого огня осветил его, и в то же мгновенье раздался оглушающий, зазвеневший в ушах гром, треск и свист.
Пьер, очнувшись, сидел на заду, опираясь руками о землю; ящика, около которого он был, не было; только валялись зеленые обожженные доски и тряпки на выжженной траве, и лошадь, трепля обломками оглобель, проскакала от него, а другая, так же как и сам Пьер, лежала на земле и пронзительно, протяжно визжала.


Пьер, не помня себя от страха, вскочил и побежал назад на батарею, как на единственное убежище от всех ужасов, окружавших его.
В то время как Пьер входил в окоп, он заметил, что на батарее выстрелов не слышно было, но какие то люди что то делали там. Пьер не успел понять того, какие это были люди. Он увидел старшего полковника, задом к нему лежащего на валу, как будто рассматривающего что то внизу, и видел одного, замеченного им, солдата, который, прорываясь вперед от людей, державших его за руку, кричал: «Братцы!» – и видел еще что то странное.
Но он не успел еще сообразить того, что полковник был убит, что кричавший «братцы!» был пленный, что в глазах его был заколон штыком в спину другой солдат. Едва он вбежал в окоп, как худощавый, желтый, с потным лицом человек в синем мундире, со шпагой в руке, набежал на него, крича что то. Пьер, инстинктивно обороняясь от толчка, так как они, не видав, разбежались друг против друга, выставил руки и схватил этого человека (это был французский офицер) одной рукой за плечо, другой за гордо. Офицер, выпустив шпагу, схватил Пьера за шиворот.
Несколько секунд они оба испуганными глазами смотрели на чуждые друг другу лица, и оба были в недоумении о том, что они сделали и что им делать. «Я ли взят в плен или он взят в плен мною? – думал каждый из них. Но, очевидно, французский офицер более склонялся к мысли, что в плен взят он, потому что сильная рука Пьера, движимая невольным страхом, все крепче и крепче сжимала его горло. Француз что то хотел сказать, как вдруг над самой головой их низко и страшно просвистело ядро, и Пьеру показалось, что голова французского офицера оторвана: так быстро он согнул ее.
Пьер тоже нагнул голову и отпустил руки. Не думая более о том, кто кого взял в плен, француз побежал назад на батарею, а Пьер под гору, спотыкаясь на убитых и раненых, которые, казалось ему, ловят его за ноги. Но не успел он сойти вниз, как навстречу ему показались плотные толпы бегущих русских солдат, которые, падая, спотыкаясь и крича, весело и бурно бежали на батарею. (Это была та атака, которую себе приписывал Ермолов, говоря, что только его храбрости и счастью возможно было сделать этот подвиг, и та атака, в которой он будто бы кидал на курган Георгиевские кресты, бывшие у него в кармане.)
Французы, занявшие батарею, побежали. Наши войска с криками «ура» так далеко за батарею прогнали французов, что трудно было остановить их.
С батареи свезли пленных, в том числе раненого французского генерала, которого окружили офицеры. Толпы раненых, знакомых и незнакомых Пьеру, русских и французов, с изуродованными страданием лицами, шли, ползли и на носилках неслись с батареи. Пьер вошел на курган, где он провел более часа времени, и из того семейного кружка, который принял его к себе, он не нашел никого. Много было тут мертвых, незнакомых ему. Но некоторых он узнал. Молоденький офицерик сидел, все так же свернувшись, у края вала, в луже крови. Краснорожий солдат еще дергался, но его не убирали.
Пьер побежал вниз.
«Нет, теперь они оставят это, теперь они ужаснутся того, что они сделали!» – думал Пьер, бесцельно направляясь за толпами носилок, двигавшихся с поля сражения.
Но солнце, застилаемое дымом, стояло еще высоко, и впереди, и в особенности налево у Семеновского, кипело что то в дыму, и гул выстрелов, стрельба и канонада не только не ослабевали, но усиливались до отчаянности, как человек, который, надрываясь, кричит из последних сил.


Главное действие Бородинского сражения произошло на пространстве тысячи сажен между Бородиным и флешами Багратиона. (Вне этого пространства с одной стороны была сделана русскими в половине дня демонстрация кавалерией Уварова, с другой стороны, за Утицей, было столкновение Понятовского с Тучковым; но это были два отдельные и слабые действия в сравнении с тем, что происходило в середине поля сражения.) На поле между Бородиным и флешами, у леса, на открытом и видном с обеих сторон протяжении, произошло главное действие сражения, самым простым, бесхитростным образом.
Сражение началось канонадой с обеих сторон из нескольких сотен орудий.
Потом, когда дым застлал все поле, в этом дыму двинулись (со стороны французов) справа две дивизии, Дессе и Компана, на флеши, и слева полки вице короля на Бородино.
От Шевардинского редута, на котором стоял Наполеон, флеши находились на расстоянии версты, а Бородино более чем в двух верстах расстояния по прямой линии, и поэтому Наполеон не мог видеть того, что происходило там, тем более что дым, сливаясь с туманом, скрывал всю местность. Солдаты дивизии Дессе, направленные на флеши, были видны только до тех пор, пока они не спустились под овраг, отделявший их от флеш. Как скоро они спустились в овраг, дым выстрелов орудийных и ружейных на флешах стал так густ, что застлал весь подъем той стороны оврага. Сквозь дым мелькало там что то черное – вероятно, люди, и иногда блеск штыков. Но двигались ли они или стояли, были ли это французы или русские, нельзя было видеть с Шевардинского редута.
Солнце взошло светло и било косыми лучами прямо в лицо Наполеона, смотревшего из под руки на флеши. Дым стлался перед флешами, и то казалось, что дым двигался, то казалось, что войска двигались. Слышны были иногда из за выстрелов крики людей, но нельзя было знать, что они там делали.
Наполеон, стоя на кургане, смотрел в трубу, и в маленький круг трубы он видел дым и людей, иногда своих, иногда русских; но где было то, что он видел, он не знал, когда смотрел опять простым глазом.
Он сошел с кургана и стал взад и вперед ходить перед ним.
Изредка он останавливался, прислушивался к выстрелам и вглядывался в поле сражения.
Не только с того места внизу, где он стоял, не только с кургана, на котором стояли теперь некоторые его генералы, но и с самых флешей, на которых находились теперь вместе и попеременно то русские, то французские, мертвые, раненые и живые, испуганные или обезумевшие солдаты, нельзя было понять того, что делалось на этом месте. В продолжение нескольких часов на этом месте, среди неумолкаемой стрельбы, ружейной и пушечной, то появлялись одни русские, то одни французские, то пехотные, то кавалерийские солдаты; появлялись, падали, стреляли, сталкивались, не зная, что делать друг с другом, кричали и бежали назад.
С поля сражения беспрестанно прискакивали к Наполеону его посланные адъютанты и ординарцы его маршалов с докладами о ходе дела; но все эти доклады были ложны: и потому, что в жару сражения невозможно сказать, что происходит в данную минуту, и потому, что многие адъютапты не доезжали до настоящего места сражения, а передавали то, что они слышали от других; и еще потому, что пока проезжал адъютант те две три версты, которые отделяли его от Наполеона, обстоятельства изменялись и известие, которое он вез, уже становилось неверно. Так от вице короля прискакал адъютант с известием, что Бородино занято и мост на Колоче в руках французов. Адъютант спрашивал у Наполеона, прикажет ли он пореходить войскам? Наполеон приказал выстроиться на той стороне и ждать; но не только в то время как Наполеон отдавал это приказание, но даже когда адъютант только что отъехал от Бородина, мост уже был отбит и сожжен русскими, в той самой схватке, в которой участвовал Пьер в самом начале сраженья.
Прискакавший с флеш с бледным испуганным лицом адъютант донес Наполеону, что атака отбита и что Компан ранен и Даву убит, а между тем флеши были заняты другой частью войск, в то время как адъютанту говорили, что французы были отбиты, и Даву был жив и только слегка контужен. Соображаясь с таковыми необходимо ложными донесениями, Наполеон делал свои распоряжения, которые или уже были исполнены прежде, чем он делал их, или же не могли быть и не были исполняемы.
Маршалы и генералы, находившиеся в более близком расстоянии от поля сражения, но так же, как и Наполеон, не участвовавшие в самом сражении и только изредка заезжавшие под огонь пуль, не спрашиваясь Наполеона, делали свои распоряжения и отдавали свои приказания о том, куда и откуда стрелять, и куда скакать конным, и куда бежать пешим солдатам. Но даже и их распоряжения, точно так же как распоряжения Наполеона, точно так же в самой малой степени и редко приводились в исполнение. Большей частью выходило противное тому, что они приказывали. Солдаты, которым велено было идти вперед, подпав под картечный выстрел, бежали назад; солдаты, которым велено было стоять на месте, вдруг, видя против себя неожиданно показавшихся русских, иногда бежали назад, иногда бросались вперед, и конница скакала без приказания догонять бегущих русских. Так, два полка кавалерии поскакали через Семеновский овраг и только что въехали на гору, повернулись и во весь дух поскакали назад. Так же двигались и пехотные солдаты, иногда забегая совсем не туда, куда им велено было. Все распоряжение о том, куда и когда подвинуть пушки, когда послать пеших солдат – стрелять, когда конных – топтать русских пеших, – все эти распоряжения делали сами ближайшие начальники частей, бывшие в рядах, не спрашиваясь даже Нея, Даву и Мюрата, не только Наполеона. Они не боялись взыскания за неисполнение приказания или за самовольное распоряжение, потому что в сражении дело касается самого дорогого для человека – собственной жизни, и иногда кажется, что спасение заключается в бегстве назад, иногда в бегстве вперед, и сообразно с настроением минуты поступали эти люди, находившиеся в самом пылу сражения. В сущности же, все эти движения вперед и назад не облегчали и не изменяли положения войск. Все их набегания и наскакивания друг на друга почти не производили им вреда, а вред, смерть и увечья наносили ядра и пули, летавшие везде по тому пространству, по которому метались эти люди. Как только эти люди выходили из того пространства, по которому летали ядра и пули, так их тотчас же стоявшие сзади начальники формировали, подчиняли дисциплине и под влиянием этой дисциплины вводили опять в область огня, в которой они опять (под влиянием страха смерти) теряли дисциплину и метались по случайному настроению толпы.


Генералы Наполеона – Даву, Ней и Мюрат, находившиеся в близости этой области огня и даже иногда заезжавшие в нее, несколько раз вводили в эту область огня стройные и огромные массы войск. Но противно тому, что неизменно совершалось во всех прежних сражениях, вместо ожидаемого известия о бегстве неприятеля, стройные массы войск возвращались оттуда расстроенными, испуганными толпами. Они вновь устроивали их, но людей все становилось меньше. В половине дня Мюрат послал к Наполеону своего адъютанта с требованием подкрепления.